Commit 7aaa36e
authored
* feat(theme): premium light theme + Light/Dark/System toggle (closes #79)
Adds a full light theme alongside the existing dark, switchable via a sidebar
toggle and Settings > Appearance (Light / Dark / System). Everything is driven
from ONE place -- index.css tokens -- so the whole app flips with no per-page
logic. An inline script in index.html applies the saved theme before first
paint (no flash); ThemeWatcher follows the OS preference in System mode.
Light palette: warm off-white page background (LAB, perceptually even warmth,
matching the kalchar sibling-repo approach), pure-white cards that lift off it
with soft layered shadows, hairline cool-grey borders, near-black text,
darkened accent colors for AA contrast on white.
The real work was removing pre-existing hardcoded-color tech debt so 'one
variable controls all' is actually true:
- 364 text-white -> text-foreground (themed: near-white in dark, near-black in light)
- 291 bg-white/N + border-white/N -> a semantic --overlay-N / --hairline-N
ladder that flips per theme (white-alpha in dark, dark-alpha in light)
- hardcoded dark literals (bg-[#1a1a1c] modals, bg-zinc-900 dropdowns,
bg-[#0a0a0c] tab bar, bg-[#111113] sidebar, bg-[rgba(44,44,46,.6)] selects)
-> existing surface tokens
- new --sidebar-bg / --header-bg / --skeleton-* / --divider tokens
Dark theme is byte-identical (the new tokens default to the exact prior
values). New: lib/theme.ts, store/themeStore.ts, Sidebar/ThemeToggle.tsx.
Verified live at desktop in both themes (sidebar, search, cards, modals,
dropdowns, charts) + dark regression check; tsc + eslint + 266 tests + build
all green.
* fix(theme): synchronized cross-fade on theme switch
Parts were easing at different speeds on switch (body 250ms, glass cards
200/300ms, others 150ms or instant). Now a short-lived 'theme-transition'
class is added to <html> only during the switch (auto-removed after 400ms by
the theme lib), giving EVERY element + pseudo-element one uniform 300ms
background/border/color/fill/stroke/shadow transition -- so the whole UI
cross-fades in sync. transform/opacity excluded so the active-tab pill and
hovers aren't dragged in; respects prefers-reduced-motion; no transition on
first paint. Verified live: real toggle adds the class, theme flips, class
auto-clears; body/card/sidebar all report identical 0.3s timing mid-switch.
* fix(theme): light demo banner + keep white text on solid accent buttons
- DemoBanner: bg-black/80 -> bg-surface-dropdown/90 so it flips to light (was
a dark pill with now-dark text = invisible in light mode).
- Revert text-foreground -> text-white on SOLID/gradient accent buttons
(bg-app-blue, from-primary, bg-app-red/90, bg-primary) where white-on-color
is correct in both themes; tinted selected states (bg-*/15, /20) keep
text-foreground (dark text on light tint is correct in light).
Verified live: light demo banner readable, buttons correct in both themes;
266 tests + build green.
* fix(theme): make charts theme-aware + reactive, fix leftover literals, restore dark fidelity
- Add 20 --chart-* CSS tokens (dark defaults verbatim, AA-contrast light overrides)
so chart axis/grid/tooltip/label colors flip with the theme.
- chartColors.ts now sources from rawColors.chart; refreshChartConstants() rebuilds
palettes (CHART_COLORS/WARM/INCOME), CHART_TEXT/SURFACE/INPUT, axis/grid, semantics
in place on theme toggle. colors.ts gains refreshRawColors()/onRawColorsRefresh().
- metricColorConfig + EXPENSE_CATEGORY_COLORS rebuild in place on toggle (were frozen
at module load, leaving KPI chips/category hues stale after switching).
- AppLayout remounts routed content on resolved-theme change so charts recompute;
applyTheme() calls refreshRawColors() first.
- Fix leftover chart literals: StandardPie center label, StandardArea/StandardBar
reference lines + labels, Sankey node text, EffectiveTaxRate/YearInReview dots.
- Home page: header bg-black -> --header-bg, invisible from-white heading gradient
-> from-foreground, add theme toggle to public header. Toast + select option +
focus ring + mobile scrollbar -> theme-aware tokens.
- Restore dark fidelity: --glow-base-shadow (none in dark, glass-shadow in light),
distinct --glass-border-ultra/-thin/-strong-hover tiers, skeleton 0.03/0.06,
--scrollbar-thumb-hover, so dark stays visually unchanged.
* feat(ui): world-class UI/UX elevation pass across all pages
Result of a 14-lens audit (189 findings) -> synthesis -> surgical implementation.
52 safe, behavior-preserving improvements; gates green (type-check, lint, 266 tests).
- Token discipline: remaining hardcoded text-white/text-black/bg-black/N/bg-white/
placeholder-gray/SVG-hex swapped for theme-aware tokens so both themes stay readable.
- tabular-nums on currency/KPI/table numeric readouts (flows, goals, projections,
comparison/tax/net-worth tables, bill-calendar) so digits stop shifting width.
- a11y: ariaLabel on the four StandardChart primitives + per-call-site chart labels,
listbox/option roles on CurrencySwitcher/NotificationCenter, aria-label on icon-only
sidebar buttons + skip link, aria-valuenow on FIRE slider.
- Nav/IA: page headers now mirror the canonical sidebar labels (Expense Analysis,
Cash Flow, Comparison, Budget Manager, Recurring, Income Tax, FIRE Calculator,
Anomaly Review); PAGE_TITLES covers /upload, /more, /demo.
- Mobile-first: 2-col KPI grids on phone with progressive sm:/md: steps, >=44px targets.
- States: standardized PageSkeleton / ChartEmptyState / EmptyState usage.
- Motion (kept visible): shared whileTap/hover feedback, synced collapsible timing.
- Overflow safety: title attrs on truncated values, break-friendly large currency.
- Removed dead getStoredTheme(); dropped erroneous static aria-current on NavLinks
(NavLink sets it on the active link automatically).
* chore(release): 2.19.0 -- light theme + world-class UI/UX elevation
* chore(gitignore): ignore Playwright MCP + ad-hoc verification artifacts
* feat(ui): implement the 12 needs-review items -- tokens, IA, structure, resilience
Design-decision + shared-primitive items (stage 1):
- New semantic tokens: --color-on-accent (white-on-solid-accent, both themes),
--color-on-warning (near-black on yellow warning pairs), --modal-backdrop
(dialog scrim). Swept the 4 modals + sidebar drawer onto --modal-backdrop,
text-black warning pairs onto text-on-warning.
- Removed dead --color-border-strong alias (line 41 already won the cascade).
- PageContainer now mirrors PageHeader's safe-area horizontal padding so the
sticky header lines up on notched iOS PWA; added optional maxWidth prop (7xl
default, 5xl/4xl) so narrow pages can adopt the scaffold.
- AnalyticsTimeFilter mode tabs go full-width/flex on phone (no overflow <400px).
- Settings Toggle gets a 44px ::before hit area; goal-form buttons min-h-11 on mobile.
Page-breadth items (stage 2, via workflow):
- PageContainer adoption across hand-rolled page roots (kept deliberate centered
layouts like UploadSync hand-rolled).
- isError branches added where query hooks expose it but only isLoading was handled.
- KPI sizing/padding converged onto --text-kpi scale where it had drifted.
- Split oversized files: Sidebar -> BrandHeader + navConfig, SubscriptionTracker
-> components/{AddRecurringForm,RecurringCard} + constants + types, YearInReview
-> MonthlyBreakdownChart + YearInsightsPanel.
Fixed regressions from the earlier text-white->text-foreground sweep: 5 solid-accent
buttons (ConfirmDialog, SubscriptionTracker, Goals, HomePage, Hero) were rendering
near-black text on solid accent fills in light theme; now use text-on-accent.
Comparison KPI grid 3+1 orphan at md fixed (2x2 -> 1x4).
Gate: type-check + lint clean, 266 tests pass. Both themes verified live.
* feat(ia): information-architecture restructure (nav, Overview, settings, workflows)
From a 5-lens IA audit; user-approved scope A-F + quick-wins.
Navigation:
- Merge Net Worth + Investments into one 'Wealth' section (D).
- Fold the dead-end single-item Transactions section into a new 'Data' section
with Upload & Sync (elevated, E) + Settings (C); reorder sidebar to the money
decision-flow; rename Tracking -> Commitments.
- Mobile parity: Transactions now on the More page; More tab shows an alert
badge (unreviewed anomalies + over-budget count). MorePage groups mirror desktop.
Overview page (F):
- New /overview composing existing hooks (income/spend/net/savings-rate KPIs,
budgets-at-risk, goals progress, top income/expense) with deep links + empty
state. Route + lazy import + sidebar entry + page title wired.
Settings (A) + feature-config (B):
- Regroup 11 flat sections into 4 task groups (Money Setup, Categories &
Classification, Profile & Display, Advanced) via a new GroupHeader primitive;
essential setup expanded first.
- Budget Defaults and Anomaly Detection now also render as collapsible panels on
the Budget and Anomaly pages (same components/endpoints, context-of-use).
Quick wins:
- Dashboard shows an upload CTA empty state for zero-data users (qw2).
- Income Tax <-> GST reciprocal cross-links (qw4).
Tokens/cleanup:
- New --color-on-accent / --color-on-warning / --modal-backdrop tokens; swept 16
files of raw text-white -> text-on-accent; modal scrims -> --modal-backdrop;
warning pairs -> text-on-warning; removed dead --color-border-strong alias.
- PageContainer mirrors PageHeader safe-area padding + optional maxWidth prop.
- AnalyticsTimeFilter tabs full-width on phone; settings Toggle 44px hit area.
- theme-color meta now tracks the active theme (pre-paint + live).
Gate: type-check + lint clean, 266 tests pass. Both themes verified live
(Overview, settings groups, new sidebar).
* fix(a11y): WCAG 2.2 focus-not-obscured + target-size (from web.dev/WCAG research)
- Focus Not Obscured (SC 2.4.11): add scroll-padding-top (sticky PageHeader) and
phone-only scroll-padding-bottom (fixed MobileTabBar + safe-area) to #main-content
so a keyboard-focused control near an edge is never hidden behind the chrome.
- Target Size Minimum (SC 2.5.8): bump three sub-24px icon buttons to a >=24px hit
area (min-w-6 min-h-6) without changing icon size -- BudgetTracker edit/delete
(was ~20px), DemoBanner + NotificationCenter close (was ~22px). Added the two
missing aria-labels on the BudgetTracker icon buttons.
Researched current best practices (web.dev CWV/PWA, WCAG 2.2 quickref, React 19);
backend security headers (CSP/HSTS preload/Permissions-Policy) and the PWA config
were already best-practice, so no change needed there. CSS/attribute-only; no
behavior change. type-check + lint clean, 266 tests pass.
* chore(deps): refresh frontend + backend to latest compatible
Stack is already on the latest majors (React 19.2, Vite 8, Tailwind 4, TS 6,
Python 3.13, pandas 3, FastAPI 0.138) -- this is the routine patch/minor freshness
pass, no breaking upgrades.
Frontend: @tanstack/react-query 5.101.1->.2, framer-motion 12.41->12.42,
eslint 10.5->10.6, @types/node 26.0.0->.1. type-check + lint + 266 tests + prod
build (incl PWA SW) all green.
Backend: uv lock --upgrade -- pandas 3.0.1->3.0.3, numpy 2.4.2->2.5, fastapi
0.138.0->.1, alembic/ruff/pydantic-core/anyio/requests/etc patch bumps. ruff +
mypy (131 files) clean, 239 tests pass.
1 parent 635a7d0 commit 7aaa36e
210 files changed
Lines changed: 4762 additions & 3209 deletions
File tree
- backend
- frontend
- src
- components
- analytics
- health
- period-comparison
- chat
- layout
- Sidebar
- transactions
- ui
- upload
- constants
- lib
- pages
- bill-calendar
- components
- budget
- components
- comparison
- components
- goals
- components
- gst-analysis
- home
- components
- income-analysis
- income-expense-flow
- components
- investment-analytics
- components
- mutual-fund-projection
- components
- net-worth
- components
- returns-analysis
- settings
- sections
- ai
- salary
- spending-analysis
- components
- subscription-tracker
- components
- tax-planning
- components
- trends-forecasts
- components
- upload-sync
- year-in-review
- components
- store
Some content is hidden
Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
222 | 222 | | |
223 | 223 | | |
224 | 224 | | |
| 225 | + | |
| 226 | + | |
| 227 | + | |
| 228 | + | |
| 229 | + | |
| 230 | + | |
| 231 | + | |
| 232 | + | |
| 233 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
6 | 6 | | |
7 | 7 | | |
8 | 8 | | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
9 | 32 | | |
10 | 33 | | |
11 | 34 | | |
| |||
0 commit comments