Files
jiang13-bbs/frontend/components/markdown/remarkInlineShortcodes.ts
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

59 lines
1.9 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 { Root as MdastRoot } from "mdast";
import type { Text } from "mdast";
import { visit, SKIP } from "unist-util-visit";
import { splitInlineShortcodes } from "@/lib/inlineShortcodes";
const QUICK_RE = /==|\[(?:kbd|color|bg)[=\]]/i;
type MdastParent = { children: Array<Record<string, unknown>>; type: string };
/** 行内短代码 → mdast 节点(mdast-util-to-hast 支持 data.hName / data.hProperties) */
function segToNodes(
seg: Exclude<ReturnType<typeof splitInlineShortcodes>, null>[number]
): Record<string, unknown>[] {
if (seg.type === "text") return [{ type: "text", value: seg.value }];
if (seg.type === "mark" || seg.type === "kbd") {
return [
{
type: "emphasis",
data: { hName: seg.type },
children: [{ type: "text", value: seg.value }],
},
];
}
const style = [
seg.fg ? `color:${seg.fg}` : null,
seg.bg ? `background-color:${seg.bg}` : null,
]
.filter(Boolean)
.join(";");
return [
{
type: "emphasis",
data: { hName: "span", hProperties: { style } },
children: [{ type: "text", value: seg.value }],
},
];
}
/**
* remark 插件:把文本节点中的 ==高亮== / [kbd] / [color] / [bg] 展开为
* mark/kbd/span 节点。code/inlineCode 是字面节点没有子文本,天然免疫;
* 未命中短代码的文本原样保留。
*/
export function remarkInlineShortcodes() {
return (tree: MdastRoot) => {
visit(tree, "text", (node: Text, index, parent) => {
const p = parent as unknown as MdastParent | null;
if (!p || index === undefined) return;
const value = node.value;
if (!QUICK_RE.test(value)) return;
const segs = splitInlineShortcodes(value);
if (!segs) return;
const nodes = segs.flatMap(segToNodes);
p.children.splice(index, 1, ...nodes);
return [SKIP, index + nodes.length];
});
};
}