mirror of
https://github.com/abhigyanpatwari/GitNexus.git
synced 2026-08-28 05:25:25 +00:00
mermaid fixes
This commit is contained in:
parent
898e28ba1f
commit
055f13f9c8
5 changed files with 1304 additions and 1487 deletions
2576
gitnexus/package-lock.json
generated
2576
gitnexus/package-lock.json
generated
File diff suppressed because it is too large
Load diff
|
|
@ -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"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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
6
package-lock.json
generated
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"name": "GitnexusV2",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {}
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue