"use client"; import ReactMarkdown, { type Components } from "react-markdown"; import remarkGfm from "remark-gfm"; import { mergeMarkdownComponents } from "@/components/markdown/mergeComponents"; import { splitContentSegments } from "@/lib/directiveBlocks"; import { expandDyEmojiShortcodes } from "@/lib/dyEmoji"; import type { HideKind } from "@/lib/hideBlocks"; import MdHideBlock from "@/components/markdown/MdHideBlock"; import MdTimeline from "@/components/markdown/MdTimeline"; import { MdEntriesView } from "@/components/markdown/MdEntries"; type MarkdownBodyClientProps = { content: string; className?: string; components?: Components; postId?: number; loginHref?: string; loggedIn?: boolean; /** 书级「全章节条目卡模式」:章节内容免写 [entries] 壳 */ entriesAuto?: boolean; /** 按分段索引的条目标题锚点 id(与章内目录共享;阅读页传入,其他场景缺省) */ entriesTitleIds?: (string[] | undefined)[]; }; /** * 客户端 Markdown(发帖预览 / 评论):GFM + 隐藏块 / 时间线 / 条目卡预览。 */ export default function MarkdownBodyClient({ content, className = "prose-content", components, postId, loginHref, loggedIn = false, entriesAuto = false, entriesTitleIds, }: MarkdownBodyClientProps) { const segs = splitContentSegments(expandDyEmojiShortcodes(content || ""), { entriesAuto, }); const mdComponents = mergeMarkdownComponents(components); // 时间线/隐藏块正文不套外层 heading 覆盖,避免预览与正文目录 id 错位 const nestedMd = mergeMarkdownComponents(); return (
{segs.map((seg, i) => { if (seg.type === "md") { if (!seg.text.trim()) return null; return ( {seg.text} ); } if (seg.type === "timeline") { return ( it.body.trim() ? ( {expandDyEmojiShortcodes(it.body)} ) : null } /> ); } if (seg.type === "entries") { return ( ( {expandDyEmojiShortcodes(t)} )} /> ); } const kind = seg.kind as HideKind; if (seg.locked) { return ( ); } return ( {seg.body.trim() ? ( {expandDyEmojiShortcodes(seg.body)} ) : null} ); })}
); }