fix(ui): keep detail back navigation available while scrolling (#1576)

This commit is contained in:
4gray authored and GitHub committed 2026-09-10 21:34:10 +02:00
1 parent e76447975b
commit fff022afe4
28 files changed
+679 -138

No files matched your search

@@ -162,9 +162,12 @@ Contracts:
player subtree, so shell state changes cannot recreate the `<video>`.
- **External MPV/VLC sessions do not flip the layout to watch** — browse
layout stays, and the primary CTA keeps its "Stop <player>" behavior.
- Escape closes inline playback: the shell emits `closePlayerRequested`
when playback is active, the event was not `defaultPrevented`, and no
element is in browser fullscreen; hosts wire it to `closeInlinePlayer()`.
- The shell's sticky control and Escape close inline playback through
`closePlayerRequested`; hosts wire it to `closeInlinePlayer()`. From browse,
they emit the host-owned `backClicked` instead (unless `backAvailable=false`).
Escape respects fullscreen, menus/dialogs, editable fields and hidden/inert
surfaces, and consumes a handled key so one press performs only one action.
See [Portal Detail Navigation](./portal-detail-navigation.md).
- The now-playing bar separates two exits: the back arrow emits
`backClicked`, which hosts wire to their route-level `goBack()` (straight
back to the list — everything browse offers is also visible in watch, so
+28 -1
View File
@@ -23,6 +23,32 @@ do not reach global player shortcuts. Descendant controls retain their native
keys and Tab order. Entering watch still scrolls to the top; Back and saved
catalog scroll positions retain the existing navigation contract below.
The shell owns a single sticky Back control, outside the collapsing hero. Its
zero-height wrapper is a direct child of the scroll owner, so the control stays
16 px from the top throughout long episode lists without shifting the hero.
The button has an opaque app-themed surface, visible keyboard focus, an Escape
shortcut hint via native `title` and Electron `no-drag` hit testing. The hint
does not create an overlay that could consume the first Escape press.
The sticky control and Escape unwind one level: watch emits
`closePlayerRequested`, browse emits `backClicked`. Hosts retain their existing
route/inline/collection return behavior. The now-playing bar's separate route
Back action still returns directly to the list. Browse Escape requires focus
inside this shell; watch keeps the existing global close shortcut, including
M3U playback started from its sidebar. Handled events, key repeats/modifiers,
editable fields, inert/hidden shells, fullscreen, dialogs and menus are ignored.
Escape bubbles through the shell before Material's body-level tooltip dispatcher,
so focused detail actions return with one press even while their tooltip is open.
The document listener remains the outside-shell watch fallback; `defaultPrevented`
prevents duplicate actions and preserves descendant handlers' priority.
After closing a player, lost focus moves to the sticky control (or the shell
when there is no browse Back), without scrolling or stealing existing focus.
Hosts without browse navigation set `backAvailable=false`: M3U uses its channel
sidebar, and collection bootstrap placeholders have no return handler. They
have no browse button or browse Escape action; M3U watch still offers Close
player. Loading/error shells with a return handler keep Back available.
## Summary
- Xtream category browsing uses a route-first detail model.
@@ -30,7 +56,8 @@ catalog scroll positions retain the existing navigation contract below.
- Detail pages themselves are two-state (browse ↔ watch) inside
`PortalDetailShellComponent`; entering/leaving watch is a layout state,
not a navigation. Route-level back semantics are unchanged; the
watch-state back button only closes the inline player. See
sticky watch control closes the inline player, while the now-playing bar
retains its separate direct return to the list. See
[Embedded Inline Playback](./embedded-inline-playback.md).
- Favorites and recently viewed collections now use collection-owned inline detail
for non-live Xtream and Stalker items.