| 'use client'; | |
| import { cn } from '@/lib/utils'; | |
| import { LucideIcon } from 'lucide-react'; | |
| interface StatCardProps { | |
| title: string; | |
| value: string; | |
| change?: string; | |
| changeType?: 'positive' | 'negative' | 'neutral'; | |
| icon: LucideIcon; | |
| iconColor?: string; | |
| } | |
| export function StatCard({ title, value, change, changeType = 'neutral', icon: Icon, iconColor = 'text-emerald-600' }: StatCardProps) { | |
| return ( | |
| <div className="group relative overflow-hidden rounded-2xl border border-zinc-200/60 bg-white p-6 shadow-sm transition-all hover:shadow-md hover:border-zinc-300/60 dark:border-zinc-800 dark:bg-zinc-900"> | |
| <div className="flex items-start justify-between"> | |
| <div className="space-y-2"> | |
| <p className="text-sm font-medium text-zinc-500 dark:text-zinc-400">{title}</p> | |
| <p className="text-3xl font-bold tracking-tight text-zinc-900 dark:text-zinc-100">{value}</p> | |
| {change && ( | |
| <p className={cn( | |
| 'text-sm font-medium', | |
| changeType === 'positive' && 'text-emerald-600', | |
| changeType === 'negative' && 'text-red-600', | |
| changeType === 'neutral' && 'text-zinc-500' | |
| )}> | |
| {change} | |
| </p> | |
| )} | |
| </div> | |
| <div className={cn('rounded-xl bg-zinc-50 p-3 dark:bg-zinc-800', iconColor)}> | |
| <Icon className="h-5 w-5" /> | |
| </div> | |
| </div> | |
| <div className="absolute inset-x-0 bottom-0 h-0.5 bg-gradient-to-r from-emerald-500 to-cyan-500 opacity-0 transition-opacity group-hover:opacity-100" /> | |
| </div> | |
| ); | |
| } | |