mirror of
https://github.com/4gray/iptvnator.git
synced 2026-10-08 17:06:15 -08:00
feat(ui): cinematic movie and series details pages and dashboard hero (#1792)
This commit is contained in:
1 parent
07c5dffab0
commit
ab8460338a
213 files changed
+12494
-3930
No files matched your search
@@ -153,14 +153,41 @@ Do not add extra badges, left rails, or second selection systems unless there is
|
||||
|
||||
## Detail Views
|
||||
|
||||
VOD and series detail screens share the detail-view Sass mixin (`@mixin base`)
|
||||
from `libs/ui/styles/_detail-view.scss`. Feature-local `styles/detail-view.scss`
|
||||
files should only `@use` that module and `@include detail-view.base(...)` with
|
||||
small typography overrides when a provider needs them.
|
||||
VOD and series detail screens share `app-portal-detail-shell` and
|
||||
`app-content-hero` (`libs/ui/components`). The hero orders its column as
|
||||
kind label ("Movie · playlist") → title → chips → description (three lines,
|
||||
"More") → resume bar → action row → credits, with the poster bottom-aligned
|
||||
on the left and the backdrop filling the hero behind a two-layer scrim built
|
||||
from `--app-content-bg`. The hero keeps `min(480px, 60vh)` of stage for a
|
||||
16:9 backdrop. Without one, or when the provider sends the poster as the
|
||||
backdrop, the hero is compact (`hero--compact`, sized by its content) over
|
||||
the blurred poster. The layout is decided once per title, so a backdrop that
|
||||
TMDB enrichment adds a moment later fills the compact hero instead of
|
||||
growing it. The pane is a size container (`detail`); the poster hides below
|
||||
760px of pane width.
|
||||
|
||||
Do not copy the full detail-view stylesheet into feature libraries. Add shared
|
||||
layout changes to the mixin, and keep provider-specific differences explicit in
|
||||
the wrapper file that includes it.
|
||||
The pieces are shared and provider-neutral (`libs/ui/components/src/lib/detail-ui/`):
|
||||
`app-meta-chip` (pill; `rating` and `status` variants; facets as projected
|
||||
`.meta-chip__facet` buttons), `app-detail-action-button` (the light primary
|
||||
with a two-line label, or the ghost `secondary` text button),
|
||||
`app-detail-icon-button` (44px ghost with tooltip and `aria-label`),
|
||||
`app-vod-more-menu` (the "…" dropdown: right-aligned, flips upward, arrow
|
||||
keys, Escape, hosts the alternative-sources panel), `app-detail-credits`
|
||||
("Starring" + three names + "and more", "Director"), `app-cast-crew-row`,
|
||||
`app-detail-rail`/`app-similar-rail` (hidden scrollbar, prev/next arrows,
|
||||
title + year) and `TrailerDialogService`. The dashboard hero reuses the same
|
||||
light primary (`light-primary-button` in `libs/ui/styles/_detail-view-actions.scss`)
|
||||
and chip. Series titles drop their season marker (`splitSeasonSuffix`) into a
|
||||
"Season N" chip. Rows a provider cannot serve are left out of the menu, never
|
||||
disabled. The page-level Sass mixin (`libs/ui/styles/_detail-view.scss`)
|
||||
only carries the page shell, meta items and the episodes section.
|
||||
|
||||
With `detailTrailerBackdrop` on (Settings → Playback → "Play trailers in
|
||||
details background", default off) the hosts hand the trailer embed URL to the
|
||||
shell and `app-hero-trailer-backdrop` plays it muted and looping under the
|
||||
scrim after three idle seconds, with a 32px mute toggle in the corner. It
|
||||
never starts under `prefers-reduced-motion` or with `saveData`, and stops
|
||||
while the hero is off screen or the window is unfocused.
|
||||
|
||||
## Electron Drag Regions
|
||||
|
||||
@@ -664,23 +691,20 @@ If the label is too long for the rail, shorten the label key instead of shrinkin
|
||||
|
||||
## Detail Actions And Episode Surfaces
|
||||
|
||||
Secondary detail buttons, episode cards and list rows, and the season view
|
||||
toggle must keep visible edges in both themes before hover. Use app-owned
|
||||
surface colors and neutral borders derived from `--app-on-surface`; fixed
|
||||
white-alpha fills and borders disappear over the light detail background.
|
||||
Grid cards keep the thumbnail and title on one continuous widget surface.
|
||||
List rows use a subtle neutral fill, with the number on a slightly stronger
|
||||
inset surface. The checked grid/list toggle uses `--app-selection-surface`
|
||||
and `--app-selection-color`; hover uses the app's neutral surface treatment.
|
||||
Keep these treatments in the shared season components and detail-action
|
||||
partial so Xtream and Stalker share the same behavior.
|
||||
The action row never wraps on a desktop window: the primary, the Trailer
|
||||
button, then the 44px icon buttons and the "…" menu. Season and series
|
||||
actions (mark watched, download season, reset progress) live in that menu
|
||||
and drive the season container's presenters; the container's header is
|
||||
"Episodes" with the season pills and the episode count, plus the grid/list
|
||||
toggle. The checked toggle uses `--app-selection-surface` and
|
||||
`--app-selection-color`; hover uses the app's neutral surface treatment.
|
||||
|
||||
The season header's actions wrap onto their own row, starting under the
|
||||
"Seasons and Episodes" heading, before the heading itself would wrap. The
|
||||
detail pane is narrower than the window (rail and context panel), so the
|
||||
header's own width decides, not a viewport breakpoint. A translation
|
||||
wider than the pane itself wraps rather than ellipsizing: unlike a fixed-height
|
||||
panel title, a content heading has room to wrap and should not lose words.
|
||||
Episode cards are flat: a 16:9 thumbnail (with a light hairline so its edge
|
||||
survives the light theme) and a 3px watched bar at its bottom edge, "N. Title", the plot clamped to two lines and a "42 min ·
|
||||
18m left / watched" line. List rows keep a subtle neutral fill. The selected
|
||||
season's cover and synopsis sit in a compact strip under the header only
|
||||
when present. Keep these treatments in the shared season components so
|
||||
Xtream and Stalker share the same behavior.
|
||||
|
||||
Browser regression coverage measures the composited neutral edges and selected
|
||||
toggle fill, in addition to capturing light/dark grid and list screenshots.
|
||||
|
||||
@@ -132,13 +132,21 @@ discovery slides open the detail page; live slides open the channel. TMDB
|
||||
extras (backdrop, rating, genres, overview, year) come from
|
||||
`DashboardHeroTmdbService` per featured title and vanish when TMDB is off.
|
||||
|
||||
Artwork: a title's backdrop, else its poster blurred and scaled past the
|
||||
edges (no second, sharp copy); a live channel's logo sits on the right as key
|
||||
art over its own wash. Series titles drop their season marker
|
||||
(`splitSeasonSuffix`) — the `S1·E1` chip names the season. Chips are
|
||||
`app-meta-chip`; the primary is the details pages' light primary
|
||||
(`light-primary-button` from `libs/ui/styles`).
|
||||
|
||||
Rotation is the active dot's CSS fill animation (8 s); its `animationend`
|
||||
advances. The fill animates `transform` only (a bar sliding in under the
|
||||
pill's rounded clip), so it runs on the compositor; animating `width` there
|
||||
cost a style, layout and paint pass on every frame of an idle dashboard.
|
||||
Hover, focus inside the hero and the pause button pause it; an
|
||||
explicit Play clears the hover/focus pause until they re-arm; under
|
||||
`prefers-reduced-motion` nothing auto-advances. The active slide is tracked
|
||||
Hover, focus inside the hero, a hidden document and the pause button pause
|
||||
it; an explicit Play clears the hover/focus pause until they re-arm; under
|
||||
`prefers-reduced-motion` nothing auto-advances. The hero is a focusable
|
||||
region: ←/→ switch slides and Enter follows the primary action. The active slide is tracked
|
||||
by id, so a late live slide never moves the user off the current one. Test
|
||||
hooks: `dashboard-hero`, `dashboard-hero-slide` (`data-hero-kind`),
|
||||
`dashboard-hero-dot`, `dashboard-hero-pause`,
|
||||
|
||||
Reference in new issue
Block a user