diff --git a/.planning/ROADMAP.md b/.planning/ROADMAP.md index 2d5f077..716c2f8 100644 --- a/.planning/ROADMAP.md +++ b/.planning/ROADMAP.md @@ -31,8 +31,8 @@ Decimal phases appear between their surrounding integers in numeric order. 5. A single `lib/palette.ts` file exists as the source of truth for all category-to-color mappings; `InlineEditCell.tsx` is extracted as a shared component replacing three duplicated local definitions **Plans:** 2/2 plans complete Plans: -- [ ] 01-01-PLAN.md — CSS token foundation, palette.ts module, and test infrastructure -- [ ] 01-02-PLAN.md — Component wiring, InlineEditCell extraction, and visual verification +- [x] 01-01-PLAN.md — CSS token foundation, palette.ts module, and test infrastructure +- [x] 01-02-PLAN.md — Component wiring, InlineEditCell extraction, and visual verification ### Phase 2: Layout and Brand Identity **Goal**: Users encounter a visually branded, polished experience on every high-visibility surface — login page, sidebar, and dashboard layout — establishing the perceptual quality bar for the entire app @@ -44,7 +44,10 @@ Plans: 3. The sidebar has a pastel background visually distinct from the main content area, with a branded typographic treatment for the app name 4. The active navigation item has a clearly visible color indicator — clicking a nav item produces a visible selected state 5. The sidebar can be collapsed via a toggle button, reducing screen space usage on smaller layouts -**Plans**: TBD +**Plans:** 2 plans +Plans: +- [ ] 02-01-PLAN.md — Auth screen branding (gradient background, wordmark, alert errors) +- [ ] 02-02-PLAN.md — Sidebar polish (wordmark, active indicator, collapse trigger) ### Phase 3: Interaction Quality and Completeness **Goal**: Every user action and app state has appropriate visual feedback — loading states, empty states, edit affordances, and delete confirmations — so the app feels complete and trustworthy @@ -76,6 +79,6 @@ Phases execute in numeric order: 1 → 2 → 3 → 4 | Phase | Plans Complete | Status | Completed | |-------|----------------|--------|-----------| | 1. Design Token Foundation | 2/2 | Complete | 2026-03-11 | -| 2. Layout and Brand Identity | 0/TBD | Not started | - | +| 2. Layout and Brand Identity | 0/2 | In progress | - | | 3. Interaction Quality and Completeness | 0/TBD | Not started | - | | 4. Chart Polish and Bug Fixes | 0/TBD | Not started | - | diff --git a/.planning/phases/02-layout-and-brand-identity/02-01-PLAN.md b/.planning/phases/02-layout-and-brand-identity/02-01-PLAN.md new file mode 100644 index 0000000..a7d284b --- /dev/null +++ b/.planning/phases/02-layout-and-brand-identity/02-01-PLAN.md @@ -0,0 +1,228 @@ +--- +phase: 02-layout-and-brand-identity +plan: 01 +type: execute +wave: 1 +depends_on: [] +files_modified: + - frontend/src/components/ui/alert.tsx + - frontend/src/pages/LoginPage.tsx + - frontend/src/pages/RegisterPage.tsx + - frontend/src/pages/LoginPage.test.tsx + - frontend/src/pages/RegisterPage.test.tsx +autonomous: true +requirements: [AUTH-01, AUTH-02, AUTH-03, AUTH-04] + +must_haves: + truths: + - "Login page renders on a pastel gradient background, not plain white" + - "Login page displays a gradient text wordmark for the app name" + - "Register page has the same branded gradient and wordmark as login" + - "Auth form errors display inside a styled Alert with an error icon" + artifacts: + - path: "frontend/src/components/ui/alert.tsx" + provides: "shadcn Alert component with destructive variant" + - path: "frontend/src/pages/LoginPage.tsx" + provides: "Branded login with gradient bg, wordmark, alert errors" + contains: "linear-gradient" + - path: "frontend/src/pages/RegisterPage.tsx" + provides: "Branded register matching login look" + contains: "linear-gradient" + - path: "frontend/src/pages/LoginPage.test.tsx" + provides: "Unit tests for AUTH-01, AUTH-02, AUTH-04" + - path: "frontend/src/pages/RegisterPage.test.tsx" + provides: "Unit tests for AUTH-03" + key_links: + - from: "frontend/src/pages/LoginPage.tsx" + to: "frontend/src/lib/palette.ts" + via: "import palette for gradient light shades" + pattern: "palette\\." + - from: "frontend/src/pages/LoginPage.tsx" + to: "frontend/src/components/ui/alert.tsx" + via: "Alert destructive for error display" + pattern: "Alert.*destructive" +--- + + +Brand the auth screens (login and register) with a pastel gradient background, gradient text wordmark, and styled error alerts -- transforming them from plain white cards into the first branded touchpoint users see. + +Purpose: Login is the first impression. A branded auth surface sets the perceptual quality bar before users even reach the dashboard. +Output: Polished LoginPage.tsx and RegisterPage.tsx with gradient backgrounds, wordmark, Alert errors, and passing unit tests. + + + +@/home/jean-luc-makiola/.claude/get-shit-done/workflows/execute-plan.md +@/home/jean-luc-makiola/.claude/get-shit-done/templates/summary.md + + + +@.planning/PROJECT.md +@.planning/ROADMAP.md +@.planning/STATE.md +@.planning/phases/02-layout-and-brand-identity/02-RESEARCH.md +@.planning/phases/02-layout-and-brand-identity/02-VALIDATION.md + +@frontend/src/pages/LoginPage.tsx +@frontend/src/pages/RegisterPage.tsx +@frontend/src/lib/palette.ts + + + + +From frontend/src/lib/palette.ts: +```typescript +export const palette: Record = { + saving: { light: 'oklch(0.95 0.04 280)', ... }, + bill: { light: 'oklch(0.96 0.03 250)', ... }, + investment: { light: 'oklch(0.96 0.04 320)', ... }, + // ... other types +} +``` + +From frontend/src/index.css (token values for wordmark gradient): +```css +--primary: oklch(0.50 0.12 260); +/* Shift hue to ~300-320 for the gradient end stop */ +``` + +From LoginPage.tsx current structure: +```typescript +interface Props { + auth: AuthContext + onToggle: () => void +} +// Uses: useState for email, password, error, loading +// Renders: Card with CardHeader, form with CardContent, CardFooter +// Current wrapper:
+// Current error:

{error}

+``` + + + + + + + Task 1: Install shadcn Alert and create test scaffolds for auth pages + frontend/src/components/ui/alert.tsx, frontend/src/pages/LoginPage.test.tsx, frontend/src/pages/RegisterPage.test.tsx + +1. Install the shadcn alert component: + ```bash + cd frontend && bunx --bun shadcn add alert + ``` + Verify `frontend/src/components/ui/alert.tsx` exists after installation. + +2. Create `frontend/src/pages/LoginPage.test.tsx` with these test cases (all should FAIL initially since the features are not yet implemented): + - AUTH-01: Login page wrapper div has an inline style containing `linear-gradient` (gradient background) + - AUTH-02: Login page renders an element with `data-testid="wordmark"` that has an inline style containing `background` (gradient text) + - AUTH-04: When error state is set, an element with `role="alert"` is rendered (shadcn Alert uses role="alert") + - AUTH-04: The alert contains an AlertCircle icon (verify by checking for an SVG inside the alert) + +3. Create `frontend/src/pages/RegisterPage.test.tsx` with these test cases: + - AUTH-03: Register page wrapper div has an inline style containing `linear-gradient` + - AUTH-03: Register page renders an element with `data-testid="wordmark"` + +Test setup notes: +- Import `{ render, screen }` from `@testing-library/react` +- LoginPage requires `auth` prop with `login` function and `onToggle` prop -- mock them with `vi.fn()` +- RegisterPage requires `auth` prop with `register` function and `onToggle` prop +- Both pages use `useTranslation` -- mock `react-i18next` with `vi.mock('react-i18next', () => ({ useTranslation: () => ({ t: (key: string) => key }) }))` +- The `AuthContext` type must be satisfied: `{ user: null, loading: false, login: vi.fn(), register: vi.fn(), logout: vi.fn(), token: null }` + + + cd /home/jean-luc-makiola/Development/projects/SimpleFinanceDash/frontend && bun vitest run src/pages/LoginPage.test.tsx src/pages/RegisterPage.test.tsx --reporter=verbose 2>&1 | tail -20 + + alert.tsx exists in ui/, LoginPage.test.tsx has 4 test cases, RegisterPage.test.tsx has 2 test cases. Tests run (expected: most FAIL since features not yet implemented). + + + + Task 2: Brand LoginPage and RegisterPage with gradient background, wordmark, and Alert errors + frontend/src/pages/LoginPage.tsx, frontend/src/pages/RegisterPage.tsx + +Apply all four AUTH requirements to both auth pages simultaneously (AUTH-03 requires register to mirror login). + +**LoginPage.tsx changes:** + +1. Add imports: + ```typescript + import { palette } from '@/lib/palette' + import { Alert, AlertDescription } from '@/components/ui/alert' + import { AlertCircle } from 'lucide-react' + ``` + +2. Replace the outer wrapper div `bg-background` with a gradient background using palette light shades (AUTH-01): + ```tsx +
+ ``` + Use the `light` shades (lightness 0.95-0.97, chroma 0.03-0.04) for a subtle tinted-paper feel, NOT medium or base shades which would be too saturated as backgrounds. + +3. Add a gradient text wordmark in the CardHeader (AUTH-02). Replace the `{t('app.title')}` with a styled wordmark element: + ```tsx + + {t('app.title')} + + ``` + The gradient goes from --primary hue (260) to a pink-shifted hue (320). Keep `{t('auth.login')}` as-is above the wordmark. + +4. Replace the plain error `

` with a shadcn Alert (AUTH-04): + ```tsx + {error && ( + + + {error} + + )} + ``` + +5. Add `shadow-lg` to the Card for visual lift against the gradient: `` + +**RegisterPage.tsx changes (AUTH-03):** + +Apply the identical structural changes as LoginPage: +- Same gradient background wrapper with palette light shades +- Same wordmark element with `data-testid="wordmark"` +- Same Alert destructive for error display +- Same Card shadow-lg +- Keep `{t('auth.register')}` (not login) +- Import palette, Alert, AlertDescription, AlertCircle + +Both files should be near-mirrors structurally. The only differences are: CardTitle text, form fields (register has displayName), submit handler, footer link text. + + + cd /home/jean-luc-makiola/Development/projects/SimpleFinanceDash/frontend && bun vitest run src/pages/ --reporter=verbose && bun run build 2>&1 | tail -5 + + All 6 test cases pass (4 LoginPage + 2 RegisterPage). Production build succeeds. LoginPage and RegisterPage both render gradient backgrounds, gradient text wordmarks, and Alert-based error displays. + + + + + +- `cd frontend && bun vitest run src/pages/ --reporter=verbose` -- all tests green +- `cd frontend && bun run build` -- zero errors +- `cd frontend && bun vitest run` -- full suite green (no regressions) + + + +- Login page has a pastel gradient background using palette.ts light shades (not plain white) +- Both auth pages display a gradient text wordmark for the app name +- Auth errors render in a shadcn Alert with destructive variant and AlertCircle icon +- Register page is structurally identical to login in branding treatment +- All new and existing tests pass, production build succeeds + + + +After completion, create `.planning/phases/02-layout-and-brand-identity/02-layout-and-brand-identity-02-01-SUMMARY.md` + diff --git a/.planning/phases/02-layout-and-brand-identity/02-02-PLAN.md b/.planning/phases/02-layout-and-brand-identity/02-02-PLAN.md new file mode 100644 index 0000000..1cb44d0 --- /dev/null +++ b/.planning/phases/02-layout-and-brand-identity/02-02-PLAN.md @@ -0,0 +1,205 @@ +--- +phase: 02-layout-and-brand-identity +plan: 02 +type: execute +wave: 1 +depends_on: [] +files_modified: + - frontend/src/components/AppLayout.tsx + - frontend/src/components/AppLayout.test.tsx +autonomous: true +requirements: [NAV-01, NAV-02, NAV-03, NAV-04] + +must_haves: + truths: + - "Sidebar has a visually distinct pastel background from the main content area" + - "Sidebar app name displays as a branded gradient text wordmark" + - "Clicking a nav item produces a clearly visible active state indicator" + - "A toggle button exists to collapse/expand the sidebar" + artifacts: + - path: "frontend/src/components/AppLayout.tsx" + provides: "Branded sidebar with wordmark, active indicator, collapse trigger" + contains: "SidebarTrigger" + - path: "frontend/src/components/AppLayout.test.tsx" + provides: "Unit tests for NAV-01 through NAV-04" + key_links: + - from: "frontend/src/components/AppLayout.tsx" + to: "frontend/src/components/ui/sidebar.tsx" + via: "SidebarTrigger import for collapse toggle" + pattern: "SidebarTrigger" + - from: "frontend/src/components/AppLayout.tsx" + to: "SidebarMenuButton isActive" + via: "data-active styling override for visible indicator" + pattern: "data-\\[active=true\\]" +--- + + +Polish the sidebar shell -- branded wordmark, visible active nav indicator, and collapse toggle -- so every authenticated page load feels intentionally designed. + +Purpose: The sidebar is visible on every page after login. Its polish directly determines the perceived quality of the entire app. +Output: Updated AppLayout.tsx with branded sidebar and passing unit tests. + + + +@/home/jean-luc-makiola/.claude/get-shit-done/workflows/execute-plan.md +@/home/jean-luc-makiola/.claude/get-shit-done/templates/summary.md + + + +@.planning/PROJECT.md +@.planning/ROADMAP.md +@.planning/STATE.md +@.planning/phases/02-layout-and-brand-identity/02-RESEARCH.md +@.planning/phases/02-layout-and-brand-identity/02-VALIDATION.md + +@frontend/src/components/AppLayout.tsx + + + + +From frontend/src/components/AppLayout.tsx: +```typescript +interface Props { + auth: AuthContext + children: React.ReactNode +} +// Uses: useTranslation, useLocation from react-router-dom +// Imports from ui/sidebar: Sidebar, SidebarContent, SidebarFooter, SidebarGroup, +// SidebarGroupContent, SidebarHeader, SidebarMenu, SidebarMenuButton, +// SidebarMenuItem, SidebarProvider, SidebarInset +// NOTE: SidebarTrigger is NOT currently imported +// Current app name:

{t('app.title')}

+// Current active state: isActive={location.pathname === item.path} (no className override) +// Current SidebarInset:
{children}
(no header bar) +``` + +From frontend/src/index.css (sidebar token values): +```css +--sidebar: oklch(0.97 0.012 280); /* light lavender background */ +--sidebar-primary: oklch(0.50 0.12 260); /* strong accent for active state */ +--sidebar-primary-foreground: oklch(0.99 0.005 290); +--sidebar-accent: oklch(0.93 0.020 280); /* 4-point lightness diff from sidebar - may be too subtle */ +--primary: oklch(0.50 0.12 260); /* for wordmark gradient start */ +``` + +From frontend/src/components/ui/sidebar.tsx (already exported): +```typescript +export { SidebarTrigger } // renders PanelLeftIcon button, calls toggleSidebar() +``` + + + + + + + Task 1: Create AppLayout test scaffold + frontend/src/components/AppLayout.test.tsx + +Create `frontend/src/components/AppLayout.test.tsx` with test cases for all four NAV requirements. + +Test setup: +- Mock `react-i18next`: `vi.mock('react-i18next', () => ({ useTranslation: () => ({ t: (key: string) => key }) }))` +- Mock `react-router-dom`: `vi.mock('react-router-dom', () => ({ Link: ({ children, to, ...props }: any) => {children}, useLocation: () => ({ pathname: '/' }) }))` +- Create mock auth: `{ user: { display_name: 'Test' }, loading: false, login: vi.fn(), register: vi.fn(), logout: vi.fn(), token: 'test' } as unknown as AuthContext` +- Render with: `render(
content
)` + +Note: SidebarProvider uses ResizeObserver internally. Add to test file top: +```typescript +// Mock ResizeObserver for sidebar tests +globalThis.ResizeObserver = class { observe() {} unobserve() {} disconnect() {} } as any +``` + +Test cases: +- NAV-01: The sidebar element renders (verify `