52 lines
1.7 KiB
TypeScript
52 lines
1.7 KiB
TypeScript
import React from 'react';
|
|
|
|
interface CircularProgressProps {
|
|
value: number;
|
|
max: number;
|
|
label: string;
|
|
color: string;
|
|
size?: number;
|
|
}
|
|
|
|
export default function CircularProgress({ value, max, label, color, size = 80 }: CircularProgressProps) {
|
|
const percentage = Math.min((value / max) * 100, 100);
|
|
const strokeWidth = 6;
|
|
const radius = (size - strokeWidth) / 2;
|
|
const circumference = radius * 2 * Math.PI;
|
|
const strokeDashoffset = circumference - (percentage / 100) * circumference;
|
|
|
|
return (
|
|
<div className="flex flex-col items-center">
|
|
<div className="relative" style={{ width: size, height: size }}>
|
|
<svg className="transform -rotate-90" width={size} height={size}>
|
|
<circle
|
|
cx={size / 2}
|
|
cy={size / 2}
|
|
r={radius}
|
|
stroke="currentColor"
|
|
strokeWidth={strokeWidth}
|
|
fill="transparent"
|
|
className="text-charcoal-outline"
|
|
/>
|
|
<circle
|
|
cx={size / 2}
|
|
cy={size / 2}
|
|
r={radius}
|
|
stroke="currentColor"
|
|
strokeWidth={strokeWidth}
|
|
fill="transparent"
|
|
strokeDasharray={circumference}
|
|
strokeDashoffset={strokeDashoffset}
|
|
strokeLinecap="round"
|
|
className={color}
|
|
style={{ transition: 'stroke-dashoffset 0.5s ease-in-out' }}
|
|
/>
|
|
</svg>
|
|
<div className="absolute inset-0 flex items-center justify-center">
|
|
<span className="text-lg font-bold text-white">{percentage.toFixed(0)}%</span>
|
|
</div>
|
|
</div>
|
|
<span className="text-xs text-gray-400 mt-2">{label}</span>
|
|
</div>
|
|
);
|
|
} |