Commit Graph
6 Commits
Author SHA1 Message Date
peter af915883f9 fix(datatable): the sticky header no longer shifts or fades on first scroll
The sticky <thead> jumped up ~8px and picked up the scroller's top fade
the moment you scrolled 1px — so it read as 'not fixed'. Two causes:
- the table sat under a pt-2 gap, so its natural position was 8px below
  the sticky top:0 it snapped to. Drop the top padding (the fixed band's
  controls row already gives the visual gap) → no shift.
- the page scroller's top edge fade turned on with the first scroll and
  masked the header's top. Add a fadeTop flag (PageShell → PageScroller →
  useScrollFade), off for the Channels + Audit pages whose scroll region
  starts with a sticky header. Feed/channel keep the top fade (it fades
  cards under the fixed toolbar, as intended).

Verified: header stays at a fixed offset with no fade change from scroll 0
through scrolled, on both the manager and the audit log. Suite 15/15.
2026-07-18 05:43:19 +02:00
peter 02bd0d433b polish(channel): tighten toolbar-to-grid gap + restore top scroll fade
Two UAT nits on the channel page:
- the chip-row-to-cards gap was ~36px (toolbar pb-3 + wrapper pb-2 + grid
  pt-3 stacking); drop the wrapper/grid pads so the toolbar's own pb-3 is
  the only gap (~15px).
- restore the page scroller's TOP edge fade. It was dropped when the chrome
  was a sticky sub-header (the fade bit into it); now the chrome is a fixed
  band ABOVE the scroller, so the top fade correctly hints at cards
  scrolling up under the toolbar. Reverts the useScrollFade edges option.

Suite 15/15, tsc + knip clean.
2026-07-18 05:01:31 +02:00
peter 0e03e561eb feat(shell): sticky tabs+toolbar on the channel page
Generalise the fixed-chrome pattern to the channel detail page: the
banner + identity now scroll away, while the tab row and the channel
feed's toolbar stick to the top as a sticky sub-header — only the video
grid scrolls.

Mechanism: PageToolbarSlot (the toolbar portal target) is now an exported,
overridable context. ChannelPage provides its own sticky sub-header node
as the target, so the channelScoped Feed portals its toolbar up next to
the tabs instead of into the shell's top band. Feed always portals its
toolbar now (the slot decides where it lands).

Also: the page scroller now fades only its BOTTOM edge — the top is
bounded by the fixed/sticky chrome, so a top fade only bit into it.

E2E: adds a lock that the channel tabs/toolbar stay pinned while the
banner scrolls away; suite 15/15 on :5173, tsc + knip clean.
2026-07-18 04:45:11 +02:00
peter 9b4ee83ec8 fix(plex): portal the full-screen player out of the page scroller
The player is `fixed left-0 top-0 z-50` but rendered from inside the page
scroller, so it only ever covered the viewport because that scroller happened
not to be a stacking context. Giving it the edge-fade made it one, and the mask
scoped the player's z-50 inside it: the rail, the side panel and the header
painted straight over the player, and its edges faded. Measured both ways, then
fixed where every other full-screen overlay here already sits — <body>.

Same for the Suspense fallback that stands in while the player chunk loads, and
for the floating draft save bar on the Configuration page. Swept the rest: every
other `fixed` element is either App-level or already portaled.
2026-07-17 03:30:55 +02:00
peter a032324513 improvement(scroll): fade the page scroller's clipped edges
The subdued edge-fade the rail and side panels use now hints at more content on
the page scroller too, which the feed, the channel page and Plex all scroll
inside. Both <main>s move into one PageScroller so the invariants they share —
the load-bearing scrollbar gutter, and the bar staying visible because hiding it
would zero that gutter — are stated once.

Two fixes the hook needed first: it set fresh state on every scroll event, which
above a page tree would re-render it per frame; and it watched a single child
captured at mount, so a lazy page swapping out its Suspense fallback left the
observer on a detached node and the fade frozen at its pre-load value (measured
on the Plex page: no bottom fade over a 3119px list).
2026-07-17 03:14:37 +02:00
peter facb3ac9cb feat(ui): unified floating side panels for filters and playlists
Replace the full-height filter rails with one shared floating glass SidePanel
used by Feed, Plex and Playlists. Each collapses to a slim tab beside the nav;
its sections are reorderable "islands" (drag / hide / per-group collapse) with a
per-panel saved layout; the body hides its scrollbar with a soft top/bottom edge
fade. The nav rail becomes a matching floating rounded card.

- New shared SidePanel / PanelGroup / PanelGroups + useScrollFade hook.
- Generalise the feed-only sidebarLayout into a per-panel panelLayout (feed keeps
  its storage key; plex/playlists get their own; persisted per account).
- Lift the Playlists rail to App level (selected playlist is now App state) so it
  floats and collapses like the filter rails; remove the old CollapsedFilterRail.
- The floating top header's fixed offset accounts for the panels' margins.
2026-07-13 05:13:40 +02:00