102 lines
3.4 KiB
JavaScript
102 lines
3.4 KiB
JavaScript
// Make Mermaid diagrams use the active site theme and zoom controls.
|
|
(function () {
|
|
function cssVar(name, fallback) {
|
|
const value = getComputedStyle(document.documentElement).getPropertyValue(name).trim();
|
|
return value || fallback;
|
|
}
|
|
|
|
function mermaidConfig() {
|
|
return {
|
|
startOnLoad: false,
|
|
theme: "base",
|
|
themeVariables: {
|
|
background: cssVar("--bg", "#faf9f6"),
|
|
mainBkg: cssVar("--surface", "#ffffff"),
|
|
primaryColor: cssVar("--surface", "#ffffff"),
|
|
primaryTextColor: cssVar("--fg", "#000000"),
|
|
primaryBorderColor: cssVar("--accent", "#2563eb"),
|
|
secondaryColor: cssVar("--surface-soft", "#f3f1eb"),
|
|
tertiaryColor: cssVar("--bg", "#faf9f6"),
|
|
clusterBkg: cssVar("--surface-soft", "#f3f1eb"),
|
|
clusterBorder: cssVar("--border", "#d7d7d7"),
|
|
lineColor: cssVar("--border", "#d7d7d7"),
|
|
textColor: cssVar("--fg", "#000000"),
|
|
edgeLabelBackground: cssVar("--surface", "#ffffff"),
|
|
fontFamily: cssVar("--font-body", "Noto, system-ui, sans-serif")
|
|
},
|
|
flowchart: {
|
|
htmlLabels: true,
|
|
curve: "basis"
|
|
}
|
|
};
|
|
}
|
|
|
|
function decodeMermaidSource(source) {
|
|
const textarea = document.createElement("textarea");
|
|
textarea.innerHTML = source;
|
|
return textarea.value.trim();
|
|
}
|
|
|
|
async function renderMermaid() {
|
|
if (!window.mermaid) return;
|
|
const diagrams = document.querySelectorAll(".mermaid");
|
|
if (!diagrams.length) return;
|
|
|
|
diagrams.forEach((el) => {
|
|
if (!el.dataset.source) {
|
|
el.dataset.source = decodeMermaidSource(el.textContent || el.innerHTML);
|
|
}
|
|
el.removeAttribute("data-processed");
|
|
el.innerHTML = el.dataset.source;
|
|
});
|
|
|
|
mermaid.initialize(mermaidConfig());
|
|
await mermaid.run({ querySelector: ".mermaid" });
|
|
wrapMermaidDiagrams();
|
|
}
|
|
|
|
function wrapMermaidDiagrams() {
|
|
document.querySelectorAll(".mermaid").forEach((el) => {
|
|
if (el.closest(".mermaid-container")) return;
|
|
|
|
const container = document.createElement("div");
|
|
container.className = "mermaid-container";
|
|
if ((el.dataset.source || "").includes('root(["zxh"])')) {
|
|
container.classList.add("mermaid-container--site-map");
|
|
}
|
|
const controls = document.createElement("div");
|
|
controls.className = "mermaid-zoom-controls";
|
|
controls.innerHTML = `
|
|
<button class="zoom-in" type="button" aria-label="Zoom in">+</button>
|
|
<button class="zoom-out" type="button" aria-label="Zoom out">-</button>
|
|
`;
|
|
|
|
el.replaceWith(container);
|
|
container.appendChild(controls);
|
|
container.appendChild(el);
|
|
|
|
let scale = 1;
|
|
const setScale = (next) => {
|
|
const svg = container.querySelector(".mermaid svg");
|
|
if (!svg) return;
|
|
scale = Math.max(0.2, Math.min(3, next));
|
|
svg.style.transform = `scale(${scale})`;
|
|
};
|
|
|
|
controls.querySelector(".zoom-in").addEventListener("click", () => setScale(scale + 0.1));
|
|
controls.querySelector(".zoom-out").addEventListener("click", () => setScale(scale - 0.1));
|
|
container.addEventListener("wheel", (e) => {
|
|
if (!e.ctrlKey) return;
|
|
e.preventDefault();
|
|
setScale(scale + (e.deltaY < 0 ? 0.05 : -0.05));
|
|
});
|
|
});
|
|
}
|
|
|
|
if (document.readyState === "loading") {
|
|
document.addEventListener("DOMContentLoaded", renderMermaid);
|
|
} else {
|
|
renderMermaid();
|
|
}
|
|
})();
|