({ title, value, icon: Icon, color, trend }: StatCardProps)
| 186 | } |
| 187 | |
| 188 | function StatCard({ title, value, icon: Icon, color, trend }: StatCardProps) { |
| 189 | const colorMap = { |
| 190 | primary: 'var(--color-primary)', |
| 191 | accent: 'var(--color-accent)', |
| 192 | success: 'var(--color-success)', |
| 193 | warning: 'var(--color-warning)', |
| 194 | error: 'var(--color-error)', |
| 195 | }; |
| 196 | |
| 197 | return ( |
| 198 | <div className="card"> |
| 199 | <div className="flex items-start justify-between"> |
| 200 | <div> |
| 201 | <p className="text-sm text-[var(--color-text-muted)]">{title}</p> |
| 202 | <p className="text-2xl font-bold text-[var(--color-text-primary)] mt-1"> |
| 203 | {value} |
| 204 | </p> |
| 205 | </div> |
| 206 | <div |
| 207 | className="p-2 rounded-lg" |
| 208 | style={{ backgroundColor: `${colorMap[color]}20` }} |
| 209 | > |
| 210 | <Icon className="w-5 h-5" style={{ color: colorMap[color] }} /> |
| 211 | </div> |
| 212 | </div> |
| 213 | {trend !== undefined && ( |
| 214 | <div className="flex items-center gap-1 mt-2"> |
| 215 | <TrendingUp |
| 216 | className={`w-4 h-4 ${ |
| 217 | trend >= 0 ? 'text-[var(--color-success)]' : 'text-[var(--color-error)]' |
| 218 | }`} |
| 219 | /> |
| 220 | <span |
| 221 | className={`text-sm ${ |
| 222 | trend >= 0 ? 'text-[var(--color-success)]' : 'text-[var(--color-error)]' |
| 223 | }`} |
| 224 | > |
| 225 | {trend >= 0 ? '+' : ''} |
| 226 | {formatPercent(trend)} |
| 227 | </span> |
| 228 | </div> |
| 229 | )} |
| 230 | </div> |
| 231 | ); |
| 232 | } |
nothing calls this directly
no test coverage detected