Skip to content

Commit ddcdc1a

Browse files
committed
Use global script instead of Mermaid component to avoid wrapping all the code fences into it
1 parent 27a42f4 commit ddcdc1a

File tree

5 files changed

+103
-79
lines changed

5 files changed

+103
-79
lines changed

src/components/Mermaid.astro

Lines changed: 0 additions & 79 deletions
This file was deleted.

src/globals.css

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -512,6 +512,11 @@ astro-island[component-export="GraphQLEditor"] {
512512
}
513513
}
514514

515+
/* Using attribute selector instead of :has() for better compatibility */
516+
figure pre[data-language="mermaid"] {
517+
display: none;
518+
}
519+
515520
header.header {
516521
padding-top: 0;
517522
padding-bottom: 0;

src/lib/mermaid.ts

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
import { cssId } from "./random/cssId";
2+
import { ensureNonNullable } from "~/lib/ensureNonNullable";
3+
import type { Theme } from "~/lib/theme";
4+
import { $theme } from "~/stores/theme";
5+
import { createIntersectionObserverAtom } from "~/lib/nanostores/createIntersectionObserverAtom";
6+
import { effect } from "~/lib/nanostores/effect";
7+
8+
interface MermaidOptions {
9+
id: string;
10+
container: HTMLElement;
11+
graph: string;
12+
theme: Theme;
13+
}
14+
15+
async function renderMermaid({ id, container, graph, theme }: MermaidOptions) {
16+
const { default: mermaid } = await import("mermaid");
17+
18+
try {
19+
mermaid.initialize({
20+
startOnLoad: false,
21+
securityLevel: "loose",
22+
fontFamily: "inherit",
23+
themeCSS: "margin: 1.5rem auto 0;",
24+
theme: theme === "dark" ? "dark" : "default",
25+
});
26+
27+
container.innerHTML = (await mermaid.render(id, graph)).svg;
28+
} catch (error) {
29+
// eslint-disable-next-line no-console -- show error
30+
console.error("Error while rendering mermaid", error);
31+
}
32+
}
33+
34+
function upsertGraphContainer(element: HTMLDivElement) {
35+
let container: HTMLDivElement | null = element.querySelector(".mermaid-graph");
36+
37+
if (!container) {
38+
container = document.createElement("div");
39+
container.classList.add("mermaid-graph");
40+
element.appendChild(container);
41+
}
42+
43+
return container;
44+
}
45+
46+
export function processMermaidExpressiveCodeBlock() {
47+
const expressiveCodeBlocks = document.querySelectorAll<HTMLDivElement>(".expressive-code");
48+
49+
for (const codeBlock of expressiveCodeBlocks) {
50+
const { $atom: $diagramIsVisible, intersectionObserver } = createIntersectionObserverAtom({
51+
element: codeBlock,
52+
initialValue: false,
53+
mapper: (entry) => entry.isIntersecting,
54+
observerOptions: {
55+
rootMargin: "0px 0px 100% 0px", // Trigger when it is on the next screen
56+
},
57+
});
58+
const id = cssId();
59+
60+
effect([$diagramIsVisible, $theme], (diagramIsVisible, theme) => {
61+
if (!diagramIsVisible) {
62+
return;
63+
}
64+
65+
// Disconnect the observer once the diagram is visible
66+
// $diagramIsVisible will never change after this point
67+
intersectionObserver?.disconnect();
68+
69+
const container = upsertGraphContainer(codeBlock);
70+
const copyButton = ensureNonNullable(
71+
codeBlock.querySelector<HTMLButtonElement>(".copy button"),
72+
);
73+
const graphData = (copyButton.dataset.code ?? "")
74+
.replace(/\u007F/g, "\n")
75+
.replaceAll("\\n", "\n");
76+
77+
void renderMermaid({ id, theme, graph: graphData, container });
78+
});
79+
}
80+
}

src/lib/random/cssId.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
const alphabet = "abcdefghijklmnopqrstuvwxyz";
2+
3+
export function cssId(length = 20) {
4+
const randomArray = crypto.getRandomValues(new Uint8Array(length));
5+
let id = "";
6+
7+
for (const i of randomArray) {
8+
id += alphabet[i % alphabet.length] ?? "";
9+
}
10+
11+
return id;
12+
}

src/starlight-overrides/Head.astro

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,13 @@ const ogImageUrl = await getImageUrl(new URL("/api/og-image.png", Astro.site), {
4242
}
4343
<meta name="twitter:title" content={entryData.title} />
4444
{entryData.description && <meta name="twitter:description" content={entryData.description} />}
45+
<script>
46+
import { processMermaidExpressiveCodeBlock } from "~/lib/mermaid";
4547

48+
document.addEventListener("DOMContentLoaded", () => {
49+
processMermaidExpressiveCodeBlock();
50+
});
51+
</script>
4652
<!-- <style is:global>
4753
::view-transition-old(root),
4854
::view-transition-new(root) {

0 commit comments

Comments
 (0)