mermaid diagram
This commit is contained in:
@@ -0,0 +1,98 @@
|
||||
let mermaidPromise;
|
||||
|
||||
async function getMermaid() {
|
||||
if (!mermaidPromise) {
|
||||
mermaidPromise = import("https://cdn.jsdelivr.net/npm/mermaid@11/dist/mermaid.esm.min.mjs").then(
|
||||
(module) => {
|
||||
const mermaid = module.default ?? module;
|
||||
mermaid.initialize({ startOnLoad: false });
|
||||
return mermaid;
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
return mermaidPromise;
|
||||
}
|
||||
|
||||
function readDiagramSource(block) {
|
||||
const code = block.querySelector("code");
|
||||
return (code?.textContent ?? block.textContent ?? "").trim();
|
||||
}
|
||||
|
||||
async function renderBlock(block) {
|
||||
if (block.dataset.mermaidOverrideState) {
|
||||
return;
|
||||
}
|
||||
|
||||
const source = readDiagramSource(block);
|
||||
if (!source) {
|
||||
block.dataset.mermaidOverrideState = "empty";
|
||||
return;
|
||||
}
|
||||
|
||||
block.dataset.mermaidOverrideState = "pending";
|
||||
|
||||
try {
|
||||
const mermaid = await getMermaid();
|
||||
const replacement = document.createElement("div");
|
||||
replacement.className = "mermaid";
|
||||
replacement.textContent = source;
|
||||
replacement.dataset.mermaidOverrideState = "rendered";
|
||||
block.replaceWith(replacement);
|
||||
await mermaid.run({ nodes: [replacement] });
|
||||
} catch (error) {
|
||||
block.dataset.mermaidOverrideState = "failed";
|
||||
console.warn("Mermaid override failed", error);
|
||||
}
|
||||
}
|
||||
|
||||
function findBlocks(root = document) {
|
||||
const blocks = [];
|
||||
|
||||
if (root instanceof Element && root.matches("pre.mermaid")) {
|
||||
blocks.push(root);
|
||||
}
|
||||
|
||||
if (root instanceof Document || root instanceof Element) {
|
||||
blocks.push(...root.querySelectorAll("pre.mermaid"));
|
||||
}
|
||||
|
||||
return blocks;
|
||||
}
|
||||
|
||||
function renderAll(root = document) {
|
||||
for (const block of findBlocks(root)) {
|
||||
void renderBlock(block);
|
||||
}
|
||||
}
|
||||
|
||||
function installObserver() {
|
||||
if (!(document.body instanceof HTMLBodyElement)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const observer = new MutationObserver((mutations) => {
|
||||
for (const mutation of mutations) {
|
||||
for (const node of mutation.addedNodes) {
|
||||
if (node instanceof Element) {
|
||||
renderAll(node);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
observer.observe(document.body, { childList: true, subtree: true });
|
||||
}
|
||||
|
||||
if (document.readyState === "loading") {
|
||||
document.addEventListener("DOMContentLoaded", () => {
|
||||
renderAll();
|
||||
installObserver();
|
||||
});
|
||||
} else {
|
||||
renderAll();
|
||||
installObserver();
|
||||
}
|
||||
|
||||
window.addEventListener("pageshow", () => renderAll());
|
||||
window.addEventListener("popstate", () => renderAll());
|
||||
Reference in New Issue
Block a user