import markdownItLatex from "@vscode/markdown-it-katex" import MarkdownIt, { Options, Renderer, Token } from "markdown-it" import blockEmbedPlugin from "markdown-it-block-embed" import markdownItCheckbox from "markdown-it-checkbox" import MarkdownItGitHubAlerts from "markdown-it-github-alerts" import markdownItIframe from "markdown-it-iframe" import Shikiji from "markdown-it-shikiji" import { Ref, toValue } from "vue" import { decodeBase64ToUTF8 } from "@/utils/decodeBase64ToUTF8" import { html5Media } from "@/utils/markdown/markdown-html5-media" import { twitterPlugin } from "@/utils/markdown/markdown-it-twitter" import mermaid from "mermaid" const markdownItMermaidExtractor = (md: MarkdownIt) => { const defaultFence = md.renderer.rules.fence || function ( tokens: Array, index: number, options: Options, _: unknown, self: Renderer, ) { return self.renderToken(tokens, index, options) } md.renderer.rules.fence = function ( tokens: Array, index: number, options: Options, env: unknown, self: Renderer, ) { const token = tokens[index] if (token.info.trim() === "mermaid") { const content = token.content.trim() return `
\n${md.utils.escapeHtml(content)}\n
\n` } return defaultFence(tokens, index, options, env, self) } } const md = new MarkdownIt({ typographer: true, quotes: ["«\xA0", "\xA0»", "‹\xA0", "\xA0›"], }) .use(markdownItMermaidExtractor) .use(html5Media) .use(blockEmbedPlugin, { youtube: { width: "100%", height: 300, }, }) .use(twitterPlugin) .use(markdownItCheckbox) .use(markdownItLatex) .use(markdownItIframe, { width: "100%", }) .use(MarkdownItGitHubAlerts) let shikijiInitialized = false export const useShikiji = async () => { if (shikijiInitialized) { return } shikijiInitialized = true md.use( await Shikiji({ themes: { light: "vitesse-light", dark: "vitesse-black", }, langs: [ "bash", "javascript", "typescript", "markdown", "mermaid", "html", "css", "json", ], }), ) } let mermaidInitialized = false export const runMermaid = (querySelector: string) => { if (!mermaidInitialized) { mermaidInitialized = true mermaid.initialize({ theme: "dark", startOnLoad: false, flowchart: { curve: "natural" }, }) } mermaid.run({ querySelector, }) } const rules: Renderer.RenderRuleRecord = { table_open: () => '
', table_close: () => "
", } md.renderer.rules = { ...md.renderer.rules, ...rules } export const markdownBuilder = (defaultPrefix?: Ref | string) => { const getRawContent = (content: string) => decodeBase64ToUTF8(content) const renderFromUTF8 = (content: string, prefix?: string) => content ? md.render(content, { docId: defaultPrefix ? toValue(defaultPrefix) : (prefix ?? ""), }) : "" return { toHTML: (content: string) => (content ? md.render(content) : ""), render: (content: string, prefix?: string) => renderFromUTF8(decodeBase64ToUTF8(content), prefix), renderFromUTF8, getRawContent, } }