import Link from 'next/link'; import { Sparkline } from '@/components/charts/sparkline'; import { cn } from '@/lib/cn'; import { fmtPctSigned, fmtScore, num } from '@/lib/format'; import { METRIC_LABELS } from '@/lib/site'; import type { CompanyDetail, Metric, MetricDetail } from '@/lib/types'; const TILES: { metric: Metric; spark?: 'activity_30d' | 'hiring_90d'; pct?: boolean }[] = [ { metric: 'activity_score', spark: 'activity_30d' }, { metric: 'hiring_momentum_30d', spark: 'hiring_90d', pct: true }, { metric: 'product_velocity' }, { metric: 'ai_adoption' }, { metric: 'corporate_change_index' }, ]; /** * Metric tiles with sparklines and confidence. A metric with no value is shown as "not enough evidence" rather than 0 * (API omits metrics without inputs — spec §165). Each tile links to the methodology. */ export function MetricTiles({ c, className }: { c: CompanyDetail; className?: string }) { const detail = new Map((c.metrics_detail ?? []).map((m) => [m.metric, m])); return (
*]:border-b [&>*]:border-rule md:[&>*]:border-b-0', className)} data-metric-tiles> {TILES.map((t) => { const v = num(c.metrics[t.metric]); const d = detail.get(t.metric); const spark = t.spark ? c.sparklines?.[t.spark] : undefined; return (

{METRIC_LABELS[t.metric]}

0 ? 'text-positive' : v < 0 ? 'text-danger' : ''))}>{v === null ? '—' : t.pct ? fmtPctSigned(v) : fmtScore(v)}

{spark && spark.length > 1 && }

{v === null ? 'not enough monitored evidence' : d ? `confidence ${Math.round(d.confidence * 100)} %${d.formula_version ? ` · ${d.formula_version}` : ''}` : t.pct ? 'vs 30 days ago' : '0–100'}

); })}
); }