import { type LucideIcon } from "lucide-react" import { cn } from "@/lib/utils" function formatValue(value: string | number) { if (typeof value !== "number") return value const formatted = Intl.NumberFormat(undefined, { notation: "compact", maximumFractionDigits: 1, }).format(value) // Normalize compact suffix casing to a consistent form to avoid // hydration mismatches between server and client environments. return formatted.replace(/(k|K|m|M|b|B)$/u, (s) => s.toUpperCase()) } function Sparkline({ points }: { points: number[] }) { const width = 48 const height = 18 const min = Math.min(...points) const max = Math.max(...points) const range = max - min || 1 const coords = points.map((point, index) => { const x = (index / (points.length - 1)) * width const y = height - ((point - min) / range) * height return [x, y] as const }) const path = coords.map(([x, y], i) => `${i === 0 ? "M" : "L"}${x},${y}`).join(" ") const [lastX, lastY] = coords[coords.length - 1] return ( ) } export interface StatCardProps { label: string value: string | number icon?: LucideIcon delta?: number deltaLabel?: string /** Set true for metrics where an increase is bad (e.g. churn, costs). */ invert?: boolean trend?: number[] className?: string } export function StatCard({ label, value, icon: Icon, delta, deltaLabel, invert = false, trend, className, }: StatCardProps) { const hasDelta = typeof delta === "number" && delta !== 0 const isPositive = hasDelta && delta > 0 const isGood = hasDelta && (invert ? !isPositive : isPositive) return (
{label}
{Icon && ({formatValue(value)}
{trend && trend.length > 1 &&