docs: document two-state detail layout and season tabs

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
4grayandClaude Fable 5 committed 2026-07-04 18:39:28 +02:00
1 parent 3bd0f3121c
commit 81605d3ded
3 files changed
+65

No files matched your search

@@ -82,8 +82,60 @@ Current limitation:
- because of that, the setting is auto-sanitized back to the default inline player unless support detection reports that the experimental runtime is available
- this follows the rollout gate: keep the native work in-tree, but do not leave it user-facing until playback, resize, focus, and packaging are stable
## Two-State Detail Layout (Browse ↔ Watch)
Portal VOD/series detail pages are hosted by the shared
`PortalDetailShellComponent`
(`libs/ui/components/src/lib/portal-detail-shell/portal-detail-shell.component.ts`),
which owns the page scroll container and two layout states:
- **Browse** (`playbackActive=false`): the hero (`ContentHeroComponent`,
now a natural-height, non-scrolling block) renders poster, title, chips,
description, credits, and actions. Episodes render below.
- **Watch** (`playbackActive=true`, bound by hosts to
`inlinePlayback() !== null`): the hero collapses (~300ms CSS morph,
disabled under `prefers-reduced-motion`), the host-projected
`[detail-player]` slot renders the inline player at full content width,
and the shell renders an About block (`ContentAboutComponent`) below the
`[detail-episodes]` slot so the hero metadata stays reachable.
Contracts:
- Hosts provide hero chips/meta/actions as `*detailTags` / `*detailMeta` /
`*detailActions` templates; the shell stamps them into the hero and again
into the About block. Degradation stays "missing → not rendered".
- The shell never wraps the `[detail-player]` slot in a conditional; the
host's `@if (inlinePlayback())` is the only creator/destroyer of the
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 inline player's now-playing bar has a back button that emits the
existing `closed` output — in watch state, back returns to browse, it
does not navigate the route.
- Entering watch scrolls the shell to the top; leaving keeps the scroll
position.
Season navigation inside `SeasonContainerComponent` uses season tabs
(`SeasonTabsComponent`; a dropdown beyond 6 seasons) instead of the old
seasons-grid + "Back to seasons" level. A season is auto-selected
(inline-playing episode's season → most recently updated in-progress
episode's season → first) and the auto-selection emits `seasonSelected`,
so host lazy-load/enrichment hooks (Stalker VOD-series episode fetch,
TMDB season fetch, Xtream `enrichSelectedSerialSeason`) fire on open
without a click. Switching tabs never stops playback; a "back to playing
episode" chip appears when the playing episode is outside the opened
season. Season descriptions come from `get_series_info` seasons (Xtream)
or `TmdbEnrichmentService.getSeason` (Stalker).
## Components
Shared detail layout shell:
- `/Users/4gray/Code/iptvnator/libs/ui/components/src/lib/portal-detail-shell/portal-detail-shell.component.ts`
Shared inline player shell:
- `/Users/4gray/Code/iptvnator/libs/ui/playback/src/lib/portal-inline-player/portal-inline-player.component.ts`
@@ -10,6 +10,11 @@ Related:
- Xtream category browsing uses a route-first detail model.
- Stalker uses an inline/store-state detail model.
- 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
[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.
- Provider-scoped collection routes fall back to the matching global collection