AUDIT / src /components /MermaidBlock.tsx
Arypulka98's picture
feat(audit): deploy full backend cluster node
aea470f verified
Raw
History Blame Contribute Delete
2.96 kB
import { memo, useEffect, useRef, useState } from "react";
interface MermaidBlockProps { content: string }
let mermaidLoaded = false;
let mermaidInstance: typeof import("mermaid").default | null = null;
async function getMermaid() {
if (mermaidInstance) return mermaidInstance;
const m = await import("mermaid");
mermaidInstance = m.default;
if (!mermaidLoaded) {
mermaidInstance.initialize({
startOnLoad: false,
securityLevel: "sandbox", // S167-Fix3: previene esecuzione JS in SVG
theme: "dark",
themeVariables: {
primaryColor: "#1a3a6b",
primaryTextColor: "#e2e2f0",
primaryBorderColor: "#2a3a5e",
lineColor: "#4f8ef7",
secondaryColor: "#12121f",
tertiaryColor: "#12121f",
background: "#0a0a0f",
mainBkg: "#12121f",
nodeBorder: "#2a2a40",
clusterBkg: "#12121f",
titleColor: "#e2e2f0",
edgeLabelBackground: "#12121f",
fontSize: "13px",
},
flowchart: { curve: "basis" },
});
mermaidLoaded = true;
}
return mermaidInstance;
}
const MermaidBlock = memo(function MermaidBlock({ content }: MermaidBlockProps) {
const [svg, setSvg] = useState<string | null>(null);
const [error, setError] = useState<string | null>(null);
const [loading, setLoading] = useState(true);
const idRef = useRef(`mermaid-${Math.random().toString(36).slice(2)}`);
useEffect(() => {
let cancelled = false;
setLoading(true); setSvg(null); setError(null);
(async () => {
try {
const mermaid = await getMermaid();
const { svg } = await mermaid.render(idRef.current, content.trim());
if (!cancelled) { setSvg(svg); setLoading(false); }
} catch (e) {
if (!cancelled) {
setError(e instanceof Error ? e.message : "Errore parsing Mermaid");
setLoading(false);
}
}
})();
return () => { cancelled = true; };
}, [content]);
return (
<div style={{ background: "#0d0d18", border: "1px solid #1e1e2e", borderRadius: 10, marginBottom: "0.6em", overflow: "hidden" }}>
<div style={{ display: "flex", alignItems: "center", gap: 6, padding: "0.4rem 0.85rem", background: "#0a0a14", borderBottom: "1px solid #1e1e2e" }}>
<span style={{ fontSize: "0.78rem", color: "#6b6b7b", fontWeight: 600 }}>Diagramma</span>
{loading && <span className="spin" style={{ fontSize: "0.8rem", color: "#6b6b7b" }}></span>}
</div>
<div style={{ padding: "0.75rem", display: "flex", justifyContent: "center", minHeight: 60 }}>
{loading && <div style={{ color: "#5a5a72", fontSize: "0.78rem", alignSelf: "center" }}>Rendering...</div>}
{error && <div style={{ color: "#fca5a5", fontSize: "0.78rem" }}>! {error}</div>}
{svg && <div dangerouslySetInnerHTML={{ __html: svg }} style={{ maxWidth: "100%", overflow: "auto" }} />}
</div>
</div>
);
}
);
export default MermaidBlock;