- {!ready && !err &&
EPUB 加载中…
}
+ {!ready && !err && (
+
EPUB 加载中…
+ )}
-
{children}
@@ -105,7 +97,12 @@ function ReaderSheet({
/>
))}
-
pr.bump(-1)} disabled={pr.prefs.sizeIdx === 0} aria-label="减小字号">
+ pr.bump(-1)}
+ disabled={pr.prefs.sizeIdx === 0}
+ aria-label="减小字号"
+ >
A−
{
it("卷不感知:只按章切,卷题行留在正文里", () => {
const t =
- "第一卷 天云世界\n第一章 铜镜\n" + pad(500) + "\n第二章 修炼\n" + pad(500) +
- "\n\n\n第二卷 仙界\n第三章 飞升\n" + pad(300);
+ "第一卷 天云世界\n第一章 铜镜\n" +
+ pad(500) +
+ "\n第二章 修炼\n" +
+ pad(500) +
+ "\n\n\n第二卷 仙界\n第三章 飞升\n" +
+ pad(300);
const chs = splitChapters(t);
expect(chs.map((c) => c.title)).toEqual(["第一章 铜镜", "第二章 修炼", "第三章 飞升"]);
expect(chs[0].start).toBe(t.indexOf("第一章"));
diff --git a/frontend/test/group.test.ts b/frontend/test/group.test.ts
index 3558e23..01eaab2 100644
--- a/frontend/test/group.test.ts
+++ b/frontend/test/group.test.ts
@@ -4,8 +4,19 @@ import type { Book } from "../src/api/types";
let seq = 1;
const mk = (path: string): Book => ({
- id: seq++, library_id: 1, path, title: path, format: "cbz", size: 1, mtime: 1, pages: 0,
- state: "ready", error: "", added_at: "", percent: 0, cover_url: "/api/books/0/cover",
+ id: seq++,
+ library_id: 1,
+ path,
+ title: path,
+ format: "cbz",
+ size: 1,
+ mtime: 1,
+ pages: 0,
+ state: "ready",
+ error: "",
+ added_at: "",
+ percent: 0,
+ cover_url: "/api/books/0/cover",
});
it("根目录组为空串且排最前;目录组按字典序;组内保持输入顺序", () => {
diff --git a/frontend/test/shelf.test.ts b/frontend/test/shelf.test.ts
index 5cd36c5..3cec567 100644
--- a/frontend/test/shelf.test.ts
+++ b/frontend/test/shelf.test.ts
@@ -3,20 +3,45 @@ import type { Book } from "../src/api/types";
import { sections, sortBooks } from "../src/lib/shelf";
const b = (over: Partial): Book =>
- ({ id: 1, path: "p", title: "t", format: "cbz", size: 1, pages: 1, percent: 0, added_at: "2026-01-01T00:00:00Z", library_id: 1, state: "ready", cover_url: "", page_url_fmt: "", pages_url: "", error: "", ...over }) as Book;
+ ({
+ id: 1,
+ path: "p",
+ title: "t",
+ format: "cbz",
+ size: 1,
+ pages: 1,
+ percent: 0,
+ added_at: "2026-01-01T00:00:00Z",
+ library_id: 1,
+ state: "ready",
+ cover_url: "",
+ page_url_fmt: "",
+ pages_url: "",
+ error: "",
+ ...over,
+ }) as Book;
it("sortBooks: added 新→旧 / title zh 本地化 / progress 高→低且并列按 added", () => {
const old = b({ id: 1, added_at: "2026-01-01T00:00:00Z", title: "b" });
const nw = b({ id: 2, added_at: "2026-02-01T00:00:00Z", title: "a" });
expect(sortBooks([old, nw], "added").map((x) => x.id)).toEqual([2, 1]);
expect(sortBooks([old, nw], "title").map((x) => x.id)).toEqual([2, 1]);
- expect(sortBooks([b({ id: 3, percent: 0.2 }), b({ id: 4, percent: 0.9 })], "progress").map((x) => x.id)).toEqual([4, 3]);
- const tie = [b({ id: 5, percent: 0.5, added_at: "2026-01-01T00:00:00Z" }), b({ id: 6, percent: 0.5, added_at: "2026-03-01T00:00:00Z" })];
+ expect(sortBooks([b({ id: 3, percent: 0.2 }), b({ id: 4, percent: 0.9 })], "progress").map((x) => x.id)).toEqual([
+ 4, 3,
+ ]);
+ const tie = [
+ b({ id: 5, percent: 0.5, added_at: "2026-01-01T00:00:00Z" }),
+ b({ id: 6, percent: 0.5, added_at: "2026-03-01T00:00:00Z" }),
+ ];
expect(sortBooks(tie, "progress").map((x) => x.id)).toEqual([6, 5]);
});
it("sections: flat 单段无标题;dir 按目录分组且组内排序、根目录置顶", () => {
- const books = [b({ id: 1, path: "x/a.cbz" }), b({ id: 2, path: "b.cbz", title: "B" }), b({ id: 3, path: "x/c.cbz", title: "A" })];
+ const books = [
+ b({ id: 1, path: "x/a.cbz" }),
+ b({ id: 2, path: "b.cbz", title: "B" }),
+ b({ id: 3, path: "x/c.cbz", title: "A" }),
+ ];
// 容器 Intl zh 实测序 A < B < t (localeCompare("zh")),故 title 升序为 id3,id2,id1
expect(sections(books, "title", "flat")).toEqual([{ label: "", books: [books[2], books[1], books[0]] }]);
const g = sections(books, "title", "dir");