feat: 友链/书库/移动端导航/排行榜等多模块功能
新增模块: - 友链(friendlink)后端处理 + 前端管理页与友链板 - 书库(library):导入、章节、封面、阅读页、横竖版自适应 AdaptiveCoverSlot - 顶栏导航(header_nav)配置与 MobileTabBar/MobileRailDrawers 移动端抽屉 - 排行榜 service 测试、站点页面测试、时间线发布(timeline_release) 其它改动: - 后端 handlers/services 全量小幅调整 - 前端组件、库函数、URL/品牌/站点 URL 工具更新 - Lightbox 图片、MdEntries 条目卡、coverColor 派生色相等前端能力
This commit is contained in:
@@ -4,6 +4,9 @@ import {
|
||||
announcementPath,
|
||||
entityPath,
|
||||
leaderboardPath,
|
||||
libraryDocPath,
|
||||
libraryDocReadPath,
|
||||
libraryPath,
|
||||
matchPrettyPath,
|
||||
matchStandardPath,
|
||||
normalizeUrlStyle,
|
||||
@@ -57,6 +60,29 @@ describe("路径构造器", () => {
|
||||
assert.equal(leaderboardPath("html"), "/leaderboard.html");
|
||||
assert.equal(leaderboardPath("discuz"), "/rank.html");
|
||||
});
|
||||
it("书库三风格(html/discuz 同模板;章节 = 详情路径 + ?sec=)", () => {
|
||||
assert.equal(libraryPath("default"), "/library");
|
||||
assert.equal(libraryPath("html"), "/library.html");
|
||||
assert.equal(libraryPath("discuz"), "/library.html");
|
||||
assert.equal(libraryDocPath("default", "abc"), "/library/abc");
|
||||
assert.equal(libraryDocPath("html", "abc"), "/library-abc.html");
|
||||
assert.equal(libraryDocPath("discuz", "abc"), "/library-abc.html");
|
||||
assert.equal(
|
||||
libraryDocPath("html", "使用指南"),
|
||||
`/library-${encodeURIComponent("使用指南")}.html`
|
||||
);
|
||||
assert.equal(libraryDocPath("default", " "), "/library");
|
||||
assert.equal(libraryDocPath("html", " "), "/library.html");
|
||||
// 阅读页:chapterNo 为书内章序号(1 起),缺省表示第一章
|
||||
assert.equal(libraryDocReadPath("default", "abc"), "/library/abc/read");
|
||||
assert.equal(libraryDocReadPath("default", "abc", 5), "/library/abc/read?c=5");
|
||||
assert.equal(libraryDocReadPath("html", "abc"), "/library-abc.html?sec=1");
|
||||
assert.equal(libraryDocReadPath("discuz", "abc", 5), "/library-abc.html?sec=5");
|
||||
assert.equal(
|
||||
libraryDocReadPath("html", "使用指南", 2),
|
||||
`/library-${encodeURIComponent("使用指南")}.html?sec=2`
|
||||
);
|
||||
});
|
||||
it("entityPath 与标准路径", () => {
|
||||
assert.equal(entityPath("discuz", "post", 9), "/thread-9.html");
|
||||
assert.equal(entityPath("default", "user", 9), "/u/9");
|
||||
@@ -76,6 +102,41 @@ describe("matchPrettyPath", () => {
|
||||
assert.deepEqual(matchPrettyPath("/leaderboard.html"), { style: "html", kind: "leaderboard" });
|
||||
assert.deepEqual(matchPrettyPath("/rank.html"), { style: "discuz", kind: "leaderboard" });
|
||||
});
|
||||
it("书库两风格同模板:prefer 优先当前风格,缺省首条兜底", () => {
|
||||
assert.equal(matchPrettyPath("/library.html", "html")?.style, "html");
|
||||
assert.equal(matchPrettyPath("/library.html", "discuz")?.style, "discuz");
|
||||
assert.equal(matchPrettyPath("/library.html")?.style, "html");
|
||||
assert.deepEqual(matchPrettyPath("/library-x.html", "discuz"), {
|
||||
style: "discuz",
|
||||
kind: "libraryDoc",
|
||||
slug: "x",
|
||||
});
|
||||
assert.deepEqual(matchPrettyPath("/library-x.html"), { style: "html", kind: "libraryDoc", slug: "x" });
|
||||
});
|
||||
it("旧版章节伪静态 -read-{n} 仍可解析(不再生成)", () => {
|
||||
assert.deepEqual(matchPrettyPath("/library-x-read-2.html", "discuz"), {
|
||||
style: "discuz",
|
||||
kind: "libraryRead",
|
||||
slug: "x",
|
||||
id: 2,
|
||||
});
|
||||
assert.deepEqual(matchPrettyPath("/library-x-read-2.html"), {
|
||||
style: "html",
|
||||
kind: "libraryRead",
|
||||
slug: "x",
|
||||
id: 2,
|
||||
});
|
||||
// 详情模板不再吞掉 -read-{n};纯详情仍命中 libraryDoc
|
||||
assert.deepEqual(matchPrettyPath("/library-x.html"), { style: "html", kind: "libraryDoc", slug: "x" });
|
||||
assert.equal(matchPrettyPath("/library-x-read-2.htmlx"), null);
|
||||
assert.equal(matchPrettyPath("/library-x-read-2.html/edit"), null);
|
||||
});
|
||||
it("书库 pretty 排除子路径与伪造路径", () => {
|
||||
assert.equal(matchPrettyPath("/library-x.htmlx"), null);
|
||||
assert.equal(matchPrettyPath("/library-x.html/edit"), null);
|
||||
assert.equal(matchPrettyPath("/library-.html"), null);
|
||||
assert.equal(matchPrettyPath("/library.html/x"), null);
|
||||
});
|
||||
it("page slug 保持 encoded 原样", () => {
|
||||
const enc = encodeURIComponent("使用指南");
|
||||
assert.deepEqual(matchPrettyPath(`/page-${enc}.html`), { style: "discuz", kind: "page", slug: enc });
|
||||
@@ -104,11 +165,18 @@ describe("matchStandardPath / parseEntityPath", () => {
|
||||
assert.deepEqual(matchStandardPath("/p/about"), { kind: "page", slug: "about" });
|
||||
assert.deepEqual(matchStandardPath("/leaderboard"), { kind: "leaderboard" });
|
||||
assert.deepEqual(matchStandardPath("/leaderboard/"), { kind: "leaderboard" });
|
||||
assert.deepEqual(matchStandardPath("/library"), { kind: "library" });
|
||||
assert.deepEqual(matchStandardPath("/library/"), { kind: "library" });
|
||||
assert.deepEqual(matchStandardPath("/library/abc"), { kind: "libraryDoc", slug: "abc" });
|
||||
assert.equal(matchStandardPath("/post/12/edit"), null);
|
||||
assert.equal(matchStandardPath("/post/abc"), null);
|
||||
assert.equal(matchStandardPath("/u/5/followers"), null);
|
||||
assert.equal(matchStandardPath("/p/"), null);
|
||||
assert.equal(matchStandardPath("/p/a/b"), null);
|
||||
// 读页单独识别(?c= 走 query),不得被详情模式误伤
|
||||
assert.deepEqual(matchStandardPath("/library/abc/read"), { kind: "libraryRead", slug: "abc" });
|
||||
assert.equal(matchStandardPath("/library/a/b"), null);
|
||||
assert.equal(matchStandardPath("/libraryx"), null);
|
||||
});
|
||||
it("parseEntityPath 兼容标准与全部模板", () => {
|
||||
assert.deepEqual(parseEntityPath("/post/12"), { kind: "post", id: 12 });
|
||||
@@ -125,4 +193,12 @@ describe("matchStandardPath / parseEntityPath", () => {
|
||||
assert.equal(parseEntityPath("/chat/5"), null);
|
||||
assert.equal(parseEntityPath("/"), null);
|
||||
});
|
||||
it("parseEntityPath 兼容书库路径并解码 slug", () => {
|
||||
const enc = encodeURIComponent("三体");
|
||||
assert.deepEqual(parseEntityPath(`/library/${enc}`), { kind: "libraryDoc", slug: "三体" });
|
||||
assert.deepEqual(parseEntityPath(`/library-${enc}.html`), { kind: "libraryDoc", slug: "三体" });
|
||||
assert.deepEqual(parseEntityPath("/library.html"), { kind: "library" });
|
||||
assert.deepEqual(parseEntityPath("/library/abc/read"), { kind: "libraryRead", slug: "abc" });
|
||||
assert.deepEqual(parseEntityPath("/library-abc-read-2.html"), { kind: "libraryRead", slug: "abc" });
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user