From 4b2b7ee66a1e540db65f749603c0af894afc9611 Mon Sep 17 00:00:00 2001 From: John O'Keefe Date: Sat, 4 Apr 2026 13:48:47 -0400 Subject: [PATCH] feat: Add ebook view modes with Feature Registration Pattern Convert view-modes.ts to init(context) pattern with: - Paginated mode with pagination controls - Scrolled mode for continuous reading - Single and double column layouts - Event-based navigation and mode switching --- web/src/reader/ebook/view-modes.ts | 62 +++++++++++++++++++++++++----- 1 file changed, 53 insertions(+), 9 deletions(-) diff --git a/web/src/reader/ebook/view-modes.ts b/web/src/reader/ebook/view-modes.ts index ff7c75b..1846e6e 100644 --- a/web/src/reader/ebook/view-modes.ts +++ b/web/src/reader/ebook/view-modes.ts @@ -1,4 +1,38 @@ // Different viewing modes for ebooks +// Feature Registration Pattern implementation + +import type { ReaderContext } from "../core/reader-context"; + +export function init(context: ReaderContext): void { + let state: ViewModeState | null = null; + + context.events.on("reader:loaded", (detail: { container: HTMLElement }) => { + state = { currentMode: "paginated", currentPage: 1 }; + setViewMode(detail.container, "paginated"); + }); + + context.events.on("view-mode:set", (detail: { mode: ViewMode }) => { + if (state && context.elements.readerContent) { + state.currentMode = detail.mode; + setViewMode(context.elements.readerContent, detail.mode); + context.events.emit("view-mode:changed", { mode: detail.mode }); + } + }); + + context.events.on("view-mode:get", () => { + if (state) { + context.events.emit("view-mode:current", state); + } + }); + + context.events.on("pagination:go-to-page", (detail: { page: number }) => { + if (state && context.elements.readerContent) { + state.currentPage = detail.page; + goToPage(context.elements.readerContent, detail.page); + context.events.emit("pagination:page-changed", { page: detail.page }); + } + }); +} type ViewMode = "paginated" | "scrolled" | "single-column" | "double-column"; @@ -11,7 +45,9 @@ function setViewMode(container: HTMLElement, mode: ViewMode): void { const content = container.querySelector(".ebook-content"); if (!content) return; - content.classList.remove( + const element = content as HTMLElement; + + element.classList.remove( "paginated", "scrolled", "single-column", @@ -20,16 +56,16 @@ function setViewMode(container: HTMLElement, mode: ViewMode): void { switch (mode) { case "paginated": - applyPaginatedMode(container, content as HTMLElement); + applyPaginatedMode(container, element); break; case "scrolled": - applyScrolledMode(container, content as HTMLElement); + applyScrolledMode(container, element); break; case "single-column": - applySingleColumn(content as HTMLElement); + applySingleColumn(element); break; case "double-column": - applyDoubleColumn(content as HTMLElement); + applyDoubleColumn(element); break; } } @@ -93,7 +129,7 @@ function disablePagination(container: HTMLElement): void { function addPaginationControls( container: HTMLElement, pageCount: number, -): ViewModeState { +): void { let currentPage = 1; const controls = document.createElement("div"); @@ -120,8 +156,6 @@ function addPaginationControls( }); container.appendChild(controls); - - return { currentMode: "paginated", currentPage }; } function goToPage(container: HTMLElement, pageNumber: number): void { @@ -152,4 +186,14 @@ function getTotalPageCount(container: HTMLElement): number { return Math.ceil(totalHeight / pageHeight); } -export { setViewMode, getCurrentViewMode }; +export function getCurrentViewMode(container: HTMLElement): ViewMode { + const content = container.querySelector(".ebook-content") as HTMLElement; + if (!content) return "paginated"; + + if (content.classList.contains("paginated")) return "paginated"; + if (content.classList.contains("scrolled")) return "scrolled"; + if (content.classList.contains("single-column")) return "single-column"; + if (content.classList.contains("double-column")) return "double-column"; + + return "paginated"; +} \ No newline at end of file