feat(pdftract-46jjf): complete coordinator - navigation features

This commit completes the coordinator bead for Phase 7.9.7 navigation
features. All sub-beads (pdftract-2z88j, pdftract-2wqir, pdftract-47e42)
were previously closed; this adds the coordinator-level glue:

- Added updatePageIndicator() function to display "Page X of Y" in toolbar
- Added prefetchAdjacentPages() to preload prev/next page JSON and SVG
- Added prefetchPage() helper for individual page prefetching
- Added page-indicator span to HTML toolbar
- Added .page-indicator CSS styling

Acceptance criteria (all PASS):
- Sidebar clickable with thumbnails (pdftract-2z88j)
- Prev/Next buttons work + indicator updates
- ArrowLeft/Right navigation works (pdftract-2wqir)
- '/' focuses search (pdftract-2wqir)
- '1'-'8' toggle layers (pdftract-2wqir)
- URL fragment #page=N navigates on load (pdftract-47e42)
- Sharing URL with #page=14 jumps to page 14 (pdftract-47e42)
- Browser back/forward works (pdftract-47e42)

Closes pdftract-46jjf
This commit is contained in:
jedarden 2026-06-01 09:25:44 -04:00
parent df21126d99
commit f5e045f26d
3 changed files with 30 additions and 1 deletions

View file

@ -641,7 +641,15 @@ function nextPage(){
function updateNavState(){
document.getElementById('btn-prev').disabled=currentPage<=0;
document.getElementById('btn-next').disabled=currentPage>=totalPages-1
document.getElementById('btn-next').disabled=currentPage>=totalPages-1;
updatePageIndicator()
}
function updatePageIndicator(){
const indicator=document.getElementById('page-indicator');
if(indicator){
indicator.textContent=`Page ${currentPage+1} of ${totalPages}`;
}
}
function renderThumbnails(){
@ -699,6 +707,25 @@ function updateActiveThumbnail(){
t.classList.toggle('active',parseInt(t.dataset.index)===currentPage);
t.disabled=false;
});
prefetchAdjacentPages()
}
function prefetchAdjacentPages(){
// Prefetch previous page
if(currentPage>0){
prefetchPage(currentPage-1);
}
// Prefetch next page
if(currentPage<totalPages-1){
prefetchPage(currentPage+1);
}
}
function prefetchPage(index){
// Prefetch the page JSON
fetch(`/api/page/${index}`).catch(()=>{});
// Prefetch the SVG
fetch(`/api/page/${index}/svg`).catch(()=>{});
}
function scrollPage(delta){

View file

@ -15,6 +15,7 @@
<main class="main">
<div class="toolbar">
<button id="btn-prev" class="btn" aria-label="Previous page">← Prev</button>
<span id="page-indicator" class="page-indicator">Page 1 of 1</span>
<button id="btn-next" class="btn" aria-label="Next page">Next →</button>
<input id="search-input" type="search" placeholder="Search spans... (press /)" aria-label="Search spans" class="search-input">
<span id="match-count" class="match-count"></span>

View file

@ -15,6 +15,7 @@ body{font-family:system-ui,-apple-system,sans-serif;font-size:14px;line-height:1
.btn:hover{background:#f0f0f0}
.btn:active{background:#e0e0e0}
.btn:disabled{opacity:.5;cursor:not-allowed}
.page-indicator{font-size:13px;font-weight:500;color:#666;white-space:nowrap;padding:0 8px;min-width:100px;text-align:center}
.search-input{flex:1;max-width:300px;padding:6px 10px;border:1px solid #ddd;border-radius:4px;font-size:13px;font-family:inherit}
.search-input:focus{outline:none;border-color:#0078d4;box-shadow:0 0 0 2px rgba(0,120,212,.2)}
.match-count{font-size:12px;color:#666;white-space:nowrap;padding:0 8px}