Files
SimpleFinanceDash/.planning/phases/01-design-token-foundation/01-02-PLAN.md

17 KiB

phase, plan, type, wave, depends_on, files_modified, autonomous, requirements, must_haves
phase plan type wave depends_on files_modified autonomous requirements must_haves
01-design-token-foundation 02 execute 2
01-01
frontend/src/components/BillsTracker.tsx
frontend/src/components/VariableExpenses.tsx
frontend/src/components/DebtTracker.tsx
frontend/src/components/AvailableBalance.tsx
frontend/src/components/ExpenseBreakdown.tsx
frontend/src/components/FinancialOverview.tsx
frontend/src/components/InlineEditCell.tsx
frontend/src/components/InlineEditCell.test.tsx
false
DSGN-03
DSGN-04
DSGN-05
FIX-02
truths artifacts key_links
Card headers on BillsTracker, VariableExpenses, DebtTracker, AvailableBalance, ExpenseBreakdown use palette-driven gradients — no hardcoded Tailwind color classes remain
FinancialOverview header uses a multi-pastel gradient from overviewHeaderGradient()
FinancialOverview and AvailableBalance have hero typography (text-2xl titles, p-6 padding) while other cards have regular typography (text-base titles, px-4 py-3 padding)
AvailableBalance center amount is text-3xl font-bold with green/red color coding
Actual amount columns show green for positive income, amber for over-budget expenses, red for negative available — budget column stays neutral
InlineEditCell.tsx is a shared component replacing three duplicate InlineEditRow functions
FinancialOverview rows are tinted with their category's light shade
path provides exports min_lines
frontend/src/components/InlineEditCell.tsx Shared inline edit cell component
InlineEditCell
25
path provides min_lines
frontend/src/components/InlineEditCell.test.tsx Unit tests for InlineEditCell 30
path provides contains
frontend/src/components/BillsTracker.tsx Bills section with palette gradient header and InlineEditCell headerGradient
path provides contains
frontend/src/components/FinancialOverview.tsx Hero overview with multi-gradient header and category-tinted rows overviewHeaderGradient
from to via pattern
frontend/src/components/BillsTracker.tsx frontend/src/lib/palette.ts import headerGradient and amountColorClass import.*palette
from to via pattern
frontend/src/components/InlineEditCell.tsx frontend/src/components/BillsTracker.tsx BillsTracker imports and uses InlineEditCell instead of local InlineEditRow InlineEditCell
from to via pattern
frontend/src/components/AvailableBalance.tsx frontend/src/lib/palette.ts Chart Cell fill uses palette[type].base instead of PASTEL_COLORS array palette.*base
Wire the palette.ts module into all dashboard components — replace hardcoded gradients, apply hero typography, add amount coloring, and extract InlineEditCell.

Purpose: This transforms the visual appearance of the dashboard from generic neutrals to a cohesive pastel-themed experience. Every component now reads from the token system established in Plan 01. Output: All 6 dashboard components updated, InlineEditCell extracted and tested.

<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>

@.planning/PROJECT.md @.planning/ROADMAP.md @.planning/STATE.md @.planning/phases/01-design-token-foundation/01-CONTEXT.md @.planning/phases/01-design-token-foundation/01-RESEARCH.md @.planning/phases/01-design-token-foundation/01-01-SUMMARY.md

@frontend/src/lib/palette.ts @frontend/src/index.css @frontend/src/components/BillsTracker.tsx @frontend/src/components/VariableExpenses.tsx @frontend/src/components/DebtTracker.tsx @frontend/src/components/AvailableBalance.tsx @frontend/src/components/ExpenseBreakdown.tsx @frontend/src/components/FinancialOverview.tsx

From src/lib/palette.ts (created in Plan 01):

export type CategoryType = 'income' | 'bill' | 'variable_expense' | 'debt' | 'saving' | 'investment' | 'carryover'

export interface CategoryShades {
  light: string   // oklch — row backgrounds, tinted surfaces
  medium: string  // oklch — header gradient to-color, badges
  base: string    // oklch — chart fills, text accents
}

export const palette: Record<CategoryType, CategoryShades>

export function headerGradient(type: CategoryType): React.CSSProperties
export function overviewHeaderGradient(): React.CSSProperties
export function amountColorClass(opts: {
  type: CategoryType
  actual: number
  budgeted: number
  isIncome?: boolean
  isAvailable?: boolean
}): string

From src/lib/utils.ts:

export function cn(...inputs: ClassValue[]): string

From src/lib/format.ts:

export function formatCurrency(value: number, currency: string): string
Task 1: Extract InlineEditCell and wire palette into all components frontend/src/components/InlineEditCell.tsx, frontend/src/components/InlineEditCell.test.tsx, frontend/src/components/BillsTracker.tsx, frontend/src/components/VariableExpenses.tsx, frontend/src/components/DebtTracker.tsx, frontend/src/components/AvailableBalance.tsx, frontend/src/components/ExpenseBreakdown.tsx, frontend/src/components/FinancialOverview.tsx - InlineEditCell renders formatted currency in display mode - InlineEditCell shows an Input on click (enters edit mode) - InlineEditCell calls onSave with parsed number on blur/Enter - InlineEditCell does NOT call onSave if value unchanged or NaN **Part A — Write InlineEditCell tests (RED):**

Create frontend/src/components/InlineEditCell.test.tsx with tests:

  • "renders formatted currency value in display mode"
  • "enters edit mode on click"
  • "calls onSave with parsed number on blur"
  • "does not call onSave when value unchanged"
  • "calls onSave on Enter key"

Use @testing-library/react render + @testing-library/user-event. Mock formatCurrency from @/lib/format if needed, or just test the DOM output.

Run tests — they must FAIL.

Part B — Create InlineEditCell (GREEN):

Create frontend/src/components/InlineEditCell.tsx following the pattern from RESEARCH.md Pattern 5. Props interface:

interface InlineEditCellProps {
  value: number
  currency: string
  onSave: (value: number) => Promise<void>
  className?: string
}

The component renders a <TableCell> that:

  • In display mode: shows a <span> with formatCurrency(value, currency), cursor-pointer rounded px-2 py-1 hover:bg-muted
  • On click: switches to edit mode with <Input type="number" step="0.01">, autofocused
  • On blur or Enter: parses the input, calls onSave if value changed and is a valid number, then returns to display mode

Run tests — they must PASS.

Part C — Wire palette into all 6 dashboard components:

For each component, apply these changes:

BillsTracker.tsx:

  1. Remove the private InlineEditRow function (lines ~59-110)
  2. Add imports: import { headerGradient, amountColorClass } from '@/lib/palette' and import { InlineEditCell } from '@/components/InlineEditCell'
  3. Replace <CardHeader className="bg-gradient-to-r from-blue-50 to-indigo-50"> with <CardHeader style={headerGradient('bill')}>
  4. Replace the <InlineEditRow> usage with <InlineEditCell> inside the existing <TableRow>. The caller keeps the label and budget cells; InlineEditCell replaces only the actual amount cell.
  5. Add amountColorClass({ type: 'bill', actual, budgeted }) as className on the InlineEditCell for amount coloring. Budget column stays neutral (no color class).

VariableExpenses.tsx:

  1. Remove the private InlineEditRow function (lines ~86-142)
  2. Add same imports as BillsTracker
  3. Replace <CardHeader className="bg-gradient-to-r from-amber-50 to-yellow-50"> with <CardHeader style={headerGradient('variable_expense')}>
  4. Replace <InlineEditRow> with <InlineEditCell> for the actual cell. Keep the "remaining" cell in VariableExpenses — it's NOT part of InlineEditCell.
  5. Add amount coloring to the InlineEditCell className.

DebtTracker.tsx:

  1. Remove the private InlineEditRow function (lines ~61-112)
  2. Add same imports
  3. Replace <CardHeader className="bg-gradient-to-r from-orange-50 to-red-50"> with <CardHeader style={headerGradient('debt')}>
  4. Replace <InlineEditRow> with <InlineEditCell> for the actual cell
  5. Add amount coloring

AvailableBalance.tsx:

  1. Remove the PASTEL_COLORS array constant
  2. Add imports: import { palette, headerGradient, type CategoryType } from '@/lib/palette'
  3. Replace <CardHeader className="bg-gradient-to-r from-sky-50 to-cyan-50"> with <CardHeader style={headerGradient('saving')} className="px-6 py-5"> (hero padding per locked decision)
  4. Update <CardTitle> to className="text-2xl font-semibold" (hero typography)
  5. Replace <Cell fill={PASTEL_COLORS[index % ...]} with <Cell fill={palette[entry.categoryType as CategoryType]?.base ?? palette.carryover.base}>
  6. Style the center donut amount: text-3xl font-bold tabular-nums with cn() applying text-success when available >= 0, text-destructive when negative
  7. Add small text-xs text-muted-foreground label "Available" (or translated equivalent) below the center amount

ExpenseBreakdown.tsx:

  1. Remove the PASTEL_COLORS array constant
  2. Add imports: import { palette, type CategoryType } from '@/lib/palette'
  3. Replace <CardHeader className="bg-gradient-to-r from-pink-50 to-rose-50"> with <CardHeader style={headerGradient('debt')}>
  4. Replace <Cell fill={PASTEL_COLORS[index % ...]} with <Cell fill={palette[entry.categoryType as CategoryType]?.base ?? palette.carryover.base}>

FinancialOverview.tsx:

  1. Add imports: import { palette, overviewHeaderGradient, amountColorClass, type CategoryType } from '@/lib/palette'
  2. Replace <CardHeader className="bg-gradient-to-r from-sky-50 to-indigo-50"> with <CardHeader style={overviewHeaderGradient()} className="px-6 py-5"> (hero padding)
  3. Update <CardTitle> to className="text-2xl font-semibold" (hero typography)
  4. Tint each summary row with its category's light shade: add style={{ backgroundColor: palette[categoryType].light }} to each <TableRow> that represents a category
  5. Apply amountColorClass() to actual amount cells. For the income row, pass isIncome: true. For the remaining/available summary row, pass isAvailable: true. Budget column stays neutral.

CRITICAL anti-patterns to avoid:

  • Do NOT add style to <Card> — only to <CardHeader> for gradients
  • Do NOT color the budget column — only actual gets colored
  • Do NOT use raw Tailwind color classes like text-green-600 — use text-success from the semantic token
  • Do NOT edit any files in src/components/ui/
  • Do NOT use Tailwind v3 bracket syntax bg-[--var] — use v4 parenthesis syntax bg-(--var) if needed cd /home/jean-luc-makiola/Development/projects/SimpleFinanceDash/frontend && bun vitest run --reporter=verbose
    • InlineEditCell.test.tsx passes all tests
    • palette.test.ts still passes (no regressions)
    • No InlineEditRow private function exists in BillsTracker, VariableExpenses, or DebtTracker
    • No PASTEL_COLORS array exists in AvailableBalance or ExpenseBreakdown
    • No bg-gradient-to-r from-blue-50 or similar hardcoded gradient classes exist in any dashboard component
    • All 6 dashboard components import from @/lib/palette
    • FinancialOverview and AvailableBalance use hero sizing (text-2xl, p-6/px-6 py-5)
    • Amount coloring uses amountColorClass() — only on actual column
Task 2: Build verification — ensure app compiles and no hardcoded colors remain frontend/src/components/BillsTracker.tsx, frontend/src/components/VariableExpenses.tsx, frontend/src/components/DebtTracker.tsx, frontend/src/components/AvailableBalance.tsx, frontend/src/components/ExpenseBreakdown.tsx, frontend/src/components/FinancialOverview.tsx 1. Run the Vite build to confirm no TypeScript errors: `cd frontend && bun run build`
  1. Run the full test suite: cd frontend && bun vitest run

  2. Verify no hardcoded gradient color classes remain in dashboard components: grep -rn "from-blue-50\|from-amber-50\|from-orange-50\|from-sky-50\|from-pink-50\|from-sky-50 to-indigo-50\|PASTEL_COLORS" frontend/src/components/ This should return zero results.

  3. Verify no raw Tailwind color utilities for amount coloring: grep -rn "text-green-\|text-red-\|text-amber-" frontend/src/components/ This should return zero results (all amount colors use text-success, text-warning, text-destructive).

  4. Verify InlineEditRow is fully removed: grep -rn "InlineEditRow" frontend/src/components/ This should return zero results.

If any issues are found, fix them before proceeding. cd /home/jean-luc-makiola/Development/projects/SimpleFinanceDash/frontend && bun run build 2>&1 | tail -5 && bun vitest run 2>&1 | tail -5 Vite production build succeeds with zero errors. All tests pass. No hardcoded gradient classes, PASTEL_COLORS arrays, InlineEditRow functions, or raw Tailwind color utilities exist in dashboard components.

Task 3: Visual verification of pastel design token system Human verifies the complete pastel design token system and visual dashboard overhaul.

What was built:

  • All shadcn components display in pastel tones (lavender-tinted backgrounds, borders, and surfaces)
  • Card headers have category-specific pastel gradients (blue for bills, amber for variable expenses, rose for debt, etc.)
  • FinancialOverview and AvailableBalance are visually dominant hero elements with larger text and more padding
  • AvailableBalance donut center shows the amount in green (positive) or red (negative)
  • Amount coloring: green for positive income, amber for over-budget expenses, red for negative available
  • FinancialOverview rows are tinted with their category's pastel shade
  • Charts use category colors from palette.ts (same colors as table headers)
  • InlineEditCell is extracted as a shared component (click to edit actual amounts)

How to verify:

  1. Start the app: cd frontend && bun run dev (ensure backend is running or use docker compose up db for database)
  2. Open http://localhost:5173 in browser
  3. Check these specific items: a. Background tint: The page background should have a very subtle lavender tint; cards should be pure white floating on it b. Card headers: Each section (Bills, Variable Expenses, Debt) should have a distinct pastel gradient header color — blue, amber, rose respectively c. Hero elements: FinancialOverview and AvailableBalance should look visually larger/more prominent than other cards d. Donut center: The available amount in the donut chart should be large text, colored green if positive or red if negative e. Amount coloring: In any tracker, if an actual amount exceeds budget, it should show amber. Income actual amounts should be green. Remaining/available should be green (positive) or red (negative) f. Row tinting: FinancialOverview summary rows should each have a subtle category-colored background g. Inline editing: Click any actual amount in Bills/Variable Expenses/Debt — it should enter edit mode with an input field h. Chart colors: Donut/bar chart segments should use the same colors as their corresponding card headers Human visual inspection of dashboard at http://localhost:5173 User confirms pastel theme, hero hierarchy, amount coloring, row tinting, inline editing, and chart colors all look correct.
1. `cd frontend && bun run build` — zero TypeScript errors 2. `cd frontend && bun vitest run` — all tests pass 3. `grep -rn "PASTEL_COLORS\|InlineEditRow\|from-blue-50\|from-amber-50\|from-orange-50\|from-sky-50\|from-pink-50" frontend/src/components/` — zero results 4. `grep -rn "text-green-\|text-red-\|text-amber-" frontend/src/components/` — zero results 5. Visual inspection confirms pastel theme, hero hierarchy, amount coloring, and inline editing

<success_criteria>

  • All 6 dashboard components use palette.ts for gradients (no hardcoded Tailwind color classes)
  • FinancialOverview and AvailableBalance have hero typography and padding
  • Amount coloring follows locked rules: green income, amber over-budget, red negative
  • InlineEditCell is the single shared component for inline editing (3 duplicates removed)
  • Charts use palette.ts base colors matching their card header categories
  • Vite build succeeds, all tests pass
  • User approves visual result at checkpoint </success_criteria>
After completion, create `.planning/phases/01-design-token-foundation/01-02-SUMMARY.md`