feat(04-01): wire BrowserRouter + BottomTabBar + empty Lists surface

- App.tsx: BrowserRouter with /calendar, /lists, /lists/:listId routes; / redirects to /calendar
- BottomTabBar.tsx: fixed-bottom 56px tab bar with Calendar + Lists NavLinks, active accent
- AppNav.tsx: add Calendar/Lists NavLinks to desktop sidebar (≥768px)
- ListsIndex.tsx: full-height surface with isLoading/isError/empty state branches; "+ New List" FAB placeholder
- ListDetail.tsx: placeholder stub for /lists/:listId (Plan 04-04 fills in)
- listsStore.ts: Zustand UI-only store (activeTab, createListSheetOpen)
- listsClient.ts: fetchLists + List/ListItem types (initial; Plans 04-02/03 expand)
- Fix Wave-0 RED stubs: add vitest imports so stubs execute (todo) not error on import
- Fix CalendarShell.test.tsx: wrap renderWithClient in MemoryRouter (AppNav uses NavLink)
This commit is contained in:
Lucas Berger
2026-06-09 12:03:52 -04:00
parent 2f25b15949
commit c0088edf44
10 changed files with 563 additions and 3 deletions
+37 -1
View File
@@ -11,6 +11,8 @@
* - Grid is primary focal point; AppNav is secondary chrome
*/
import { NavLink } from 'react-router'
import { CalendarDays, List } from 'lucide-react'
import { ColorLegend, type LegendMember } from './ColorLegend.js'
interface AppNavProps {
@@ -102,8 +104,23 @@ function PhoneNav({
)
}
/** Tablet/Desktop: 240px left sidebar — app name + color legend */
/** Tablet/Desktop: 240px left sidebar — app name + nav links + color legend */
function DesktopNav({ members }: { members: LegendMember[] }) {
const navLinkStyle = ({ isActive }: { isActive: boolean }): React.CSSProperties => ({
display: 'flex',
alignItems: 'center',
gap: '10px',
padding: 'var(--space-2) var(--space-3, 12px)',
borderRadius: 'var(--space-1, 4px)',
textDecoration: 'none',
fontSize: 'var(--text-body-size, 15px)',
fontWeight: isActive ? 600 : 400,
color: isActive ? 'var(--color-member-0)' : 'var(--color-text-primary)',
background: isActive ? 'color-mix(in srgb, var(--color-member-0) 10%, transparent)' : 'transparent',
minHeight: '44px',
transition: 'color 0.1s ease, background 0.1s ease',
})
return (
<nav
style={{
@@ -133,6 +150,25 @@ function DesktopNav({ members }: { members: LegendMember[] }) {
FamilySync
</div>
{/* Section nav links */}
<div
style={{
display: 'flex',
flexDirection: 'column',
gap: 'var(--space-1, 4px)',
marginBottom: 'var(--space-6)',
}}
>
<NavLink to="/calendar" style={navLinkStyle} aria-label="Calendar">
<CalendarDays size={18} aria-hidden="true" />
Calendar
</NavLink>
<NavLink to="/lists" style={navLinkStyle} aria-label="Lists">
<List size={18} aria-hidden="true" />
Lists
</NavLink>
</div>
{/* Color legend */}
<div
style={{