fix(spa): episode anchor nav must handle in-app popstate + not re-scroll on refetch (#220 review)
Build ErsatzTV Image / Build & test (.NET) (pull_request) Successful in 7m30s
Build ErsatzTV Image / Docs update reminder (pull_request) Successful in 11s
Build ErsatzTV Image / EF migration integrity (SQLite + MySql) (pull_request) Successful in 9m53s
Build ErsatzTV Image / Build & push image (amd64) (pull_request) Has been skipped

Adversarial review of #220 found in-grid episode card clicks never
scrolled/highlighted: navigateToPath() (routing.ts) does pushState +
a synthetic popstate, not a real hash change, so the anchor effect's
hashchange-only listener never fired for same-pathname navigation.
Now listens to both hashchange and popstate.

Also: track the last anchor value actually scrolled to so a
refetch/pagination that recreates the items array (anchor unchanged)
doesn't hijack scroll position; document the known CHILD_PAGE_SIZE
deep-link limitation (parity with the Blazor fragment link); and fix
the MediaPosterCard/shell.css comments that described the highlight
ring as "temporary" when only its glow pulse fades, not the ring
itself.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
2026-07-10 23:36:15 +02:00
co-authored by Claude Fable 5
parent 7129d9c5b5
commit 5b945c308d
4 changed files with 130 additions and 10 deletions
+5 -3
View File
@@ -2529,14 +2529,16 @@ body {
box-shadow: 0 0 0 1px var(--action-primary);
}
/* Deep-link target highlight (#220), e.g. `#episode-{id}` from search/browse episode cards. */
/* Deep-link target highlight (#220), e.g. `#episode-{id}` from search/browse episode cards.
The ring itself (border + 2px box-shadow) persists for as long as the hash names this card;
only the outer glow pulse fades out shortly after mount. */
.ctv-media-card-highlighted {
border-color: var(--action-primary);
box-shadow: 0 0 0 2px var(--action-primary);
animation: ctv-media-card-highlight-fade 2400ms ease-out 1;
animation: ctv-media-card-highlight-pulse 2400ms ease-out 1;
}
@keyframes ctv-media-card-highlight-fade {
@keyframes ctv-media-card-highlight-pulse {
0% {
box-shadow: 0 0 0 4px var(--action-primary);
}