learning_ai_clock/web/src/components/CountdownRing.tsx

69 lines
1.9 KiB
TypeScript

'use client';
interface CountdownRingProps {
progress: number; // 0-1, where 1 = full, 0 = empty
size?: number;
strokeWidth?: number;
color?: string;
trackColor?: string;
children?: React.ReactNode;
}
export function CountdownRing({
progress,
size = 200,
strokeWidth = 8,
color,
trackColor = 'var(--cm-surface-muted)',
children,
}: CountdownRingProps) {
const radius = (size - strokeWidth) / 2;
const circumference = 2 * Math.PI * radius;
const offset = circumference * (1 - Math.min(1, Math.max(0, progress)));
// Color transitions: green → yellow → orange → red
const dynamicColor = color ?? getProgressColor(progress);
return (
<div className="relative inline-flex items-center justify-center" style={{ width: size, height: size }}>
<svg width={size} height={size} className="transform -rotate-90">
{/* Track */}
<circle
cx={size / 2}
cy={size / 2}
r={radius}
fill="none"
stroke={trackColor}
strokeWidth={strokeWidth}
/>
{/* Progress */}
<circle
cx={size / 2}
cy={size / 2}
r={radius}
fill="none"
stroke={dynamicColor}
strokeWidth={strokeWidth}
strokeLinecap="round"
strokeDasharray={circumference}
strokeDashoffset={offset}
className="transition-all duration-300"
/>
</svg>
{/* Center content */}
{children && (
<div className="absolute inset-0 flex items-center justify-center">
{children}
</div>
)}
</div>
);
}
function getProgressColor(progress: number): string {
if (progress > 0.6) return 'var(--cm-gentle)'; // green
if (progress > 0.3) return 'var(--cm-standard)'; // yellow
if (progress > 0.1) return 'var(--cm-important)'; // orange
return 'var(--cm-critical)'; // red
}