import React, { useState } from "react"; import ReactMarkdown from "react-markdown"; import remarkGfm from "remark-gfm"; import { Prism, SyntaxHighlighterProps } from "react-syntax-highlighter"; import { tomorrow } from "react-syntax-highlighter/dist/esm/styles/prism"; const SyntaxHighlighter = Prism as any as React.FC; interface MarkdownRendererProps { content: string; fileExtension?: string; truncate?: boolean; maxLength?: number; indented?: boolean; } // Map file extensions to syntax highlighting languages const extensionToLanguage: Record = { js: "javascript", jsx: "jsx", ts: "typescript", tsx: "tsx", py: "python", rb: "ruby", java: "java", c: "c", cpp: "cpp", cs: "csharp", go: "go", php: "php", html: "html", css: "css", json: "json", md: "markdown", sql: "sql", sh: "bash", bash: "bash", yaml: "yaml", yml: "yaml", xml: "xml", txt: "text", }; const CodeBlock: React.FC<{ language: string; value: string }> = ({ language, value, }) => { const [copied, setCopied] = useState(false); const [expanded, setExpanded] = useState(false); const handleCopy = async () => { await navigator.clipboard.writeText(value); setCopied(true); setTimeout(() => setCopied(false), 2000); }; // Split code into lines const lines = value.split("\n"); const isLong = lines.length > 20; const displayedValue = !expanded && isLong ? lines.slice(0, 20).join("\n") : value; return (
{language || "text"}
{displayedValue} {isLong && (
)}
); }; const MarkdownRenderer: React.FC = ({ content, fileExtension, truncate, maxLength, indented = false, }) => { // Determine if we should render as a file preview const isFilePreview = !!fileExtension; const color = indented ? "var(--color-text-secondary)" : "var(--color-text-primary)"; // If this is a file preview, wrap the content in a code block const processedContent = isFilePreview ? `\`\`\`${ extensionToLanguage[fileExtension?.toLowerCase() || ""] || "text" }\n${content}\n\`\`\`` : content; // Truncate content if needed const truncatedContent = truncate && maxLength && content.length > maxLength ? content.slice(0, maxLength) + "..." : content; return (
{indented && (
)}

{children}

, h2: ({ children }) =>

{children}

, h3: ({ children }) =>

{children}

, h4: ({ children }) =>

{children}

, h5: ({ children }) =>
{children}
, h6: ({ children }) =>
{children}
, p: ({ children }) => (

{children}

), strong: ({ children }) => ( {children} ), a: ({ href, children }) => ( {children} ), code: ({ node, className, children, ...props }) => { const match = /language-(\w+)/.exec(className || ""); const language = match ? match[1] : ""; const inline = !language; if (inline) { return ( {children} ); } return ( ); }, blockquote: ({ children }) => (
{children}
), }} > {truncate ? truncatedContent : processedContent}
); }; export default MarkdownRenderer;