From cfdc61a4b84a87930612b803147f500901e79054 Mon Sep 17 00:00:00 2001 From: XShine555 Date: Wed, 23 Sep 2026 23:52:27 +0200 Subject: [PATCH] Scroll content inside the shell so the player shares the ambient backdrop The player dock used to sit fixed over the scrolling page, so it needed an opaque background. The shell is now a fixed-height frame where only the content column scrolls, letting the dock stay transparent like the sidebar and queue. Scroll reset/restore on navigation moves to restoreScroll(), and the stable scrollbar gutter moves from to the content scroller. --- web-player/CLAUDE.md | 6 +++- web-player/src/app.html | 2 +- .../src/lib/components/layout/Sidebar.svelte | 4 +-- .../src/lib/components/layout/TabsBar.svelte | 2 +- .../lib/components/player/PlayerBar.svelte | 4 +-- .../lib/components/player/PlayerDock.svelte | 4 +-- .../src/lib/components/player/Queue.svelte | 6 ++-- web-player/src/lib/state/navigation.svelte.ts | 22 +++++++++++- web-player/src/routes/+layout.svelte | 34 +++++++++++-------- web-player/src/routes/layout.css | 19 ++++------- 10 files changed, 61 insertions(+), 42 deletions(-) diff --git a/web-player/CLAUDE.md b/web-player/CLAUDE.md index e1da22c..444ea62 100644 --- a/web-player/CLAUDE.md +++ b/web-player/CLAUDE.md @@ -57,9 +57,13 @@ The design system lives in `src/routes/layout.css` (`@theme` tokens plus `@utili - Reach for these base components before creating a new one: `Artwork`, `Avatar`, `ListRow`, `MediaIdentity`, `TrackList`, `MediaCard`, `PageHeader`, `ContextMenu`, `ConfirmDialog`, `PlayButton`, `Slider`, `Logo`, `Chip`, `SegmentedControl`, `CoverForm`. - **Icon stroke:** one global rule (`svg.lucide { stroke-width: 1.5 }` in `layout.css`) sets the stroke for every icon. Never pass `strokeWidth` to an icon, since any CSS rule overrides the SVG attribute and it would do nothing. For a different stroke on one icon, use a Tailwind `stroke-*` utility. +## App shell + +The shell in `src/routes/+layout.svelte` is a fixed `h-dvh` frame: Sidebar | (content column over PlayerDock) | Queue. Only the content column (`app-scroll`) scrolls, so nothing ever passes under the dock and the chrome can stay transparent over `app-backdrop`. Because the window never scrolls, scroll reset/restore on navigation is handled by `restoreScroll()` in `$lib/state/navigation.svelte.ts`; don't use `window.scrollTo`/`scrollY`. + ## Motion -Every animation follows one scale of three durations and one easing curve, all defined in `theme.css`. Fast (`--mf-motion-fast`, 150ms) is for hover, focus and press feedback: color, opacity and small scale changes. Plain `transition` or `transition-colors` already uses it because it is the Tailwind default, so never write `duration-150`. Base (`--mf-motion-base`, 200ms) is for things that appear on top of the page or move inside a control: modals, menus, the queue panel, `animate-pop`, `animate-fade` and the segmented control thumb. Slow (`--mf-motion-slow`, 300ms) is for content entering the page and larger movement: `animate-enter`, cover zoom on hover and the player dock padding. +Every animation follows one scale of three durations and one easing curve, all defined in `theme.css`. Fast (`--mf-motion-fast`, 150ms) is for hover, focus and press feedback: color, opacity and small scale changes. Plain `transition` or `transition-colors` already uses it because it is the Tailwind default, so never write `duration-150`. Base (`--mf-motion-base`, 200ms) is for things that appear on top of the page or move inside a control: modals, menus, the queue panel, `animate-pop`, `animate-fade` and the segmented control thumb. Slow (`--mf-motion-slow`, 300ms) is for content entering the page and larger movement: `animate-enter`, cover zoom on hover. Entrances and movement always use `--mf-ease` (`ease-snappy` in Tailwind, `expoOut` in Svelte transitions), which feels immediate because most of the motion happens at the start. Color transitions keep the Tailwind default curve. Overlays must feel instant: the modal backdrop uses `transition:fade={{ duration: 200 }}` and the panel uses a local `pop` transition (opacity + scale + translateY, `expoOut`, 200ms) mirroring `animate-pop`'s keyframes — both directives so the modal fades and pops on close too, not just on open, and the whole thing settles in 200ms. Staggered lists use `--i` with 40ms steps capped at ten items. diff --git a/web-player/src/app.html b/web-player/src/app.html index 4d12503..58bf673 100644 --- a/web-player/src/app.html +++ b/web-player/src/app.html @@ -1,5 +1,5 @@ - + diff --git a/web-player/src/lib/components/layout/Sidebar.svelte b/web-player/src/lib/components/layout/Sidebar.svelte index b1322e0..7649cf9 100644 --- a/web-player/src/lib/components/layout/Sidebar.svelte +++ b/web-player/src/lib/components/layout/Sidebar.svelte @@ -31,7 +31,7 @@