mermaid fixes

This commit is contained in:
abhigyanpatwari 2026-01-18 01:04:24 +05:30
parent 898e28ba1f
commit 055f13f9c8
5 changed files with 1304 additions and 1487 deletions

File diff suppressed because it is too large Load diff

View file

@ -11,12 +11,12 @@
"dependencies": {
"@huggingface/transformers": "^3.0.0",
"@isomorphic-git/lightning-fs": "^4.6.2",
"@langchain/anthropic": "^0.3.34",
"@langchain/core": "^0.3.0",
"@langchain/google-genai": "^0.1.0",
"@langchain/langgraph": "^0.2.74",
"@langchain/anthropic": "^1.3.10",
"@langchain/core": "^1.1.15",
"@langchain/google-genai": "^2.1.10",
"@langchain/langgraph": "^1.1.0",
"@langchain/ollama": "^1.2.0",
"@langchain/openai": "^0.3.0",
"@langchain/openai": "^1.2.2",
"@sigma/edge-curve": "^3.1.0",
"@tailwindcss/vite": "^4.1.18",
"axios": "^1.13.2",
@ -30,7 +30,7 @@
"isomorphic-git": "^1.36.1",
"jszip": "^3.10.1",
"kuzu-wasm": "^0.11.1",
"langchain": "^0.3.37",
"langchain": "^1.2.10",
"lru-cache": "^11.2.4",
"lucide-react": "^0.562.0",
"mermaid": "^11.12.2",
@ -61,4 +61,4 @@
"vite": "^5.2.0",
"vite-plugin-static-copy": "^3.1.4"
}
}
}

View file

@ -72,89 +72,96 @@ export const MarkdownRenderer: React.FC<MarkdownRendererProps> = ({
// External links open in new tab (default behavior)
};
const formattedContent = formatMarkdownForDisplay(content);
const formattedContent = React.useMemo(() => formatMarkdownForDisplay(content), [content]);
const markdownComponents = React.useMemo(() => ({
a: ({ href, children, ...props }: any) => {
const hrefStr = href || '';
// Grounding links (Code refs & Node refs)
if (hrefStr.startsWith('code-ref:') || hrefStr.startsWith('node-ref:')) {
const isNodeRef = hrefStr.startsWith('node-ref:');
const inner = decodeURIComponent(hrefStr.slice(isNodeRef ? 9 : 9)); // length is same? wait.. code-ref: (9), node-ref: (9). Yes.
// Styles
const baseParams = "code-ref-btn inline-flex items-center px-2 py-0.5 rounded-md font-mono text-[12px] !no-underline hover:!no-underline transition-colors";
const colorParams = isNodeRef
? "border border-amber-300/55 bg-amber-400/10 !text-amber-200 visited:!text-amber-200 hover:bg-amber-400/15 hover:border-amber-200/70"
: "border border-cyan-300/55 bg-cyan-400/10 !text-cyan-200 visited:!text-cyan-200 hover:bg-cyan-400/15 hover:border-cyan-200/70";
return (
<a
href={hrefStr}
onClick={(e) => handleLinkClick(e, hrefStr)}
className={`${baseParams} ${colorParams}`}
title={isNodeRef ? `View ${inner} in Code panel` : `Open in Code panel • ${inner}`}
{...props}
>
<span className="text-inherit">{children}</span>
</a>
);
}
// External links
return (
<a
href={hrefStr}
className="text-accent underline underline-offset-2 hover:text-purple-300"
target="_blank"
rel="noopener noreferrer"
{...props}
>
{children}
</a>
);
},
code: ({ className, children, ...props }: any) => {
const match = /language-(\w+)/.exec(className || '');
const isInline = !className && !match;
const codeContent = String(children).replace(/\n$/, '');
if (isInline) {
return <code {...props}>{children}</code>;
}
const language = match ? match[1] : 'text';
// Render Mermaid diagrams
if (language === 'mermaid') {
return <MermaidDiagram code={codeContent} />;
}
return (
<SyntaxHighlighter
style={customTheme}
language={language}
PreTag="div"
customStyle={{
margin: 0,
padding: '14px 16px',
borderRadius: '8px',
fontSize: '13px',
background: '#0a0a10',
border: '1px solid #1e1e2a',
}}
>
{codeContent}
</SyntaxHighlighter>
);
},
pre: ({ children }: any) => <>{children}</>,
}), [onLinkClick]); // Removed handleLinkClick dependency as it is defined inside component but depends on onLinkClick
return (
<div className="text-text-primary text-sm">
<ReactMarkdown
remarkPlugins={[remarkGfm]}
components={{
a: ({ href, children, ...props }) => {
const hrefStr = href || '';
// Grounding links (Code refs & Node refs)
if (hrefStr.startsWith('code-ref:') || hrefStr.startsWith('node-ref:')) {
const isNodeRef = hrefStr.startsWith('node-ref:');
const inner = decodeURIComponent(hrefStr.slice(isNodeRef ? 9 : 9)); // length is same? wait.. code-ref: (9), node-ref: (9). Yes.
// Styles
const baseParams = "code-ref-btn inline-flex items-center px-2 py-0.5 rounded-md font-mono text-[12px] !no-underline hover:!no-underline transition-colors";
const colorParams = isNodeRef
? "border border-amber-300/55 bg-amber-400/10 !text-amber-200 visited:!text-amber-200 hover:bg-amber-400/15 hover:border-amber-200/70"
: "border border-cyan-300/55 bg-cyan-400/10 !text-cyan-200 visited:!text-cyan-200 hover:bg-cyan-400/15 hover:border-cyan-200/70";
return (
<a
href={hrefStr}
onClick={(e) => handleLinkClick(e, hrefStr)}
className={`${baseParams} ${colorParams}`}
title={isNodeRef ? `View ${inner} in Code panel` : `Open in Code panel • ${inner}`}
{...props}
>
<span className="text-inherit">{children}</span>
</a>
);
}
// External links
return (
<a
href={hrefStr}
className="text-accent underline underline-offset-2 hover:text-purple-300"
target="_blank"
rel="noopener noreferrer"
{...props}
>
{children}
</a>
);
},
code: ({ className, children, ...props }) => {
const match = /language-(\w+)/.exec(className || '');
const isInline = !className && !match;
const codeContent = String(children).replace(/\n$/, '');
if (isInline) {
return <code {...props}>{children}</code>;
}
const language = match ? match[1] : 'text';
// Render Mermaid diagrams
if (language === 'mermaid') {
return <MermaidDiagram code={codeContent} />;
}
return (
<SyntaxHighlighter
style={customTheme}
language={language}
PreTag="div"
customStyle={{
margin: 0,
padding: '14px 16px',
borderRadius: '8px',
fontSize: '13px',
background: '#0a0a10',
border: '1px solid #1e1e2a',
}}
>
{codeContent}
</SyntaxHighlighter>
);
},
pre: ({ children }) => <>{children}</>,
urlTransform={(url) => {
if (url.startsWith('code-ref:') || url.startsWith('node-ref:')) return url;
// Default behavior for http/https/etc
return url;
}}
components={markdownComponents}
>
{formattedContent}
</ReactMarkdown>
@ -170,3 +177,5 @@ export const MarkdownRenderer: React.FC<MarkdownRendererProps> = ({
</div>
);
};

View file

@ -36,8 +36,14 @@ mermaid.initialize({
},
fontFamily: '"JetBrains Mono", "Fira Code", monospace',
fontSize: 13,
suppressErrorRendering: true, // Prevent default error div appending
});
// Override the default error handler to prevent it from logging to UI
mermaid.parseError = (_err) => {
// Silent catch
};
interface MermaidDiagramProps {
code: string;
}
@ -55,19 +61,27 @@ export const MermaidDiagram = ({ code }: MermaidDiagramProps) => {
try {
// Generate unique ID for this diagram
const id = `mermaid-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
// Render the diagram
const { svg: renderedSvg } = await mermaid.render(id, code.trim());
setSvg(renderedSvg);
setError(null);
} catch (err) {
console.error('Mermaid render error:', err);
setError(err instanceof Error ? err.message : 'Failed to render diagram');
setSvg('');
// Silent catch for streaming:
// If render fails (common during partial streaming), we:
// 1. Log to console for debugging
// 2. Do NOT set error state (avoids flashing red box)
// 3. Do NOT clear existing SVG (keeps last valid state visible)
console.debug('Mermaid render skipped (incomplete):', err);
}
};
renderDiagram();
// Debounce rendering to prevent "jerking" during high-speed streaming
const timeoutId = setTimeout(() => {
renderDiagram();
}, 300);
return () => clearTimeout(timeoutId);
}, [code]);
if (error) {
@ -94,12 +108,12 @@ export const MermaidDiagram = ({ code }: MermaidDiagramProps) => {
<div className={`my-3 relative group ${isExpanded ? 'fixed inset-4 z-50' : ''}`}>
{/* Backdrop for expanded view */}
{isExpanded && (
<div
<div
className="absolute inset-0 -m-4 bg-deep/95 backdrop-blur-sm"
onClick={() => setIsExpanded(false)}
/>
)}
<div className={`
relative bg-gradient-to-b from-surface to-elevated
border border-border-subtle rounded-xl overflow-hidden
@ -122,9 +136,9 @@ export const MermaidDiagram = ({ code }: MermaidDiagramProps) => {
)}
</button>
</div>
{/* Diagram container */}
<div
<div
ref={containerRef}
className={`
flex items-center justify-center p-4 overflow-auto

6
package-lock.json generated Normal file
View file

@ -0,0 +1,6 @@
{
"name": "GitnexusV2",
"lockfileVersion": 3,
"requires": true,
"packages": {}
}