Files
the-other-dude/frontend/src/components/dashboard/KpiCards.tsx
Jason Staack 298ed89c75 fix(ui): refine dashboard components for Warm Precision tone
- KpiCards: remove gradient/glow, flatten to data-oriented panels
- BandwidthChart: replace hardcoded blue (#38BDF8) with accent token,
  use token colors for axis text and cursor
- QuickActions: replace icon grid with command-style list rows
  with left-border hover interaction
- EventsTimeline: remove timeline/skeleton, tighten to log-stream
  layout with divide separators and monospace timestamps
- Light mode: bump border-default opacity 0.12→0.14, darken
  text-secondary for dense readability

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-21 12:04:28 -05:00

119 lines
3.2 KiB
TypeScript

import { Server, Wifi, AlertTriangle, Activity } from 'lucide-react'
import { Card, CardContent } from '@/components/ui/card'
import { useAnimatedCounter } from '@/hooks/useAnimatedCounter'
import { cn } from '@/lib/utils'
export interface KpiCardsProps {
totalDevices: number
onlinePercent: number // 0-100
activeAlerts: number
totalBandwidthBps: number // bytes per second
}
/**
* Formats bytes-per-second into a human-readable bandwidth string.
* Auto-scales through bps, Kbps, Mbps, Gbps.
*/
// eslint-disable-next-line react-refresh/only-export-components
export function formatBandwidth(bps: number): { value: number; unit: string } {
if (bps < 1_000) return { value: bps, unit: 'bps' }
if (bps < 1_000_000) return { value: bps / 1_000, unit: 'Kbps' }
if (bps < 1_000_000_000) return { value: bps / 1_000_000, unit: 'Mbps' }
return { value: bps / 1_000_000_000, unit: 'Gbps' }
}
interface KpiCardProps {
icon: React.ReactNode
label: string
value: number
suffix?: string
decimals?: number
colorClass: string
highlight?: boolean
}
function KpiCard({
icon,
label,
value,
suffix,
decimals = 0,
colorClass,
highlight,
}: KpiCardProps) {
const animatedValue = useAnimatedCounter(value, 800, decimals)
return (
<div
className={cn(
'bg-panel border border-border px-3 py-2.5 rounded-sm',
highlight && 'border-l-2 border-l-warning',
)}
>
<div className="text-[7px] font-medium text-text-muted uppercase tracking-[1.5px] mb-1">
{label}
</div>
<div className="flex items-baseline gap-1">
<span
className={cn(
'text-lg font-medium tabular-nums font-mono',
colorClass,
)}
>
{decimals > 0 ? animatedValue.toFixed(decimals) : animatedValue}
</span>
{suffix && (
<span className="text-xs text-text-muted">
{suffix}
</span>
)}
</div>
</div>
)
}
export function KpiCards({
totalDevices,
onlinePercent,
activeAlerts,
totalBandwidthBps,
}: KpiCardsProps) {
const bandwidth = formatBandwidth(totalBandwidthBps)
// Determine appropriate decimal places for bandwidth display
const bwDecimals = bandwidth.value < 10 ? 2 : bandwidth.value < 100 ? 1 : 0
return (
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-4">
<KpiCard
icon={<Server className="h-5 w-5" />}
label="Total Devices"
value={totalDevices}
colorClass="text-accent"
/>
<KpiCard
icon={<Wifi className="h-5 w-5" />}
label="Online"
value={onlinePercent}
suffix="%"
decimals={1}
colorClass="text-success"
/>
<KpiCard
icon={<AlertTriangle className="h-5 w-5" />}
label="Active Alerts"
value={activeAlerts}
colorClass={activeAlerts > 0 ? 'text-warning' : 'text-text-muted'}
highlight={activeAlerts > 0}
/>
<KpiCard
icon={<Activity className="h-5 w-5" />}
label="Total Bandwidth"
value={bandwidth.value}
suffix={bandwidth.unit}
decimals={bwDecimals}
colorClass="text-accent"
/>
</div>
)
}