Lots of frontend changes
This commit is contained in:
parent
ec29631c44
commit
555ba7cf53
38 changed files with 1508 additions and 648 deletions
78
frontend/src/components/map/StackedEnumChart.tsx
Normal file
78
frontend/src/components/map/StackedEnumChart.tsx
Normal file
|
|
@ -0,0 +1,78 @@
|
|||
import type { EnumFeatureStats } from '../../types';
|
||||
|
||||
interface StackedEnumChartProps {
|
||||
components: { label: string; stats: EnumFeatureStats }[];
|
||||
valueOrder: string[];
|
||||
valueColors: string[];
|
||||
}
|
||||
|
||||
/** Strip common suffixes to produce short row labels */
|
||||
function shortenLabel(name: string): string {
|
||||
return name.replace(/ risk$/, '');
|
||||
}
|
||||
|
||||
export default function StackedEnumChart({
|
||||
components,
|
||||
valueOrder,
|
||||
valueColors,
|
||||
}: StackedEnumChartProps) {
|
||||
const visibleRows = components.filter(({ stats }) => {
|
||||
const total = Object.values(stats.counts).reduce((a, b) => a + b, 0);
|
||||
if (total === 0) return false;
|
||||
const lowCount = stats.counts[valueOrder[0]] ?? 0;
|
||||
return total - lowCount > 0;
|
||||
});
|
||||
|
||||
if (visibleRows.length === 0) {
|
||||
return (
|
||||
<div className="text-xs text-warm-400 dark:text-warm-500 italic mt-1">All low</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="space-y-1.5">
|
||||
{visibleRows.map(({ label, stats }) => {
|
||||
const total = Object.values(stats.counts).reduce((a, b) => a + b, 0);
|
||||
|
||||
return (
|
||||
<div key={label} className="flex items-center gap-2 text-xs">
|
||||
<span className="w-24 truncate text-warm-500 dark:text-warm-400 text-right shrink-0">
|
||||
{shortenLabel(label)}
|
||||
</span>
|
||||
<div className="flex-1 flex h-3.5 rounded overflow-hidden bg-warm-200 dark:bg-warm-700">
|
||||
{valueOrder.map((value, i) => {
|
||||
const count = stats.counts[value] ?? 0;
|
||||
const pct = (count / total) * 100;
|
||||
if (pct < 0.5) return null;
|
||||
return (
|
||||
<div
|
||||
key={value}
|
||||
className="h-full"
|
||||
style={{
|
||||
width: `${pct}%`,
|
||||
backgroundColor: valueColors[i],
|
||||
}}
|
||||
title={`${value}: ${count} (${pct.toFixed(0)}%)`}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
|
||||
{/* Legend */}
|
||||
<div className="flex gap-x-3 gap-y-0.5 justify-center">
|
||||
{valueOrder.map((value, i) => (
|
||||
<div key={value} className="flex items-center gap-1">
|
||||
<span
|
||||
className="w-2 h-2 rounded-sm shrink-0"
|
||||
style={{ backgroundColor: valueColors[i] }}
|
||||
/>
|
||||
<span className="text-[10px] text-warm-600 dark:text-warm-400">{value}</span>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue