feat(frontend): cbz page/spread view math (TDD)
This commit is contained in:
@@ -0,0 +1,21 @@
|
|||||||
|
export type PageMode = "page" | "spread";
|
||||||
|
|
||||||
|
export function viewCount(count: number, mode: PageMode): number {
|
||||||
|
return mode === "page" ? count : Math.ceil(count / 2);
|
||||||
|
}
|
||||||
|
export function pageIndexToView(i: number, mode: PageMode): number {
|
||||||
|
return mode === "page" ? i : Math.floor(i / 2);
|
||||||
|
}
|
||||||
|
export function viewToPageIndex(v: number, mode: PageMode): number {
|
||||||
|
return mode === "page" ? v : v * 2;
|
||||||
|
}
|
||||||
|
/** 一个 spread 视图要渲染的页,按显示顺序(LTR=[左,右];RTL=[右,左] 即先读页在前)。 */
|
||||||
|
export function spreadPages(first: number, count: number, rtl: boolean): number[] {
|
||||||
|
const pages = [first, ...(first + 1 < count ? [first + 1] : [])];
|
||||||
|
return rtl ? [...pages].reverse() : pages;
|
||||||
|
}
|
||||||
|
/** 翻一屏/页;rtl 时方向翻转;越界钳制。 */
|
||||||
|
export function turnView(v: number, d: number, rtl: boolean, views: number): number {
|
||||||
|
const step = rtl ? -d : d;
|
||||||
|
return Math.max(0, Math.min(views - 1, v + step));
|
||||||
|
}
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
import { describe, expect, it } from "vitest";
|
||||||
|
import { spreadPages, pageIndexToView, turnView, viewCount, viewToPageIndex } from "../src/lib/cbzPages";
|
||||||
|
|
||||||
|
describe("cbzPages", () => {
|
||||||
|
it("page mode: one page per view", () => {
|
||||||
|
expect(viewCount(5, "page")).toBe(5);
|
||||||
|
expect(viewToPageIndex(2, "page")).toBe(2);
|
||||||
|
expect(pageIndexToView(2, "page")).toBe(2);
|
||||||
|
});
|
||||||
|
it("spread mode: pairs [0,1] [2,3] [4]", () => {
|
||||||
|
expect(viewCount(5, "spread")).toBe(3);
|
||||||
|
expect(pageIndexToView(3, "spread")).toBe(1);
|
||||||
|
expect(viewToPageIndex(1, "spread")).toBe(2);
|
||||||
|
expect(spreadPages(2, 5, false)).toEqual([2, 3]);
|
||||||
|
expect(spreadPages(4, 5, false)).toEqual([4]); // 落单页
|
||||||
|
expect(spreadPages(2, 5, true)).toEqual([3, 2]); // RTL 右页为先
|
||||||
|
});
|
||||||
|
it("turnView clamps and RTL flips direction", () => {
|
||||||
|
expect(turnView(0, 1, false, 3)).toBe(1);
|
||||||
|
expect(turnView(2, 1, false, 3)).toBe(2); // 右边界钳制
|
||||||
|
expect(turnView(0, -1, false, 3)).toBe(0); // 左边界钳制
|
||||||
|
expect(turnView(1, 1, true, 3)).toBe(0); // RTL:d=+1 变后退
|
||||||
|
});
|
||||||
|
});
|
||||||
Reference in New Issue
Block a user