hydropd / website /src /components /BarRow.tsx
rikardsaqe's picture
Instrument redesign + copy/functional fixes
8c51b20 verified
Raw
History Blame Contribute Delete
1.86 kB
// Tiny dependency-free horizontal bar for inline charts (leaderboard species view,
// cross-model analysis, data page). Value in [0,1] by default; optional min–max
// whisker overlaid on the bar. Purely presentational, theme-aware via CSS vars.
interface BarRowProps {
label: string
value: number | null
min?: number | null
max?: number | null
/** domain max (default 1) */
domain?: number
/** bar fill color CSS var name, e.g. 'var(--accent)' */
color?: string
/** show the numeric value at the end */
showValue?: boolean
/** right-side annotation (e.g. species name) */
note?: string
labelWidth?: number
/** format the numeric value (default: 3 decimals) */
format?: (v: number) => string
}
export default function BarRow({
label,
value,
min,
max,
domain = 1,
color = 'var(--accent)',
showValue = true,
note,
labelWidth = 150,
format = (v) => v.toFixed(3),
}: BarRowProps) {
const pct = value == null ? 0 : Math.max(0, Math.min(100, (value / domain) * 100))
const hasWhisker = min != null && max != null && max > min
return (
<div className="bar-row">
<div className="bar-label" style={{ width: labelWidth }} title={label}>
{label}
</div>
<div className="bar-track">
{value != null && <div className="bar-fill" style={{ width: `${pct}%`, background: color }} />}
{hasWhisker && (
<div
className="bar-whisker"
style={{ left: `${(min! / domain) * 100}%`, width: `${((max! - min!) / domain) * 100}%` }}
title={`range ${min!.toFixed(3)}–${max!.toFixed(3)}`}
/>
)}
</div>
{showValue && (
<div className="bar-value">
{value == null ? 'n/a' : format(value)}
{note && <span className="bar-note"> {note}</span>}
</div>
)}
</div>
)
}