// Tiny generic table component. // // Each column declares: a header label, a key, and an optional // `render` function that takes the row and returns a ReactNode. // Without `render` the column reads `row[key]` and stringifies it. // // Intentionally not a heavy table lib (TanStack Table, AG Grid). // v1 SPA needs columnar reads, link cells, status badges, and // filtering by a free-text input — all trivially handcoded. A // future chunk can swap this out the day a real consumer asks for // virtualised rows or column resizing. import type { ReactNode } from 'react' export interface Column { header: string key: string render?: (row: T) => ReactNode className?: string } interface Props { rows: T[] columns: Column[] empty?: ReactNode rowKey?: (row: T) => string } export function DataTable({ rows, columns, empty =
No rows.
, rowKey, }: Props) { if (rows.length === 0) { return
{empty}
} return (
{columns.map((c) => ( ))} {rows.map((row, idx) => { const key = rowKey ? rowKey(row) : ((row as { id?: string }).id ?? String(idx)) return ( {columns.map((c) => ( ))} ) })}
{c.header}
{c.render ? c.render(row) : ((row as unknown as Record)[c.key] as ReactNode) ?? ''}
) }