import React from 'react'; import ReactMarkdown from 'react-markdown'; import remarkGfm from 'remark-gfm'; import remarkMath from 'remark-math'; import rehypeKatex from 'rehype-katex'; import 'katex/dist/katex.min.css'; import { Prism as SyntaxHighlighter } from 'react-syntax-highlighter'; import { oneDark } from 'react-syntax-highlighter/dist/esm/styles/prism'; interface MarkdownRendererProps { content: string; className?: string; studyId?: string; // Optional study ID for resolving relative image paths } /** * Shared markdown renderer with syntax highlighting, GFM, and LaTeX support. * Used by both the Home page (README display) and Results page (reports). */ export const MarkdownRenderer: React.FC = ({ content, className = '', studyId }) => { // Helper to resolve image URLs - converts relative paths to API endpoints const resolveImageSrc = (src: string | undefined): string => { if (!src) return ''; // If it's already an absolute URL or data URL, return as-is if (src.startsWith('http://') || src.startsWith('https://') || src.startsWith('data:')) { return src; } // If we have a studyId, route through the API if (studyId) { // Remove leading ./ or / from the path const cleanPath = src.replace(/^\.?\//, ''); return `/api/optimization/studies/${studyId}/image/${cleanPath}`; } // Fallback: return original src return src; }; return (
(

{children}

), h2: ({ children }) => (

{children}

), h3: ({ children }) => (

{children}

), h4: ({ children }) => (

{children}

), // Paragraphs p: ({ children }) => (

{children}

), // Strong/Bold strong: ({ children }) => ( {children} ), // Links a: ({ href, children }) => ( {children} ), // Lists ul: ({ children }) => (
    {children}
), ol: ({ children }) => (
    {children}
), li: ({ children }) => (
  • {children}
  • ), // Code blocks with syntax highlighting code: ({ inline, className, children, ...props }: any) => { const match = /language-(\w+)/.exec(className || ''); const language = match ? match[1] : ''; if (!inline && language) { return (
    {language}
    {String(children).replace(/\n$/, '')}
    ); } if (!inline) { return (
                      {children}
                    
    ); } return ( {children} ); }, // Tables table: ({ children }) => (
    {children}
    ), thead: ({ children }) => ( {children} ), tbody: ({ children }) => ( {children} ), tr: ({ children }) => ( {children} ), th: ({ children }) => ( {children} ), td: ({ children }) => ( {children} ), // Blockquotes blockquote: ({ children }) => (
    {children}
    ), // Horizontal rules hr: () => (
    ), // Images - resolve relative paths through API img: ({ src, alt }) => ( {alt { // Hide broken images (e.target as HTMLImageElement).style.display = 'none'; }} /> ), }} > {content}
    ); }; export default MarkdownRenderer;