diff --git a/frontend/src/markdown.ts b/frontend/src/markdown.ts new file mode 100644 index 0000000..c418e6a --- /dev/null +++ b/frontend/src/markdown.ts @@ -0,0 +1,53 @@ +function applyInline(text: string): string { + text = text.replace(/\*\*(.+?)\*\*/g, '$1') + text = text.replace(/\*(.+?)\*/g, '$1') + return text +} + +export function renderSimpleMarkdown(raw: string): string { + // escape HTML first + const text = raw + .replace(/&/g, '&') + .replace(//g, '>') + .replace(/"/g, '"') + + // split into blocks by double newlines + const blocks = text.split(/\n\n+/) + const rendered = blocks.map(block => { + const lines = block.split('\n') + // check if block is a list + const isList = lines.every(l => l.match(/^\s*- /)) + if (isList) { + const items = lines.map(l => { + let item = l.replace(/^\s*- /, '') + item = applyInline(item) + return `
  • ${item}
  • ` + }) + return `` + } + // process each line + const processed = lines.map(line => { + // headings + if (line.match(/^## /)) return `

    ${applyInline(line.slice(3))}

    ` + if (line.match(/^# /)) return `

    ${applyInline(line.slice(2))}

    ` + // single list item within a paragraph block + if (line.match(/^\s*- /)) return `
  • ${applyInline(line.replace(/^\s*- /, ''))}
  • ` + return applyInline(line) + }) + // wrap non-heading lines in

    + const out: string[] = [] + let buf: string[] = [] + for (const p of processed) { + if (p.startsWith('

    ') || p.startsWith('

    ') || p.startsWith('
  • ') || p.startsWith('