--- phase: 01-foundation-dashboard plan: 04 type: execute wave: 3 depends_on: - 01-01 - 01-02 - 01-03 files_modified: - src/app/components/Sidebar.tsx - src/app/components/LoginIndicator.tsx - src/app/components/Navigation.tsx - src/app/routes.ts - vite.config.ts - .bundlesize.json - src/app/components/__tests__/Sidebar.test.tsx - src/app/components/__tests__/LoginIndicator.test.tsx autonomous: true requirements: - DASH-07 - UI-02 - UI-03 - UI-04 - UI-05 must_haves: truths: - Sidebar navigation has Settings, Calibration, Flash Memory links - Login indicator shows logged-in state - Bundle size is under 170KB (target) / 200KB (limit) - All routes defined and working - Touch-friendly navigation (44px+ targets) artifacts: - path: src/app/components/Sidebar.tsx provides: Navigation sidebar exports: Sidebar min_lines: 50 - path: src/app/components/LoginIndicator.tsx provides: Login status indicator exports: LoginIndicator - path: src/app/routes.ts provides: Route definitions exports: router - path: .bundlesize.json provides: Bundle size budget config key_links: - from: Sidebar to: routes.ts via: Link components - from: LoginIndicator to: Header via: Header composition - from: routes.ts to: RainfallView via: Route configuration --- Complete the dashboard with navigation, login indicator, route configuration, and verify performance budget (<170KB bundle size). Purpose: Navigation provides access to other sections (Settings, Calibration, Flash Memory). Login indicator shows authentication status. Performance verification ensures Pi Zero 2 W compatibility. Output: Working navigation, login indicator, routes configured, bundle size verified under budget. @./.opencode/get-shit-done/workflows/execute-plan.md @./.opencode/get-shit-done/templates/summary.md @.planning/phases/01-foundation-dashboard/01-CONTEXT.md @.planning/phases/01-foundation-dashboard/01-RESEARCH.md @sample_interface/src/app/components/Sidebar.tsx @sample_interface/src/app/routes.ts ## Key Implementation Details **Navigation Items:** - Dashboard (home) - Settings (with sub-items) - Calibration - Flash Memory **Sidebar Design:** - Fixed width (64px icons-only or 240px expanded) - Touch-friendly items (44px+ height) - Active state highlighting - Collapsible on mobile **Login Indicator:** - Green dot/icon when logged in - Gray/red when logged out - Text label: "Logged In" / "Logged Out" - Small and compact for header **Routes:** - `/` → Dashboard (RainfallView) - `/utility/*` → Settings (placeholder for Phase 2) - `/calibration` → Calibration (placeholder) - `/flash-memory` → Flash Memory (placeholder) **Bundle Size Budget:** - Target: <170KB gzipped initial JS - Limit: <200KB gzipped - Tools: bundlesize, rollup-plugin-analyzer task 1: Create LoginIndicator component src/app/components/LoginIndicator.tsx, src/app/components/__tests__/LoginIndicator.test.tsx - Shows green status when isLoggedIn=true - Shows gray/red status when isLoggedIn=false - Compact size for header placement - Accessible (aria-label) 1. Create src/app/components/LoginIndicator.tsx: - Props: isLoggedIn (boolean), className (optional) - Use shadcn/ui Badge or custom indicator - Logged in: Green dot + "Logged In" text - Logged out: Gray dot + "Login" text - Compact: h-6, text-xs - Use Lucide User icon - Add aria-label for accessibility 2. Create tests: - Shows correct state for logged in/out - Has accessible label - Accepts custom className npm test -- --run LoginIndicator 2>&1 | grep -E "(PASS|FAIL|✓|✗)" LoginIndicator with accessible states created task 2: Update Sidebar navigation src/app/components/Sidebar.tsx, src/app/components/__tests__/Sidebar.test.tsx - Shows Dashboard, Settings, Calibration, Flash Memory links - Touch-friendly items (44px+ height) - Active state for current route - Collapsible sections 1. Update src/app/components/Sidebar.tsx: - Import NavLink from react-router - Define navigation items array: * Dashboard (Home icon) → / * Settings (Settings icon) → /utility * Calibration (Gauge icon) → /calibration * Flash Memory (HardDrive icon) → /flash-memory - Map items to NavLink components - Item height: min-h-[44px] - Active state: bg-accent class - Icon + label layout - Collapsible on mobile with hamburger 2. Create tests: - Renders all navigation items - Items have correct links - Touch target size adequate - Active state applied correctly npm test -- --run Sidebar 2>&1 | grep -E "(PASS|FAIL|✓|✗)" Sidebar with 4 navigation items created task 3: Configure routes for all views src/app/routes.ts, src/app/components/views/SettingsView.tsx, src/app/components/views/CalibrationView.tsx, src/app/components/views/FlashMemoryView.tsx - All routes defined in routes.ts - Settings, Calibration, Flash Memory have placeholder views - Routes use lazy loading where appropriate - Navigation between routes works 1. Create placeholder views: - src/app/components/views/SettingsView.tsx: "Settings - Phase 2" placeholder - src/app/components/views/CalibrationView.tsx: "Calibration - Phase 3" placeholder - src/app/components/views/FlashMemoryView.tsx: "Flash Memory - Phase 3" placeholder 2. Update src/app/routes.ts: - Import all views - Define routes array: * path: "/", element: RainfallView * path: "/utility/*", element: SettingsView * path: "/calibration", element: CalibrationView * path: "/flash-memory", element: FlashMemoryView - Use createBrowserRouter - Add error boundary for 404s grep -n "SettingsView\|CalibrationView\|FlashMemoryView" src/app/routes.ts 2>/dev/null | head -10 Routes configured for all 4 main sections task 4: Integrate LoginIndicator into Header src/app/components/Header.tsx - Header displays LoginIndicator - Gets login state from sensor store - Compact placement in header row 1. Update src/app/components/Header.tsx: - Import LoginIndicator - Get isLoggedIn from sensor store (or mock for now) - Place LoginIndicator in header layout - Ensure proper spacing and alignment 2. Test integration: - Login indicator visible in header - Updates when login state changes grep -n "LoginIndicator" src/app/components/Header.tsx 2>/dev/null | head -5 LoginIndicator integrated into Header task 5: Configure bundle size checking .bundlesize.json, vite.config.ts, package.json - Bundle size limit configured (170KB target, 200KB max) - Build fails if bundle exceeds limit - Size checking integrated in CI 1. Create .bundlesize.json: ```json { "files": [ { "path": "dist/assets/*.js", "maxSize": "200kb", "compression": "gzip" } ] } ``` 2. Update package.json scripts: - "build:check": "npm run build && bundlesize" - Add bundlesize as devDependency 3. Update vite.config.ts for optimization: - Manual chunks for vendor code - Drop console in production - Minification settings 4. Install bundlesize: `pnpm add -D bundlesize` test -f .bundlesize.json && echo "Config exists" || echo "Config missing" Bundle size checking configured task 6: Build and verify bundle size dist/ - Production build succeeds - Bundle size under 200KB limit - Ideally under 170KB target - No build errors or warnings 1. Run production build: - `npm run build` - Check for errors 2. Analyze bundle size: - `npm run build:check` or check dist/ folder - Look at main JS file size - Use rollup-plugin-visualizer if needed 3. If over budget, investigate: - Run `npx vite-bundle-visualizer` - Identify large dependencies - Consider code splitting 4. Document actual size in SUMMARY ls -lh dist/assets/*.js 2>/dev/null | awk '{print $5, $9}' | head -5 Bundle built and size verified (target: <170KB, limit: <200KB) task 7: Final integration test src/app/App.tsx - Full app renders without errors - Navigation works between routes - Dashboard shows all data - No console errors 1. Verify App.tsx integration: - RouterProvider with routes - DashboardLayout with Header and Sidebar - Outlet for route content 2. Run all tests: - `npm test` — should pass 3. Verify no TypeScript errors: - `npx tsc --noEmit` 4. Check for console errors: - Review any warnings in test output npm test 2>&1 | tail -5 Full integration verified, all tests passing After completing all tasks: 1. Run `npm test` — all tests should pass 2. Run `npm run build` — should succeed 3. Verify bundle size: Check dist/ folder, should be <200KB 4. Check routes: `grep -r "path:" src/app/routes.ts | wc -l` should be 4+ 5. Verify navigation: `grep -r "NavLink\|Link" src/app/components/Sidebar.tsx` 6. Check LoginIndicator in Header: `grep "LoginIndicator" src/app/components/Header.tsx` - LoginIndicator component shows logged-in state - Sidebar has navigation to Settings, Calibration, Flash Memory - All routes configured and working - Bundle size under 200KB (target <170KB) - No TypeScript errors - All tests passing - Full app integrates without errors After completion, create `.planning/phases/01-foundation-dashboard/01-04-SUMMARY.md`