Files
NetMesh/components/systemManager/ResourceBar.tsx

91 lines
2.7 KiB
TypeScript
Raw Normal View History

import React, { memo } from 'react';
import { cn } from '../../lib/utils';
interface ResourceBarProps {
label: string;
value: number | null | undefined;
className?: string;
/** Slightly taller track for GPU cards. */
size?: 'sm' | 'md';
/** Accent color tone override */
tone?: 'primary' | 'sky' | 'emerald' | 'amber' | 'rose' | 'auto';
}
const toneClasses: Record<string, string> = {
primary: 'bg-primary',
sky: 'bg-sky-500',
emerald: 'bg-emerald-500',
amber: 'bg-amber-500',
rose: 'bg-rose-500',
auto: '',
};
function barToneClass(clamped: number): string {
if (clamped > 85) return 'bg-destructive';
if (clamped > 60) return 'bg-amber-500';
return 'bg-primary';
}
function barGlowStyle(clamped: number): React.CSSProperties {
if (clamped <= 60) return {};
const intensity = Math.min(1, (clamped - 60) / 40);
const color = clamped > 85
? 'hsl(var(--destructive) / 0.4)'
: 'rgba(245, 158, 11, 0.4)';
return {
boxShadow: `0 0 ${4 + intensity * 6}px ${color}`,
};
}
export const ResourceBar = memo(function ResourceBar({
label,
value,
className,
size = 'sm',
tone = 'auto',
}: ResourceBarProps) {
const finite = typeof value === 'number' && Number.isFinite(value);
const clamped = finite ? Math.max(0, Math.min(100, value)) : 0;
const fillClass = tone === 'auto' ? barToneClass(clamped) : toneClasses[tone];
return (
<div className={cn('flex items-center gap-2 min-w-0', className)}>
{label ? (
<span className="text-[10px] text-muted-foreground w-7 shrink-0">{label}</span>
) : null}
<div
className={cn(
'flex-1 rounded-full overflow-hidden min-w-[48px]',
'bg-muted/60',
'shadow-inner',
size === 'md' ? 'h-2' : 'h-1.5',
)}
>
<div
className={cn(
'h-full rounded-full transition-[width,background-color] duration-500 ease-out motion-reduce:transition-none relative',
finite ? fillClass : 'opacity-0',
)}
style={{
width: `${clamped}%`,
...(finite && clamped > 60 ? barGlowStyle(clamped) : {}),
}}
>
{/* Subtle highlight sheen */}
{finite && clamped > 5 && (
<div
className="absolute top-0 left-0 right-0 h-1/2 rounded-t-full opacity-30"
style={{
background: 'linear-gradient(to bottom, rgba(255,255,255,0.5), transparent)',
}}
/>
)}
</div>
</div>
<span className="text-[10px] tabular-nums text-muted-foreground w-10 text-right shrink-0">
{finite ? `${value.toFixed(1)}%` : '--'}
</span>
</div>
);
});