Spaces:
Paused
Paused
| "use client"; | |
| import { motion } from "framer-motion"; | |
| import { LucideIcon } from "lucide-react"; | |
| interface StatCardProps { | |
| title: string; | |
| value: string | number; | |
| icon: LucideIcon; | |
| change?: number; | |
| suffix?: string; | |
| color?: "cyan" | "violet" | "emerald" | "amber" | "rose" | "neutral"; | |
| delay?: number; | |
| } | |
| const colorMap = { | |
| cyan: { border: "border-[#38bdf8]/30", text: "text-[#38bdf8]", glow: "glow-cyan", iconBg: "bg-[#38bdf8]/10" }, | |
| violet: { border: "border-[#818cf8]/30", text: "text-[#818cf8]", glow: "glow-violet", iconBg: "bg-[#818cf8]/10" }, | |
| emerald: { border: "border-[#00d68f]/30", text: "text-[#00d68f]", glow: "glow-emerald", iconBg: "bg-[#00d68f]/10" }, | |
| amber: { border: "border-[#f59e0b]/30", text: "text-[#f59e0b]", glow: "glow-amber", iconBg: "bg-[#f59e0b]/10" }, | |
| rose: { border: "border-[#f43f5e]/30", text: "text-[#f43f5e]", glow: "glow-rose", iconBg: "bg-[#f43f5e]/10" }, | |
| neutral: { border: "border-white/[0.06]", text: "text-[#9a9aae]", glow: "", iconBg: "bg-white/[0.04]" }, | |
| }; | |
| export default function StatCard({ title, value, icon: Icon, change, suffix = "", color = "cyan", delay = 0 }: StatCardProps) { | |
| const cfg = colorMap[color]; | |
| return ( | |
| <motion.div | |
| initial={{ opacity: 0, y: 12 }} | |
| animate={{ opacity: 1, y: 0 }} | |
| transition={{ duration: 0.4, delay: delay * 0.05, ease: [0.23, 1, 0.32, 1] }} | |
| className={`glass rounded-xl p-4 border-l-2 ${cfg.border} ${cfg.glow}`} | |
| > | |
| <div className="flex items-center justify-between mb-3"> | |
| <div className={`p-2 rounded-lg ${cfg.iconBg}`}> | |
| <Icon className={`w-4 h-4 ${cfg.text}`} /> | |
| </div> | |
| {change !== undefined && ( | |
| <span className={`text-[11px] font-medium ${change >= 0 ? "text-[#00d68f]" : "text-[#f43f5e]"}`}> | |
| {change >= 0 ? "+" : ""}{change.toFixed(2)}% | |
| </span> | |
| )} | |
| </div> | |
| <div className="text-[10px] font-bold text-[#5a5a6e] uppercase tracking-widest mb-1">{title}</div> | |
| <div className={`text-xl font-bold tabular-nums ${cfg.text}`}> | |
| {typeof value === "number" ? value.toLocaleString() : value}{suffix} | |
| </div> | |
| </motion.div> | |
| ); | |
| } | |