feat: 友链/书库/移动端导航/排行榜等多模块功能
新增模块: - 友链(friendlink)后端处理 + 前端管理页与友链板 - 书库(library):导入、章节、封面、阅读页、横竖版自适应 AdaptiveCoverSlot - 顶栏导航(header_nav)配置与 MobileTabBar/MobileRailDrawers 移动端抽屉 - 排行榜 service 测试、站点页面测试、时间线发布(timeline_release) 其它改动: - 后端 handlers/services 全量小幅调整 - 前端组件、库函数、URL/品牌/站点 URL 工具更新 - Lightbox 图片、MdEntries 条目卡、coverColor 派生色相等前端能力
This commit is contained in:
78
frontend/lib/headerNav.test.ts
Normal file
78
frontend/lib/headerNav.test.ts
Normal file
@@ -0,0 +1,78 @@
|
||||
import assert from "node:assert/strict";
|
||||
import { describe, it } from "node:test";
|
||||
import {
|
||||
DEFAULT_HEADER_NAV,
|
||||
HEADER_NAV_BUILTIN_KEYS,
|
||||
isHeaderNavCustom,
|
||||
normalizeHeaderNav,
|
||||
type HeaderNavItem,
|
||||
} from "./headerNav.ts";
|
||||
|
||||
describe("normalizeHeaderNav", () => {
|
||||
it("缺行/非法输入回落内置默认三项", () => {
|
||||
assert.deepEqual(normalizeHeaderNav(undefined), DEFAULT_HEADER_NAV);
|
||||
assert.deepEqual(normalizeHeaderNav(null), DEFAULT_HEADER_NAV);
|
||||
assert.deepEqual(normalizeHeaderNav("home"), DEFAULT_HEADER_NAV);
|
||||
});
|
||||
|
||||
it("默认三项顺序与注册表一致", () => {
|
||||
assert.equal(DEFAULT_HEADER_NAV.length, 3);
|
||||
assert.deepEqual(
|
||||
DEFAULT_HEADER_NAV.map((i) => (i.type === "builtin" ? i.key : "")),
|
||||
[...HEADER_NAV_BUILTIN_KEYS],
|
||||
);
|
||||
});
|
||||
|
||||
it("显式空数组表示全部隐藏,不回落默认", () => {
|
||||
assert.deepEqual(normalizeHeaderNav([]), []);
|
||||
});
|
||||
|
||||
it("自定义顺序与内容原样保留", () => {
|
||||
const items: HeaderNavItem[] = [
|
||||
{ type: "builtin", key: "library" },
|
||||
{ type: "custom", label: "关于", url: "/p/about", new_tab: false },
|
||||
{ type: "builtin", key: "home" },
|
||||
{ type: "custom", label: "官网", url: "https://example.com", new_tab: true },
|
||||
];
|
||||
assert.deepEqual(normalizeHeaderNav(items), items);
|
||||
});
|
||||
|
||||
it("内置 key 去空白/小写容错、重复去重", () => {
|
||||
assert.deepEqual(
|
||||
normalizeHeaderNav([
|
||||
{ type: "builtin", key: " HOME " },
|
||||
{ type: "builtin", key: "home" },
|
||||
{ type: "builtin", key: "library" },
|
||||
]),
|
||||
[
|
||||
{ type: "builtin", key: "home" },
|
||||
{ type: "builtin", key: "library" },
|
||||
],
|
||||
);
|
||||
});
|
||||
|
||||
it("未知内置 key 与非法自定义项被剔除", () => {
|
||||
assert.deepEqual(
|
||||
normalizeHeaderNav([
|
||||
{ type: "builtin", key: "nope" },
|
||||
{ type: "custom", label: "", url: "/x" },
|
||||
{ type: "custom", label: "坏地址", url: "javascript:alert(1)" },
|
||||
{ type: "custom", label: "相对路径", url: "relative" },
|
||||
{ type: "weird", key: "home" },
|
||||
{ type: "custom", label: "合法", url: "/links" },
|
||||
]),
|
||||
[{ type: "custom", label: "合法", url: "/links", new_tab: false }],
|
||||
);
|
||||
});
|
||||
|
||||
it("自定义外链 new_tab 缺省为 true,站内为 false", () => {
|
||||
const got = normalizeHeaderNav([
|
||||
{ type: "custom", label: "外链", url: "https://example.com" },
|
||||
{ type: "custom", label: "站内", url: "/p/about" },
|
||||
]);
|
||||
assert.equal(got.length, 2);
|
||||
assert.ok(got.every(isHeaderNavCustom));
|
||||
assert.equal((got[0] as { new_tab: boolean }).new_tab, true);
|
||||
assert.equal((got[1] as { new_tab: boolean }).new_tab, false);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user