Files
jiang13-bbs/frontend/components/markdown/renderMarkdown.tsx
freefire 99c0f0319d feat: 品牌裁剪弹窗/Markdown 行内短代码与详情视频块等
新增:
- BrandCropModal 品牌图裁剪弹窗 + cropImage 工具
- Markdown 行内短代码(inlineShortcodes + remark 插件)
- MdDetails 折叠块、MdVideo 视频块组件
- directiveBlocks/inlineShortcodes 测试

其它:
- 聊天后端(handler/service chat)调整
- Markdown 渲染链路、编辑器、全局样式与品牌相关面板更新
2026-10-02 01:40:06 +08:00

76 lines
2.3 KiB
TypeScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import type { Components } from "react-markdown";
import type { ReactElement } from "react";
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
import { toJsxRuntime } from "hast-util-to-jsx-runtime";
import { unified } from "unified";
import remarkParse from "remark-parse";
import remarkGfm from "remark-gfm";
import remarkRehype from "remark-rehype";
import rehypePrettyCode, { type Options as PrettyCodeOptions } from "rehype-pretty-code";
import type { Root } from "hast";
import type { Root as MdastRoot } from "mdast";
import { visit } from "unist-util-visit";
import { mergeMarkdownComponents } from "./mergeComponents";
import { remarkInlineShortcodes } from "./remarkInlineShortcodes";
import {
getPrettyCodeHighlighter,
resolveShikiLang,
SHIKI_THEMES,
} from "./shikiHighlighter";
/**
* 将代码围栏语言归一到白名单(未知 → plaintext),
* 避免 rehype-pretty-code 对未装载语言 loadLanguage 失败。
*/
function remarkNormalizeCodeLang() {
return (tree: MdastRoot) => {
visit(tree, "code", (node) => {
node.lang = resolveShikiLang(node.lang);
});
};
}
export const prettyCodeOptions: PrettyCodeOptions = {
theme: {
light: SHIKI_THEMES.light,
dark: SHIKI_THEMES.dark,
},
keepBackground: false,
defaultLang: "plaintext",
// HighlighterCore 与 pretty-code 期望的 Highlighter 在运行时兼容
getHighlighter: getPrettyCodeHighlighter as unknown as PrettyCodeOptions["getHighlighter"],
// 空行在 display:grid 下会塌缩成 0 高,补一个空格撑住行高
onVisitLine(element) {
if (element.children.length === 0) {
element.children = [{ type: "text", value: " " }];
}
},
};
/** 服务端异步管线:GFM + Shiki 双主题高亮 → React 树 */
export async function renderMarkdownToReact(
content: string,
overrides?: Components
): Promise<ReactElement> {
const processor = unified()
.use(remarkParse)
.use(remarkGfm)
.use(remarkInlineShortcodes)
.use(remarkNormalizeCodeLang)
.use(remarkRehype)
.use(rehypePrettyCode, { ...prettyCodeOptions });
const mdast = processor.parse(content || "");
const hast = (await processor.run(mdast)) as Root;
return toJsxRuntime(hast, {
Fragment,
jsx,
jsxs,
components: mergeMarkdownComponents(overrides) as Record<
string,
React.ElementType
>,
}) as ReactElement;
}