Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 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 52 53 54 55 56 57 | 38x 38x 2x 3x 3x 3x 670x 670x 670x | import type { LucideIcon } from 'lucide-react'
import { Card, CardContent } from '@/components/ui/card'
import { TokenDisplay } from './TokenDisplay'
interface StatsCardProps {
icon: LucideIcon
label: string
value: number
accent?: string
tint?: string
onClick?: () => void
}
const labelStyles: Record<string, { tint: string; icon: string }> = {
'Running': { tint: 'bg-blue-500/10 text-blue-500', icon: 'text-blue-500' },
'Today': { tint: 'bg-gray-500/10 text-gray-500', icon: 'text-gray-500' },
'Failed': { tint: 'bg-red-500/10 text-red-500', icon: 'text-red-500' },
'Token In': { tint: 'bg-purple-500/10 text-purple-500', icon: 'text-purple-500' },
'Token Out': { tint: 'bg-orange-500/10 text-orange-500', icon: 'text-orange-500' },
}
export function StatsCard({ icon: Icon, label, value, accent, onClick }: StatsCardProps) {
const styles = labelStyles[label]
const interactive = !!onClick
return (
<Card
className={`transition-shadow hover:shadow-md ${accent ?? ''} ${interactive ? 'cursor-pointer' : ''}`}
onClick={onClick}
role={interactive ? 'button' : undefined}
tabIndex={interactive ? 0 : undefined}
data-testid={`stats-card-${label.toLowerCase().replace(/\s+/g, '-')}`}
onKeyDown={
interactive
? (e) => {
if (e.key === 'Enter' || e.key === ' ') {
e.preventDefault()
onClick?.()
}
}
: undefined
}
>
<CardContent className="flex items-center gap-4 p-4">
<div className={`flex h-10 w-10 items-center justify-center rounded-full ${styles?.tint ?? 'bg-muted'}`}>
<Icon className={`h-5 w-5 ${styles?.icon ?? 'text-muted-foreground'}`} />
</div>
<div className="flex flex-col">
<span className="text-sm text-muted-foreground">{label}</span>
<span className="text-2xl font-bold">
<TokenDisplay value={value} />
</span>
</div>
</CardContent>
</Card>
)
}
|