docs(02-01): complete plan 02-01 shell components summary

- HeaderBar, BottomNav, MoreDrawer, analyzer placeholder created
- TypeScript and Next.js build both pass (273 routes)
- Requirements SHELL-02..04, SHELL-06, NAV-01..03, DRAWER-01..05 addressed
This commit is contained in:
lorentz 2026-05-03 16:05:11 -04:00
parent 29ff7fd8fd
commit 08467494bf

View file

@ -0,0 +1,129 @@
---
phase: 02-mobile-shell-more-drawer
plan: 01
subsystem: mobile-shell
tags: [mobile, navigation, shell, drawer, components]
dependency_graph:
requires: []
provides:
- components/mobile/HeaderBar.tsx
- components/mobile/BottomNav.tsx
- components/mobile/MoreDrawer.tsx
- app/mobile/analyzer/page.tsx
affects:
- app/mobile/layout.tsx (Plan 02 will wire these in)
tech_stack:
added: []
patterns:
- shadcn Sheet (side="right") for drawer
- Controlled open/onOpenChange props for shared drawer state
- pathname.startsWith(href) for active tab detection
- initials-circle pattern from UserMenu (no shadcn avatar primitive)
- pt-safe / pb-safe from Phase 1 brand.css utilities
key_files:
created:
- components/mobile/HeaderBar.tsx
- components/mobile/BottomNav.tsx
- components/mobile/MoreDrawer.tsx
- app/mobile/analyzer/page.tsx
modified: []
decisions:
- Sheet side="right" (locked per DRAWER-02 in CONTEXT.md)
- No shadcn avatar primitive — initials-circle pattern matches existing UserMenu
- Bell onClick intentionally empty (SHELL-03 placeholder, Phase 7+ wires real notifications)
- No page title in HeaderBar — pages render their own H1
- analyzer/page.tsx is a deliberate "coming soon" placeholder — Phase 6 owns the real feed
metrics:
duration_minutes: 5
completed_date: "2026-05-03"
tasks_completed: 5
tasks_total: 5
files_created: 4
files_modified: 0
---
# Phase 02 Plan 01: Mobile Shell Components Summary
Three new reusable shell components and an analyzer route placeholder — the building blocks Plan 02 will wire into `app/mobile/layout.tsx` to complete the mobile shell redesign.
## What Was Built
**MoreDrawer** (`components/mobile/MoreDrawer.tsx`) — shadcn Sheet (side="right") with controlled `open`/`onOpenChange` props so both the header avatar and the bottom-nav More button share one drawer instance. Three sections:
- Mobile sections: Engagement (in-shell, no ExternalLink)
- Full site: Quotes, Configuration Items, Backup Status, Ticket Digest, Admin/Sync (each with ExternalLink icon)
- Account: user initials + name/email (read-only) + Sign out (calls `signOut()` then navigates to `/auth/sign-in`)
**HeaderBar** (`components/mobile/HeaderBar.tsx`) — sticky header with `bg-background/95 backdrop-blur border-b pt-safe`. Left: WulfMark + "Pulse" wordmark linked to `/mobile/dashboard`. Right: Bell placeholder (`aria-label="Notifications"`, empty onClick) + compact avatar circle (h-7 w-7) calling `onAvatarClick` prop. No page title in the header.
**BottomNav** (`components/mobile/BottomNav.tsx`) — fixed bottom bar (`border-t bg-background pb-safe`, `max-w-lg mx-auto`, `h-16`). Four tabs: Dashboard (LayoutDashboard), Tickets (Ticket), Finance (DollarSign), Analyzer (Sparkles) — all with `pathname.startsWith(href)` active detection (text-primary when active, text-muted-foreground otherwise). Fifth cell: More button calling `onMoreClick` prop.
**Analyzer placeholder** (`app/mobile/analyzer/page.tsx`) — minimal server component with "coming soon" card. Resolves the `/mobile/analyzer` route so the new Analyzer tab doesn't 404 before Phase 6 (ANL-01..06) ships the real feed.
## Requirements Addressed
| Requirement | Status |
|-------------|--------|
| SHELL-02 | Sticky header, brand mark+wordmark, /mobile/dashboard link, backdrop blur, border-b |
| SHELL-03 | Bell placeholder with aria-label, empty onClick |
| SHELL-04 | Avatar circle h-7 w-7, triggers drawer via onAvatarClick |
| SHELL-06 | Fixed bottom nav, max-w-lg mx-auto, border-t, pb-safe |
| NAV-01 | 4 tab icons: LayoutDashboard, Ticket, DollarSign, Sparkles + Menu for More |
| NAV-02 | 4 routes: /mobile/dashboard, /mobile/tickets, /mobile/finance, /mobile/analyzer |
| NAV-03 | pathname.startsWith(href) active detection, text-primary/text-muted-foreground |
| DRAWER-01 | More button in BottomNav triggers shared drawer via onMoreClick prop |
| DRAWER-02 | Sheet side="right" (locked decision) |
| DRAWER-03 | Mobile sections: Engagement /mobile/engagement (no ExternalLink) |
| DRAWER-04 | Full site: Quotes, Config Items, Backup Status, Ticket Digest, Admin/Sync with ExternalLink |
| DRAWER-05 | Account: user display (read-only) + Sign out via signOut() + router.push('/auth/sign-in') |
## Locked Decisions Honored
- `side="right"` — locked in CONTEXT.md DRAWER-02
- No shadcn `avatar` primitive — uses existing initials-circle pattern from UserMenu
- Bell `onClick` is empty — SHELL-03 explicitly says "placeholder only this iteration"
- No `<h1>` in HeaderBar — SHELL-02 explicit: "pages render their own H1"
- MoreDrawer uses controlled state (props, not internal) — both triggers share one drawer
## Notes for Plan 02
Plan 02 rewrites `app/mobile/layout.tsx` and deletes `app/mobile/nav/page.tsx`. When wiring the new components:
```tsx
// In layout.tsx (Plan 02):
const [drawerOpen, setDrawerOpen] = useState(false);
<HeaderBar onAvatarClick={() => setDrawerOpen(true)} />
<MoreDrawer open={drawerOpen} onOpenChange={setDrawerOpen} />
<BottomNav onMoreClick={() => setDrawerOpen(true)} />
```
## Deviations from Plan
None — plan executed exactly as written.
## Known Stubs
| File | Stub | Reason |
|------|------|--------|
| `app/mobile/analyzer/page.tsx` | "coming soon" card, no data | Intentional — Phase 6 (ANL-01..06) owns the real mobile analyzer feed. This file exists only to prevent a 404 on the new BottomNav Analyzer tab. |
| `components/mobile/HeaderBar.tsx` | Bell onClick is empty | Intentional — SHELL-03 explicitly defers real notifications to Phase 7+. |
## Threat Flags
None — no new network endpoints, no new auth paths, no new DB access. All trust boundaries match the plan's threat model exactly.
## Self-Check: PASSED
Files verified:
- `components/mobile/HeaderBar.tsx` — exists
- `components/mobile/BottomNav.tsx` — exists
- `components/mobile/MoreDrawer.tsx` — exists
- `app/mobile/analyzer/page.tsx` — exists
Commits verified:
- `6630589` — feat(02-01): create MoreDrawer component
- `14375f1` — feat(02-01): create HeaderBar component
- `a42c0a8` — feat(02-01): create BottomNav component
- `3fc0ee3` — feat(02-01): add /mobile/analyzer placeholder
Build: `npx tsc --noEmit --pretty` exits 0, `npm run build` exits 0 (273 routes generated, `/mobile/analyzer` in route table).