skl/resources/js/components/Dashboard/ChartCard.tsx

187 lines
7.6 KiB
TypeScript

import { useState } from "react";
import { TrendingUp, BarChart2 } from "lucide-react";
import {
Bar,
BarChart,
CartesianGrid,
XAxis,
YAxis,
ResponsiveContainer,
} from "recharts";
import {
Card,
CardContent,
CardDescription,
CardHeader,
CardTitle,
} from "@/components/ui/card";
import {
ChartConfig,
ChartContainer,
ChartTooltip,
ChartTooltipContent,
} from "@/components/ui/chart";
const chartData = [
{ month: "Genset", desktop: 186, color: "#22c55e" },
{ month: "Boiler", desktop: 305, color: "#16a34a" },
{ month: "Proses", desktop: 237, color: "#15803d" },
];
const chartConfig = {
desktop: {
label: "Value",
color: "hsl(var(--chart-1))",
},
} satisfies ChartConfig;
export function ChartCard() {
const [activeIndex, setActiveIndex] = useState<number | null>(null);
const handleMouseEnter = (index: number) => {
setActiveIndex(index);
};
const handleMouseLeave = () => {
setActiveIndex(null);
};
return (
<Card className="relative overflow-hidden transition-all duration-300 hover:shadow-lg">
<div className="absolute inset-0 bg-gradient-to-br from-green-50/30 to-transparent dark:from-green-950/30" />
<CardHeader className="relative">
<div className="flex items-center gap-2">
<BarChart2 className="h-6 w-6 text-green-600" />
<CardTitle className="text-xl font-bold">
Sumber Emisi
</CardTitle>
</div>
<CardDescription className="text-sm text-green-600 font-medium">
Total Emisi per Sumber
</CardDescription>
</CardHeader>
<CardContent className="relative pb-6">
<div className="h-[300px] w-full">
<ResponsiveContainer width="100%" height="100%">
<BarChart data={chartData}>
<defs>
{chartData.map((entry, index) => (
<linearGradient
key={`gradient-${index}`}
id={`barGradient-${index}`}
x1="0"
y1="0"
x2="0"
y2="1"
>
<stop
offset="0%"
stopColor={entry.color}
stopOpacity={0.8}
/>
<stop
offset="100%"
stopColor={entry.color}
stopOpacity={0.3}
/>
</linearGradient>
))}
</defs>
<CartesianGrid
vertical={false}
stroke="#e5e7eb"
strokeDasharray="4 4"
/>
<XAxis
dataKey="month"
tickLine={false}
axisLine={false}
tick={{ fill: "#6b7280", fontSize: 12 }}
tickMargin={12}
/>
<YAxis
axisLine={false}
tickLine={false}
tick={{ fill: "#6b7280", fontSize: 12 }}
tickMargin={8}
/>
<ChartTooltip
cursor={false}
content={({ active, payload }) => {
if (active && payload && payload.length) {
return (
<div className="rounded-lg bg-white p-3 shadow-lg border border-green-100 backdrop-blur-sm">
<p className="font-medium text-green-800">
{payload[0].payload.month}
</p>
<p className="text-sm text-green-600">
{payload[0].value} ton CO
</p>
</div>
);
}
return null;
}}
/>
<Bar
dataKey="desktop"
radius={[8, 8, 0, 0]}
onMouseEnter={(data, index) =>
handleMouseEnter(index)
}
onMouseLeave={handleMouseLeave}
>
{chartData.map((entry, index) => (
<rect
key={`bar-${index}`}
fill={`url(#barGradient-${index})`}
className={`transition-all duration-300 ${
activeIndex === index
? "opacity-100 scale-y-105"
: activeIndex === null
? "opacity-90"
: "opacity-50"
}`}
/>
))}
</Bar>
</BarChart>
</ResponsiveContainer>
</div>
<div className="mt-6 flex justify-between items-center px-4">
{chartData.map((item, index) => (
<div
key={item.month}
className="flex flex-col items-center gap-2"
onMouseEnter={() => handleMouseEnter(index)}
onMouseLeave={handleMouseLeave}
>
<div
className={`h-3 w-3 rounded-full transition-all duration-300 ${
activeIndex === index
? "scale-150"
: activeIndex === null
? "scale-100"
: "scale-75 opacity-50"
}`}
style={{ backgroundColor: item.color }}
/>
<span className="text-sm font-medium text-gray-600">
{item.month}
</span>
</div>
))}
</div>
</CardContent>
</Card>
);
}