58 lines
1.8 KiB
TypeScript
58 lines
1.8 KiB
TypeScript
import React from 'react'
|
|
import { Box, Group, Stack, Text } from '@mantine/core'
|
|
|
|
export interface BarChartDatum {
|
|
label: React.ReactNode
|
|
value: number
|
|
/** Mantine color key for the bar (e.g. 'teal', 'red'). Defaults to the theme primary. */
|
|
color?: string
|
|
}
|
|
|
|
export interface BarChartProps {
|
|
data: BarChartDatum[]
|
|
/** Format the numeric value shown at the end of each bar. */
|
|
valueFormatter?: (value: number) => string
|
|
}
|
|
|
|
// A dependency-free horizontal bar chart (CSS only, theme colours). Feed it
|
|
// aggregated counts from a stats RPC — no charting library to install or break.
|
|
export function BarChart({ data, valueFormatter }: BarChartProps) {
|
|
const max = Math.max(1, ...data.map((d) => d.value))
|
|
const fmt = valueFormatter ?? ((n: number) => String(n))
|
|
|
|
return (
|
|
<Stack gap="sm">
|
|
{data.map((datum, index) => (
|
|
<Stack key={index} gap={4}>
|
|
<Group justify="space-between" gap="xs">
|
|
<Text size="sm">{datum.label}</Text>
|
|
<Text size="sm" fw={600}>
|
|
{fmt(datum.value)}
|
|
</Text>
|
|
</Group>
|
|
<Box
|
|
style={{
|
|
height: 8,
|
|
borderRadius: 'var(--mantine-radius-xl)',
|
|
background: 'var(--mantine-color-default-hover)',
|
|
overflow: 'hidden',
|
|
}}
|
|
>
|
|
<Box
|
|
style={{
|
|
height: '100%',
|
|
width: `${(datum.value / max) * 100}%`,
|
|
borderRadius: 'var(--mantine-radius-xl)',
|
|
background: datum.color
|
|
? `var(--mantine-color-${datum.color}-6)`
|
|
: 'var(--mantine-primary-color-6)',
|
|
transition: 'width 200ms ease',
|
|
}}
|
|
/>
|
|
</Box>
|
|
</Stack>
|
|
))}
|
|
</Stack>
|
|
)
|
|
}
|