Commit Graph

14 Commits

Author SHA1 Message Date
bvandeusen d43719516e feat(web): drop hero row + compact Rediscover tiles
test-web / test (push) Successful in 33s
Operator UI review on the merged build:

- Hero row felt 'odd' — operator chose remove-entirely on the
  AskUserQuestion options. The Playlists row already leads with
  For-You and Recently Added leads with the newest album, so the
  hero duplicated both anchors. Pulled HomeHeroCard.svelte + all
  page-level wiring (systemShuffle/getPlaylist imports + playForYou/
  playLatestAlbum handlers) and reverted the within() test scoping
  added in 682d7a5e.

- Rediscover tiles step down to w-32 (albums) / w-28 (artists),
  matching the Most Played CompactTrackCard visual weight on web.
  Reinforces the page hierarchy: fresh content gets real estate,
  throwbacks recede.
2026-06-01 20:34:21 -04:00
bvandeusen 17b276b5f5 feat(web): hero row at top of Home (For You + most recently added)
test-web / test (push) Failing after 36s
#6 — Adds a 2-up grid above the Playlists carousel:
- Today's pick: For-You playlist card with a Play button that
  invokes the system-shuffle endpoint (same path as PlaylistCard
  uses for the play overlay).
- Just added: most recently added album card with a Play button
  that fetches the album detail and queues the tracks.

Both cards share HomeHeroCard.svelte — cover left, eyebrow + title
+ subtitle + Play right, on a from-accent/15 → surface gradient so
the eye lands here before scrolling into the carousels. Each card
links to its detail page; the Play button is event-stopped so it
plays in-place. md:grid-cols-2 stacks on narrow viewports.

Only renders when at least one of the two pieces of data is
available so the page degrades cleanly on fresh installs.
2026-06-01 20:10:47 -04:00
bvandeusen 5f297c4c21 feat(web): dominant-color accent strip on PlayerBar + bigger Home tiles
test-web / test (push) Successful in 36s
#9 — new lib/media/dominantColor.ts: load cover image, downsample to
1x1 canvas, read pixel. Approximates the dominant tone via the
browser's bilinear mean — close enough for an ambient accent without
the 5KB ColorThief dependency. Same-origin cover URLs so no CORS
dance. Result cached by URL so revisits are free.

PlayerBar samples the current track's cover and pipes the resulting
rgb into a 2px accent strip above both the compact and desktop
variants. Transparent until the first resolve; 300ms transition on
colour change so track-skips fade rather than snap.

#10 — slight bump to Home tile widths so a typical viewport shows
roughly 5-6 across instead of cramming 8-9: Playlists w-56, all
remaining AlbumCard rows w-48 (Recently Added + both Rediscover
album scrollers). Replaces the wave-2 sizes that were still showing
7-8 across on wider screens.
2026-06-01 20:03:48 -04:00
bvandeusen a92f2c0121 feat(web): radial gradient + playlist title overlay + tile-size hierarchy
test-web / test (push) Failing after 33s
Second wave of Home visual polish (UI tasks 80/82/84):

- Shell main background gets a 1200x600 radial gradient at the top
  using color-mix on fs-iron so the page reads with subtle depth
  instead of as a flat slab.
- PlaylistCard moves the title onto the cover with a bottom-to-top
  gradient overlay. The server-generated 2x2 collage becomes mood
  texture; the Fraunces playlist name becomes the dominant element.
  Track count and refresh label stay below the art. Mirror albums
  shadow-sm/shadow-lg/ring-accent hover treatment on the art-wrap.
- Tile-size hierarchy: Playlists w-52, Recently added w-44,
  Rediscover w-40. Visual weight tapers as you scroll down the
  page so the freshest content reads as most important.
2026-06-01 19:57:05 -04:00
bvandeusen 5393174a27 feat(web): surface secondary system playlists on Home
test-web / test (push) Successful in 31s
Mirrors the Android change from commit bf61d6cf. Web's Home Playlists
row gains the 5 secondary system kinds (deep_cuts, rediscover,
new_for_you, on_this_day, first_listens) after the Songs-like slots,
in server-registry order, when they exist. No placeholders for these
— they depend on library shape (Deep cuts needs deep albums, On this
day needs prior history, etc.) so a missing one means "not enough
data," not "still building."

Test coverage: new `renders secondary system kinds` test creates a
mocked owned set with for_you + deep_cuts + new_for_you and asserts
all three card names render. Existing tests (5 placeholders, building
variant, For-You + 3 placeholders) unchanged since none seed
secondary kinds.

Most Played multi-row is NOT touched — web already chunks the 75
tracks into 3 rows of 25 via the existing HorizontalScrollRow rows=
{chunk(...,25)} pattern. My initial task description was wrong on
that point.

Naming collision (`rediscover` playlist vs Rediscover recommendations
section both read "Rediscover" on the same Home) deferred — operator
follow-up. Same on Android.

Scribe 531, local task #61.
2026-06-01 11:25:25 -04:00
bvandeusen 96aa2407d9 feat(home): surface Discover system playlist as a tile (web + flutter)
Server has been generating system_variant='discover' playlists since
M6a (internal/playlists/system.go and POST
/api/playlists/system/discover/refresh) but neither client surfaced
it. The Flutter home filtered system playlists by exact match on
'for_you' and 'songs_like_artist', dropping Discover. The web home
did the same. Tiles were generated server-side and silently
discarded by both clients.

Add a Discover slot to the playlists row in both:
- Flutter: 5-slot row now (For You, Discover, 3× Songs-like) with
  matching placeholder state machine.
- Web: same shape, same placeholderVariant() call.

When the engine has built it, the real playlist tile renders;
otherwise a placeholder with the same building/pending/failed
status semantics as the other system tiles.
2026-05-11 23:41:01 -04:00
bvandeusen 5698cfe8e4 feat(web/m7-352): home Playlists row — For-You + Songs-like + user playlists
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-04 18:34:03 -04:00
bvandeusen 9ad2e0343a feat(web/m7-363): per-route svelte:head titles for static routes
Add browser tab titles to all 18 static page routes using the pageTitle()
helper from $lib/branding. Titles follow the Minstrel · Section format.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-03 17:37:13 -04:00
bvandeusen 2946ec4222 feat(web): coupled section scrolling, earlier infinite-scroll, fuller player cover
Three coordinated polish changes:

1. PlayerBar cover bumps from h-20 (80px) to h-24 (96px) and the bar's
   vertical padding tightens from py-4 to py-1.5. Bar height stays
   ~108px but the cover now fills ~89% of it (was ~74%) — reads as the
   substantial primary content the operator wanted, not a thumbnail.

2. InfiniteScrollSentinel default rootMargin moves from 300px to 800px
   so the next page fetches well before the user reaches the bottom of
   the rendered set. Empirically that's ~3-4 rows of cards on a typical
   library grid — loading feels seamless rather than catching up.

3. HorizontalScrollRow takes rows: T[][] instead of items: T[]. Multiple
   rows of items now render inside one shared overflow-x-auto container,
   so the rows scroll together as a single coupled section. Recently
   added (2 album rows) and Most played (3 track rows) on the home page
   now scroll as one unit. Rediscover keeps two separate scrollers
   because its rows are different card types (square albums vs circular
   artists) — coupling those would interleave shapes awkwardly. The
   item snippet's second arg is now the global flat index so consumers
   like CompactTrackCard (which needs sectionTracks + index for play
   actions) work without per-row re-indexing.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-01 23:52:03 -04:00
bvandeusen 4e47b2e7f5 feat(web): pair scroll arrows beside section title; bleed scroller to viewport edge
Restructures HorizontalScrollRow so paired arrows sit in a flex header
beside an optional section title (instead of absolute-positioned at the
row's left/right edges). Adds margin-right: -1rem to the row so the
scroller's items extend to the viewport's right edge, escaping Shell's
p-4 padding. The header bar keeps its right gutter so titles align with
the rest of the page content.

Home page passes 'title' to the first row of each section; subsequent
rows in multi-row sections render arrow-only headers.
2026-05-01 21:05:16 -04:00
bvandeusen 7d09e605cc feat(web): rewrite / as home page composing 4 horizontal-scroll sections
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-01 20:23:20 -04:00
bvandeusen 5174b093b9 feat(web): replace / placeholder with real artists list
Uses createArtistsQuery (infinite), URL-driven sort dropdown, Load
more pagination, delayed skeleton, and shared error banner. Also
introduces the test-utils/query.ts helpers for subsequent page tests.
2026-04-23 19:43:37 -04:00
bvandeusen d2d5d18e74 feat(web): add Library/Search/Playlists placeholder pages
Library replaces the scaffold splash. Search and Playlists are routable
so the Shell's sidebar nav works end-to-end before the real features land.
2026-04-22 22:22:11 -04:00
bvandeusen 86b024dc47 feat(web): scaffold SvelteKit SPA with Tailwind + adapter-static
- SvelteKit 2.x + Svelte 5 + TypeScript + Vite 5
- adapter-static with fallback:'index.html' for SPA deep-link routing
- Tailwind configured with dark-only palette matching spec
- Placeholder landing page at /
- Committed web/build/index.html placeholder (via .gitignore negation) so
  go:embed works before the SvelteKit build has been run
2026-04-22 09:26:36 -04:00