// Author: Simon-Pierre Boucher // Contact: contact@spboucher.ai // Project: chat.spboucher.ai "use client"; import { memo, useState, type ReactNode } from "react"; import ReactMarkdown from "react-markdown"; import remarkGfm from "remark-gfm"; import remarkMath from "remark-math"; import rehypeKatex from "rehype-katex"; import rehypeHighlight from "rehype-highlight"; function CodeBlock({ className, children }: { className?: string; children?: ReactNode }) { const [copied, setCopied] = useState(false); const language = /language-(\w+)/.exec(className ?? "")?.[1] ?? ""; const 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 ""; }; const copy = async () => { try { await navigator.clipboard.writeText(extractText(children)); setCopied(true); setTimeout(() => setCopied(false), 1500); } catch { /* clipboard unavailable */ } }; return (
{language || "text"}
{children}
);
}
export const Markdown = memo(function Markdown({ content }: { content: string }) {
return (
{children};
},
a: ({ href, children }) => (
{children}
),
}}
>
{content}