fix(web): drop back button from movie and series pages (#229)

The rail, browser back, and Esc already cover navigation — the back
button was a third way to do what two other things already do, and it
cost the page its first line.

- Remove #movie-back and #series-back buttons and their event listeners
- Focus lands on the title element (tabindex=-1) instead of the removed
  button on open
- TV releases back button is untouched
- Hero banner now meets the rail with zero top padding on movie/series
- Esc and parent-route behaviour unchanged
- Deep link fallback for TV releases uses #nav-library instead of the
  removed #series-back
This commit is contained in:
Miguel Palhas
2026-08-25 10:40:37 +01:00
parent 8c3e1c4a92
commit 815a072ef0
3 changed files with 15 additions and 19 deletions
+2 -8
View File
@@ -218,10 +218,7 @@
--> -->
<main class="deck" id="movie" hidden aria-label="movie detail"> <main class="deck" id="movie" hidden aria-label="movie detail">
<header class="releases-head"> <p class="deck-status readout" id="movie-status" role="status" hidden></p>
<button type="button" class="control" id="movie-back">back</button>
<p class="deck-status readout" id="movie-status" role="status" hidden></p>
</header>
<section class="module movie-hero" id="movie-hero" aria-label="title metadata"> <section class="module movie-hero" id="movie-hero" aria-label="title metadata">
<div class="movie-body"> <div class="movie-body">
@@ -470,10 +467,7 @@
--> -->
<main class="deck releases" id="series" hidden aria-label="series detail"> <main class="deck releases" id="series" hidden aria-label="series detail">
<header class="releases-head"> <p class="deck-status readout" id="series-status" role="status" hidden></p>
<button type="button" class="control" id="series-back">back</button>
<p class="deck-status readout" id="series-status" role="status" hidden></p>
</header>
<section class="module movie-hero" id="series-hero" aria-label="title metadata"> <section class="module movie-hero" id="series-hero" aria-label="title metadata">
<div class="movie-body"> <div class="movie-body">
+7 -11
View File
@@ -393,14 +393,14 @@ function main() {
must<HTMLElement>("#library"), must<HTMLElement>("#library"),
{ kind: "library" }, { kind: "library" },
); );
// no origin click to restore focus to on a deep link — the series // no origin click to restore focus to on a deep link — the library
// view's back control is the closest stand-in // rail button is the closest stand-in
tvDeck.open({ tvDeck.open({
title, title,
sub, sub,
seriesId, seriesId,
target, target,
origin: must<HTMLButtonElement>("#series-back"), origin: must<HTMLElement>("#nav-library"),
returnTo: must<HTMLElement>("#series"), returnTo: must<HTMLElement>("#series"),
parentRoute: { kind: "series", seriesId }, parentRoute: { kind: "series", seriesId },
}); });
@@ -1294,7 +1294,6 @@ function externalLink(label: string, href: string): HTMLAnchorElement {
function movieMain(views: HideableView[]): MovieView { function movieMain(views: HideableView[]): MovieView {
const view = must<HTMLElement>("#movie"); const view = must<HTMLElement>("#movie");
const deckEl = must<HTMLElement>("#deck"); const deckEl = must<HTMLElement>("#deck");
const back = must<HTMLButtonElement>("#movie-back");
const statusEl = must<HTMLElement>("#movie-status"); const statusEl = must<HTMLElement>("#movie-status");
const hero = must<HTMLElement>("#movie-hero"); const hero = must<HTMLElement>("#movie-hero");
const poster = must<HTMLImageElement>("#movie-poster"); const poster = must<HTMLImageElement>("#movie-poster");
@@ -1906,7 +1905,8 @@ function movieMain(views: HideableView[]): MovieView {
filesSection.hidden = true; filesSection.hidden = true;
diskRows.replaceChildren(); diskRows.replaceChildren();
sweep.disabled = false; sweep.disabled = false;
back.focus(); titleEl.setAttribute("tabindex", "-1");
titleEl.focus();
await load(); await load();
} }
@@ -1929,8 +1929,6 @@ function movieMain(views: HideableView[]): MovieView {
target?.focus(); target?.focus();
} }
back.addEventListener("click", close);
// capture + stopImmediatePropagation: one Escape steps back one layer — // capture + stopImmediatePropagation: one Escape steps back one layer —
// the library and search decks also listen for Escape on this window // the library and search decks also listen for Escape on this window
window.addEventListener( window.addEventListener(
@@ -3125,7 +3123,6 @@ const SERIES_REFRESH_WAIT_MS = 30_000;
function seriesMain(tvDeck: TvReleasesView, views: HideableView[]): SeriesView { function seriesMain(tvDeck: TvReleasesView, views: HideableView[]): SeriesView {
const view = must<HTMLElement>("#series"); const view = must<HTMLElement>("#series");
const deckEl = must<HTMLElement>("#deck"); const deckEl = must<HTMLElement>("#deck");
const back = must<HTMLButtonElement>("#series-back");
const hero = must<HTMLElement>("#series-hero"); const hero = must<HTMLElement>("#series-hero");
const poster = must<HTMLImageElement>("#series-poster"); const poster = must<HTMLImageElement>("#series-poster");
const titleEl = must<HTMLElement>("#series-title"); const titleEl = must<HTMLElement>("#series-title");
@@ -3793,7 +3790,8 @@ function seriesMain(tvDeck: TvReleasesView, views: HideableView[]): SeriesView {
view.hidden = false; view.hidden = false;
clearRemove(); clearRemove();
clearRichDetail(); clearRichDetail();
back.focus(); titleEl.setAttribute("tabindex", "-1");
titleEl.focus();
await load(); await load();
} }
@@ -3814,8 +3812,6 @@ function seriesMain(tvDeck: TvReleasesView, views: HideableView[]): SeriesView {
origin?.focus(); origin?.focus();
} }
back.addEventListener("click", close);
// capture, like every other layer: the tv deck's listener is registered // capture, like every other layer: the tv deck's listener is registered
// first, so one Esc steps back one layer // first, so one Esc steps back one layer
window.addEventListener( window.addEventListener(
+6
View File
@@ -528,6 +528,12 @@ body {
flex: 1; flex: 1;
} }
/* movie and series: the hero banner meets the rail — no top padding (#229) */
.deck#movie,
.deck#series {
padding-top: 0;
}
.deck-status { .deck-status {
margin: 0 0 var(--space-4); margin: 0 0 var(--space-4);
color: var(--ink-muted); color: var(--ink-muted);