diff --git a/src/components/dashboard/DashboardSkeleton.tsx b/src/components/dashboard/DashboardSkeleton.tsx
new file mode 100644
index 0000000..2936e68
--- /dev/null
+++ b/src/components/dashboard/DashboardSkeleton.tsx
@@ -0,0 +1,49 @@
+import { Skeleton } from "@/components/ui/skeleton"
+import { Card, CardContent, CardHeader } from "@/components/ui/card"
+
+function SkeletonStatCard() {
+ return (
+
+
+
+
+
+
+
+
+
+ )
+}
+
+export function DashboardSkeleton() {
+ return (
+
+ {/* Summary cards skeleton */}
+
+
+
+
+
+
+ {/* Chart area skeleton */}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ )
+}
diff --git a/src/components/dashboard/StatCard.tsx b/src/components/dashboard/StatCard.tsx
new file mode 100644
index 0000000..bdc7b33
--- /dev/null
+++ b/src/components/dashboard/StatCard.tsx
@@ -0,0 +1,58 @@
+import { TrendingUp, TrendingDown, Minus } from "lucide-react"
+
+import { cn } from "@/lib/utils"
+import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"
+
+interface StatCardProps {
+ title: string
+ value: string
+ valueClassName?: string
+ variance?: {
+ amount: string
+ direction: "up" | "down" | "neutral"
+ label: string
+ }
+}
+
+const directionIcon = {
+ up: TrendingUp,
+ down: TrendingDown,
+ neutral: Minus,
+} as const
+
+export function StatCard({
+ title,
+ value,
+ valueClassName,
+ variance,
+}: StatCardProps) {
+ return (
+
+
+
+ {title}
+
+
+
+
+ {value}
+
+ {variance && (
+
+ {(() => {
+ const Icon = directionIcon[variance.direction]
+ return
+ })()}
+ {variance.amount}
+ {variance.label}
+
+ )}
+
+
+ )
+}
diff --git a/src/components/dashboard/SummaryStrip.tsx b/src/components/dashboard/SummaryStrip.tsx
new file mode 100644
index 0000000..c22d9b9
--- /dev/null
+++ b/src/components/dashboard/SummaryStrip.tsx
@@ -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 (
+
+
+
+
+
+ )
+}
diff --git a/src/components/shared/PageShell.tsx b/src/components/shared/PageShell.tsx
new file mode 100644
index 0000000..32907a1
--- /dev/null
+++ b/src/components/shared/PageShell.tsx
@@ -0,0 +1,28 @@
+interface PageShellProps {
+ title: string
+ description?: string
+ action?: React.ReactNode
+ children: React.ReactNode
+}
+
+export function PageShell({
+ title,
+ description,
+ action,
+ children,
+}: PageShellProps) {
+ return (
+
+
+
+
{title}
+ {description && (
+
{description}
+ )}
+
+ {action &&
{action}
}
+
+ {children}
+
+ )
+}