import { cn } from "@/lib/utils"; import { cva, type VariantProps } from "class-variance-authority"; import { LucideIcon } from "lucide-react"; /** * Stat card component for displaying statistical metrics * * @example * ```tsx * * ``` */ const statCardVariants = cva( "rounded-lg border p-4 flex flex-col space-y-2", { variants: { variant: { default: "bg-background border-border", primary: "bg-primary/10 border-primary/20", secondary: "bg-secondary/10 border-secondary/20", accent: "bg-russet/10 border-russet/20 dark:bg-russet/5", success: "bg-emerald-50 border-emerald-200 dark:bg-emerald-950/20 dark:border-emerald-900/30", warning: "bg-amber-50 border-amber-200 dark:bg-amber-950/20 dark:border-amber-900/30", danger: "bg-rose-50 border-rose-200 dark:bg-rose-950/20 dark:border-rose-900/30", }, size: { default: "p-4", sm: "p-3", lg: "p-6", }, }, defaultVariants: { variant: "default", size: "default", }, } ); export interface StatCardProps extends VariantProps { /** * The title of the stat */ title: string; /** * The value to display */ value: string | number; /** * Optional description text (like change from previous period) */ description?: string; /** * Optional trend direction */ trend?: "up" | "down" | "neutral"; /** * Optional icon to display */ icon?: LucideIcon; /** * Additional CSS classes */ className?: string; /** * Whether the stat is loading */ isLoading?: boolean; } export function StatCard({ title, value, description, trend, icon: Icon, variant, size, className, isLoading = false, }: StatCardProps) { // Determine the color for trend const trendColor = trend === "up" ? "text-emerald-600 dark:text-emerald-400" : trend === "down" ? "text-rose-600 dark:text-rose-400" : "text-gray-600 dark:text-gray-400"; // Determine the arrow for trend const trendSymbol = trend === "up" ? "↑" : trend === "down" ? "↓" : "→"; return (
{/* Header with icon and title */}

{title}

{Icon && (
)}
{/* Value */} {isLoading ? (
) : (
{value}
)} {/* Description with trend */} {description && (
{trend && {trendSymbol}} {description}
)}
); }