feat: 品牌裁剪弹窗/Markdown 行内短代码与详情视频块等

新增:
- BrandCropModal 品牌图裁剪弹窗 + cropImage 工具
- Markdown 行内短代码(inlineShortcodes + remark 插件)
- MdDetails 折叠块、MdVideo 视频块组件
- directiveBlocks/inlineShortcodes 测试

其它:
- 聊天后端(handler/service chat)调整
- Markdown 渲染链路、编辑器、全局样式与品牌相关面板更新
This commit is contained in:
2026-10-02 01:40:06 +08:00
parent 3e98052c16
commit 99c0f0319d
23 changed files with 2012 additions and 119 deletions

View File

@@ -0,0 +1,80 @@
import assert from "node:assert/strict";
import { describe, it } from "node:test";
import {
isValidColorValue,
splitInlineShortcodes,
} from "./inlineShortcodes.ts";
describe("isValidColorValue", () => {
it("放行 #hex 与英文颜色名", () => {
assert.equal(isValidColorValue("#e03131"), true);
assert.equal(isValidColorValue("#FFF"), true);
assert.equal(isValidColorValue("#ffffffff"), true);
assert.equal(isValidColorValue("tomato"), true);
});
it("拒绝注入向量与非法值", () => {
assert.equal(isValidColorValue("url(https://evil)", ), false);
assert.equal(isValidColorValue("red;padding:0"), false);
assert.equal(isValidColorValue("#GGG"), false);
assert.equal(isValidColorValue(""), false);
});
});
describe("splitInlineShortcodes", () => {
it("无短代码时返回 null", () => {
assert.equal(splitInlineShortcodes("普通文本 == 未闭合 [kbd]未闭合"), null);
});
it("==高亮==", () => {
assert.deepEqual(splitInlineShortcodes("前==高亮==后"), [
{ type: "text", value: "前" },
{ type: "mark", value: "高亮" },
{ type: "text", value: "后" },
]);
});
it("[kbd]", () => {
assert.deepEqual(splitInlineShortcodes("[kbd]Ctrl+C[/kbd]"), [
{ type: "kbd", value: "Ctrl+C" },
]);
});
it("[color=前景] 与 [bg=背景]", () => {
assert.deepEqual(splitInlineShortcodes("[color=#e03131]红字[/color]"), [
{ type: "color", value: "红字", fg: "#e03131" },
]);
assert.deepEqual(splitInlineShortcodes("[bg=#fff3bf]黄底[/bg]"), [
{ type: "color", value: "黄底", bg: "#fff3bf" },
]);
});
it("[color=前景 bg=背景] 组合", () => {
assert.deepEqual(splitInlineShortcodes("[color=#fff bg=#c92a2a]白字红底[/color]"), [
{ type: "color", value: "白字红底", fg: "#fff", bg: "#c92a2a" },
]);
});
it("非法颜色整段回退为原文(返回 null 表示无需改写)", () => {
assert.equal(splitInlineShortcodes("[color=url(https://evil)]x[/color]"), null);
assert.equal(splitInlineShortcodes("[bg=red;padding:0]x[/bg]"), null);
});
it("未闭合标记保持字面", () => {
assert.equal(splitInlineShortcodes("[color=#fff]未闭合"), null);
});
it("混合片段按顺序拆分", () => {
assert.deepEqual(splitInlineShortcodes("a==b==[kbd]C[/kbd]d"), [
{ type: "text", value: "a" },
{ type: "mark", value: "b" },
{ type: "kbd", value: "C" },
{ type: "text", value: "d" },
]);
});
it("大小写不敏感", () => {
assert.deepEqual(splitInlineShortcodes("[KBD]Esc[/KBD]"), [
{ type: "kbd", value: "Esc" },
]);
});
});