From ad7dca60c12fbd104b64bb80c0435ca38d7cdec0 Mon Sep 17 00:00:00 2001 From: Jit Corn Leow Date: Fri, 23 Jan 2026 12:18:02 +0800 Subject: [PATCH 01/42] style(financial-data): match Stitch design for Financial Data panel - Update CategoryCardHeader with solid icon backgrounds and circular add buttons - Add theme-aware styling for Monet mode across all components - Update SummaryCards with white backgrounds and colored dot indicators - Refactor Header with Cashflow/Family pill buttons and theme-aware slider - Add iconBgLight/iconColorLight to config for light mode support Co-Authored-By: Claude Opus 4.5 --- .../components/CategoryCard.tsx | 29 +- .../CategoryCard/CategoryCardHeader.tsx | 111 ++++++-- .../CategoryCard/CategoryCardTotal.tsx | 26 +- .../components/Header.tsx | 253 +++++++++++------- .../components/SummaryCards.tsx | 52 +++- .../FinancialDataManagement/config.ts | 30 ++- .../FinancialDataManagement/index.tsx | 7 +- .../FinancialDataManagement/types.ts | 7 + 8 files changed, 354 insertions(+), 161 deletions(-) diff --git a/frontend/src/components/dashboard/FinancialDataManagement/components/CategoryCard.tsx b/frontend/src/components/dashboard/FinancialDataManagement/components/CategoryCard.tsx index 5b8cf0071..a6f6791a9 100644 --- a/frontend/src/components/dashboard/FinancialDataManagement/components/CategoryCard.tsx +++ b/frontend/src/components/dashboard/FinancialDataManagement/components/CategoryCard.tsx @@ -5,6 +5,7 @@ import type { ScenarioEvent } from '@/types/scenario' import type { CashAccount } from '@/types/financial' import type { PropertyLinkRecord } from '@/types/property' import type { IncomeAllocation } from '@/api/financial/incomes' +import { useColorScheme } from '@/stores' import { categoryConfig } from '../config' import { getItemId, sortItems } from '../utils' import { parseDecimal } from '../converters' @@ -140,6 +141,10 @@ export function CategoryCard({ compact = false, onCollapseChange, }: CategoryCardProps) { + // Theme + const colorScheme = useColorScheme() + const isMonet = colorScheme === 'monet' + // Start collapsed in compact mode (side-by-side layout) const [isCollapsed, setIsCollapsed] = useState(compact) @@ -232,8 +237,12 @@ export function CategoryCard({ return (
- {/* Collapsible content */} + {/* Collapsible content - Stitch style: no separate total section, items directly */}
- + {/* Hide the large total section - Stitch shows total in header subtitle */} + {false && ( + + )} {/* List Items */}
diff --git a/frontend/src/components/dashboard/FinancialDataManagement/components/CategoryCard/CategoryCardHeader.tsx b/frontend/src/components/dashboard/FinancialDataManagement/components/CategoryCard/CategoryCardHeader.tsx index 8e9cbf803..347bd4f68 100644 --- a/frontend/src/components/dashboard/FinancialDataManagement/components/CategoryCard/CategoryCardHeader.tsx +++ b/frontend/src/components/dashboard/FinancialDataManagement/components/CategoryCard/CategoryCardHeader.tsx @@ -1,5 +1,8 @@ import { useState, useRef, useEffect } from 'react' -import { Plus, ArrowDownWideNarrow, Wallet, BarChart3, Shield, ChevronDown } from 'lucide-react' +import { Plus, Wallet, BarChart3, Shield, ChevronRight } from 'lucide-react' +import clsx from 'clsx' +import { useColorScheme } from '@/stores' +import { formatCurrency } from '@/lib/format' import { categoryConfig } from '../../config' import type { FinancialCategory } from '../../types' @@ -13,19 +16,24 @@ interface CategoryCardHeaderProps { onAddCpf?: () => void isCollapsed?: boolean onToggleCollapse?: () => void + /** Total amount to display as subtitle like Stitch */ + total?: number } export function CategoryCardHeader({ category, showMonthlyData, - sortDirection, - onToggleSortDirection, + sortDirection: _sortDirection, + onToggleSortDirection: _onToggleSortDirection, onAddItem, onAddInvestment, onAddCpf, isCollapsed = false, onToggleCollapse, + total, }: CategoryCardHeaderProps) { + const colorScheme = useColorScheme() + const isMonet = colorScheme === 'monet' const config = categoryConfig[category] const [showAssetMenu, setShowAssetMenu] = useState(false) const menuRef = useRef(null) @@ -57,39 +65,57 @@ export function CategoryCardHeader({ const showAssetDropdown = category === 'asset' && (onAddInvestment || onAddCpf) return ( -
+
+ {/* Left side: Icon + Title/Total - clickable to expand */} -
- + {/* Right side: Add button + Chevron */} +
{showAssetDropdown ? (
) : ( )} + + {/* Chevron at far right - Stitch style */} + {onToggleCollapse && ( + + )}
) diff --git a/frontend/src/components/dashboard/FinancialDataManagement/components/CategoryCard/CategoryCardTotal.tsx b/frontend/src/components/dashboard/FinancialDataManagement/components/CategoryCard/CategoryCardTotal.tsx index 0847c1567..4ed5ee887 100644 --- a/frontend/src/components/dashboard/FinancialDataManagement/components/CategoryCard/CategoryCardTotal.tsx +++ b/frontend/src/components/dashboard/FinancialDataManagement/components/CategoryCard/CategoryCardTotal.tsx @@ -1,5 +1,7 @@ import { ArrowUpRight, ArrowDownRight } from 'lucide-react' +import clsx from 'clsx' import { formatCurrency } from '@/lib/format' +import { useColorScheme } from '@/stores' import type { FinancialCategory } from '../../types' interface CategoryCardTotalProps { @@ -13,27 +15,41 @@ export function CategoryCardTotal({ total, showMonthlyData, }: CategoryCardTotalProps) { + const colorScheme = useColorScheme() + const isMonet = colorScheme === 'monet' + // Mock trend (you may want to calculate real trends) const mockTrend = category === 'asset' ? 12.5 : category === 'income' ? 5.2 : category === 'liability' ? -2.1 : 1.2 const isPositiveTrend = mockTrend >= 0 const showMonthSuffix = showMonthlyData && (category === 'income' || category === 'expense') return ( -
+
-
+
{formatCurrency(total)}
{showMonthSuffix && ( - /mo + /mo )}
-
+
{isPositiveTrend ? : } {Math.abs(mockTrend)}%
- vs last month + vs last month
) diff --git a/frontend/src/components/dashboard/FinancialDataManagement/components/Header.tsx b/frontend/src/components/dashboard/FinancialDataManagement/components/Header.tsx index 57e715c05..81cd11ace 100644 --- a/frontend/src/components/dashboard/FinancialDataManagement/components/Header.tsx +++ b/frontend/src/components/dashboard/FinancialDataManagement/components/Header.tsx @@ -2,9 +2,10 @@ import { useCallback, useMemo, useState, useRef, useEffect } from 'react' import * as Slider from '@radix-ui/react-slider' import { useQuery } from '@tanstack/react-query' import { Check, ChevronDown, Receipt, Users } from 'lucide-react' +import clsx from 'clsx' import type { TimeResolution, TimelineYear, TimelineMonth } from '@/types/timeline' -import { useTaxModeStore } from '@/stores' +import { useTaxModeStore, useColorScheme } from '@/stores' import { usePersonFilterOptional } from '@/contexts/PersonFilterContext' import { settingsApi } from '@/api/financial' import { QUERY_KEYS } from '@/lib/queryKeys' @@ -61,6 +62,8 @@ export function Header({ onViewModeChange, compact = false, }: HeaderProps) { + const colorScheme = useColorScheme() + const isMonet = colorScheme === 'monet' const [yearDisplayMode, setYearDisplayMode] = useState<'calendar' | 'relative'>('calendar') const { data: userSettings } = useQuery({ @@ -186,14 +189,25 @@ export function Header({
{/* Row 1: Title */}
-

Financial Data

-

{`${absoluteYear} (Age ${displayAge})`}

+

Financial Data

+

{`${absoluteYear} (Age ${displayAge})`}

{/* Row 2: Timeline controls on left, Action buttons on right */}
{/* Timeline navigation controls */} -
+
{resolution === 'monthly' && ( <> @@ -207,8 +221,9 @@ export function Header({ { value: 'annualized', label: 'Yearly' }, { value: 'monthly', label: 'Monthly' }, ]} + isMonet={isMonet} /> -
+
)} @@ -227,11 +242,12 @@ export function Header({ className="w-16" onLabelClick={() => setYearDisplayMode(m => m === 'calendar' ? 'relative' : 'calendar')} labelTitle="Click to toggle year format" + isMonet={isMonet} /> {resolution === 'monthly' && ( <> -
+
)}
{shouldShowSlider && ( -
+
- - + + - +
)}
- {/* Action buttons */} -
- {/* Tax Estimate Icon */} + {/* Action buttons - Cashflow & Family pills like Stitch */} +
+ {/* Cashflow Button */} - {/* Persons Filter Icon */} + {/* Family Button */}
@@ -319,9 +354,10 @@ interface SelectFieldProps { className?: string onLabelClick?: () => void labelTitle?: string + isMonet?: boolean } -function SelectField({ label, id, value, disabled, onChange, options, className, onLabelClick, labelTitle }: SelectFieldProps) { +function SelectField({ label, id, value, disabled, onChange, options, className, onLabelClick, labelTitle, isMonet }: SelectFieldProps) { const [isOpen, setIsOpen] = useState(false) const containerRef = useRef(null) @@ -338,9 +374,16 @@ function SelectField({ label, id, value, disabled, onChange, options, className, const selectedOption = options.find(opt => opt.value === value) return ( -
+