feat: 品牌裁剪弹窗/Markdown 行内短代码与详情视频块等
新增: - BrandCropModal 品牌图裁剪弹窗 + cropImage 工具 - Markdown 行内短代码(inlineShortcodes + remark 插件) - MdDetails 折叠块、MdVideo 视频块组件 - directiveBlocks/inlineShortcodes 测试 其它: - 聊天后端(handler/service chat)调整 - Markdown 渲染链路、编辑器、全局样式与品牌相关面板更新
This commit is contained in:
58
frontend/components/markdown/remarkInlineShortcodes.ts
Normal file
58
frontend/components/markdown/remarkInlineShortcodes.ts
Normal file
@@ -0,0 +1,58 @@
|
||||
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];
|
||||
});
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user