From 815a072ef0e86c80163d1c8bbeca0a1c3bc99dd1 Mon Sep 17 00:00:00 2001 From: Miguel Palhas Date: Tue, 25 Aug 2026 10:40:37 +0100 Subject: [PATCH] fix(web): drop back button from movie and series pages (#229) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 --- web/index.html | 10 ++-------- web/src/main.ts | 18 +++++++----------- web/src/style.css | 6 ++++++ 3 files changed, 15 insertions(+), 19 deletions(-) diff --git a/web/index.html b/web/index.html index dd45e56..4a56b13 100644 --- a/web/index.html +++ b/web/index.html @@ -218,10 +218,7 @@ -->
-
- - -
+
@@ -470,10 +467,7 @@ -->
-
- - -
+
diff --git a/web/src/main.ts b/web/src/main.ts index 410aa33..4dc735c 100644 --- a/web/src/main.ts +++ b/web/src/main.ts @@ -393,14 +393,14 @@ function main() { must("#library"), { kind: "library" }, ); - // no origin click to restore focus to on a deep link — the series - // view's back control is the closest stand-in + // no origin click to restore focus to on a deep link — the library + // rail button is the closest stand-in tvDeck.open({ title, sub, seriesId, target, - origin: must("#series-back"), + origin: must("#nav-library"), returnTo: must("#series"), parentRoute: { kind: "series", seriesId }, }); @@ -1294,7 +1294,6 @@ function externalLink(label: string, href: string): HTMLAnchorElement { function movieMain(views: HideableView[]): MovieView { const view = must("#movie"); const deckEl = must("#deck"); - const back = must("#movie-back"); const statusEl = must("#movie-status"); const hero = must("#movie-hero"); const poster = must("#movie-poster"); @@ -1906,7 +1905,8 @@ function movieMain(views: HideableView[]): MovieView { filesSection.hidden = true; diskRows.replaceChildren(); sweep.disabled = false; - back.focus(); + titleEl.setAttribute("tabindex", "-1"); + titleEl.focus(); await load(); } @@ -1929,8 +1929,6 @@ function movieMain(views: HideableView[]): MovieView { target?.focus(); } - back.addEventListener("click", close); - // capture + stopImmediatePropagation: one Escape steps back one layer — // the library and search decks also listen for Escape on this window window.addEventListener( @@ -3125,7 +3123,6 @@ const SERIES_REFRESH_WAIT_MS = 30_000; function seriesMain(tvDeck: TvReleasesView, views: HideableView[]): SeriesView { const view = must("#series"); const deckEl = must("#deck"); - const back = must("#series-back"); const hero = must("#series-hero"); const poster = must("#series-poster"); const titleEl = must("#series-title"); @@ -3793,7 +3790,8 @@ function seriesMain(tvDeck: TvReleasesView, views: HideableView[]): SeriesView { view.hidden = false; clearRemove(); clearRichDetail(); - back.focus(); + titleEl.setAttribute("tabindex", "-1"); + titleEl.focus(); await load(); } @@ -3814,8 +3812,6 @@ function seriesMain(tvDeck: TvReleasesView, views: HideableView[]): SeriesView { origin?.focus(); } - back.addEventListener("click", close); - // capture, like every other layer: the tv deck's listener is registered // first, so one Esc steps back one layer window.addEventListener( diff --git a/web/src/style.css b/web/src/style.css index 8a0ca95..efe15b9 100644 --- a/web/src/style.css +++ b/web/src/style.css @@ -528,6 +528,12 @@ body { flex: 1; } +/* movie and series: the hero banner meets the rail — no top padding (#229) */ +.deck#movie, +.deck#series { + padding-top: 0; +} + .deck-status { margin: 0 0 var(--space-4); color: var(--ink-muted);