diff --git a/components/mermaid.tsx b/components/mermaid.tsx index dd6bc32..c13d40b 100644 --- a/components/mermaid.tsx +++ b/components/mermaid.tsx @@ -1,94 +1,84 @@ "use client"; +import { cn } from "@/lib/utils"; import mermaid from "mermaid"; import { useEffect, useState } from "react"; mermaid.initialize({ startOnLoad: true, - theme: "default", securityLevel: "loose", + sequence: { mirrorActors: false }, + theme: "base", + themeVariables: { + background: "#fff", + mainBkg: "#fff", + primaryColor: "#fff", + textColor: "#171717", + lineColor: "#171717", + actorBorder: "#171717", + }, themeCSS: ` - g.classGroup rect { - fill: #282a36; - stroke: #6272a4; - } - g.classGroup text { - fill: #f8f8f2; + .actor { + stroke-width: 2px; } - g.classGroup line { - stroke: #f8f8f2; - stroke-width: 0.5; - } - .classLabel .box { - stroke: #21222c; - stroke-width: 3; - fill: #21222c; - opacity: 1; - } - .classLabel .label { - fill: #f1fa8c; - } - .relation { - stroke: #ff79c6; - stroke-width: 1; - } - #compositionStart, #compositionEnd { - fill: #bd93f9; - stroke: #bd93f9; - stroke-width: 1; - } - #aggregationEnd, #aggregationStart { - fill: #21222c; - stroke: #50fa7b; - stroke-width: 1; + + .messageText a { + text-decoration: underline; } - #dependencyStart, #dependencyEnd { - fill: #00bcd4; - stroke: #00bcd4; - stroke-width: 1; - } - #extensionStart, #extensionEnd { - fill: #f8f8f2; - stroke: #f8f8f2; - stroke-width: 1; - }`, - fontFamily: "Fira Code", + `, }); -const replacer = (tag: string) => - ({ - "<": "<", - ">": ">", - "&": "&", - "'": "'", - """: '"', - })[tag] ?? ""; +const htmlReplacer = { + regex: /(<|>|&|'|")/g, + fn: (tag: string) => + ({ "<": "<", ">": ">", "&": "&", "'": "'", """: '"' })[ + tag + ] ?? "", +}; export default function Mermaid({ chart }: { chart: string }) { - const [isBrowserRendering, setIsBrowserRendering] = useState(false); + const [renderStage, setRenderStage] = useState< + "server" | "browser" | "mermaid" + >("server"); + + useEffect(() => { + setRenderStage("browser"); + }, []); useEffect(() => { - if (isBrowserRendering) { - mermaid.contentLoaded(); + if (renderStage !== "browser") { + return; + } + + mermaid.contentLoaded(); + + const interval = setInterval(() => { + const msgs = Array.from( + document.getElementsByClassName("messageText"), + ) as HTMLElement[]; - setTimeout(() => { - const elems = Array.from( - document.getElementsByClassName("messageText"), - ) as HTMLElement[]; + if (!msgs.length) { + return; + } - for (const elem of elems) { - if (elem.textContent?.startsWith("<")) { - elem.innerHTML = elem.innerHTML.replace( - /(<|>|&|'|")/g, - replacer, - ); - } + for (const msg of msgs) { + if (msg.textContent?.startsWith("<")) { + msg.innerHTML = msg.innerHTML.replace( + htmlReplacer.regex, + htmlReplacer.fn, + ); } - }, 100); - } else { - setIsBrowserRendering(true); - } - }, [isBrowserRendering]); + } + + setRenderStage("mermaid"); + }); + + return () => clearInterval(interval); + }, [renderStage]); - return isBrowserRendering ?
{chart}
: null; + return renderStage !== "server" ? ( +
+ {chart} +
+ ) : null; } diff --git a/tests/e2e/happy-paths.test.ts b/tests/e2e/happy-paths.test.ts index 46fe4e6..8889220 100644 --- a/tests/e2e/happy-paths.test.ts +++ b/tests/e2e/happy-paths.test.ts @@ -28,11 +28,11 @@ test("navigates to a correctly rendered tx detail", async ({ page }) => { //TODO: use non-image snapshot testing (for svg) await expect( page.getByText("slay3r1pkptre7fdkl6gfrzlesjjvhxhlc3r4gmvk3r3j"), - ).toHaveCount(2); + ).toHaveCount(1); await expect( page.getByText("slay3r1fqg7raeca9peg0zkfp629m92qnjrpyggd2cfgj"), - ).toHaveCount(2); + ).toHaveCount(1); await expect(page.getByText("Send")).toBeVisible(); });