docs: restore mermaid on pages and mobile

This commit is contained in:
h3p 2026-03-18 11:07:24 +01:00
parent 4370f1259a
commit 0ad19f2a75
4 changed files with 385 additions and 118 deletions

View file

@ -361,7 +361,7 @@
CODE_SIGNING_ALLOWED = YES;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 536;
CURRENT_PROJECT_VERSION = 537;
DEAD_CODE_STRIPPING = YES;
DEVELOPMENT_TEAM = CS727NF72U;
ENABLE_APP_SANDBOX = YES;
@ -444,7 +444,7 @@
CODE_SIGNING_ALLOWED = YES;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 536;
CURRENT_PROJECT_VERSION = 537;
DEAD_CODE_STRIPPING = YES;
DEVELOPMENT_TEAM = CS727NF72U;
ENABLE_APP_SANDBOX = YES;

View file

@ -319,12 +319,55 @@ Create polished share images directly from your selected code.
- Export: use `Share` to generate a PNG snapshot and share/save it.
## Architecture At A Glance
<p align="center">
<a href="docs/images/architecture-at-a-glance.svg">
<img src="docs/images/architecture-at-a-glance.svg" alt="Architecture overview showing platform shells feeding app orchestration, core services, and infrastructure" width="1100">
</a><br>
<sub>Static architecture map for GitHub Pages and mobile browsers.</sub>
</p>
```mermaid
flowchart LR
Mac["Platform: macOS shell (SwiftUI + AppKit bridges)"]
IOS["Platform: iOS/iPadOS shell (SwiftUI + UIKit bridges)"]
ACT["App Layer: user actions (toolbar/menu/shortcuts)"]
VM["App Layer: EditorViewModel (@MainActor state owner)"]
CMD["App Layer: command reducers (Flux-style mutations)"]
IO["Core: file I/O + load/sanitize pipeline"]
HL["Core: syntax highlighting + runtime limits"]
FIND["Core: find/replace + selection engine"]
PREV["Core: markdown preview renderer"]
SAFE["Core: unsupported-file safety guards"]
STORE["Infra: tabs + session restore store"]
PREFS["Infra: settings + persistence"]
SEC["Infra: SecureTokenStore (Keychain)"]
UPD["Infra: release update manager"]
Mac --> ACT
IOS --> ACT
ACT --> VM
VM --> CMD
CMD --> STORE
VM --> IO
VM --> HL
VM --> FIND
VM --> PREV
VM --> SAFE
VM --> PREFS
VM --> UPD
PREFS --> STORE
IO --> STORE
VM --> SEC
classDef platform stroke:#2563EB,stroke-width:3px,fill:transparent,font-family:ui-monospace\, SFMono-Regular\, Menlo\, Monaco\, Consolas\, Liberation Mono\, monospace,font-size:13px;
classDef app stroke:#059669,stroke-width:3px,fill:transparent,font-family:ui-monospace\, SFMono-Regular\, Menlo\, Monaco\, Consolas\, Liberation Mono\, monospace,font-size:13px;
classDef core stroke:#EA580C,stroke-width:3px,fill:transparent,font-family:ui-monospace\, SFMono-Regular\, Menlo\, Monaco\, Consolas\, Liberation Mono\, monospace,font-size:13px;
classDef infra stroke:#9333EA,stroke-width:3px,fill:transparent,font-family:ui-monospace\, SFMono-Regular\, Menlo\, Monaco\, Consolas\, Liberation Mono\, monospace,font-size:13px;
class Mac,IOS platform;
class ACT,VM,CMD app;
class IO,HL,FIND,PREV,SAFE core;
class STORE,PREFS,SEC,UPD infra;
linkStyle 0,1 stroke:#2563EB,stroke-width:2px;
linkStyle 2,3 stroke:#059669,stroke-width:2px;
linkStyle 5,6,7,8,9,13 stroke:#EA580C,stroke-width:2px;
linkStyle 4,10,11,12,14 stroke:#9333EA,stroke-width:2px;
```
- `EditorViewModel` is the single UI-facing orchestration point per window/scene.
- Commands mutate editor state predictably; session/tabs persist through store services.

View file

@ -1,110 +0,0 @@
<svg width="1200" height="760" viewBox="0 0 1200 760" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect width="1200" height="760" rx="32" fill="#F8FAFC"/>
<rect x="24" y="24" width="1152" height="712" rx="28" fill="#FFFFFF" stroke="#E2E8F0" stroke-width="2"/>
<text x="80" y="92" fill="#0F172A" font-family="ui-sans-serif, -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif" font-size="34" font-weight="700">Architecture At A Glance</text>
<text x="80" y="126" fill="#475569" font-family="ui-sans-serif, -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif" font-size="18">Platform shells route actions into shared app orchestration, core services, and infrastructure.</text>
<rect x="80" y="182" width="240" height="78" rx="20" fill="#EFF6FF" stroke="#2563EB" stroke-width="3"/>
<text x="104" y="214" fill="#1D4ED8" font-family="ui-monospace, 'SFMono-Regular', Menlo, monospace" font-size="17" font-weight="700">Platform: macOS shell</text>
<text x="104" y="238" fill="#1E3A8A" font-family="ui-monospace, 'SFMono-Regular', Menlo, monospace" font-size="14">SwiftUI + AppKit bridges</text>
<rect x="80" y="286" width="240" height="78" rx="20" fill="#EFF6FF" stroke="#2563EB" stroke-width="3"/>
<text x="104" y="318" fill="#1D4ED8" font-family="ui-monospace, 'SFMono-Regular', Menlo, monospace" font-size="17" font-weight="700">Platform: iOS/iPadOS shell</text>
<text x="104" y="342" fill="#1E3A8A" font-family="ui-monospace, 'SFMono-Regular', Menlo, monospace" font-size="14">SwiftUI + UIKit bridges</text>
<rect x="420" y="160" width="314" height="86" rx="20" fill="#ECFDF5" stroke="#059669" stroke-width="3"/>
<text x="446" y="193" fill="#047857" font-family="ui-monospace, 'SFMono-Regular', Menlo, monospace" font-size="17" font-weight="700">App Layer: user actions</text>
<text x="446" y="218" fill="#065F46" font-family="ui-monospace, 'SFMono-Regular', Menlo, monospace" font-size="14">toolbar / menu / shortcuts</text>
<rect x="420" y="272" width="314" height="86" rx="20" fill="#ECFDF5" stroke="#059669" stroke-width="3"/>
<text x="446" y="305" fill="#047857" font-family="ui-monospace, 'SFMono-Regular', Menlo, monospace" font-size="17" font-weight="700">App Layer: EditorViewModel</text>
<text x="446" y="330" fill="#065F46" font-family="ui-monospace, 'SFMono-Regular', Menlo, monospace" font-size="14">@MainActor state owner</text>
<rect x="420" y="384" width="314" height="86" rx="20" fill="#ECFDF5" stroke="#059669" stroke-width="3"/>
<text x="446" y="417" fill="#047857" font-family="ui-monospace, 'SFMono-Regular', Menlo, monospace" font-size="17" font-weight="700">App Layer: command reducers</text>
<text x="446" y="442" fill="#065F46" font-family="ui-monospace, 'SFMono-Regular', Menlo, monospace" font-size="14">predictable state mutations</text>
<rect x="800" y="136" width="304" height="72" rx="18" fill="#FFF7ED" stroke="#EA580C" stroke-width="3"/>
<text x="824" y="168" fill="#C2410C" font-family="ui-monospace, 'SFMono-Regular', Menlo, monospace" font-size="16" font-weight="700">Core: file I/O pipeline</text>
<text x="824" y="190" fill="#9A3412" font-family="ui-monospace, 'SFMono-Regular', Menlo, monospace" font-size="13">load / sanitize / decode</text>
<rect x="800" y="226" width="304" height="72" rx="18" fill="#FFF7ED" stroke="#EA580C" stroke-width="3"/>
<text x="824" y="258" fill="#C2410C" font-family="ui-monospace, 'SFMono-Regular', Menlo, monospace" font-size="16" font-weight="700">Core: syntax highlighting</text>
<text x="824" y="280" fill="#9A3412" font-family="ui-monospace, 'SFMono-Regular', Menlo, monospace" font-size="13">runtime limits</text>
<rect x="800" y="316" width="304" height="72" rx="18" fill="#FFF7ED" stroke="#EA580C" stroke-width="3"/>
<text x="824" y="348" fill="#C2410C" font-family="ui-monospace, 'SFMono-Regular', Menlo, monospace" font-size="16" font-weight="700">Core: find / replace</text>
<text x="824" y="370" fill="#9A3412" font-family="ui-monospace, 'SFMono-Regular', Menlo, monospace" font-size="13">selection engine</text>
<rect x="800" y="406" width="304" height="72" rx="18" fill="#FFF7ED" stroke="#EA580C" stroke-width="3"/>
<text x="824" y="438" fill="#C2410C" font-family="ui-monospace, 'SFMono-Regular', Menlo, monospace" font-size="16" font-weight="700">Core: markdown preview</text>
<text x="824" y="460" fill="#9A3412" font-family="ui-monospace, 'SFMono-Regular', Menlo, monospace" font-size="13">renderer + export path</text>
<rect x="800" y="496" width="304" height="72" rx="18" fill="#FFF7ED" stroke="#EA580C" stroke-width="3"/>
<text x="824" y="528" fill="#C2410C" font-family="ui-monospace, 'SFMono-Regular', Menlo, monospace" font-size="16" font-weight="700">Core: unsupported-file safety</text>
<text x="824" y="550" fill="#9A3412" font-family="ui-monospace, 'SFMono-Regular', Menlo, monospace" font-size="13">guardrails + fallback paths</text>
<rect x="420" y="530" width="314" height="72" rx="18" fill="#FAF5FF" stroke="#9333EA" stroke-width="3"/>
<text x="446" y="562" fill="#7E22CE" font-family="ui-monospace, 'SFMono-Regular', Menlo, monospace" font-size="16" font-weight="700">Infra: tabs + session restore</text>
<text x="446" y="584" fill="#6B21A8" font-family="ui-monospace, 'SFMono-Regular', Menlo, monospace" font-size="13">window-isolated persistence</text>
<rect x="420" y="618" width="314" height="72" rx="18" fill="#FAF5FF" stroke="#9333EA" stroke-width="3"/>
<text x="446" y="650" fill="#7E22CE" font-family="ui-monospace, 'SFMono-Regular', Menlo, monospace" font-size="16" font-weight="700">Infra: settings + persistence</text>
<text x="446" y="672" fill="#6B21A8" font-family="ui-monospace, 'SFMono-Regular', Menlo, monospace" font-size="13">preferences + restore policies</text>
<rect x="800" y="618" width="146" height="72" rx="18" fill="#FAF5FF" stroke="#9333EA" stroke-width="3"/>
<text x="822" y="650" fill="#7E22CE" font-family="ui-monospace, 'SFMono-Regular', Menlo, monospace" font-size="16" font-weight="700">Keychain</text>
<text x="822" y="672" fill="#6B21A8" font-family="ui-monospace, 'SFMono-Regular', Menlo, monospace" font-size="13">SecureTokenStore</text>
<rect x="958" y="618" width="146" height="72" rx="18" fill="#FAF5FF" stroke="#9333EA" stroke-width="3"/>
<text x="980" y="650" fill="#7E22CE" font-family="ui-monospace, 'SFMono-Regular', Menlo, monospace" font-size="16" font-weight="700">Updater</text>
<text x="980" y="672" fill="#6B21A8" font-family="ui-monospace, 'SFMono-Regular', Menlo, monospace" font-size="13">release manager</text>
<path d="M320 221H392" stroke="#2563EB" stroke-width="4" stroke-linecap="round"/>
<path d="M320 325H392" stroke="#2563EB" stroke-width="4" stroke-linecap="round"/>
<path d="M392 221L378 213V229L392 221Z" fill="#2563EB"/>
<path d="M392 325L378 317V333L392 325Z" fill="#2563EB"/>
<path d="M577 246V262" stroke="#059669" stroke-width="4" stroke-linecap="round"/>
<path d="M577 272L569 258H585L577 272Z" fill="#059669"/>
<path d="M577 358V374" stroke="#059669" stroke-width="4" stroke-linecap="round"/>
<path d="M577 384L569 370H585L577 384Z" fill="#059669"/>
<path d="M734 315H780" stroke="#EA580C" stroke-width="4" stroke-linecap="round"/>
<path d="M780 315L766 307V323L780 315Z" fill="#EA580C"/>
<path d="M734 315C786 315 786 172 780 172" stroke="#EA580C" stroke-width="3" stroke-linecap="round"/>
<path d="M780 172L766 164V180L780 172Z" fill="#EA580C"/>
<path d="M734 315C790 315 790 262 780 262" stroke="#EA580C" stroke-width="3" stroke-linecap="round"/>
<path d="M780 262L766 254V270L780 262Z" fill="#EA580C"/>
<path d="M734 315C790 315 790 352 780 352" stroke="#EA580C" stroke-width="3" stroke-linecap="round"/>
<path d="M780 352L766 344V360L780 352Z" fill="#EA580C"/>
<path d="M734 315C790 315 790 442 780 442" stroke="#EA580C" stroke-width="3" stroke-linecap="round"/>
<path d="M780 442L766 434V450L780 442Z" fill="#EA580C"/>
<path d="M734 315C790 315 790 532 780 532" stroke="#EA580C" stroke-width="3" stroke-linecap="round"/>
<path d="M780 532L766 524V540L780 532Z" fill="#EA580C"/>
<path d="M577 470V514" stroke="#9333EA" stroke-width="4" stroke-linecap="round"/>
<path d="M577 514L569 500H585L577 514Z" fill="#9333EA"/>
<path d="M577 602V618" stroke="#9333EA" stroke-width="4" stroke-linecap="round"/>
<path d="M577 618L569 604H585L577 618Z" fill="#9333EA"/>
<path d="M734 315C770 315 770 654 790 654" stroke="#9333EA" stroke-width="3" stroke-linecap="round"/>
<path d="M790 654L776 646V662L790 654Z" fill="#9333EA"/>
<path d="M734 315C740 315 740 654 410 654" stroke="#9333EA" stroke-width="3" stroke-linecap="round"/>
<path d="M410 654L424 646V662L410 654Z" fill="#9333EA"/>
<path d="M734 426C770 426 770 566 410 566" stroke="#9333EA" stroke-width="3" stroke-linecap="round"/>
<path d="M410 566L424 558V574L410 566Z" fill="#9333EA"/>
<path d="M734 315C782 315 782 654 948 654" stroke="#9333EA" stroke-width="3" stroke-linecap="round"/>
<path d="M948 654L934 646V662L948 654Z" fill="#9333EA"/>
<circle cx="96" cy="720" r="9" fill="#2563EB"/>
<text x="114" y="726" fill="#1E293B" font-family="ui-sans-serif, -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif" font-size="15">Platform shell</text>
<circle cx="286" cy="720" r="9" fill="#059669"/>
<text x="304" y="726" fill="#1E293B" font-family="ui-sans-serif, -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif" font-size="15">App orchestration</text>
<circle cx="506" cy="720" r="9" fill="#EA580C"/>
<text x="524" y="726" fill="#1E293B" font-family="ui-sans-serif, -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif" font-size="15">Core services</text>
<circle cx="674" cy="720" r="9" fill="#9333EA"/>
<text x="692" y="726" fill="#1E293B" font-family="ui-sans-serif, -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif" font-size="15">Infrastructure</text>
</svg>

Before

Width:  |  Height:  |  Size: 9.7 KiB

334
index.html Normal file
View file

@ -0,0 +1,334 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Neon Vision Editor</title>
<meta name="color-scheme" content="light dark">
<style>
:root {
--page-background: #f5f7fb;
--surface: rgba(255, 255, 255, 0.92);
--surface-border: rgba(148, 163, 184, 0.22);
--text: #0f172a;
--muted: #475569;
--link: #2563eb;
--code-background: #eef2f7;
--code-border: #d7dee8;
--shadow: rgba(15, 23, 42, 0.08);
}
@media (prefers-color-scheme: dark) {
:root {
--page-background: #07111d;
--surface: rgba(9, 16, 28, 0.84);
--surface-border: rgba(148, 163, 184, 0.18);
--text: #e5edf8;
--muted: #94a3b8;
--link: #7fb0ff;
--code-background: #0f172a;
--code-border: #1e293b;
--shadow: rgba(0, 0, 0, 0.28);
}
}
* {
box-sizing: border-box;
}
html, body {
margin: 0;
padding: 0;
background:
radial-gradient(circle at top, rgba(59, 130, 246, 0.08), transparent 28%),
radial-gradient(circle at bottom right, rgba(168, 85, 247, 0.08), transparent 24%),
var(--page-background);
color: var(--text);
font-family: -apple-system, BlinkMacSystemFont, "SF Pro Text", "Segoe UI", sans-serif;
}
a {
color: var(--link);
}
.page-shell {
width: min(1160px, calc(100vw - 24px));
margin: 24px auto 48px;
padding: clamp(20px, 3vw, 40px);
border: 1px solid var(--surface-border);
border-radius: 28px;
background: var(--surface);
backdrop-filter: blur(18px) saturate(1.15);
-webkit-backdrop-filter: blur(18px) saturate(1.15);
box-shadow: 0 18px 50px var(--shadow);
}
.markdown-body {
color: var(--text);
line-height: 1.7;
font-size: 16px;
}
.markdown-body h1,
.markdown-body h2,
.markdown-body h3,
.markdown-body h4 {
line-height: 1.2;
color: var(--text);
}
.markdown-body h1 {
font-size: clamp(2.4rem, 4vw, 3.4rem);
margin-top: 0;
}
.markdown-body h2 {
font-size: clamp(1.7rem, 3vw, 2.3rem);
margin-top: 2rem;
border-bottom: 1px solid color-mix(in srgb, var(--text) 12%, transparent);
padding-bottom: 0.4rem;
}
.markdown-body h3 {
font-size: clamp(1.35rem, 2.2vw, 1.8rem);
}
.markdown-body p,
.markdown-body li,
.markdown-body td,
.markdown-body th,
.markdown-body blockquote {
color: var(--text);
}
.markdown-body blockquote {
margin-left: 0;
padding: 0.7rem 1rem;
border-left: 4px solid color-mix(in srgb, var(--link) 70%, transparent);
background: color-mix(in srgb, var(--link) 8%, transparent);
border-radius: 10px;
}
.markdown-body table {
border-collapse: collapse;
width: 100%;
}
.markdown-body th,
.markdown-body td {
padding: 0.65rem 0.8rem;
border: 1px solid color-mix(in srgb, var(--text) 10%, transparent);
}
.markdown-body img {
max-width: 100%;
height: auto;
border-radius: 16px;
}
.markdown-body pre:not(.mermaid-source) {
overflow: auto;
padding: 1rem 1.1rem;
border-radius: 14px;
background: var(--code-background);
border: 1px solid var(--code-border);
}
.markdown-body code {
font-family: "SF Mono", Menlo, Monaco, Consolas, monospace;
font-size: 0.92em;
}
.mermaid-scroll {
width: 100%;
overflow-x: auto;
overflow-y: hidden;
margin: 1.4rem 0 1rem;
padding-bottom: 6px;
-webkit-overflow-scrolling: touch;
}
.mermaid-host {
min-width: 980px;
text-align: center;
}
.mermaid-host .mermaid {
display: inline-block;
min-width: 980px;
background: transparent;
}
.markdown-body svg {
max-width: none;
}
@media (max-width: 760px) {
.page-shell {
width: min(100vw - 12px, 100%);
margin: 10px auto 24px;
padding: 16px 14px 24px;
border-radius: 20px;
}
.markdown-body {
font-size: 15px;
}
.mermaid-host,
.mermaid-host .mermaid {
min-width: 760px;
}
}
.loading,
.error {
padding: 18px 20px;
border-radius: 16px;
border: 1px solid var(--surface-border);
background: color-mix(in srgb, var(--surface) 92%, transparent);
color: var(--muted);
}
</style>
</head>
<body>
<main class="page-shell">
<article id="content" class="markdown-body">
<div class="loading">Loading README…</div>
</article>
</main>
<script type="module">
import { marked } from "https://cdn.jsdelivr.net/npm/marked/lib/marked.esm.js";
import mermaid from "https://cdn.jsdelivr.net/npm/mermaid@11/dist/mermaid.esm.min.mjs";
const content = document.getElementById("content");
function slugify(text) {
return text
.toLowerCase()
.trim()
.replace(/<[^>]+>/g, "")
.replace(/[^\w\s-]/g, "")
.replace(/\s+/g, "-");
}
function architectureMobileGraph() {
return String.raw`flowchart TB
Mac["Platform: macOS shell (SwiftUI + AppKit bridges)"]
IOS["Platform: iOS/iPadOS shell (SwiftUI + UIKit bridges)"]
ACT["App Layer: user actions (toolbar/menu/shortcuts)"]
VM["App Layer: EditorViewModel (@MainActor state owner)"]
CMD["App Layer: command reducers (Flux-style mutations)"]
IO["Core: file I/O + load/sanitize pipeline"]
HL["Core: syntax highlighting + runtime limits"]
FIND["Core: find/replace + selection engine"]
PREV["Core: markdown preview renderer"]
SAFE["Core: unsupported-file safety guards"]
STORE["Infra: tabs + session restore store"]
PREFS["Infra: settings + persistence"]
SEC["Infra: SecureTokenStore (Keychain)"]
UPD["Infra: release update manager"]
Mac --> ACT
IOS --> ACT
ACT --> VM
VM --> CMD
CMD --> STORE
VM --> IO
VM --> HL
VM --> FIND
VM --> PREV
VM --> SAFE
VM --> PREFS
VM --> UPD
PREFS --> STORE
IO --> STORE
VM --> SEC
classDef platform stroke:#2563EB,stroke-width:3px,fill:transparent,font-family:ui-monospace\, SFMono-Regular\, Menlo\, Monaco\, Consolas\, Liberation Mono\, monospace,font-size:13px;
classDef app stroke:#059669,stroke-width:3px,fill:transparent,font-family:ui-monospace\, SFMono-Regular\, Menlo\, Monaco\, Consolas\, Liberation Mono\, monospace,font-size:13px;
classDef core stroke:#EA580C,stroke-width:3px,fill:transparent,font-family:ui-monospace\, SFMono-Regular\, Menlo\, Monaco\, Consolas\, Liberation Mono\, monospace,font-size:13px;
classDef infra stroke:#9333EA,stroke-width:3px,fill:transparent,font-family:ui-monospace\, SFMono-Regular\, Menlo\, Monaco\, Consolas\, Liberation Mono\, monospace,font-size:13px;
class Mac,IOS platform;
class ACT,VM,CMD app;
class IO,HL,FIND,PREV,SAFE core;
class STORE,PREFS,SEC,UPD infra;
linkStyle 0,1 stroke:#2563EB,stroke-width:2px;
linkStyle 2,3 stroke:#059669,stroke-width:2px;
linkStyle 5,6,7,8,9,13 stroke:#EA580C,stroke-width:2px;
linkStyle 4,10,11,12,14 stroke:#9333EA,stroke-width:2px;`;
}
function wrapMermaid(source) {
return `<div class="mermaid-scroll"><div class="mermaid-host"><pre class="mermaid">${source}</pre></div></div>`;
}
function escapeHTML(text) {
return text
.replaceAll("&", "&amp;")
.replaceAll("<", "&lt;")
.replaceAll(">", "&gt;")
.replaceAll("\"", "&quot;")
.replaceAll("'", "&#39;");
}
function patchArchitectureMermaid(markdown) {
if (window.innerWidth > 760) {
return markdown;
}
return markdown.replace(
/## Architecture At A Glance\s+```mermaid[\s\S]*?```/,
`## Architecture At A Glance\n\n\`\`\`mermaid\n${architectureMobileGraph()}\n\`\`\``
);
}
const renderer = new marked.Renderer();
renderer.heading = ({ tokens, depth }) => {
const text = marked.parserInline(tokens);
const id = slugify(text);
return `<h${depth} id="${id}">${text}</h${depth}>`;
};
renderer.code = ({ text, lang }) => {
if (lang === "mermaid") {
return wrapMermaid(text);
}
const languageClass = lang ? ` class="language-${lang}"` : "";
return `<pre><code${languageClass}>${escapeHTML(text)}</code></pre>`;
};
marked.setOptions({
gfm: true,
breaks: false,
renderer
});
mermaid.initialize({
startOnLoad: false,
securityLevel: "loose",
theme: window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "default"
});
async function render() {
try {
const response = await fetch("./README.md", { cache: "no-store" });
if (!response.ok) {
throw new Error(`README request failed: ${response.status}`);
}
let markdown = await response.text();
markdown = patchArchitectureMermaid(markdown);
content.innerHTML = marked.parse(markdown);
await mermaid.run({
nodes: content.querySelectorAll(".mermaid")
});
} catch (error) {
content.innerHTML = `<div class="error">Failed to render README for GitHub Pages.<br><code>${String(error)}</code></div>`;
}
}
render();
</script>
</body>
</html>