feat(reader): immersive chrome + WeChat-Read/Mihon-style bottom sheets — tap-center toggles header/toolbar, progress & page sliders seek anywhere, WYSIWYG theme swatches, A± font size; CBZ gains 连读/整页/适高 modes, edge-tap & arrow-key paging, persisted mode (seekChapter helper + test)
This commit is contained in:
@@ -47,3 +47,10 @@ export function splitChapters(text: string): TxtChapter[] {
|
||||
export function chapterText(text: string, chapters: TxtChapter[], i: number): string {
|
||||
return text.slice(chapters[i].start, chapters[i + 1]?.start ?? text.length);
|
||||
}
|
||||
|
||||
/** 全书进度分数(0..1)→ 章序号 + 章内分数。进度滑条用。 */
|
||||
export function seekChapter(n: number, frac: number): { idx: number; intra: number } {
|
||||
const p = Math.min(0.9999, Math.max(0, frac)) * n;
|
||||
const idx = Math.min(n - 1, Math.floor(p));
|
||||
return { idx, intra: p - idx };
|
||||
}
|
||||
|
||||
@@ -28,8 +28,7 @@ export function useReaderPrefs() {
|
||||
return {
|
||||
prefs,
|
||||
fontSize: FONT_SIZES[prefs.sizeIdx],
|
||||
cycleTheme: () =>
|
||||
setPrefs((p) => ({ ...p, theme: RD_THEMES[(RD_THEMES.indexOf(p.theme) + 1) % RD_THEMES.length] })),
|
||||
setTheme: (theme: RdTheme) => setPrefs((p) => ({ ...p, theme })),
|
||||
bump: (d: number) =>
|
||||
setPrefs((p) => ({ ...p, sizeIdx: Math.min(FONT_SIZES.length - 1, Math.max(0, p.sizeIdx + d)) })),
|
||||
};
|
||||
|
||||
@@ -4,9 +4,16 @@ import { api } from "../api/client";
|
||||
import type { Book } from "../api/types";
|
||||
import { createProgressSaver, type ProgressSaver } from "./progress";
|
||||
|
||||
export interface Chrome {
|
||||
on: boolean;
|
||||
toggle(): void;
|
||||
show(): void;
|
||||
}
|
||||
|
||||
export interface ReaderProps {
|
||||
book: Book;
|
||||
initialLocator?: Record<string, unknown>;
|
||||
chrome: Chrome;
|
||||
}
|
||||
|
||||
export function useProgressSaver(bookId: number): ProgressSaver {
|
||||
|
||||
Reference in New Issue
Block a user