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 |
|
|
false |
|
|
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
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>withformatCurrency(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
onSaveif 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:
- Remove the private
InlineEditRowfunction (lines ~59-110) - Add imports:
import { headerGradient, amountColorClass } from '@/lib/palette'andimport { InlineEditCell } from '@/components/InlineEditCell' - Replace
<CardHeader className="bg-gradient-to-r from-blue-50 to-indigo-50">with<CardHeader style={headerGradient('bill')}> - 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. - Add
amountColorClass({ type: 'bill', actual, budgeted })asclassNameon the InlineEditCell for amount coloring. Budget column stays neutral (no color class).
VariableExpenses.tsx:
- Remove the private
InlineEditRowfunction (lines ~86-142) - Add same imports as BillsTracker
- Replace
<CardHeader className="bg-gradient-to-r from-amber-50 to-yellow-50">with<CardHeader style={headerGradient('variable_expense')}> - Replace
<InlineEditRow>with<InlineEditCell>for the actual cell. Keep the "remaining" cell in VariableExpenses — it's NOT part of InlineEditCell. - Add amount coloring to the InlineEditCell className.
DebtTracker.tsx:
- Remove the private
InlineEditRowfunction (lines ~61-112) - Add same imports
- Replace
<CardHeader className="bg-gradient-to-r from-orange-50 to-red-50">with<CardHeader style={headerGradient('debt')}> - Replace
<InlineEditRow>with<InlineEditCell>for the actual cell - Add amount coloring
AvailableBalance.tsx:
- Remove the
PASTEL_COLORSarray constant - Add imports:
import { palette, headerGradient, type CategoryType } from '@/lib/palette' - 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) - Update
<CardTitle>toclassName="text-2xl font-semibold"(hero typography) - Replace
<Cell fill={PASTEL_COLORS[index % ...]}with<Cell fill={palette[entry.categoryType as CategoryType]?.base ?? palette.carryover.base}> - Style the center donut amount:
text-3xl font-bold tabular-numswithcn()applyingtext-successwhen available >= 0,text-destructivewhen negative - Add small
text-xs text-muted-foregroundlabel "Available" (or translated equivalent) below the center amount
ExpenseBreakdown.tsx:
- Remove the
PASTEL_COLORSarray constant - Add imports:
import { palette, type CategoryType } from '@/lib/palette' - Replace
<CardHeader className="bg-gradient-to-r from-pink-50 to-rose-50">with<CardHeader style={headerGradient('debt')}> - Replace
<Cell fill={PASTEL_COLORS[index % ...]}with<Cell fill={palette[entry.categoryType as CategoryType]?.base ?? palette.carryover.base}>
FinancialOverview.tsx:
- Add imports:
import { palette, overviewHeaderGradient, amountColorClass, type CategoryType } from '@/lib/palette' - Replace
<CardHeader className="bg-gradient-to-r from-sky-50 to-indigo-50">with<CardHeader style={overviewHeaderGradient()} className="px-6 py-5">(hero padding) - Update
<CardTitle>toclassName="text-2xl font-semibold"(hero typography) - Tint each summary row with its category's light shade: add
style={{ backgroundColor: palette[categoryType].light }}to each<TableRow>that represents a category - Apply
amountColorClass()to actual amount cells. For the income row, passisIncome: true. For the remaining/available summary row, passisAvailable: true. Budget column stays neutral.
CRITICAL anti-patterns to avoid:
- Do NOT add
styleto<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— usetext-successfrom the semantic token - Do NOT edit any files in
src/components/ui/ - Do NOT use Tailwind v3 bracket syntax
bg-[--var]— use v4 parenthesis syntaxbg-(--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
InlineEditRowprivate function exists in BillsTracker, VariableExpenses, or DebtTracker - No
PASTEL_COLORSarray exists in AvailableBalance or ExpenseBreakdown - No
bg-gradient-to-r from-blue-50or 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
-
Run the full test suite:
cd frontend && bun vitest run -
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. -
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). -
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:
- Start the app:
cd frontend && bun run dev(ensure backend is running or usedocker compose up dbfor database) - Open http://localhost:5173 in browser
- 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.
<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>