60 lines
1.4 KiB
TypeScript
60 lines
1.4 KiB
TypeScript
import { ReactNode } from "react";
|
|
|
|
interface ProgressBarProps {
|
|
value: number; // 0-100
|
|
color?: "primary" | "success" | "error" | "warning" | "info";
|
|
size?: "sm" | "md" | "lg";
|
|
showLabel?: boolean;
|
|
label?: string;
|
|
className?: string;
|
|
}
|
|
|
|
export const ProgressBar: React.FC<ProgressBarProps> = ({
|
|
value,
|
|
color = "primary",
|
|
size = "md",
|
|
showLabel = false,
|
|
label,
|
|
className = "",
|
|
}) => {
|
|
const sizeClasses = {
|
|
sm: "h-1",
|
|
md: "h-2",
|
|
lg: "h-3",
|
|
};
|
|
|
|
const colorClasses = {
|
|
primary: "bg-brand-500",
|
|
success: "bg-success-500",
|
|
error: "bg-error-500",
|
|
warning: "bg-warning-500",
|
|
info: "bg-blue-light-500",
|
|
};
|
|
|
|
const clampedValue = Math.min(100, Math.max(0, value));
|
|
|
|
return (
|
|
<div className={className}>
|
|
{showLabel && (
|
|
<div className="flex items-center justify-between mb-2">
|
|
<span className="text-sm font-medium text-gray-700 dark:text-gray-300">
|
|
{label || `${clampedValue}%`}
|
|
</span>
|
|
<span className="text-sm text-gray-500 dark:text-gray-400">
|
|
{clampedValue}%
|
|
</span>
|
|
</div>
|
|
)}
|
|
<div
|
|
className={`w-full rounded-full bg-gray-200 dark:bg-gray-700 ${sizeClasses[size]}`}
|
|
>
|
|
<div
|
|
className={`rounded-full transition-all duration-300 ${sizeClasses[size]} ${colorClasses[color]}`}
|
|
style={{ width: `${clampedValue}%` }}
|
|
/>
|
|
</div>
|
|
</div>
|
|
);
|
|
};
|
|
|