File size: 1,687 Bytes
65d68f5 | 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 58 59 60 61 | "use client";
import { cn } from "@/lib/utils";
// =============================================================================
// CleanProgressBar — Thin black-on-gray progress bar
// =============================================================================
export interface CleanProgressBarProps {
value: number; // 0–100
max?: number;
label?: string;
showPercent?: boolean;
size?: "sm" | "md";
variant?: "default" | "success";
className?: string;
}
export function CleanProgressBar({
value,
max = 100,
label,
showPercent = false,
size = "sm",
variant = "default",
className,
}: CleanProgressBarProps) {
const pct = Math.min(100, Math.max(0, (value / max) * 100));
return (
<div className={cn("flex flex-col gap-1.5", className)}>
{(label || showPercent) && (
<div className="flex items-center justify-between">
{label && <span className="text-[12px] font-medium text-[#6B7280]">{label}</span>}
{showPercent && (
<span className="text-[12px] font-semibold text-[#111] tabular-nums">{Math.round(pct)}%</span>
)}
</div>
)}
<div
className={cn(
"w-full overflow-hidden rounded-full bg-[#E5E7EB]",
size === "sm" ? "h-1.5" : "h-2.5",
)}
role="progressbar"
aria-valuenow={value}
aria-valuemin={0}
aria-valuemax={max}
>
<div
className={cn(
"h-full rounded-full transition-all duration-500 ease-out",
variant === "success" ? "bg-[#059669]" : "bg-[#111111]",
)}
style={{ width: `${pct}%` }}
/>
</div>
</div>
);
}
|