fix(web,learner): navigation swaps at once; content-only entrance, loading line, focus (R19)

Drops document-level View Transitions and the lesson hold: they dropped clicks for 120-180 ms, froze the screen
while route code loaded, and let the dock act on a stale lesson. Navigation now swaps immediately; only the
content region enters (opacity and a 6 px rise, 160 ms); a 2 px loading line appears when code or data takes over
150 ms; the dock works from the outline and the URL, so a second Next advances again; focus moves to the new h1
and a polite live region announces it. Route chunks of a feature preload together so the sidebar never drops.
Scroll restore stops on user input; pdf.js never starts a load after cleanup.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Lucas WintherandClaude Opus 5.5 committed 2026-10-30 21:49:49 +01:00
1 parent 305c262ff1
commit b5e00af4f7
18 files changed
+231 -275

No files matched your search

@@ -78,6 +78,7 @@ export function DeckViewer({ deck, notes, initialPage = 1, keyboard = true, titl
setDoc(null); setError(null); setPages(0); setView({ front: 0, page: 0, dir: null });
loadPdfjs()
.then((pdfjs) => {
if (!live) throw new Error("unmounted"); // never start a load (and its worker) after cleanup
const t = pdfjs.getDocument({ url: deck.url, withCredentials: true });
task = t;
return t.promise;
@@ -146,7 +147,7 @@ export function DeckViewer({ deck, notes, initialPage = 1, keyboard = true, titl
<canvas
key={i} ref={i ? canvasB : canvasA} hidden={!doc || !!error}
data-front={front ? "" : undefined} data-page={front && view.page ? view.page : undefined} data-leaving={!front && view.dir ? "" : undefined} data-dir={view.dir ?? undefined}
role={front ? "img" : undefined} aria-hidden={front ? undefined : true} aria-label={front ? `Slide ${page} of ${pages}` : undefined}
role={front ? "img" : undefined} aria-hidden={front ? undefined : true} aria-label={front ? `Slide ${view.page || page} of ${pages}` : undefined}
/>
);
})}