docs(02-layout-and-brand-identity): create phase plan
This commit is contained in:
@@ -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 | - |
|
||||
|
||||
228
.planning/phases/02-layout-and-brand-identity/02-01-PLAN.md
Normal file
228
.planning/phases/02-layout-and-brand-identity/02-01-PLAN.md
Normal file
@@ -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"
|
||||
---
|
||||
|
||||
<objective>
|
||||
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.
|
||||
</objective>
|
||||
|
||||
<execution_context>
|
||||
@/home/jean-luc-makiola/.claude/get-shit-done/workflows/execute-plan.md
|
||||
@/home/jean-luc-makiola/.claude/get-shit-done/templates/summary.md
|
||||
</execution_context>
|
||||
|
||||
<context>
|
||||
@.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
|
||||
|
||||
<interfaces>
|
||||
<!-- Executor needs these from palette.ts for the gradient background -->
|
||||
|
||||
From frontend/src/lib/palette.ts:
|
||||
```typescript
|
||||
export const palette: Record<CategoryType, CategoryShades> = {
|
||||
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: <div className="flex min-h-screen items-center justify-center bg-background">
|
||||
// Current error: <p className="text-sm text-destructive">{error}</p>
|
||||
```
|
||||
</interfaces>
|
||||
</context>
|
||||
|
||||
<tasks>
|
||||
|
||||
<task type="auto">
|
||||
<name>Task 1: Install shadcn Alert and create test scaffolds for auth pages</name>
|
||||
<files>frontend/src/components/ui/alert.tsx, frontend/src/pages/LoginPage.test.tsx, frontend/src/pages/RegisterPage.test.tsx</files>
|
||||
<action>
|
||||
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 }`
|
||||
</action>
|
||||
<verify>
|
||||
<automated>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</automated>
|
||||
</verify>
|
||||
<done>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).</done>
|
||||
</task>
|
||||
|
||||
<task type="auto">
|
||||
<name>Task 2: Brand LoginPage and RegisterPage with gradient background, wordmark, and Alert errors</name>
|
||||
<files>frontend/src/pages/LoginPage.tsx, frontend/src/pages/RegisterPage.tsx</files>
|
||||
<action>
|
||||
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
|
||||
<div
|
||||
className="flex min-h-screen items-center justify-center"
|
||||
style={{
|
||||
background: `linear-gradient(135deg, ${palette.saving.light}, ${palette.bill.light}, ${palette.investment.light})`,
|
||||
}}
|
||||
>
|
||||
```
|
||||
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 `<CardDescription>{t('app.title')}</CardDescription>` with a styled wordmark element:
|
||||
```tsx
|
||||
<span
|
||||
data-testid="wordmark"
|
||||
className="text-2xl font-bold tracking-tight"
|
||||
style={{
|
||||
background: `linear-gradient(to right, oklch(0.50 0.12 260), oklch(0.50 0.12 320))`,
|
||||
WebkitBackgroundClip: 'text',
|
||||
WebkitTextFillColor: 'transparent',
|
||||
backgroundClip: 'text',
|
||||
}}
|
||||
>
|
||||
{t('app.title')}
|
||||
</span>
|
||||
```
|
||||
The gradient goes from --primary hue (260) to a pink-shifted hue (320). Keep `<CardTitle>{t('auth.login')}</CardTitle>` as-is above the wordmark.
|
||||
|
||||
4. Replace the plain error `<p>` with a shadcn Alert (AUTH-04):
|
||||
```tsx
|
||||
{error && (
|
||||
<Alert variant="destructive">
|
||||
<AlertCircle className="h-4 w-4" />
|
||||
<AlertDescription>{error}</AlertDescription>
|
||||
</Alert>
|
||||
)}
|
||||
```
|
||||
|
||||
5. Add `shadow-lg` to the Card for visual lift against the gradient: `<Card className="w-full max-w-md shadow-lg">`
|
||||
|
||||
**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 `<CardTitle>{t('auth.register')}</CardTitle>` (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.
|
||||
</action>
|
||||
<verify>
|
||||
<automated>cd /home/jean-luc-makiola/Development/projects/SimpleFinanceDash/frontend && bun vitest run src/pages/ --reporter=verbose && bun run build 2>&1 | tail -5</automated>
|
||||
</verify>
|
||||
<done>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.</done>
|
||||
</task>
|
||||
|
||||
</tasks>
|
||||
|
||||
<verification>
|
||||
- `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)
|
||||
</verification>
|
||||
|
||||
<success_criteria>
|
||||
- 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
|
||||
</success_criteria>
|
||||
|
||||
<output>
|
||||
After completion, create `.planning/phases/02-layout-and-brand-identity/02-layout-and-brand-identity-02-01-SUMMARY.md`
|
||||
</output>
|
||||
205
.planning/phases/02-layout-and-brand-identity/02-02-PLAN.md
Normal file
205
.planning/phases/02-layout-and-brand-identity/02-02-PLAN.md
Normal file
@@ -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\\]"
|
||||
---
|
||||
|
||||
<objective>
|
||||
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.
|
||||
</objective>
|
||||
|
||||
<execution_context>
|
||||
@/home/jean-luc-makiola/.claude/get-shit-done/workflows/execute-plan.md
|
||||
@/home/jean-luc-makiola/.claude/get-shit-done/templates/summary.md
|
||||
</execution_context>
|
||||
|
||||
<context>
|
||||
@.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
|
||||
|
||||
<interfaces>
|
||||
<!-- Current AppLayout structure the executor will modify -->
|
||||
|
||||
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: <h2 className="text-lg font-semibold">{t('app.title')}</h2>
|
||||
// Current active state: isActive={location.pathname === item.path} (no className override)
|
||||
// Current SidebarInset: <main className="flex-1">{children}</main> (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()
|
||||
```
|
||||
</interfaces>
|
||||
</context>
|
||||
|
||||
<tasks>
|
||||
|
||||
<task type="auto">
|
||||
<name>Task 1: Create AppLayout test scaffold</name>
|
||||
<files>frontend/src/components/AppLayout.test.tsx</files>
|
||||
<action>
|
||||
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) => <a href={to} {...props}>{children}</a>, 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(<AppLayout auth={mockAuth}><div>content</div></AppLayout>)`
|
||||
|
||||
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 `<aside>` or element with `data-sidebar="sidebar"` exists). The `--sidebar` token is already applied by the shadcn sidebar component via `bg-sidebar` -- this test confirms the sidebar renders, and the visual distinction comes from the token value in index.css.
|
||||
- NAV-02: An element with `data-testid="sidebar-wordmark"` exists inside the sidebar header (gradient wordmark).
|
||||
- NAV-03: The first nav item (dashboard, matching pathname `/`) has `data-active="true"` attribute on its SidebarMenuButton. Verify with `screen.getByRole('link', { name: /nav.dashboard/i })` and check closest `[data-active]` parent.
|
||||
- NAV-04: A button with accessible name matching the SidebarTrigger (look for a button containing the PanelLeft icon, or query `screen.getByRole('button', { name: /toggle sidebar/i })` -- the SidebarTrigger renders with `sr-only` text "Toggle Sidebar").
|
||||
|
||||
These tests verify structural presence. Visual correctness (contrast, color distinction) will be verified in the checkpoint.
|
||||
</action>
|
||||
<verify>
|
||||
<automated>cd /home/jean-luc-makiola/Development/projects/SimpleFinanceDash/frontend && bun vitest run src/components/AppLayout.test.tsx --reporter=verbose 2>&1 | tail -20</automated>
|
||||
</verify>
|
||||
<done>AppLayout.test.tsx exists with 4 test cases. Tests run (expected: most FAIL since features not yet implemented).</done>
|
||||
</task>
|
||||
|
||||
<task type="auto">
|
||||
<name>Task 2: Brand sidebar with wordmark, active indicator override, and collapse trigger</name>
|
||||
<files>frontend/src/components/AppLayout.tsx</files>
|
||||
<action>
|
||||
Apply all four NAV requirements to AppLayout.tsx.
|
||||
|
||||
1. Add `SidebarTrigger` to imports from `@/components/ui/sidebar` (NAV-04).
|
||||
|
||||
2. Replace the plain `<h2>` app name in SidebarHeader with a gradient text wordmark (NAV-02):
|
||||
```tsx
|
||||
<SidebarHeader className="border-b px-4 py-3">
|
||||
<span
|
||||
data-testid="sidebar-wordmark"
|
||||
className="text-base font-semibold tracking-wide"
|
||||
style={{
|
||||
background: `linear-gradient(to right, oklch(0.50 0.12 260), oklch(0.50 0.12 300))`,
|
||||
WebkitBackgroundClip: 'text',
|
||||
WebkitTextFillColor: 'transparent',
|
||||
backgroundClip: 'text',
|
||||
}}
|
||||
>
|
||||
{t('app.title')}
|
||||
</span>
|
||||
{auth.user && (
|
||||
<p className="text-sm text-muted-foreground">{auth.user.display_name}</p>
|
||||
)}
|
||||
</SidebarHeader>
|
||||
```
|
||||
The gradient starts at --primary hue (260) and shifts to hue 300 for a subtle purple-to-pink sweep.
|
||||
|
||||
3. Add a className override to SidebarMenuButton for a stronger active state indicator (NAV-03):
|
||||
```tsx
|
||||
<SidebarMenuButton
|
||||
asChild
|
||||
isActive={location.pathname === item.path}
|
||||
className="data-[active=true]:bg-sidebar-primary data-[active=true]:text-sidebar-primary-foreground"
|
||||
>
|
||||
```
|
||||
This overrides the default `bg-sidebar-accent` (only 4 lightness points difference, nearly invisible) with `bg-sidebar-primary` (oklch 0.50 vs 0.97 -- very visible).
|
||||
|
||||
4. Add a header bar with SidebarTrigger inside SidebarInset (NAV-04):
|
||||
```tsx
|
||||
<SidebarInset>
|
||||
<header className="flex h-12 shrink-0 items-center gap-2 border-b px-4">
|
||||
<SidebarTrigger className="-ml-1" />
|
||||
</header>
|
||||
<main className="flex-1 p-4">{children}</main>
|
||||
</SidebarInset>
|
||||
```
|
||||
The SidebarTrigger is placed inside SidebarInset (which is inside SidebarProvider), so the `useSidebar()` hook call is safe. Added `p-4` to main for consistent content padding.
|
||||
|
||||
5. NAV-01 is already satisfied by the existing `--sidebar: oklch(0.97 0.012 280)` token in index.css -- the sidebar renders with `bg-sidebar` natively. No code change needed; just verify it works via tests and visual check.
|
||||
|
||||
Do NOT edit `frontend/src/components/ui/sidebar.tsx` -- project constraint prohibits editing shadcn ui source files. All customization is via className props and CSS variable overrides.
|
||||
</action>
|
||||
<verify>
|
||||
<automated>cd /home/jean-luc-makiola/Development/projects/SimpleFinanceDash/frontend && bun vitest run src/components/AppLayout.test.tsx --reporter=verbose && bun run build 2>&1 | tail -5</automated>
|
||||
</verify>
|
||||
<done>All 4 AppLayout test cases pass. Production build succeeds. Sidebar renders gradient wordmark, strong active indicator using sidebar-primary, and a visible SidebarTrigger collapse button in the content header.</done>
|
||||
</task>
|
||||
|
||||
</tasks>
|
||||
|
||||
<verification>
|
||||
- `cd frontend && bun vitest run src/components/AppLayout.test.tsx --reporter=verbose` -- all tests green
|
||||
- `cd frontend && bun run build` -- zero errors
|
||||
- `cd frontend && bun vitest run` -- full suite green (no regressions)
|
||||
</verification>
|
||||
|
||||
<success_criteria>
|
||||
- Sidebar renders with bg-sidebar pastel background distinct from main content
|
||||
- App name in sidebar header is a gradient text wordmark, not a plain h2
|
||||
- Active nav item shows bg-sidebar-primary with high contrast (not the subtle default accent)
|
||||
- SidebarTrigger button is rendered in a header bar within SidebarInset
|
||||
- All new and existing tests pass, production build succeeds
|
||||
</success_criteria>
|
||||
|
||||
<output>
|
||||
After completion, create `.planning/phases/02-layout-and-brand-identity/02-layout-and-brand-identity-02-02-SUMMARY.md`
|
||||
</output>
|
||||
Reference in New Issue
Block a user