UI-24 from the UI consistency audit.
- No-artwork slides paint their gradient in CSS from the slide hue: a light
tint in the light theme, unchanged near-black in the dark one. The dark
gradient under the light page-coloured scrim read as a grey slab.
- The side scrim holds 88% of the page colour up to the slide's right edge
(inset + min(560px, 55%)), so the end of a full slide no longer sits on
about 45%.
- Narrow layout (container <= 720px): a full-bleed 90% scrim behind the text
block, a scrim-coloured text shadow, and an entrance without a fade so
that scrim never flashes the art on a rotation.
- --hero-body is 85% of the heading colour (was 72%).
- Light --app-rating-color #a16207 -> #7a4a00: measured 3.36:1 on the chip
over artwork, now 5.10:1. The details pages share the chip and token.
- Buttons cap at the slide width and end long labels in an ellipsis.
- The page gets one visually hidden h1 ("Dashboard"); slide titles are h2.
- One live region outside the re-created slide announces slide changes;
progress bars are named and VOD ones read "N% watched"; dots are 24px.
dashboard-hero-legibility.e2e.ts replaces every image with a checkerboard
and measures each piece of slide text from the screen in both themes, wide
and narrow, for backdrop, poster, no-artwork and live slides. On master the
worst cases were 2.35:1 (body text) and 2.65:1 (pills).
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Workspace Dashboard Feature
This library owns the workspace dashboard rails UI. The dashboard is a read-only surface over existing playlist, recent, favorites, EPG, and Xtream catalog data; it should not introduce Electron IPC, SQLite schema, or route contracts on its own.
Dashboard Surfaces
The dashboard renders a surface only when the matching setting is enabled. Data rails also require the underlying data slice to have at least one item.
heroshows the full-width cinematic banner that rotates between the newest unfinished title, a favourite (or recent) channel with a programme on air, and favourite / recently added titles. Contract:docs/architecture/workspace-dashboard.md#cinematic-hero.continueWatchingshows recent movies and series fromDashboardDataService.globalRecentVodItems()using cover cards with playback progress when a saved resume position is available.liveFavoritesshows favorited live TV channels fromDashboardDataService.globalFavoriteLiveItems()using the channel layout with EPG title, time range, and progress when XMLTV data is available.recentlyWatchedLiveshows recently watched live TV channels fromDashboardDataService.globalRecentLiveItems()using the same channel layout.favoriteMoviesAndSeriesshows favorited movies and series fromDashboardDataService.globalFavoriteItems(), excluding live favorites, using cover cards.recentSourcesshows recently used playlist/source entries.xtreamRecentlyAddedshows recently added Xtream catalog items.tmdbRecommendationsshows "Because you watched X" — TMDB recommendations seeded from recently watched movies/series, kept to titles that exist in an imported Xtream library. Needs the TMDB opt-in and the Electron DB worker (hidden in the PWA), and hides itself below five matched cards. Data:DashboardRecommendationsServiceinworkspace/dashboard/data-access.tmdbTrendingshows TMDB's weekly trending titles, matched against the imported Xtream libraries. Same TMDB/Electron gating; unmatched cards open the global search prefilled. Data:DashboardTrendingService.
Settings
Per-surface visibility lives on Settings.dashboardRails as a
DashboardRailsSettings object. Every surface defaults to enabled. Stored
settings are deep-merged with DEFAULT_DASHBOARD_RAILS_SETTINGS by
SettingsStore, so existing users and older partial settings keep newly added
surfaces visible unless they explicitly turn them off.
The global showDashboard flag remains a top-level Settings property because
workspace startup and route guards already depend on that contract. The Settings
UI groups showDashboard and the per-surface checkboxes in the Dashboard
section. When showDashboard is off, the per-surface checkboxes are disabled
because the dashboard route itself is hidden.
Navigation
Rail cards use the navigation state provided by DashboardDataService for the
underlying item. Rail "See all" links may also pass router state:
- live rails open the relevant collection on Live TV.
- cover rails for movies/series open Global Recent or Global Favorites on Movies when movie items are present, otherwise on Series.
This keeps the global collection pages from defaulting to Live TV when a dashboard rail is clearly about movies or series.