diff --git a/docs/javascripts/mermaid-override.js b/docs/javascripts/mermaid-override.js new file mode 100644 index 0000000..311f8aa --- /dev/null +++ b/docs/javascripts/mermaid-override.js @@ -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()); diff --git a/docs/mcp_layout.md b/docs/mcp_layout.md index 2e085fd..527bd5e 100644 --- a/docs/mcp_layout.md +++ b/docs/mcp_layout.md @@ -10,44 +10,47 @@ It also treats Markdown as the single source of truth for both MCP resources and ## Completed-State Layout -```text -project-root/ -| -|- pyproject.toml -|- uv.lock -|- zensical.toml -| -|- docs/ -| |- index.md -| |- architecture.md -| |- mcp_layout.md -| -|- site/ -| |- ... static files built by zensical ... -| -|- skills/ -| |- pytest-scaffolding/ -| | |- SKILL.md -| | |- references/ -| |- python-logging-dictconfig/ -| | |- SKILL.md -| | |- references/ -| |- fastapi-uv-docker/ -| |- SKILL.md -| |- references/ -| -|- src/ - |- personal_mcp/ - |- main.py - |- web/ - | |- app.py - | |- docs_mount.py - |- catalog/ - | |- server.py - |- skills/ - |- pytest_scaffolding/ - |- python_logging_dictconfig/ - |- fastapi_uv_docker/ +```mermaid +--- +config: + themeVariables: + treeView: + labelColor: '#FFFFFF' + lineColor: '#FFFFFF' +--- +treeView-beta + "project-root" + "pyproject.toml" + "uv.lock" + "zensical.toml" + "docs" + "index.md" + "architecture.md" + "mcp_layout.md" + "site" + "static build output" + "skills" + "pytest-scaffolding" + "SKILL.md" + "references" + "python-logging-dictconfig" + "SKILL.md" + "references" + "fastapi-uv-docker" + "SKILL.md" + "references" + "src" + "personal_mcp" + "main.py" + "web" + "app.py" + "docs_mount.py" + "catalog" + "server.py" + "skills" + "pytest_scaffolding" + "python_logging_dictconfig" + "fastapi_uv_docker" ``` Notes: diff --git a/docs/stylesheets/mermaid-override.css b/docs/stylesheets/mermaid-override.css new file mode 100644 index 0000000..1994698 --- /dev/null +++ b/docs/stylesheets/mermaid-override.css @@ -0,0 +1,14 @@ +.mermaid svg text, +.mermaid svg tspan, +.mermaid svg foreignObject, +.mermaid svg foreignObject div, +.mermaid svg foreignObject span, +.mermaid svg .nodeLabel, +.mermaid svg .edgeLabel { + color: var(--md-primary-bg-color, #fff); + fill: var(--md-primary-bg-color, #fff); +} + +.mermaid svg .treeView-node-label { + fill: var(--md-primary-bg-color, #fff) !important; +} diff --git a/zensical.toml b/zensical.toml index 1c51255..3721108 100644 --- a/zensical.toml +++ b/zensical.toml @@ -57,7 +57,7 @@ Copyright © 2026 The authors # # Read more: https://zensical.org/docs/customization/#additional-css # -#extra_css = ["stylesheets/extra.css"] +extra_css = ["stylesheets/mermaid-override.css"] # With the `extra_javascript` option you can add your own JavaScript to your # project to customize the behavior according to your needs. @@ -65,7 +65,7 @@ Copyright © 2026 The authors # The path provided should be relative to the "docs_dir". # # Read more: https://zensical.org/docs/customization/#additional-javascript -#extra_javascript = ["javascripts/extra.js"] +extra_javascript = ["javascripts/mermaid-override.js"] # ---------------------------------------------------------------------------- # Section for configuring theme options