// Mini-Markdown-Renderer für Devlog-Prosa (Discord-Stil): **fett**, *kursiv*, // `code`, [Links](url), * Bullet-Listen, --- Trenner, ## Überschriften. // Bewusst ohne Library — Input wird nie als HTML interpretiert, kein Injection. const TOKEN = /(\*\*[^*]+\*\*|\*[^*]+\*|`[^`]+`|\[[^\]]+\]\(https?:\/\/[^\s)]+\))/g; function renderInline(text) { return text.split(TOKEN).map((part, i) => { // Fett/Kursiv rekursiv rendern, damit z. B. Links darin funktionieren if (part.startsWith('**') && part.endsWith('**')) { return {renderInline(part.slice(2, -2))}; } if (part.startsWith('*') && part.endsWith('*') && part.length > 2) { return {renderInline(part.slice(1, -1))}; } if (part.startsWith('`') && part.endsWith('`')) { return {part.slice(1, -1)}; } const link = part.match(/^\[([^\]]+)\]\((https?:\/\/[^\s)]+)\)$/); if (link) { return ( {link[1]} ); } return part; }); } /** Devlog-Text als React-Elemente: Absätze, Listen, Trenner, Überschriften */ export function Markdown({ text }) { const out = []; let para = []; let list = []; let key = 0; const flushPara = () => { if (para.length === 0) return; out.push(

{para.map((line, j) => ( {renderInline(line)} {j < para.length - 1 &&
}
))}

); para = []; }; const flushList = () => { if (list.length === 0) return; out.push( ); list = []; }; for (const raw of text.split('\n')) { const line = raw.trim(); if (!line) { flushPara(); flushList(); continue; } // --- → Trenner if (/^-{3,}$/.test(line)) { flushPara(); flushList(); out.push(
); continue; } // * Punkt / - Punkt → Liste (aber nicht *kursiv am Zeilenanfang*) const li = line.match(/^[*-]\s+(.*)$/); if (li) { flushPara(); list.push(li[1]); continue; } // ## Überschrift (1-3 Raute-Ebenen) const heading = line.match(/^(#{1,3})\s+(.*)$/); if (heading) { flushPara(); flushList(); out.push(

{renderInline(heading[2])}

); continue; } flushList(); para.push(raw); } flushPara(); flushList(); return out; }