// 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"; interface ViewModeState { currentMode: ViewMode; currentPage: number; } function setViewMode(container: HTMLElement, mode: ViewMode): void { const content = container.querySelector(".ebook-content"); if (!content) return; const element = content as HTMLElement; element.classList.remove( "paginated", "scrolled", "single-column", "double-column", ); switch (mode) { case "paginated": applyPaginatedMode(container, element); break; case "scrolled": applyScrolledMode(container, element); break; case "single-column": applySingleColumn(element); break; case "double-column": applyDoubleColumn(element); break; } } function applyPaginatedMode( container: HTMLElement, element: HTMLElement, ): void { element.classList.add("paginated"); element.style.height = "100vh"; element.style.overflow = "hidden"; element.style.columnCount = "1"; element.style.columnGap = "0"; enablePagination(container, element); } function applyScrolledMode(container: HTMLElement, element: HTMLElement): void { element.classList.add("scrolled"); element.style.height = "auto"; element.style.overflowY = "auto"; element.style.columnCount = "1"; disablePagination(container); } function applySingleColumn(element: HTMLElement): void { element.classList.add("single-column"); element.style.columnCount = "1"; element.style.columnGap = "0"; element.style.maxWidth = "800px"; element.style.margin = "0 auto"; } function applyDoubleColumn(element: HTMLElement): void { element.classList.add("double-column"); element.style.columnCount = "2"; element.style.columnGap = "60px"; element.style.columnRule = "1px solid var(--text-secondary)"; element.style.maxWidth = "1400px"; element.style.margin = "0 auto"; } function enablePagination(container: HTMLElement, element: HTMLElement): void { const totalHeight = element.scrollHeight; const pageHeight = element.clientHeight; const pageCount = Math.ceil(totalHeight / pageHeight); addPaginationControls(container, pageCount); } function disablePagination(container: HTMLElement): void { const controls = container.querySelector(".pagination-controls"); controls?.remove(); } function addPaginationControls( container: HTMLElement, pageCount: number, ): void { let currentPage = 1; const controls = document.createElement("div"); controls.className = "pagination-controls fixed bottom-0 left-0 right-0 bg-opacity-95 backdrop-blur border-t"; controls.innerHTML = ` Page ${currentPage} of ${pageCount} `; controls.querySelector(".prev-page")?.addEventListener("click", () => { if (currentPage > 1) { currentPage--; goToPage(container, currentPage); } }); controls.querySelector(".next-page")?.addEventListener("click", () => { if (currentPage < pageCount) { currentPage++; goToPage(container, currentPage); } }); container.appendChild(controls); } function goToPage(container: HTMLElement, pageNumber: number): void { const content = container.querySelector(".ebook-content") as HTMLElement; if (!content) return; const pageHeight = content.clientHeight; const scrollTop = (pageNumber - 1) * pageHeight; content.scrollTo({ top: scrollTop, behavior: "smooth", }); const pageInfo = container.querySelector(".page-info"); if (pageInfo) { pageInfo.textContent = `Page ${pageNumber} of ${getTotalPageCount(container)}`; } } function getTotalPageCount(container: HTMLElement): number { const content = container.querySelector(".ebook-content") as HTMLElement; if (!content) return 1; const totalHeight = content.scrollHeight; const pageHeight = content.clientHeight; return Math.ceil(totalHeight / pageHeight); } 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"; }