Files
breakpilot-compliance/admin-compliance/app/sdk/control-provenance/_components/MarkdownRenderer.tsx
Sharang Parnerkar 0125199c76 refactor(admin): split controls, training, control-provenance, iace/verification pages
Each page.tsx exceeded the 500-LOC hard cap. Extracted components and hooks into
colocated _components/ and _hooks/ directories; page.tsx is now a thin orchestrator.

- controls/page.tsx: 944 → 180 LOC; extracted ControlCard, AddControlForm,
  LoadingSkeleton, TransitionErrorBanner, StatsCards, FilterBar, RAGPanel into
  _components/ and useControlsData, useRAGSuggestions into _hooks/; types into _types.ts
- training/page.tsx: 780 → 288 LOC; extracted ContentTab (inline content generator tab)
  into _components/ContentTab.tsx
- control-provenance/page.tsx: 739 → 122 LOC; extracted MarkdownRenderer, UsageBadge,
  PermBadge, LicenseMatrix, SourceRegistry into _components/; PROVENANCE_SECTIONS
  static data into _data/provenance-sections.ts
- iace/[projectId]/verification/page.tsx: 673 → 196 LOC; extracted StatusBadge,
  VerificationForm, CompleteModal, SuggestEvidenceModal, VerificationTable into _components/

Zero behavior changes; logic relocated verbatim.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-16 22:50:15 +02:00

39 lines
2.0 KiB
TypeScript

export function MarkdownRenderer({ content }: { content: string }) {
let html = content
.replace(/&/g, '&amp;')
.replace(/</g, '&lt;')
.replace(/>/g, '&gt;')
html = html.replace(
/^```[\w]*\n([\s\S]*?)^```$/gm,
(_m, code: string) => `<pre class="bg-gray-50 border rounded p-3 my-3 text-xs font-mono overflow-x-auto whitespace-pre">${code.trimEnd()}</pre>`
)
html = html.replace(
/^(\|.+\|)\n(\|[\s:|-]+\|)\n((?:\|.+\|\n?)*)/gm,
(_m, header: string, _sep: string, body: string) => {
const ths = header.split('|').filter((c: string) => c.trim()).map((c: string) =>
`<th class="px-3 py-2 text-left text-xs font-medium text-gray-500 uppercase border-b">${c.trim()}</th>`
).join('')
const rows = body.trim().split('\n').map((row: string) => {
const tds = row.split('|').filter((c: string) => c.trim()).map((c: string) =>
`<td class="px-3 py-2 text-sm text-gray-700 border-b border-gray-100">${c.trim()}</td>`
).join('')
return `<tr>${tds}</tr>`
}).join('')
return `<table class="w-full border-collapse my-3 text-sm"><thead><tr>${ths}</tr></thead><tbody>${rows}</tbody></table>`
}
)
html = html.replace(/^### (.+)$/gm, '<h4 class="text-sm font-semibold text-gray-800 mt-4 mb-2">$1</h4>')
html = html.replace(/^## (.+)$/gm, '<h3 class="text-base font-semibold text-gray-900 mt-5 mb-2">$1</h3>')
html = html.replace(/\*\*(.+?)\*\*/g, '<strong>$1</strong>')
html = html.replace(/`([^`]+)`/g, '<code class="bg-gray-100 px-1 py-0.5 rounded text-xs font-mono">$1</code>')
html = html.replace(/^- (.+)$/gm, '<li class="ml-4 text-sm text-gray-700 list-disc">$1</li>')
html = html.replace(/((?:<li[^>]*>.*<\/li>\n?)+)/g, '<ul class="my-2 space-y-1">$1</ul>')
html = html.replace(/^(\d+)\. (.+)$/gm, '<li class="ml-4 text-sm text-gray-700 list-decimal">$2</li>')
html = html.replace(/^(?!<[hultdp]|$)(.+)$/gm, '<p class="text-sm text-gray-700 my-2">$1</p>')
return <div dangerouslySetInnerHTML={{ __html: html }} />
}