diff --git a/frontend/package.json b/frontend/package.json index b0f1df0..d7619ec 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -8,6 +8,7 @@ "@testing-library/react": "^16.3.2", "@testing-library/user-event": "^13.5.0", "lucide-react": "^0.563.0", + "mermaid": "^11.14.0", "react": "^19.2.4", "react-dom": "^19.2.4", "react-markdown": "^10.1.0", diff --git a/frontend/src/components/KnowledgeBaseViewer.js b/frontend/src/components/KnowledgeBaseViewer.js index ef95789..a4a7144 100644 --- a/frontend/src/components/KnowledgeBaseViewer.js +++ b/frontend/src/components/KnowledgeBaseViewer.js @@ -1,7 +1,72 @@ -import React, { useState, useEffect } from 'react'; +import React, { useState, useEffect, useRef } from 'react'; import ReactMarkdown from 'react-markdown'; +import mermaid from 'mermaid'; import { X, Download, Loader, AlertCircle, FileText, File } from 'lucide-react'; +mermaid.initialize({ + startOnLoad: false, + theme: 'dark', + darkMode: true, + themeVariables: { + background: '#0f172a', + primaryColor: '#1e3a5f', + primaryTextColor: '#e2e8f0', + primaryBorderColor: '#0ea5e9', + lineColor: '#475569', + secondaryColor: '#1a2e1a', + tertiaryColor: '#2d1f14', + edgeLabelBackground: '#1e293b', + clusterBkg: '#1e293b', + titleColor: '#e2e8f0', + fontFamily: 'monospace' + } +}); + +let mermaidCounter = 0; + +function MermaidDiagram({ code }) { + const ref = useRef(null); + const [svgError, setSvgError] = useState(''); + + useEffect(() => { + let cancelled = false; + const id = `mermaid-kb-${++mermaidCounter}`; + mermaid.render(id, code) + .then(({ svg }) => { + if (!cancelled && ref.current) { + ref.current.innerHTML = svg; + // Make SVG responsive + const svgEl = ref.current.querySelector('svg'); + if (svgEl) { + svgEl.removeAttribute('width'); + svgEl.removeAttribute('height'); + svgEl.style.width = '100%'; + svgEl.style.maxWidth = '100%'; + } + } + }) + .catch((err) => { + if (!cancelled) setSvgError(err.message || 'Failed to render diagram'); + }); + return () => { cancelled = true; }; + }, [code]); + + if (svgError) { + return ( +
+ Mermaid render error: {svgError}
+
+ );
+ }
+
+ return (
+
+ );
+}
+
const API_BASE = process.env.REACT_APP_API_BASE || 'http://localhost:3001/api';
export default function KnowledgeBaseViewer({ article, onClose }) {
@@ -167,7 +232,26 @@ export default function KnowledgeBaseViewer({ article, onClose }) {
{/* Markdown Rendering */}
{isMarkdown && (
+ {children}
+
+ );
+ }
+ }}
+ >
+ {content}
+