feat(01-02): create PageShell, StatCard, SummaryStrip, and DashboardSkeleton components
- PageShell: reusable page header with title, description, and action slot - StatCard: KPI card with formatted value, semantic color, and optional variance badge - SummaryStrip: responsive 3-card grid composing StatCards for income/expenses/balance - DashboardSkeleton: pulse-animated loading placeholder mirroring real dashboard layout Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
45
src/components/dashboard/SummaryStrip.tsx
Normal file
45
src/components/dashboard/SummaryStrip.tsx
Normal file
@@ -0,0 +1,45 @@
|
||||
import { StatCard } from "./StatCard"
|
||||
|
||||
interface SummaryStripProps {
|
||||
income: { value: string; budgeted: string }
|
||||
expenses: { value: string; budgeted: string }
|
||||
balance: { value: string; isPositive: boolean }
|
||||
t: (key: string) => string
|
||||
}
|
||||
|
||||
export function SummaryStrip({
|
||||
income,
|
||||
expenses,
|
||||
balance,
|
||||
t,
|
||||
}: SummaryStripProps) {
|
||||
return (
|
||||
<div className="grid gap-4 sm:grid-cols-2 lg:grid-cols-3">
|
||||
<StatCard
|
||||
title={t("dashboard.totalIncome")}
|
||||
value={income.value}
|
||||
valueClassName="text-income"
|
||||
variance={{
|
||||
amount: income.budgeted,
|
||||
direction: "neutral",
|
||||
label: t("budgets.budgeted"),
|
||||
}}
|
||||
/>
|
||||
<StatCard
|
||||
title={t("dashboard.totalExpenses")}
|
||||
value={expenses.value}
|
||||
valueClassName="text-destructive"
|
||||
variance={{
|
||||
amount: expenses.budgeted,
|
||||
direction: "neutral",
|
||||
label: t("budgets.budgeted"),
|
||||
}}
|
||||
/>
|
||||
<StatCard
|
||||
title={t("dashboard.availableBalance")}
|
||||
value={balance.value}
|
||||
valueClassName={balance.isPositive ? "text-on-budget" : "text-over-budget"}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user