import { ChevronRight } from "lucide-react"; import type { ReactNode } from "react"; import { renderMarkdownToReact } from "@/components/markdown/renderMarkdown"; import { ENTRY_TITLE_NUM_RE, type EntryItem } from "@/lib/entryBlocks"; /** 标签 chip:"主:次" 或 "主=次" 形式渲染主次两段,否则单段;不做语义配色,保持字段通用 */ function EntryTag({ tag }: { tag: string }) { const idx = tag.search(/[::=]/); const main = idx >= 0 ? tag.slice(0, idx) : tag; const sub = idx >= 0 ? tag.slice(idx + 1) : ""; return ( {main} {sub ? ( {sub} ) : null} ); } /** * 条目卡纯展示视图:编号标题 + 标签 chips + 高亮摘要 + 通用字段行 + 折叠来源。 * 字段名不限定(成本/收益/备注只是书写约定),任何书籍可定义自己的字段; * markdown 片段由调用方注入(服务端 renderMarkdownToReact / 客户端 ReactMarkdown 预览)。 */ export function MdEntriesView({ items, renderMd, titleIds, }: { items: EntryItem[]; renderMd: (text: string) => ReactNode; /** 与目录共享的标题锚点 id(按条目顺序;缺省不挂 id) */ titleIds?: (string | undefined)[]; }) { return (
{items.map((it, i) => (
{!it.plain ? (

{ENTRY_TITLE_NUM_RE.test(it.title) ? null : ( {i + 1} )} {it.title}

) : null} {it.tags.length > 0 ? (
{it.tags.map((tag, ti) => ( ))}
) : null} {it.summary?.trim() ? (
{renderMd(it.summary)}
) : null} {it.fields.length > 0 ? (
{it.fields.map((f, fi) => (
{f.label}
{f.value.trim() ? renderMd(f.value) : null}
))}
) : null} {it.sources.length > 0 ? (
来源 · {it.sources.length} 条
{it.sources.map((s, si) => (
{si + 1}.
{s.text} {s.url ? ( {s.url} ) : null}
))}
) : null}
))}
); } /** 服务端条目卡:markdown 片段走站点统一渲染管线(Shiki 等) */ export default async function MdEntries({ items, titleIds, }: { items: EntryItem[]; titleIds?: (string | undefined)[]; }) { const cache = new Map(); await Promise.all( items.flatMap((it) => { const put = async (text?: string) => { if (!text?.trim() || cache.has(text)) return; cache.set(text, await renderMarkdownToReact(text)); }; return [put(it.summary), ...it.fields.map((f) => put(f.value))]; }) ); return cache.get(t) ?? null} />; }