import React, { useEffect, useRef } from 'react'; // ─── Minimal Markdown → HTML renderer ──────────────────────────────────────── // Handles: headings, bold, inline-code, fenced code blocks, tables, hr, // unordered lists, ordered lists, and paragraphs. function mdToHtml(md) { const lines = md.split('\n'); const out = []; let i = 0; let inUl = false; let inOl = false; let inTable = false; let tableHead = false; const closeOpenLists = () => { if (inUl) { out.push(''); inUl = false; } if (inOl) { out.push(''); inOl = false; } if (inTable) { out.push(''); inTable = false; tableHead = false; } }; const inline = (s) => s .replace(/&/g, '&') .replace(//g, '>') .replace(/\*\*(.+?)\*\*/g, '$1') .replace(/`([^`]+)`/g, '$1'); while (i < lines.length) { const line = lines[i]; // Fenced code block if (line.startsWith('```')) { closeOpenLists(); const lang = line.slice(3).trim(); const codeLines = []; i++; while (i < lines.length && !lines[i].startsWith('```')) { codeLines.push(lines[i].replace(/&/g,'&').replace(//g,'>')); i++; } out.push(`
${codeLines.join('\n')}
`); i++; continue; } // HR if (/^---+$/.test(line.trim())) { closeOpenLists(); out.push('
'); i++; continue; } // Headings const hMatch = line.match(/^(#{1,4})\s+(.+)/); if (hMatch) { closeOpenLists(); const level = hMatch[1].length; const id = hMatch[2].toLowerCase().replace(/[^a-z0-9]+/g, '-'); out.push(`${inline(hMatch[2])}`); i++; continue; } // Table row if (line.trim().startsWith('|')) { const cells = line.trim().replace(/^\||\|$/g, '').split('|').map(c => c.trim()); if (!inTable) { closeOpenLists(); inTable = true; tableHead = true; out.push(''); cells.forEach(c => out.push(``)); out.push(''); i++; // skip separator row if (i < lines.length && lines[i].trim().startsWith('|') && /^[\|\s\-:]+$/.test(lines[i])) i++; continue; } else { out.push(''); cells.forEach(c => out.push(``)); out.push(''); i++; continue; } } // Unordered list const ulMatch = line.match(/^[-*]\s+(.*)/); if (ulMatch) { if (inTable) closeOpenLists(); if (!inUl) { if (inOl) { out.push(''); inOl = false; } out.push(''); inUl = false; } out.push('
    '); inOl = true; } out.push(`
  1. ${inline(olMatch[1])}
  2. `); i++; continue; } // Blank line if (line.trim() === '') { closeOpenLists(); i++; continue; } // Paragraph closeOpenLists(); out.push(`

    ${inline(line)}

    `); i++; } closeOpenLists(); return out.join('\n'); } // ─── Styles ─────────────────────────────────────────────────────────────────── const overlay = { position: 'fixed', inset: 0, background: 'rgba(0,0,0,0.75)', zIndex: 2000, display: 'flex', alignItems: 'flex-start', justifyContent: 'flex-end', }; const panel = { background: '#111217', color: '#f8f9fa', width: '760px', maxWidth: '95vw', height: '100vh', overflowY: 'auto', boxShadow: '-4px 0 32px rgba(0,0,0,0.8)', display: 'flex', flexDirection: 'column', }; const header = { background: 'linear-gradient(135deg, #000000, #151622)', color: 'white', padding: '22px 28px', position: 'sticky', top: 0, zIndex: 10, borderBottom: '1px solid #222', display: 'flex', alignItems: 'center', justifyContent: 'space-between', }; const closeBtn = { background: 'none', border: 'none', color: 'white', fontSize: '22px', cursor: 'pointer', lineHeight: 1, }; const body = { padding: '28px 32px', flex: 1, fontSize: '13px', lineHeight: '1.7', }; // Injected
    e.stopPropagation()}> {/* Header */}
    📋 CPAS Tracker — Documentation
    Admin reference · use Esc or click outside to close
    {/* TOC strip */}
    {toc.filter(h => h.level <= 2).map((h) => ( ))}
    {/* Body */}
    {/* Footer */}
    CPAS Violation Tracker · internal admin use only
    ); }
${inline(c)}
${inline(c)}