Shitty gadgets removed. Some useful gadgets added.
This commit is contained in:
125
frontend/src/components/today/TodayDonutChart.tsx
Normal file
125
frontend/src/components/today/TodayDonutChart.tsx
Normal file
@@ -0,0 +1,125 @@
|
||||
'use client';
|
||||
|
||||
import type { CSSProperties } from 'react';
|
||||
import { Cell, Pie, PieChart, ResponsiveContainer, Tooltip } from 'recharts';
|
||||
import type { TodayChartBucket } from '@/types/today';
|
||||
import {
|
||||
TODAY_CHART_COLORS,
|
||||
TODAY_CHART_TOOLTIP_STYLE,
|
||||
} from '@/components/today/chart-theme';
|
||||
|
||||
interface TodayDonutChartProps {
|
||||
data: TodayChartBucket[];
|
||||
labelForCode: (code: string) => string;
|
||||
colorForCode?: (code: string, index: number) => string;
|
||||
swatchStyleForCode?: (code: string, index: number) => CSSProperties;
|
||||
variant?: 'donut' | 'pie';
|
||||
sideLegend?: boolean;
|
||||
}
|
||||
|
||||
export function TodayDonutChart({
|
||||
data,
|
||||
labelForCode,
|
||||
colorForCode,
|
||||
swatchStyleForCode,
|
||||
variant = 'donut',
|
||||
sideLegend = false,
|
||||
}: TodayDonutChartProps) {
|
||||
const chartData = data.map((item) => ({
|
||||
...item,
|
||||
displayLabel: labelForCode(item.code),
|
||||
}));
|
||||
|
||||
const resolveColor = (code: string, index: number) =>
|
||||
colorForCode?.(code, index) ??
|
||||
TODAY_CHART_COLORS[index % TODAY_CHART_COLORS.length];
|
||||
|
||||
const resolveSwatchStyle = (code: string, index: number): CSSProperties =>
|
||||
swatchStyleForCode?.(code, index) ?? {
|
||||
backgroundColor: resolveColor(code, index),
|
||||
borderColor: 'rgba(0, 0, 0, 0.18)',
|
||||
};
|
||||
|
||||
const innerRadius = variant === 'pie' ? 0 : 62;
|
||||
const outerRadius = sideLegend ? 100 : 92;
|
||||
|
||||
const chart = (
|
||||
<ResponsiveContainer width="100%" height={240}>
|
||||
<PieChart margin={{ top: 0, right: 0, bottom: 0, left: 0 }}>
|
||||
<Pie
|
||||
data={chartData}
|
||||
dataKey="count"
|
||||
nameKey="displayLabel"
|
||||
cx="50%"
|
||||
cy="50%"
|
||||
innerRadius={innerRadius}
|
||||
outerRadius={outerRadius}
|
||||
paddingAngle={variant === 'pie' ? 1 : 2}
|
||||
stroke="transparent"
|
||||
>
|
||||
{chartData.map((entry, index) => (
|
||||
<Cell key={entry.code} fill={resolveColor(entry.code, index)} />
|
||||
))}
|
||||
</Pie>
|
||||
<Tooltip
|
||||
contentStyle={TODAY_CHART_TOOLTIP_STYLE}
|
||||
formatter={(value, _name, item) => {
|
||||
const row = item?.payload as TodayChartBucket | undefined;
|
||||
return [value, row ? labelForCode(row.code) : ''];
|
||||
}}
|
||||
/>
|
||||
</PieChart>
|
||||
</ResponsiveContainer>
|
||||
);
|
||||
|
||||
if (!sideLegend) {
|
||||
return chart;
|
||||
}
|
||||
|
||||
const rowClass = 'flex h-4 items-center text-xs leading-none';
|
||||
const legendInset = 'px-12';
|
||||
|
||||
return (
|
||||
<div className={`flex h-full min-h-[220px] items-center ${legendInset}`}>
|
||||
<div className="flex min-w-0 flex-1 items-center overflow-y-auto max-h-full py-0.5">
|
||||
<div className="flex flex-col items-start gap-1.5 shrink-0">
|
||||
{chartData.map((entry, index) => (
|
||||
<span key={entry.code} className={rowClass}>
|
||||
<span
|
||||
className="inline-block h-3 w-3 rounded-sm border"
|
||||
style={resolveSwatchStyle(entry.code, index)}
|
||||
aria-hidden
|
||||
/>
|
||||
</span>
|
||||
))}
|
||||
</div>
|
||||
|
||||
<div className="ml-2 flex flex-col items-start gap-1.5">
|
||||
{chartData.map((entry) => (
|
||||
<span
|
||||
key={entry.code}
|
||||
className={`${rowClass} max-w-full truncate text-left text-text-primary`}
|
||||
>
|
||||
{entry.displayLabel}
|
||||
</span>
|
||||
))}
|
||||
</div>
|
||||
|
||||
<div className="ml-3 flex shrink-0 flex-col items-end gap-1.5">
|
||||
{chartData.map((entry) => (
|
||||
<span
|
||||
key={entry.code}
|
||||
className={`${rowClass} tabular-nums text-right text-text-muted`}
|
||||
>
|
||||
{entry.count}
|
||||
</span>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="ml-4 flex h-[240px] w-[min(100%,220px)] max-w-[48%] shrink-0 items-center justify-center">
|
||||
{chart}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user