76 lines
3.3 KiB
TypeScript
76 lines
3.3 KiB
TypeScript
import { LucideIcon } from "lucide-react";
|
|
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
|
|
|
|
interface StatsCardProps {
|
|
title: string;
|
|
value: string | number;
|
|
change?: string;
|
|
trend?: "up" | "down" | "neutral";
|
|
icon: LucideIcon;
|
|
color?: "blue" | "green" | "purple" | "orange";
|
|
}
|
|
|
|
export function StatsCard({ title, value, change, trend, icon: Icon, color = "blue" }: StatsCardProps) {
|
|
const colorStyles = {
|
|
blue: {
|
|
bg: "bg-gradient-to-br from-blue-600 to-blue-700",
|
|
iconBg: "bg-blue-500/20 text-blue-300",
|
|
light: "from-blue-50 to-blue-100/50",
|
|
},
|
|
green: {
|
|
bg: "bg-gradient-to-br from-emerald-600 to-emerald-700",
|
|
iconBg: "bg-emerald-500/20 text-emerald-300",
|
|
light: "from-emerald-50 to-emerald-100/50",
|
|
},
|
|
purple: {
|
|
bg: "bg-gradient-to-br from-purple-600 to-purple-700",
|
|
iconBg: "bg-purple-500/20 text-purple-300",
|
|
light: "from-purple-50 to-purple-100/50",
|
|
},
|
|
orange: {
|
|
bg: "bg-gradient-to-br from-orange-600 to-orange-700",
|
|
iconBg: "bg-orange-500/20 text-orange-300",
|
|
light: "from-orange-50 to-orange-100/50",
|
|
},
|
|
};
|
|
|
|
const styles = colorStyles[color];
|
|
|
|
return (
|
|
<Card className={`bg-gradient-to-br ${styles.light} border-0 shadow-lg hover:shadow-xl transition-all duration-300 overflow-hidden group`}>
|
|
<div className={`absolute inset-0 opacity-0 group-hover:opacity-5 ${styles.bg} transition-opacity`}></div>
|
|
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-3 relative z-10">
|
|
<CardTitle className="text-sm font-semibold text-gray-700 uppercase tracking-wide">
|
|
{title}
|
|
</CardTitle>
|
|
<div className={`p-3 rounded-2xl ${styles.iconBg} backdrop-blur-sm`}>
|
|
<Icon size={20} />
|
|
</div>
|
|
</CardHeader>
|
|
<CardContent className="relative z-10">
|
|
<div className={`text-4xl font-black bg-gradient-to-r ${styles.bg.replace('bg-gradient-to-br', '')} bg-clip-text text-transparent`}>
|
|
{value}
|
|
</div>
|
|
{change && (
|
|
<div className="flex items-center gap-2 mt-3">
|
|
<p className="text-xs text-gray-600 font-medium">
|
|
<span
|
|
className={`font-bold px-2 py-1 rounded-full text-xs ${
|
|
trend === "up"
|
|
? "bg-emerald-100 text-emerald-700"
|
|
: trend === "down"
|
|
? "bg-red-100 text-red-700"
|
|
: "bg-gray-100 text-gray-700"
|
|
}`}
|
|
>
|
|
{trend === "up" ? "↑" : trend === "down" ? "↓" : "→"} {change}
|
|
</span>
|
|
</p>
|
|
<span className="text-xs text-gray-500">vs last month</span>
|
|
</div>
|
|
)}
|
|
</CardContent>
|
|
</Card>
|
|
);
|
|
}
|