Files
bookhoard/web/src/reader/core/reader-state.ts
T
john-okeefe 1e7d13dc85 feat(ebook-reader): implement page-based pagination with CFI support
This commit implements true page-based pagination for the ebook reader,
similar to Kindle's approach where content is split into discrete pages
based on viewport size, font settings, and content layout.

Phase 1 - Bug Fixes:
- Fix goToPage to use getScrollPositionForPage instead of treating
  page numbers as spine indices
- Move page calculation to initialize before first render to avoid
  race condition with scroll handler
- Add fallback page calculation when pageCalculationResult is null

Phase 2 - Page Splitting:
- Add new page-splitter.ts module with CFI-based splitting for EPUB
  and height-based fallback for other formats
- Integrate splitContent into page-calculator to generate discrete
  page content for each spine item
- Store pages[] array in ChapterPageInfo for rendering
- Rewrite navigation (nextPage, previousPage, renderSpineItem) to
  use page-based approach with currentPage tracking
- Remove old scroll-based pagination from view-modes.ts
- Update paginated mode CSS for true page clipping

Phase 3 - Progress Display:
- Update progress-indicator to use currentPage directly instead of
  calculating from scroll position
- Fix getCurrentPage in reader-state to return currentPage for ebooks

Phase 4 - Interface Fixes:
- Add currentPage field to UniversalReader interface
- Update sendProgressUpdate to use currentPage directly
- Initialize currentPage to 1 on reader creation

Key features:
- Dynamic page count based on font size, line height, margins
- CFI-based page splitting preserves reading context
- Falls back to height-based splitting for non-EPUB formats
- Progress display updates immediately on page change
- Settings changes trigger page recalculation and re-render
2026-04-06 21:18:29 -04:00

45 lines
1.1 KiB
TypeScript

import type { ReaderState } from "./reader-context";
type CurrentReader = import("./reader-context").CurrentReader;
let currentState: ReaderState = {
currentReader: null,
readerMetadata: null,
};
export function getState(): ReaderState {
return { ...currentState };
}
export function setState(updates: Partial<ReaderState>): void {
const oldState = { ...currentState };
currentState = { ...currentState, ...updates };
// Emit events for significant changes
if (
updates.currentReader &&
oldState.currentReader !== updates.currentReader
) {
readerEvents.emit("readerReady", currentState.currentReader);
}
}
export function getCurrentReader(): CurrentReader | null {
return currentState.currentReader;
}
export function getReaderMetadata(): ReaderMetadata | null {
return currentState.readerMetadata;
}
export function getCurrentPage(): number {
const reader = currentState.currentReader;
if (!reader) return 0;
if (reader.type === "ebook") {
return reader.currentPage ?? reader.currentSpineIndex + 1;
}
return reader.currentPage;
}
import { readerEvents } from "./reader-events";