feat(compose): 正文内嵌隐藏块并升级 Markdown 编辑器

去掉整帖可见性表单,改为 :::hide 按块脱敏;工具栏补齐代码块、链接/图片对话框与粘贴拖拽上传。

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-09-17 04:58:20 +08:00
parent d1155cbd64
commit 01e2fd05ca
19 changed files with 1867 additions and 471 deletions

View File

@@ -1,21 +1,61 @@
import type { Components } from "react-markdown";
import { renderMarkdownToReact } from "@/components/markdown/renderMarkdown";
import { splitHideSegments, type HideKind } from "@/lib/hideBlocks";
import MdHideBlock from "@/components/markdown/MdHideBlock";
type MarkdownBodyProps = {
content: string;
className?: string;
components?: Components;
/** 详情页解锁门禁需要 */
postId?: number;
loggedIn?: boolean;
};
/**
* 站点统一 Markdown 渲染(服务端):GFM + Shiki 双主题、图箱、代码块复制/折叠。
* 客户端预览请用 MarkdownBodyClient。
* 站点统一 Markdown 渲染(服务端):GFM + Shiki;支持 :::hide 内嵌块。
*/
export default async function MarkdownBody({
content,
className = "prose-content",
components,
postId,
loggedIn = false,
}: MarkdownBodyProps) {
const tree = await renderMarkdownToReact(content, components);
return <div className={className}>{tree}</div>;
const segs = splitHideSegments(content || "");
const nodes = [];
for (let i = 0; i < segs.length; i++) {
const seg = segs[i];
if (seg.type === "md") {
if (!seg.text.trim()) continue;
nodes.push(
<div key={`md-${i}`}>{await renderMarkdownToReact(seg.text, components)}</div>
);
continue;
}
const kind = seg.kind as HideKind;
if (seg.locked) {
nodes.push(
<MdHideBlock
key={`hide-${i}`}
kind={kind}
points={seg.points}
locked
postId={postId}
loggedIn={loggedIn}
/>
);
continue;
}
const inner = seg.body.trim()
? await renderMarkdownToReact(seg.body, components)
: null;
nodes.push(
<MdHideBlock key={`hide-${i}`} kind={kind} points={seg.points}>
{inner}
</MdHideBlock>
);
}
return <div className={className}>{nodes}</div>;
}