Code
import * as React from "react";
import { ArrowDownRight, ArrowUpRight } from "lucide-react";
import { cn } from "@/lib/utils";
export type Kpi = { label: string; value: string; delta: number; series: number[] };
export type TopProduct = { name: string; units: number; revenue: string };
function Bars({ series, positive }: { series: number[]; positive: boolean }) {
const max = Math.max(...series, 1);
return (
<div className="flex h-10 items-end gap-[3px]" aria-hidden>
{series.map((v, i) => (
<span
key={i}
className={cn("w-full rounded-sm", positive ? "bg-emerald-500/70" : "bg-rose-500/70", i === series.length - 1 && "opacity-100", i < series.length - 1 && "opacity-50")}
style={{ height: `${Math.max(8, (v / max) * 100)}%` }}
/>
))}
</div>
);
}
export function SalesOverview({ kpis, products, period = "Last 7 days", className }: { kpis: Kpi[]; products: TopProduct[]; period?: string; className?: string }) {
const maxUnits = Math.max(...products.map((p) => p.units), 1);
return (
<div className={cn("w-full space-y-4", className)}>
<div className="flex items-baseline justify-between">
<h2 className="text-lg font-semibold">Overview</h2>
<span className="text-sm text-muted-foreground">{period}</span>
</div>
<div className="grid gap-4 sm:grid-cols-2 lg:grid-cols-4">
{kpis.map((k) => {
const up = k.delta >= 0;
return (
<div key={k.label} className="rounded-xl border bg-card p-4 text-card-foreground">
<p className="text-sm text-muted-foreground">{k.label}</p>
<div className="mt-1 flex items-baseline gap-2">
<p className="text-2xl font-semibold tracking-tight tabular-nums">{k.value}</p>
<span className={cn("flex items-center text-xs font-medium", up ? "text-emerald-600 dark:text-emerald-400" : "text-rose-600 dark:text-rose-400")}>
{up ? <ArrowUpRight className="size-3.5" /> : <ArrowDownRight className="size-3.5" />}
{Math.abs(k.delta).toFixed(1)}%
</span>
</div>
<div className="mt-3">
<Bars series={k.series} positive={up} />
</div>
</div>
);
})}
</div>
<div className="rounded-xl border bg-card p-4 text-card-foreground">
<p className="mb-3 text-sm font-medium">Top products</p>
<ul className="space-y-3">
{products.map((p, i) => (
<li key={p.name} className="grid grid-cols-[1.5rem_1fr_auto] items-center gap-3 text-sm">
<span className="text-muted-foreground tabular-nums">{i + 1}</span>
<div className="min-w-0">
<p className="truncate">{p.name}</p>
<div className="mt-1 h-1.5 rounded-full bg-muted">
<div className="h-full rounded-full bg-primary" style={{ width: `${(p.units / maxUnits) * 100}%` }} />
</div>
</div>
<span className="text-right tabular-nums">
<span className="font-medium">{p.revenue}</span>
<span className="block text-xs text-muted-foreground">{p.units} units</span>
</span>
</li>
))}
</ul>
</div>
</div>
);
}