import type { ReactNode } from 'react'; import { t } from '@/i18n'; import { cn } from '@/lib/cn'; /** Dense, plain admin primitives: heading row, key/value list, compact table, status pill. */ export function AdminSection({ title, sub, actions, children, className }: { title: string; sub?: ReactNode; actions?: ReactNode; children: ReactNode; className?: string }) { return (

{title}

{sub ?

{sub}

: null}
{actions ?
{actions}
: null}
{children}
); } export function Kv({ rows, className }: { rows: Array<[string, ReactNode]>; className?: string }) { return (
{rows.map(([k, v]) => (
{k}
{v ?? t('admin.na')}
))}
); } export interface Col { key: string; header: ReactNode; cell: (row: T) => ReactNode; numeric?: boolean; className?: string; } /** Compact table with horizontal scroll on narrow screens (admin only — dense by design). */ export function AdminTable({ rows, columns, rowKey, className, empty }: { rows: T[]; columns: Col[]; rowKey: (r: T, i: number) => string; className?: string; empty?: ReactNode }) { if (rows.length === 0) return

{empty ?? t('common.noDataLong')}

; return (
{columns.map((c) => ( ))} {rows.map((r, i) => ( {columns.map((c) => ( ))} ))}
{c.header}
{c.cell(r)}
); } export function Pill({ tone, children }: { tone: 'ok' | 'warn' | 'bad' | 'muted'; children: ReactNode }) { return ( {children} ); } export function statusTone(s: string | null | undefined): 'ok' | 'warn' | 'bad' | 'muted' { const v = (s ?? '').toLowerCase(); if (v === 'ok' || v === 'verified') return 'ok'; if (v === 'partial' || v === 'warning' || v === 'stale') return 'warn'; if (v === 'failed' || v === 'quarantined' || v === 'error') return 'bad'; return 'muted'; } export function bytes(n: number | null | undefined): string { if (n == null) return t('admin.na'); if (n >= 1e9) return `${(n / 1e9).toFixed(2)} GB`; if (n >= 1e6) return `${(n / 1e6).toFixed(1)} MB`; if (n >= 1e3) return `${(n / 1e3).toFixed(0)} kB`; return `${n} B`; } export function ts(iso: string | null | undefined): string { if (!iso) return t('admin.na'); return iso.replace('T', ' ').replace(/\.\d+/, '').replace(/\+00:00$/, 'Z'); }