Skip to content

Commit

Permalink
Better react mermaid (#9)
Browse files Browse the repository at this point in the history
* Improve styles

* Improve rendering logic

* Update tests with not mirrored actors
  • Loading branch information
abefernan authored Oct 2, 2024
1 parent b8f8359 commit 6cd05ad
Show file tree
Hide file tree
Showing 2 changed files with 64 additions and 74 deletions.
134 changes: 62 additions & 72 deletions components/mermaid.tsx
Original file line number Diff line number Diff line change
@@ -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) =>
({
"&lt;": "<",
"&gt;": ">",
"&amp;": "&",
"&#39;": "'",
"&quot;": '"',
})[tag] ?? "";
const htmlReplacer = {
regex: /(&lt;|&gt;|&amp;|&#39;|&quot;)/g,
fn: (tag: string) =>
({ "&lt;": "<", "&gt;": ">", "&amp;": "&", "&#39;": "'", "&quot;": '"' })[
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(
/(&lt;|&gt;|&amp;|&#39;|&quot;)/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 ? <div className="mermaid">{chart}</div> : null;
return renderStage !== "server" ? (
<div className={cn("mermaid", renderStage !== "mermaid" && "hidden")}>
{chart}
</div>
) : null;
}
4 changes: 2 additions & 2 deletions tests/e2e/happy-paths.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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();
});

0 comments on commit 6cd05ad

Please sign in to comment.