Spaces:
Running
Running
| "use client"; | |
| import { motion } from "framer-motion"; | |
| interface CircularProgressProps { | |
| score: number; | |
| label: string; | |
| size?: number; | |
| strokeWidth?: number; | |
| } | |
| function getScoreColor(score: number): string { | |
| if (score >= 70) return "#0070f3"; | |
| if (score >= 40) return "#00d4ff"; | |
| return "#666"; | |
| } | |
| export default function CircularProgress({ | |
| score, | |
| label, | |
| size = 96, | |
| strokeWidth = 8, | |
| }: CircularProgressProps) { | |
| const radius = (size - strokeWidth * 2) / 2; | |
| const circumference = 2 * Math.PI * radius; | |
| const progress = (score / 100) * circumference; | |
| const color = getScoreColor(score); | |
| const cx = size / 2; | |
| const cy = size / 2; | |
| return ( | |
| <div className="flex flex-col items-center gap-2"> | |
| <div className="relative" style={{ width: size, height: size }}> | |
| <svg | |
| width={size} | |
| height={size} | |
| className="-rotate-90" | |
| style={{ transform: "rotate(-90deg)" }} | |
| > | |
| {/* Background track */} | |
| <circle | |
| cx={cx} | |
| cy={cy} | |
| r={radius} | |
| fill="none" | |
| stroke="rgba(255,255,255,0.05)" | |
| strokeWidth={strokeWidth} | |
| /> | |
| {/* Progress arc */} | |
| <motion.circle | |
| cx={cx} | |
| cy={cy} | |
| r={radius} | |
| fill="none" | |
| stroke={color} | |
| strokeWidth={strokeWidth} | |
| strokeDasharray={`${progress} ${circumference}`} | |
| strokeLinecap="round" | |
| initial={{ strokeDasharray: `0 ${circumference}` }} | |
| animate={{ strokeDasharray: `${progress} ${circumference}` }} | |
| transition={{ duration: 1, ease: "easeOut" }} | |
| style={{ | |
| filter: `drop-shadow(0 0 8px ${color}60)`, | |
| }} | |
| /> | |
| </svg> | |
| {/* Center score */} | |
| <div className="absolute inset-0 flex flex-col items-center justify-center"> | |
| <motion.span | |
| initial={{ opacity: 0, scale: 0.5 }} | |
| animate={{ opacity: 1, scale: 1 }} | |
| transition={{ delay: 0.5, duration: 0.3 }} | |
| className="text-xl font-bold text-white leading-none" | |
| > | |
| {score} | |
| </motion.span> | |
| </div> | |
| </div> | |
| <span className="text-xs font-medium text-vercel-fg/60 tracking-wide uppercase">{label}</span> | |
| </div> | |
| ); | |
| } | |