370 Commits

Author SHA1 Message Date
bvandeusen 6ca877b3ad feat(web): add useDelayed rune helper
Boolean mirror that flips true only after the source stays true for
delayMs. Used to hide the skeleton on sub-100ms cache hits so
back-navigation feels instant.
2026-04-23 17:23:23 -04:00
bvandeusen 828273a78f feat(web): add cover URL helper + fallback SVG data URL 2026-04-23 08:23:59 -04:00
bvandeusen 7345625ecd feat(web): add formatDuration helper
Renders seconds as mm:ss or h:mm:ss. Negative inputs clamp to 0:00
so a bad backend value doesn't crash the UI.
2026-04-23 08:23:22 -04:00
bvandeusen d15995d19e feat(web): add library API types mirroring internal/api/types.go 2026-04-23 08:22:33 -04:00
bvandeusen 048663a4c8 feat(web): wire root layout — bootstrap, guard, Shell, QueryProvider
+layout.ts runs auth.bootstrap() in load() so the shell sees the user
synchronously. +layout.svelte installs the TanStack QueryClientProvider,
runs the route guard as a \$effect, and swaps Shell vs. bare slot
based on auth state.
2026-04-23 06:11:43 -04:00
bvandeusen 88961596b1 fix(web): rename route-colocated test to avoid +page.* collision
+page.test.ts triggered svelte-kit sync's route walker (which treats
any +-prefixed file as a route). Renaming to login.test.ts lets the
sync pass without disabling it in scripts, preserving the upstream
guarantee that types in .svelte-kit/ are fresh before check/test.

Plan bug introduced in Task 10 (filename chosen in the plan); fixing
here and updating the plan so re-runs use the correct name.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-23 06:10:11 -04:00
bvandeusen 78f69b8736 feat(web): add login page with returnTo support and typed error UX
Inline errors for invalid creds vs. server-side failures. Validates
returnTo to block open-redirect vectors (//, http://, /login,
parent-traversal).
2026-04-23 02:41:44 -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 e1504f8e6c feat(web): add Shell component with header, sidebar, and user menu
Persistent chrome used by every authenticated route. Sidebar hides
below md:; mobile nav is a separate concern for a later plan.
2026-04-22 22:20:18 -04:00
bvandeusen 7a6aa50693 feat(web): auto-logout on 401 inside apiFetch
Dynamic import breaks the apiFetch <-> auth/store cycle. silent:true
prevents re-POSTing /logout against an already-dead session.
2026-04-22 17:29:36 -04:00
bvandeusen 07b5912fae feat(web): add rune-based auth store with bootstrap/login/logout
Central synchronous source of truth for 'who is signed in'. bootstrap()
runs once in +layout.ts load(); login/logout mutate _user and the
TanStack query cache. The silent option on logout is used by the 401
interceptor (next commit) to avoid POSTing /logout against an already-
invalid session.
2026-04-22 17:28:10 -04:00
bvandeusen 8a6a496c67 fix(web): drop invalid type-arg on toMatchObject in client tests
vitest's toMatchObject doesn't accept a type parameter; tests passed
under vitest (esbuild transpile) but svelte-check rejected. Plan-spec
bug introduced in 4d1a7f8; fixing here so check is clean before Task 6.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-22 17:26:15 -04:00
bvandeusen 4591618e7b feat(web): add TanStack Query client singleton
Tuned defaults: retry disabled (we throw typed errors), 30s staleTime
to make tab-switch re-navigation feel instant, no refetchOnWindowFocus
(users on a music app don't expect spurious network when they tab back).
2026-04-22 16:20:31 -04:00
bvandeusen 37e5539e5a feat(web): add api.{get,post,del} typed facade over apiFetch 2026-04-22 16:04:25 -04:00
bvandeusen 4d1a7f8b93 feat(web): add apiFetch with typed error envelope
Wraps fetch, parses JSON, and throws ApiError{code,message,status}
on non-2xx. Degrades to {code:'unknown'} when the error body is not
the expected envelope shape.
2026-04-22 15:56:15 -04:00
bvandeusen e31242b57f feat(web): add api client types (User, LoginResponse, ApiError) 2026-04-22 15:55:00 -04:00
bvandeusen d0015d3638 build(web): add TanStack Query + Testing Library deps
Wires @tanstack/svelte-query for the data layer and
@testing-library/{svelte,jest-dom} for component-level tests. Registers
the jest-dom matchers via a new vitest setup file.
2026-04-22 15:51:35 -04:00
bvandeusen 8fe4a5f578 refactor(web): move embed package to web/ so go:embed reaches build/
go:embed paths are relative to the source file and cannot reach parent
directories, so internal/web/embed.go could not see web/build/ without
duplicating the placeholder. Relocating to web/embed.go lets the
directive resolve to the real SvelteKit build output with no copy step.
2026-04-22 10:29:31 -04:00
bvandeusen 8d88a76dbf test(web): add Vitest smoke test and jsdom config 2026-04-22 09:30:08 -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