diff --git a/content/roam-test.md b/content/roam-test.md new file mode 100644 index 000000000..ddc9a03b8 --- /dev/null +++ b/content/roam-test.md @@ -0,0 +1,43 @@ +### OR + +{{or:ONE|TWO|THREE}} + +### Tasks + +- {{[[TODO]]}} unchecked +- {{TODO}} unchecked +- {{[[DONE]]}} checked +- {{DONE}} checked + +### Text Styling + +- **Bold** +- __Italics__ +- Highlights ^^of some^^ words +- this one, ~~not this one~~ +- Blockquotes + - [[>]] Regulare quote using page brackets + - > bare quote without brackets + +### Uploaded Files + +- image + - ![](https://firebasestorage.googleapis.com/v0/b/firescript-577a2.appspot.com/o/imgs%2Fapp%2FMattVogel%2Ftiz3q_Bm-P.png?alt=media&token=ede018a1-ba7d-4099-8e6c-fa225550ef0e) +- video + - {{[[video]]: https://firebasestorage.googleapis.com/v0/b/firescript-577a2.appspot.com/o/imgs%2Fapp%2FMattVogel%2FBY1tSter6R.mp4?alt=media&token=07031095-4736-4b0b-899a-26852adbf245}} + - youtube + - {{[[video]]: https://www.youtube.com/watch?v=y1f6bfiSH94}} +- gif + - ![](https://firebasestorage.googleapis.com/v0/b/firescript-577a2.appspot.com/o/imgs%2Fapp%2FMattVogel%2FzAgByL_oF2.gif?alt=media&token=f754e4ba-aadb-43ad-82de-a2f79dc66370) +- pdf + - {{[[pdf]]: https://firebasestorage.googleapis.com/v0/b/firescript-577a2.appspot.com/o/imgs%2Fapp%2FMattVogel%2F6FtyOTB3mx.pdf?alt=media&token=0736266f-54d2-46dc-99a8-08f7e7874210}} +- audio + - This is being selected + - {{[[audio]]: this_works_and_is_selected}} + - This is not for some reason + - {{[[audio]]: https://firebasestorage.googleapis.com/v0/b/firescript-577a2.appspot.com/o/imgs%2Fapp%2FMattVogel%2FZ37C1oBWmW.mp3?alt=media&token=433c0926-dbea-47f5-ab4f-3ec4659ba815}} +- binary files + - regular file + - https://firebasestorage.googleapis.com/v0/b/firescript-577a2.appspot.com/o/imgs%2Fapp%2FMattVogel%2FkQXZxVL_6G.txt?alt=media&token=f35c8688-0ff4-4d59-845a-3bcaa53fc1ea + - .zip file + - https://firebasestorage.googleapis.com/v0/b/firescript-577a2.appspot.com/o/imgs%2Fapp%2FMattVogel%2FEzyEq4p2Zn.zip?alt=media&token=0697c12e-654d-46a6-943e-fe13293870ba diff --git a/docs/plugins/RoamFlavoredMarkdown.md b/docs/plugins/RoamFlavoredMarkdown.md index c709ecb18..227dba3d8 100644 --- a/docs/plugins/RoamFlavoredMarkdown.md +++ b/docs/plugins/RoamFlavoredMarkdown.md @@ -16,7 +16,7 @@ This plugin accepts the following configuration options: - `DONEComponent`: If `true` (default), converts Roam `{{[[DONE]]}}` shortcodes into checked html check boxes. - `videoComponent`: If `true` (default), converts Roam `{{[[video]]:URL}}` shortcodes into embeded HTML video. - `audioComponent`: If `true` (default), converts Roam `{{[[audio]]:URL}}` shortcodes into embeded HTML audio. -- `pdfComponent`: If `true` (default), converts Roam `{{[[audio]]:URL}}` shortcodes into embeded HTML PDF viewer. +- `pdfComponent`: If `true` (default), converts Roam `{{[[pdf]]:URL}}` shortcodes into embeded HTML PDF viewer. - `blockquoteComponent`: If `true` (default), converts Roam `{{[[>]]}}` shortcodes into quartz blockquotes. ## API diff --git a/quartz.config.ts b/quartz.config.ts index 2cdadb740..80030f0a3 100644 --- a/quartz.config.ts +++ b/quartz.config.ts @@ -63,6 +63,7 @@ const config: QuartzConfig = { }, keepBackground: false, }), + Plugin.RoamFlavoredMarkdown(), Plugin.ObsidianFlavoredMarkdown({ enableInHtmlEmbed: false }), Plugin.GitHubFlavoredMarkdown(), Plugin.TableOfContents(), diff --git a/quartz/plugins/transformers/roam.ts b/quartz/plugins/transformers/roam.ts index 130158532..e2f2a8967 100644 --- a/quartz/plugins/transformers/roam.ts +++ b/quartz/plugins/transformers/roam.ts @@ -1,4 +1,9 @@ import { QuartzTransformerPlugin } from "../types" +import { PluggableList } from "unified" +import { SKIP, visit } from "unist-util-visit" +import { Root, Html, BlockContent, DefinitionContent, Paragraph, Code } from "mdast" +import { FilePath, pathToRoot, slugTag, slugifyFilePath } from "../../util/path" +import { ReplaceFunction, findAndReplace as mdastFindReplace } from "mdast-util-find-and-replace" export interface Options { orComponent: boolean @@ -30,9 +35,12 @@ const DONERegex = new RegExp(/{{.*?\bDONE\b.*?}}/, "g") const videoRegex = new RegExp(/{{.*?\bvideo\b.*?\:(.*?)}}/, "g") const youtubeRegex = new RegExp(/{{.*?\bvideo\b.*?(\bhttp.*?\byoutu.*?)watch\?v=(.*?)}}/, "g") +// const multimediaRegex = new RegExp(/{{.*?\b(video|audio)\b.*?\:(.*?)}}/, "g") + + const audioRegex = new RegExp(/{{.*?\baudio\b.*?\:(.*?)}}/, "g") const pdfRegex = new RegExp(/{{.*?\bpdf\b.*?\:(.*?)}}/, "g") -const blockquoteRegex = new RegExp(/\[\[>\]\]/, "g") +const blockquoteRegex = new RegExp(/(\[\[>\]\])\s*(.*)/, "g"); const roamHighlightRegex = new RegExp(/\^\^(.+)\^\^/, "g") const roamItalicRegex = new RegExp(/__(.+)__/, "g") const tableRegex = new RegExp(/- {{.*?\btable\b.*?}}/, "g") /* TODO */ @@ -46,87 +54,167 @@ export const RoamFlavoredMarkdown: QuartzTransformerPlugin | un return { name: "RoamFlavoredMarkdown", textTransform(_ctx, src) { - if (opts.orComponent) { - src = src.toString() - src = src.replaceAll(orRegex, (value, ...capture) => { - const [match, text] = capture - const options = match.split("|") - const id = Math.random().toString(36).substring(2, 15) // Generate a unique ID - const dropdown = `` - return dropdown - }) - } - if (opts.TODOComponent) { - src = src.toString() - src = src.replaceAll(TODORegex, (value, ...capture) => { - const checkbox = '' - return checkbox - }) - } - if (opts.DONEComponent) { - src = src.toString() - src = src.replaceAll(DONERegex, (value, ...capture) => { - const checkbox = '' - return checkbox - }) - } - if (opts.videoComponent) { - //youtube first then regular video links - src = src.toString() - src = src.replaceAll(youtubeRegex, (value, ...capture) => { - const [match, text] = capture - const video = `` - return video - }) - src = src.replaceAll(videoRegex, (value, ...capture) => { - const [match, text] = capture - const video = `` - return video - }) - } - if (opts.audioComponent) { - src = src.toString() - src = src.replaceAll(audioRegex, (value, ...capture) => { - const [match, text] = capture - const audio = `` - return audio - }) - } - if (opts.pdfComponent) { - src = src.toString() - src = src.replaceAll(pdfRegex, (value, ...capture) => { - const [match, text] = capture - const pdf = `` - return pdf - }) - } - if (opts.blockquoteComponent) { - src = src.toString() - src = src.replaceAll(blockquoteRegex, (value, ...capture) => { - const bq = `>` - return bq - }) - } + // if (opts.videoComponent) { + // //youtube first then regular video links + // src = src.toString() + // src = src.replaceAll(youtubeRegex, (value, ...capture) => { + // const [match, text] = capture + // const video = `` + // return video + // }) + // src = src.replaceAll(videoRegex, (value, ...capture) => { + // const [match, text] = capture + // const video = `` + // return video + // }) + // } + // if (opts.audioComponent) { + // src = src.toString() + // src = src.replaceAll(audioRegex, (value, ...capture) => { + // const [match, text] = capture + // const audio = `` + // return audio + // }) + // } + // if (opts.pdfComponent) { + // src = src.toString() + // src = src.replaceAll(pdfRegex, (value, ...capture) => { + // const [match, text] = capture + // const pdf = `` + // return pdf + // }) + // } + // if (opts.blockquoteComponent) { + // src = src.toString() + // src = src.replaceAll(blockquoteRegex, (value, ...capture) => { + // const bq = `>` + // return bq + // }) + // } // TODO attributes in roam are sort of like block level frontmatter or tags - src = src.toString() - src = src.replaceAll(roamHighlightRegex, (value, ...capture) => { - const [match, text] = capture - const highlight = `==${match}==` - return highlight - }) // roam italics + if (src instanceof Buffer) { + src = src.toString() + } + src = src.replaceAll(roamItalicRegex, (value, ...capture) => { const [match, text] = capture const italic = `*${match}*` return italic }) + return src }, + + markdownPlugins(ctx) { + const plugins: PluggableList = [] + const cfg = ctx.cfg.configuration + + plugins.push(() => { + return (tree: Root, file) => { + const replacements: [RegExp, string | ReplaceFunction][] = [] + const base = pathToRoot(file.data.slug!) + // roam highlight syntax + replacements.push([ + roamHighlightRegex, + (_value: string, ...capture: string[]) => { + const [inner] = capture + return { + type: "html", + value: ` ${inner} `, + } + }, + ]) + if (opts.orComponent) { + replacements.push([ + orRegex, + (match: string) => { + // Attempt to extract the content within the curly braces and split by '|' + const matchResult = match.match(/{{or:(.*?)}}/); + if (matchResult === null) { + // Handle the case where no match is found, e.g., return an empty string or some default value + return { type: "html", value: "" }; + } + + const optionsString: string = matchResult[1]; + const options: string[] = optionsString.split("|"); + + // Generate the HTML ${options.map((option: string) => ``).join("")}`; + + return { + type: "html", + value: selectHtml, + }; + }, + ]); + } + if (opts.TODOComponent) { + replacements.push([ + TODORegex, + (match) => { + return { + type: "html", + value: ``, + } + }, + ]) + } + if (opts.DONEComponent) { + replacements.push([ + DONERegex, + (match) => { + return { + type: "html", + value: ``, + } + }, + ]) + } + if (opts.blockquoteComponent) { + replacements.push([ + blockquoteRegex, + (match, marker, content) => { + const blockquoteHtml = `
${content.trim()}
`; + return { + type: "html", + value: blockquoteHtml, + }; + }, + ]); + } + if (opts.audioComponent) { + replacements.push([ + audioRegex, + (_value: string, ...capture: string[]) => { + const [url] = capture; + console.log(""); + console.log(" ~", capture); + + const audioHtml = ``; + + return { + type: "html", + value: audioHtml, + }; + } + ]); + } + + mdastFindReplace(tree, replacements) + } + }) + return plugins + }, } }