| "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> |
| ); |
| } |
|
|