fix: implement viewport-based page navigation for EPUBs

- Replace spine-only navigation with scroll-based page navigation
- nextPage: scroll down within chapter, only jump to next spine at chapter end
- previousPage: scroll up within chapter, only jump to previous spine at chapter start
- Use viewportHeight - 120 for accurate page height calculation
- Fallback to spine-only navigation when page calculation not available
This commit is contained in:
2026-04-05 21:23:30 -04:00
parent 7d4c6ac142
commit 35acf87faa
+62 -43
View File
@@ -22,31 +22,43 @@ export function createNavigationAPI() {
readerEvents.emit("beforePageChange", state.currentReader); readerEvents.emit("beforePageChange", state.currentReader);
if (state.currentReader.type === "ebook") { if (state.currentReader.type === "ebook") {
if ( const container = document.getElementById("reader-content");
state.currentReader.currentSpineIndex < const viewportHeightAdjusted = window.innerHeight - 120;
state.currentReader.cif.spine.length - 1
) { if (pageCalculationResult) {
state.currentReader.currentSpineIndex++; const currentChapter = pageCalculationResult.chapterMap.get(
if (pageCalculationResult) { state.currentReader.currentSpineIndex,
const container = document.getElementById("reader-content"); );
if (container) {
const viewportHeight = window.innerHeight; if (currentChapter && container) {
const target = getScrollPositionForPage( const currentPageInChapter = Math.floor(
pageCalculationResult, container.scrollTop / viewportHeightAdjusted,
state.currentReader.currentPage || );
state.currentReader.currentSpineIndex + 1, const pagesInCurrentChapter =
viewportHeight, currentChapter.endPage - currentChapter.startPage + 1;
);
if ( if (currentPageInChapter < pagesInCurrentChapter - 1) {
target && // Still pages left in current chapter - just scroll down
target.spineIndex !== state.currentReader.currentSpineIndex container.scrollTop =
) { (currentPageInChapter + 1) * viewportHeightAdjusted;
state.currentReader.currentSpineIndex = target.spineIndex; } else if (
container.scrollTop = target.scrollTop; state.currentReader.currentSpineIndex <
} state.currentReader.cif.spine.length - 1
) {
// At end of chapter, move to next spine
state.currentReader.currentSpineIndex++;
renderSpineItem();
} }
} }
renderSpineItem(); } else {
// Fallback: just move to next spine
if (
state.currentReader.currentSpineIndex <
state.currentReader.cif.spine.length - 1
) {
state.currentReader.currentSpineIndex++;
renderSpineItem();
}
} }
} else if (state.currentReader.type === "pdf") { } else if (state.currentReader.type === "pdf") {
const totalPages = state.readerMetadata?.total_pages || 0; const totalPages = state.readerMetadata?.total_pages || 0;
@@ -80,28 +92,35 @@ export function createNavigationAPI() {
readerEvents.emit("beforePageChange", state.currentReader); readerEvents.emit("beforePageChange", state.currentReader);
if (state.currentReader.type === "ebook") { if (state.currentReader.type === "ebook") {
if (state.currentReader.currentSpineIndex > 0) { const container = document.getElementById("reader-content");
state.currentReader.currentSpineIndex--; const viewportHeightAdjusted = window.innerHeight - 120;
if (pageCalculationResult) {
const container = document.getElementById("reader-content"); if (pageCalculationResult) {
if (container) { const currentChapter = pageCalculationResult.chapterMap.get(
const viewportHeight = window.innerHeight; state.currentReader.currentSpineIndex,
const target = getScrollPositionForPage( );
pageCalculationResult,
state.currentReader.currentPage || if (currentChapter && container) {
state.currentReader.currentSpineIndex + 1, const currentPageInChapter = Math.floor(
viewportHeight, container.scrollTop / viewportHeightAdjusted,
); );
if (
target && if (currentPageInChapter > 0) {
target.spineIndex !== state.currentReader.currentSpineIndex // Not at start of chapter - just scroll up
) { container.scrollTop =
state.currentReader.currentSpineIndex = target.spineIndex; (currentPageInChapter - 1) * viewportHeightAdjusted;
container.scrollTop = target.scrollTop; } else if (state.currentReader.currentSpineIndex > 0) {
} // At start of chapter, move to previous spine
state.currentReader.currentSpineIndex--;
renderSpineItem();
} }
} }
renderSpineItem(); } else {
// Fallback: just move to previous spine
if (state.currentReader.currentSpineIndex > 0) {
state.currentReader.currentSpineIndex--;
renderSpineItem();
}
} }
} else if (state.currentReader.type === "pdf") { } else if (state.currentReader.type === "pdf") {
if (state.currentReader.currentPage > 1) { if (state.currentReader.currentPage > 1) {