feat: web UI library views — artists / artist detail / album detail #18

Merged
bvandeusen merged 262 commits from dev into main 2026-04-23 22:05:24 -04:00
bvandeusen commented 2026-04-23 22:02:04 -04:00 (Migrated from git.fabledsword.com)

Summary

  • Three browse routes on top of TanStack Query:
    • / — artists list with URL-driven sort (?sort=alpha|newest), "Load more" pagination via createInfiniteQuery, and the empty-library message when total === 0.
    • /artists/:id — artist name + album count + responsive AlbumCard grid (2→3→4→5 cols across breakpoints).
    • /albums/:id — hero with cover, title, linked artist, year, metadata summary; track list below. Back chevron targets the artist page (not Library).
  • Five reusable components (ArtistRow, AlbumCard, TrackRow, LibrarySkeleton, ApiErrorBanner) keep the pages short and the loading/error UX consistent across all three routes.
  • useDelayed rune helper suppresses flash-of-skeleton on cache-hit navigation — skeletons only render after the pending state has persisted ~100ms.
  • 404 branch on detail pages (Artist not found, Album not found) renders a non-retryable card; other errors share <ApiErrorBanner> with a retry button.
  • Cover rendering via <img src="/api/albums/:id/cover" loading="lazy"> with a data-URL SVG fallback for broken covers.
  • Test harness: src/test-utils/query.ts wraps mock query results in readable(...) to match TanStack Query's Svelte adapter return type.

Test Plan

  • go test -short -race ./... passes (unchanged; backend untouched)
  • golangci-lint run ./... clean
  • cd web && npm run check → 0 errors / 0 warnings
  • cd web && npm test → 73 tests across 16 files pass
  • cd web && npm run build succeeds (adapter-static emits web/build/)
  • docker build . builds; binary is -x in the final image
  • Manual browser walkthrough: sign in, drill artists → artist → album → back, verify sort dropdown + Load more + 404 paths
  • Forgejo CI green on this PR
## Summary - **Three browse routes on top of TanStack Query:** - `/` — artists list with URL-driven sort (`?sort=alpha|newest`), "Load more" pagination via `createInfiniteQuery`, and the empty-library message when `total === 0`. - `/artists/:id` — artist name + album count + responsive AlbumCard grid (2→3→4→5 cols across breakpoints). - `/albums/:id` — hero with cover, title, linked artist, year, metadata summary; track list below. Back chevron targets the artist page (not Library). - **Five reusable components** (`ArtistRow`, `AlbumCard`, `TrackRow`, `LibrarySkeleton`, `ApiErrorBanner`) keep the pages short and the loading/error UX consistent across all three routes. - **`useDelayed` rune helper** suppresses flash-of-skeleton on cache-hit navigation — skeletons only render after the pending state has persisted ~100ms. - **404 branch** on detail pages (`Artist not found`, `Album not found`) renders a non-retryable card; other errors share `<ApiErrorBanner>` with a retry button. - **Cover rendering** via `<img src="/api/albums/:id/cover" loading="lazy">` with a data-URL SVG fallback for broken covers. - **Test harness**: `src/test-utils/query.ts` wraps mock query results in `readable(...)` to match TanStack Query's Svelte adapter return type. ## Test Plan - [x] `go test -short -race ./...` passes (unchanged; backend untouched) - [x] `golangci-lint run ./...` clean - [x] `cd web && npm run check` → 0 errors / 0 warnings - [x] `cd web && npm test` → 73 tests across 16 files pass - [x] `cd web && npm run build` succeeds (adapter-static emits `web/build/`) - [x] `docker build .` builds; binary is `-x` in the final image - [ ] Manual browser walkthrough: sign in, drill artists → artist → album → back, verify sort dropdown + Load more + 404 paths - [ ] Forgejo CI green on this PR
Sign in to join this conversation.
No Reviewers
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: bvandeusen/minstrel#18