Untitled
'use client' import { useEffect, useState } from 'react' import { useTheme } from 'next-themes' import { Label, PolarGrid, PolarRadiusAxis, RadialBar, RadialBarChart } from "recharts" import { Card, CardContent } from "@/components/ui/card" import { ChartContainer, ChartConfig } from "@/components/ui/chart" import { cn } from "@/lib/utils" interface CircularProgressProps { binId: string fillLevel: number color: string darkColor: string name: string } export function CircularProgress({ binId, fillLevel, color, darkColor, name }: CircularProgressProps) { const { theme } = useTheme() const [progress, setProgress] = useState(0) useEffect(() => { const timer = setTimeout(() => setProgress(fillLevel), 100) return () => clearTimeout(timer) }, [fillLevel]) const isDarkMode = theme === 'dark' const bgColor = isDarkMode ? darkColor : color const textColor = getTextColor(bgColor) const progressColor = getProgressColor(fillLevel, isDarkMode) const chartConfig: ChartConfig = { [binId]: { label: name, color: progressColor, }, } const chartData = [ { name: `${binId}-progress`, value: progress, fill: progressColor } ] return ( <Card className="w-full border-0 bg-transparent shadow-none"> <CardContent className="relative p-1"> <ChartContainer config={chartConfig} className="mx-auto aspect-square w-full max-w-[400px]"> <div className="absolute inset-0 flex items-center justify-center"> <div className={cn( "rounded-full", isDarkMode ? "opacity-[0.15]" : "opacity-[0.35]" )} style={{ backgroundColor: bgColor, width: "62%", height: "62%", position: "absolute", left: "50%", top: "50%", transform: "translate(-50%, -50%)" }} /> </div> <RadialBarChart data={chartData} startAngle={90} endAngle={90 - (progress * 3.6)} innerRadius="65%" outerRadius="95%" barSize={12} > <PolarRadiusAxis tick={false} axisLine={false} tickLine={false} stroke="none" > <Label content={({ viewBox }) => { if (viewBox && "cx" in viewBox && "cy" in viewBox) { return ( <text x={viewBox.cx} y={viewBox.cy} textAnchor="middle" dominantBaseline="middle" className="fill-foreground text-2xl font-medium" > {name} </text> ) } }} /> </PolarRadiusAxis> <RadialBar background={false} dataKey="value" cornerRadius={15} className="stroke-none" /> </RadialBarChart> </ChartContainer> </CardContent> </Card> ) } function getProgressColor(level: number, isDark: boolean) { if (isDark) { if (level >= 80) return '#ff3b30' if (level >= 60) return '#ff9f0a' if (level >= 40) return '#ffd60a' return '#30d158' } else { if (level >= 80) return '#ff453a' if (level >= 60) return '#ff9f0a' if (level >= 40) return '#ffd60a' return '#34c759' } } function getTextColor(backgroundColor: string) { const rgb = parseInt(backgroundColor.slice(1), 16) const r = (rgb >> 16) & 0xff const g = (rgb >> 8) & 0xff const b = (rgb >> 0) & 0xff const luminance = (0.299 * r + 0.587 * g + 0.114 * b) / 255 return luminance > 0.5 ? '#000000' : '#ffffff' }
Leave a Comment