feat: complete MDX migration for blog, fix diagram fidelity and refactor styling architecture

This commit is contained in:
2026-02-17 21:36:59 +01:00
parent bff58e7cfa
commit cce6aa0935
75 changed files with 12282 additions and 12227 deletions

View File

@@ -5,22 +5,67 @@ import mermaid from "mermaid";
import { DiagramShareButton } from "./DiagramShareButton";
interface MermaidProps {
graph: string;
graph?: string;
children?: React.ReactNode;
id?: string;
title?: string;
showShare?: boolean;
fontSize?: string;
nodeFontSize?: string;
labelFontSize?: string;
actorFontSize?: string;
messageFontSize?: string;
noteFontSize?: string;
titleFontSize?: string;
sectionFontSize?: string;
legendFontSize?: string;
}
export const Mermaid: React.FC<MermaidProps> = ({
graph,
children,
id: providedId,
title,
showShare = false,
fontSize = "16px",
nodeFontSize,
labelFontSize,
actorFontSize,
messageFontSize,
noteFontSize,
titleFontSize,
sectionFontSize,
legendFontSize,
}) => {
const [id, setId] = useState<string | null>(null);
const containerRef = useRef<HTMLDivElement>(null);
const [svgContent, setSvgContent] = useState<string>("");
// Extract text from React children nodes (MDX parses multi-line content as React nodes)
const extractTextFromChildren = (node: React.ReactNode): string => {
if (typeof node === 'string') return node;
if (typeof node === 'number') return String(node);
if (Array.isArray(node)) return node.map(extractTextFromChildren).join('\n');
if (React.isValidElement(node)) {
const props = node.props as { children?: React.ReactNode };
if (props.children) {
return extractTextFromChildren(props.children);
}
}
return '';
};
const rawGraph = graph || extractTextFromChildren(children) || "";
// MDXRemote double-escapes \n in plain string props (e.g., "graph TD\\nA-->B" becomes "graph TD\\\\nA-->B")
// We need to unescape these back to real newlines for Mermaid to parse
const sanitizedGraph = rawGraph
.trim()
.replace(/^`+|`+$/g, '')
.replace(/\\n/g, '\n')
.replace(/\\"/g, '"')
.replace(/\\'/g, "'");
useEffect(() => {
setId(
providedId || `mermaid-${Math.random().toString(36).substring(2, 11)}`,
@@ -63,7 +108,15 @@ export const Mermaid: React.FC<MermaidProps> = ({
// Font
fontFamily: "Inter, system-ui, sans-serif",
fontSize: "14px",
fontSize: fontSize,
nodeFontSize: nodeFontSize || fontSize,
labelFontSize: labelFontSize || fontSize,
actorFontSize: actorFontSize || fontSize,
messageFontSize: messageFontSize || fontSize,
noteFontSize: noteFontSize || fontSize,
titleFontSize: titleFontSize || "20px",
sectionFontSize: sectionFontSize || fontSize,
legendFontSize: legendFontSize || fontSize,
// Pie Chart Colors - High Contrast Industrial Palette
pie1: "#0f172a", // Deep Navy
@@ -84,14 +137,21 @@ export const Mermaid: React.FC<MermaidProps> = ({
const render = async () => {
if (containerRef.current && id) {
if (!sanitizedGraph || sanitizedGraph.trim() === "") {
console.warn("Mermaid: Empty or invalid graph provided, skipping render.");
return;
}
try {
const { svg } = await mermaid.render(`${id}-svg`, graph);
const { svg } = await mermaid.render(`${id}-svg`, sanitizedGraph);
containerRef.current.innerHTML = svg;
setSvgContent(svg);
setIsRendered(true);
} catch (err) {
console.error("Mermaid rendering failed:", err);
setError("Failed to render diagram. Please check the syntax.");
console.error("Graph that failed:", sanitizedGraph);
const errorMessage = err instanceof Error ? err.message : String(err);
setError(`Failed to render diagram: ${errorMessage}`);
setIsRendered(true);
}
}
@@ -100,7 +160,7 @@ export const Mermaid: React.FC<MermaidProps> = ({
if (id) {
render();
}
}, [graph, id]);
}, [sanitizedGraph, id]);
if (!id) return null;
@@ -127,7 +187,7 @@ export const Mermaid: React.FC<MermaidProps> = ({
{error}
</div>
) : (
graph
sanitizedGraph
)}
</div>
</div>