feat(frontend): mobile account hub + library wrapper (0.60.0)
Phase 5 (final) of the mobile redesign: /profile/account becomes an
inset-grouped iOS-style hub on mobile and the new /library route hosts
a SegmentedControl over Bookmarks / Collections / History. Profile-
layout horizontal tabs hide below 640px. Desktop layout is unchanged.
- New /library/+page.ts loads bookmarks, collections, and read-history
in parallel so segmented-control tabs swap instantly without a new
round trip. 401 → unauthenticated path with sign-in prompt.
- New /library/+page.svelte renders the SegmentedControl with ?tab=
as the source of truth. Bookmarks reuses the existing BookmarkList,
Collections reuses CollectionsGrid, History inlines a slim cover +
title + "Continue Ch. N" row list. `goto(..., { replaceState: true })`
drives the URL — plain `replaceState` from $app/navigation doesn't
reliably re-trigger $page-derived state.
- BottomNav's Library tab now points at /library (Phase 1 placeholder
was /bookmarks). The Phase 1 mobile-chrome spec is updated to expect
the new target and mocks the additional library data endpoints.
- /profile/+layout.svelte hides the horizontal tabs below 640px — the
bottom-nav Library/Account tabs plus the account hub carry mobile
cross-section navigation.
- /profile/account/+page.svelte gains a mobile hub: a centered avatar
+ username + "Member since" header, a row group with Profile /
Preferences / Change password rows (the last opening a bottom
Sheet hosting the existing password form snippet), and a separate
group with a red "Log out" row that reuses the layout's logout
flow (logout API → session.setUser(null) → preferences.clearForLogout
→ goto('/login')). Desktop keeps the inline card with the form.
- matchMedia gates the hub vs. desktop card so the password form
testids never duplicate on the page — the snippet is rendered in
exactly one mount at a time.
- 9 Playwright tests cover the Library nav handoff, segmented-control
sub-tab swap with URL, sign-in CTAs on both routes, account hub
composition, password sheet open flow, logout flow (POST /auth/
logout + redirect to /login), profile tabs hiding on mobile, and
the desktop regression where the inline card is the only password
surface.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -39,6 +39,7 @@
|
||||
'/upload': 'Mangalord | Upload',
|
||||
'/bookmarks': 'Mangalord | Bookmarks',
|
||||
'/collections': 'Mangalord | Collections',
|
||||
'/library': 'Mangalord | Library',
|
||||
'/profile': 'Mangalord | Profile',
|
||||
'/profile/account': 'Mangalord | Account',
|
||||
'/profile/bookmarks': 'Mangalord | Bookmarks',
|
||||
@@ -53,19 +54,21 @@
|
||||
|
||||
const layoutTitle = $derived(STATIC_TITLES[$page.route?.id ?? ''] ?? 'Mangalord');
|
||||
|
||||
// Mobile bottom-nav tabs. Library consolidates Bookmarks / Collections /
|
||||
// History — it currently links to /bookmarks as the closest existing
|
||||
// route; Phase 5 introduces /library with internal segmented sub-tabs
|
||||
// and this href flips at that point. Browse temporarily shares Home's
|
||||
// destination until the curated-feed split lands.
|
||||
// Mobile bottom-nav tabs. Library is now its own wrapper at /library
|
||||
// (Phase 5) hosting a SegmentedControl over Bookmarks / Collections /
|
||||
// History; the older top-level /bookmarks + /collections routes stay
|
||||
// active for desktop users and as deep-link targets, so they remain
|
||||
// in the `match` set. Browse temporarily shares Home's destination
|
||||
// until the curated-feed split lands.
|
||||
const MOBILE_TABS: BottomNavTab[] = [
|
||||
{ label: 'Home', href: '/', icon: House, match: [] },
|
||||
{ label: 'Browse', href: '/', icon: Search, match: [] },
|
||||
{
|
||||
label: 'Library',
|
||||
href: '/bookmarks',
|
||||
href: '/library',
|
||||
icon: BookOpen,
|
||||
match: [
|
||||
'/library',
|
||||
'/bookmarks',
|
||||
'/collections',
|
||||
'/profile/bookmarks',
|
||||
|
||||
Reference in New Issue
Block a user