import React from "react"; import { cn } from "@/lib/utils"; /** * 轻量 Markdown 渲染器(无依赖) * 用于渲染 GitHub Release Notes 这类常见格式: * 标题、无序/有序列表、引用、代码块、粗体、行内代码、链接、分隔线、段落 */ function renderInline(text: string, keyPrefix: string): React.ReactNode[] { const parts: React.ReactNode[] = []; const regex = /(\*\*[^*]+\*\*|`[^`]+`|\[[^\]]+\]\([^)]+\))/g; let last = 0; let m: RegExpExecArray | null; let i = 0; while ((m = regex.exec(text)) !== null) { if (m.index > last) { parts.push(text.slice(last, m.index)); } const tok = m[0]; if (tok.startsWith("**")) { parts.push( {tok.slice(2, -2)} ); } else if (tok.startsWith("`")) { parts.push( {tok.slice(1, -1)} ); } else { const link = tok.match(/^\[([^\]]+)\]\(([^)]+)\)$/); if (link) { parts.push( {link[1]} ); } else { parts.push(tok); } } last = m.index + tok.length; i += 1; } if (last < text.length) { parts.push(text.slice(last)); } return parts; } export function MarkdownLite({ text, className, }: { text: string; className?: string; }) { const lines = text.split(/\r?\n/); const blocks: React.ReactNode[] = []; let key = 0; let inCode = false; let codeBuf: string[] = []; const push = (node: React.ReactNode) => { blocks.push(
{node}
); }; for (const line of lines) { // 围栏代码块 if (/^```/.test(line.trim())) { if (inCode) { push(
            {codeBuf.join("\n")}
          
); codeBuf = []; inCode = false; } else { inCode = true; } continue; } if (inCode) { codeBuf.push(line); continue; } const trimmed = line.trim(); if (!trimmed) continue; // 空行跳过 // 标题 const heading = trimmed.match(/^(#{1,4})\s+(.*)$/); if (heading) { const lv = heading[1].length; const content = renderInline(heading[2], `h${key}`); const cls = { 1: "text-xl font-bold tracking-tight", 2: "text-lg font-bold tracking-tight", 3: "text-base font-semibold", 4: "text-sm font-semibold", }[lv as 1 | 2 | 3 | 4]; push(

{content}

); continue; } // 分隔线 if (/^-{3,}$/.test(trimmed)) { push(
); continue; } // 引用 if (/^>/.test(trimmed)) { push(
{renderInline(trimmed.replace(/^>\s?/, ""), `q${key}`)}
); continue; } // 无序列表 const ul = trimmed.match(/^[-*]\s+(.*)$/); if (ul) { push(
{renderInline(ul[1], `ul${key}`)}
); continue; } // 有序列表 const ol = trimmed.match(/^\d+\.\s+(.*)$/); if (ol) { push(
{trimmed.match(/^\d+/)?.[0]}. {renderInline(ol[1], `ol${key}`)}
); continue; } // 普通段落 push(

{renderInline(trimmed, `p${key}`)}

); } return
{blocks}
; }