File size: 2,174 Bytes
0800976 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 | "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>
);
}
|