import type React from "react"; import { useState, useRef, useEffect } from "react"; import { Copy, Check } from "lucide-react"; import hljs from "highlight.js"; import "highlight.js/styles/github-dark.css"; interface CodeBlockProps { language: string; code: string; } const CodeBlock: React.FC = ({ language, code }) => { const [copied, setCopied] = useState(false); const codeRef = useRef(null); useEffect(() => { if (codeRef.current) { codeRef.current.removeAttribute("data-highlighted"); hljs.highlightElement(codeRef.current); } }, [code, language]); const handleCopy = async () => { await navigator.clipboard.writeText(code); setCopied(true); setTimeout(() => setCopied(false), 2000); }; return (
{language || "code"}
        
          {code}
        
      
); }; function looksLikeCode(text: string): boolean { const result = hljs.highlightAuto(text); return result.relevance > 5; } function parseContent(text: string): React.ReactNode[] { const parts: React.ReactNode[] = []; const codeBlockRegex = /```(\w*)\n([\s\S]*?)```/g; let lastIndex = 0; let match; while ((match = codeBlockRegex.exec(text)) !== null) { if (match.index > lastIndex) { const textBefore = text.slice(lastIndex, match.index); parts.push( {textBefore} , ); } parts.push( , ); lastIndex = match.index + match[0].length; } if (lastIndex < text.length) { const remaining = text.slice(lastIndex); // If no code fences were found and the content looks like code, render as code block if (lastIndex === 0 && remaining.trim().length > 0 && looksLikeCode(remaining)) { const detected = hljs.highlightAuto(remaining); parts.push( , ); } else { parts.push( {remaining} , ); } } return parts; } export const ChatMessage: React.FC<{ role: "user" | "assistant"; content: string; }> = ({ role, content }) => { if (role === "user") { return (

{content}

); } return (
{parseContent(content)}
); };