// Lightweight Markdown renderer – handles the subset used by the AI: // ## Headings, **bold**, bullet lists, numbered lists, line breaks export default function Markdown({ text }) { if (!text) return null const lines = text.split('\n') const elements = [] let i = 0 const parseLine = (line) => { // Parse inline **bold** and *italic* const parts = [] let remaining = line let key = 0 while (remaining.length > 0) { const boldMatch = remaining.match(/^(.*?)\*\*(.*?)\*\*(.*)$/) if (boldMatch) { if (boldMatch[1]) parts.push({boldMatch[1]}) parts.push({boldMatch[2]}) remaining = boldMatch[3] continue } const italicMatch = remaining.match(/^(.*?)\*(.*?)\*(.*)$/) if (italicMatch) { if (italicMatch[1]) parts.push({italicMatch[1]}) parts.push({italicMatch[2]}) remaining = italicMatch[3] continue } parts.push({remaining}) break } return parts.length === 1 && typeof parts[0].props?.children === 'string' ? parts[0].props.children : parts } while (i < lines.length) { const line = lines[i] // Skip empty lines (add spacing) if (line.trim() === '') { elements.push(
) i++; continue } // H1 if (line.startsWith('# ')) { elements.push(

{parseLine(line.slice(2))}

) i++; continue } // H2 if (line.startsWith('## ')) { elements.push(

{parseLine(line.slice(3))}

) i++; continue } // H3 if (line.startsWith('### ')) { elements.push(

{parseLine(line.slice(4))}

) i++; continue } // Unordered list item if (line.match(/^[-*] /)) { const listItems = [] while (i < lines.length && lines[i].match(/^[-*] /)) { listItems.push(
  • {parseLine(lines[i].slice(2))}
  • ) i++ } elements.push( ) continue } // Numbered list item if (line.match(/^\d+\. /)) { const listItems = [] while (i < lines.length && lines[i].match(/^\d+\. /)) { listItems.push(
  • {parseLine(lines[i].replace(/^\d+\. /, ''))}
  • ) i++ } elements.push(
      {listItems}
    ) continue } // Horizontal rule if (line.match(/^---+$/)) { elements.push(
    ) i++; continue } // Normal paragraph elements.push(

    {parseLine(line)}

    ) i++ } return
    {elements}
    }