feat(01-02): wire palette.ts into all 6 dashboard components

- BillsTracker: headerGradient('bill'), InlineEditCell, amountColorClass
- VariableExpenses: headerGradient('variable_expense'), InlineEditCell, amountColorClass, palette bar chart colors
- DebtTracker: headerGradient('debt'), InlineEditCell, amountColorClass
- AvailableBalance: headerGradient('saving'), palette Cell fills, text-3xl center, text-success/text-destructive
- ExpenseBreakdown: headerGradient('variable_expense'), palette Cell fills
- FinancialOverview: overviewHeaderGradient(), hero typography (text-2xl px-6 py-5), palette row tints, amountColorClass
- Remove all PASTEL_COLORS arrays and InlineEditRow private functions
This commit is contained in:
2026-03-11 20:57:53 +01:00
parent 689c88fc3e
commit 07041aed34
6 changed files with 102 additions and 237 deletions

View File

@@ -3,32 +3,32 @@ import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'
import { PieChart, Pie, Cell, ResponsiveContainer } from 'recharts'
import type { BudgetDetail } from '@/lib/api'
import { formatCurrency } from '@/lib/format'
import { palette, headerGradient, type CategoryType } from '@/lib/palette'
import { cn } from '@/lib/utils'
interface Props {
budget: BudgetDetail
}
const PASTEL_COLORS = ['#93c5fd', '#f9a8d4', '#fcd34d', '#a5b4fc', '#86efac', '#c4b5fd']
export function AvailableBalance({ budget }: Props) {
const { t } = useTranslation()
const { totals } = budget
const available = totals.available
const data = [
{ name: t('dashboard.remaining'), value: Math.max(0, available) },
{ name: t('dashboard.bills'), value: totals.bills_actual },
{ name: t('dashboard.expenses'), value: totals.expenses_actual },
{ name: t('dashboard.debts'), value: totals.debts_actual },
{ name: t('dashboard.savings'), value: totals.savings_actual },
{ name: t('dashboard.investments'), value: totals.investments_actual },
const data: Array<{ name: string; value: number; categoryType: CategoryType }> = [
{ name: t('dashboard.remaining'), value: Math.max(0, available), categoryType: 'carryover' },
{ name: t('dashboard.bills'), value: totals.bills_actual, categoryType: 'bill' },
{ name: t('dashboard.expenses'), value: totals.expenses_actual, categoryType: 'variable_expense' },
{ name: t('dashboard.debts'), value: totals.debts_actual, categoryType: 'debt' },
{ name: t('dashboard.savings'), value: totals.savings_actual, categoryType: 'saving' },
{ name: t('dashboard.investments'), value: totals.investments_actual, categoryType: 'investment' },
].filter((d) => d.value > 0)
return (
<Card>
<CardHeader className="bg-gradient-to-r from-sky-50 to-cyan-50">
<CardTitle>{t('dashboard.availableAmount')}</CardTitle>
<CardHeader style={headerGradient('saving')} className="px-6 py-5">
<CardTitle className="text-2xl font-semibold">{t('dashboard.availableAmount')}</CardTitle>
</CardHeader>
<CardContent className="flex flex-col items-center gap-4 pt-6">
<div className="relative size-48">
@@ -43,14 +43,17 @@ export function AvailableBalance({ budget }: Props) {
paddingAngle={2}
dataKey="value"
>
{data.map((_, index) => (
<Cell key={index} fill={PASTEL_COLORS[index % PASTEL_COLORS.length]} />
{data.map((entry, index) => (
<Cell key={index} fill={palette[entry.categoryType]?.base ?? palette.carryover.base} />
))}
</Pie>
</PieChart>
</ResponsiveContainer>
<div className="absolute inset-0 flex flex-col items-center justify-center">
<span className="text-2xl font-bold">{formatCurrency(available, budget.currency)}</span>
<span className={cn('text-3xl font-bold tabular-nums', available >= 0 ? 'text-success' : 'text-destructive')}>
{formatCurrency(available, budget.currency)}
</span>
<span className="text-xs text-muted-foreground">{t('dashboard.available', 'Available')}</span>
</div>
</div>
</CardContent>