import Link from 'next/link'; import type { ReactNode } from 'react'; import { cn } from '@/lib/cn'; import { fmtInt } from '@/lib/format'; /** * Compact heatmap table (rows × columns) with sequential intensity from the accent hue. Server-renderable. * Cells with null are drawn hollow, never as 0. */ export function Heatmap({ rows, cols, get, rowHref, format = fmtInt, className, colLabel = (c) => c }: { rows: { key: string; label: ReactNode }[]; cols: string[]; get: (row: string, col: string) => number | null; rowHref?: (row: string) => string | undefined; format?: (v: number) => string; className?: string; colLabel?: (c: string) => ReactNode }) { let max = 0; for (const r of rows) for (const c of cols) max = Math.max(max, get(r.key, c) ?? 0); return (
| {cols.map((c) => ( | {colLabel(c)} | ))}
|---|---|
| {href ? ( {r.label} ) : ( r.label )} | {cols.map((c) => { const v = get(r.key, c); const a = v === null || max === 0 ? 0 : 0.08 + 0.82 * Math.sqrt(v / max); return (0.55 ? 'var(--accent-ink)' : 'var(--ink)' }} title={v === null ? 'no data' : `${format(v)}`}> {v === null ? '·' : v === 0 ? '' : format(v)} | ); })}