mirror of
https://github.com/jackyzha0/quartz.git
synced 2026-03-24 15:05:42 -05:00
use markdownPlugins
This commit is contained in:
parent
d9b1fb7d37
commit
4cc8a5a192
43
content/roam-test.md
Normal file
43
content/roam-test.md
Normal file
@ -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
|
||||
- 
|
||||
- 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
|
||||
- 
|
||||
- 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
|
||||
@ -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
|
||||
|
||||
@ -63,6 +63,7 @@ const config: QuartzConfig = {
|
||||
},
|
||||
keepBackground: false,
|
||||
}),
|
||||
Plugin.RoamFlavoredMarkdown(),
|
||||
Plugin.ObsidianFlavoredMarkdown({ enableInHtmlEmbed: false }),
|
||||
Plugin.GitHubFlavoredMarkdown(),
|
||||
Plugin.TableOfContents(),
|
||||
|
||||
@ -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<Partial<Options> | 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 = `<select class="roam-or-component">${options.map((option: string) => `<option>${option}</option>`).join("")}</select>`
|
||||
return dropdown
|
||||
})
|
||||
}
|
||||
if (opts.TODOComponent) {
|
||||
src = src.toString()
|
||||
src = src.replaceAll(TODORegex, (value, ...capture) => {
|
||||
const checkbox = '<input type="checkbox" disabled>'
|
||||
return checkbox
|
||||
})
|
||||
}
|
||||
if (opts.DONEComponent) {
|
||||
src = src.toString()
|
||||
src = src.replaceAll(DONERegex, (value, ...capture) => {
|
||||
const checkbox = '<input type="checkbox" checked disabled>'
|
||||
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 = `<iframe width="560" height="315" src="https://www.youtube.com/embed/${text}" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen></iframe>`
|
||||
return video
|
||||
})
|
||||
src = src.replaceAll(videoRegex, (value, ...capture) => {
|
||||
const [match, text] = capture
|
||||
const video = `<video controls><source src="{${match}}" type="video/mp4"><source src="${match}" type="video/webm"></video>`
|
||||
return video
|
||||
})
|
||||
}
|
||||
if (opts.audioComponent) {
|
||||
src = src.toString()
|
||||
src = src.replaceAll(audioRegex, (value, ...capture) => {
|
||||
const [match, text] = capture
|
||||
const audio = `<audio controls>
|
||||
<source src="${match}" type="audio/mpeg">
|
||||
<source src="${match}" type="audio/ogg">
|
||||
Your browser does not support the audio tag.
|
||||
</audio>`
|
||||
return audio
|
||||
})
|
||||
}
|
||||
if (opts.pdfComponent) {
|
||||
src = src.toString()
|
||||
src = src.replaceAll(pdfRegex, (value, ...capture) => {
|
||||
const [match, text] = capture
|
||||
const pdf = `<embed src="${match}" type="application/pdf" width="600" height="800">`
|
||||
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 = `<iframe width="600px" height="350px" src="https://www.youtube.com/embed/${text}" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen></iframe>`
|
||||
// return video
|
||||
// })
|
||||
// src = src.replaceAll(videoRegex, (value, ...capture) => {
|
||||
// const [match, text] = capture
|
||||
// const video = `<video controls><source src="{${match}}" type="video/mp4"><source src="${match}" type="video/webm"></video>`
|
||||
// return video
|
||||
// })
|
||||
// }
|
||||
// if (opts.audioComponent) {
|
||||
// src = src.toString()
|
||||
// src = src.replaceAll(audioRegex, (value, ...capture) => {
|
||||
// const [match, text] = capture
|
||||
// const audio = `<audio controls>
|
||||
// <source src="${match}" type="audio/mpeg">
|
||||
// <source src="${match}" type="audio/ogg">
|
||||
// Your browser does not support the audio tag.
|
||||
// </audio>`
|
||||
// return audio
|
||||
// })
|
||||
// }
|
||||
// if (opts.pdfComponent) {
|
||||
// src = src.toString()
|
||||
// src = src.replaceAll(pdfRegex, (value, ...capture) => {
|
||||
// const [match, text] = capture
|
||||
// const pdf = `<embed src="${match}" type="application/pdf" width="600" height="800">`
|
||||
// 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: `<span class="text-highlight"> ${inner} </span>`,
|
||||
}
|
||||
},
|
||||
])
|
||||
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 <select> element with options
|
||||
const selectHtml: string = `<select>${options.map((option: string) => `<option value="${option}">${option}</option>`).join("")}</select>`;
|
||||
|
||||
return {
|
||||
type: "html",
|
||||
value: selectHtml,
|
||||
};
|
||||
},
|
||||
]);
|
||||
}
|
||||
if (opts.TODOComponent) {
|
||||
replacements.push([
|
||||
TODORegex,
|
||||
(match) => {
|
||||
return {
|
||||
type: "html",
|
||||
value: `<input type="checkbox" disabled>`,
|
||||
}
|
||||
},
|
||||
])
|
||||
}
|
||||
if (opts.DONEComponent) {
|
||||
replacements.push([
|
||||
DONERegex,
|
||||
(match) => {
|
||||
return {
|
||||
type: "html",
|
||||
value: `<input type="checkbox" checked disabled>`,
|
||||
}
|
||||
},
|
||||
])
|
||||
}
|
||||
if (opts.blockquoteComponent) {
|
||||
replacements.push([
|
||||
blockquoteRegex,
|
||||
(match, marker, content) => {
|
||||
const blockquoteHtml = `<blockquote>${content.trim()}</blockquote>`;
|
||||
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 = `<audio controls>
|
||||
<source src="${url}" type="audio/mpeg">
|
||||
<source src="${url}" type="audio/ogg">
|
||||
Your browser does not support the audio tag.
|
||||
</audio>`;
|
||||
|
||||
return {
|
||||
type: "html",
|
||||
value: audioHtml,
|
||||
};
|
||||
}
|
||||
]);
|
||||
}
|
||||
|
||||
mdastFindReplace(tree, replacements)
|
||||
}
|
||||
})
|
||||
return plugins
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user