/* * Markdown.tsx * Zyquo Cloud Web * * Author: Simon-Pierre Boucher * Mail: contact@spboucher.ai * * Assistant message rendering: GitHub-flavored Markdown with syntax- * highlighted code blocks (language label, copy, wrap toggle) mapped to the * Zyquo syntax tokens. Memoized — re-parsing only when text changes. */ import { lazy, memo, Suspense, useState, type ReactNode } from 'react' import ReactMarkdown from 'react-markdown' import remarkGfm from 'remark-gfm' import remarkMath from 'remark-math' import rehypeHighlight from 'rehype-highlight' import rehypeKatex from 'rehype-katex' import 'katex/dist/katex.min.css' import { IconCheck, IconCopy } from './icons' const Mermaid = lazy(() => import('./Mermaid')) function extractText(node: ReactNode): string { if (typeof node === 'string') return node if (Array.isArray(node)) return node.map(extractText).join('') if (node && typeof node === 'object' && 'props' in node) { return extractText((node as { props: { children?: ReactNode } }).props.children) } return '' } function CodeBlock({ className, children }: { className?: string; children?: ReactNode }) { const [copied, setCopied] = useState(false) const [wrap, setWrap] = useState(false) const language = /language-(\w+)/.exec(className ?? '')?.[1] ?? '' const copy = () => { void navigator.clipboard.writeText(extractText(children).replace(/\n$/, '')) setCopied(true) setTimeout(() => setCopied(false), 1200) } return (
{children}
{children}
)
}
if (/language-mermaid/.test(className ?? '')) {
return (