mirror of
https://github.com/4gray/iptvnator.git
synced 2026-10-15 21:56:18 -08:00
feat(workspace): move page Back buttons into the header and add a history fallback (#1814)
This commit is contained in:
1 parent
6f247fb538
commit
84aef83a6c
40 files changed
+902
-216
No files matched your search
@@ -93,10 +93,9 @@ The shell is intentionally split into four persistent regions:
|
||||
4. No brand mark: it only repeated the first workspace link (Dashboard,
|
||||
or Sources when the dashboard is off).
|
||||
2. Top header:
|
||||
1. Leading Back slot, shown while the current page registers a target
|
||||
with `WorkspaceBackNavigationService` (detail pages today). At
|
||||
≤640 px it takes the context drawer toggle's place. See
|
||||
[Portal Detail Navigation](./portal-detail-navigation.md).
|
||||
1. Leading Back slot: the current page's registered Back, else browser
|
||||
history while an in-app previous page exists, else nothing. See
|
||||
[Header Back](#header-back).
|
||||
2. Playlist switcher.
|
||||
3. Route-aware search input and command palette trigger.
|
||||
4. Add source action.
|
||||
@@ -130,6 +129,71 @@ When adding shell behavior, prefer placing it in the service that owns the
|
||||
nearest existing state. Keep `WorkspaceShellFacade` as a stable re-export layer
|
||||
for the template unless the template contract itself intentionally changes.
|
||||
|
||||
## Header Back
|
||||
|
||||
The header's leading slot is the workspace's one page-level Back. Pages do not
|
||||
render an arrow of their own: they register a `WorkspaceBackTarget`
|
||||
(`@iptvnator/portal/shared/util`) with `WorkspaceBackNavigationService`
|
||||
(`@iptvnator/portal/shared/data-access`), normally through
|
||||
`registerWorkspaceBack()`, which registers for the calling component's
|
||||
lifetime while its optional `available` predicate holds. The newest
|
||||
registration wins, and each release removes only its own target. The button
|
||||
(`data-test-id="workspace-header-back"`) sits beside the macOS traffic lights,
|
||||
never scrolls, and has Electron `no-drag` hit testing. A target supplies its
|
||||
label (else the translated "Back"), whether Escape on the page runs it, and
|
||||
`run()`.
|
||||
|
||||
| Page | Registered by | Back runs | ≤640 px |
|
||||
| --- | --- | --- | --- |
|
||||
| Portal, collection, offline and recording details | `PortalDetailShellComponent` while `backAvailable()` | the host's `backClicked` | replaces the drawer toggle |
|
||||
| Xtream and Stalker Discover and actor pages | `DiscoverViewComponent`, `ActorViewComponent` | the route's `Location.back()` | (no drawer) |
|
||||
| In-portal search, Xtream and Stalker | `SearchLayoutComponent` while `backAvailable()` and no inline detail replaces the results | `Location.back()` | (no drawer) |
|
||||
| Settings | `WorkspaceSettingsContextPanelComponent`, which exists exactly while the settings route shows | `Location.back()` | beside the drawer toggle |
|
||||
|
||||
Detail-page semantics (Escape, browse and watch) are in
|
||||
[Portal Detail Navigation](./portal-detail-navigation.md#detail-scroll-and-focus).
|
||||
|
||||
**History fallback.** Without a registration, the header shows Back while the
|
||||
previous history entry is an in-app one, and runs `Location.back()`. The
|
||||
service reads that from the Navigation API: the previous entry must be
|
||||
same-document (`NavigationHistoryEntry.sameDocument`), so the router pushed it
|
||||
after this document loaded. Entries from before a reload or from another page
|
||||
of the origin never count, and the fallback can neither leave nor reload the
|
||||
app. `currententrychange` keeps it current through pushes, replacements,
|
||||
traversals and guard-cancelled Back navigations that the router rewrites.
|
||||
Without the Navigation API (older Safari and Firefox, jsdom) there is no
|
||||
fallback; registered pages are unaffected. The fallback reads "Back" and
|
||||
advertises no Escape, because no page handles one for it. Pages that set
|
||||
`backAvailable=false`, such as M3U details, therefore show it too when they
|
||||
were reached by navigation.
|
||||
|
||||
When there is nowhere to go, the slot is empty rather than a disabled arrow.
|
||||
Sessions often start on a page that never navigates (an M3U playlist or live
|
||||
TV), where a disabled arrow would stay for the whole session. The cost is one
|
||||
shift of the switcher and search when Back first appears or leaves, which
|
||||
happens only at the start of the history and together with a route change.
|
||||
There is no Forward button: Stalker inline details are store state, not
|
||||
history entries, so Forward would skip them.
|
||||
|
||||
**Phone width.** `phoneDrawerToggle` sets how Back shares the leading slot with
|
||||
the context drawer toggle. `replace` (the default) takes the toggle's slot: a
|
||||
detail page's drawer belongs to the list that Back returns to. `beside` keeps
|
||||
both: the settings drawer holds the page's own sections. `yield` hides Back
|
||||
while the toggle shows: the history fallback must not cost a category list its
|
||||
only way into the drawer, and two navigation icons do not fit beside the
|
||||
switcher. System and browser Back still work there.
|
||||
|
||||
**Left in place.** These controls stay inside their surface on purpose:
|
||||
|
||||
1. Downloads offline and recording detail error states keep their labelled
|
||||
"Back to Downloads" button beside Retry or Remove. It is the error state's
|
||||
recovery action, not page chrome; the header shows the same Back.
|
||||
2. Back controls internal to a surface, which leave a panel rather than the
|
||||
page: the Embedded MPV dock panel and the alternative-sources panel inside
|
||||
the VOD "…" menu.
|
||||
3. The M3U player sidebar's Home button, which renders only outside the
|
||||
workspace shell.
|
||||
|
||||
## Context Panel Rules
|
||||
|
||||
The shell decides which secondary panel to show from the current route:
|
||||
|
||||
Reference in new issue
Block a user