import Link from 'next/link'; import type { ReactNode } from 'react'; import { cn } from '@/lib/cn'; import { fmtDate, fmtInt, fmtParams, fmtTokens, fmtUsdPerM, num } from '@/lib/format'; import { routes, typeLabel } from '@/lib/site'; import type { EntitySummary } from '@/lib/types'; import { EntityBadge, OpennessBadge, StatusBadge } from './badges'; export function EntityLink({ e, className, children }: { e: { entity_type: string; slug: string; name: string }; className?: string; children?: ReactNode }) { return ( {children ?? e.name} ); } /** Key attribute chips for a summary, type-aware (model: params · context · release; company: country; …). */ export function keyAttributes(e: EntitySummary): { label: string; value: string }[] { const a = e.attributes ?? {}; const out: { label: string; value: string }[] = []; const push = (label: string, value: string | null | undefined) => { if (value && value !== '—') out.push({ label, value }); }; switch (e.entity_type) { case 'model': case 'quantization': { const p = num(a.parameter_count); const ap = num(a.active_parameter_count); if (p !== null) push('params', ap !== null && ap !== p ? `${fmtParams(p)} (${fmtParams(ap)} active)` : fmtParams(p)); if (num(a.context_length) !== null) push('context', fmtTokens(a.context_length)); if (typeof a.release_date === 'string') push('released', fmtDate(a.release_date)); if (typeof a.license === 'string') push('license', a.license); break; } case 'company': case 'organization': case 'lab': case 'university': if (typeof a.country === 'string') push('country', a.country); if (a.founded) push('founded', String(a.founded).slice(0, 4)); if (typeof a.org_kind === 'string') push('kind', a.org_kind); break; case 'paper': if (typeof a.published_at === 'string') push('published', fmtDate(a.published_at)); if (Array.isArray(a.authors) && a.authors.length) push('authors', `${a.authors.length}`); if (typeof a.venue === 'string') push('venue', a.venue); if (typeof a.arxiv_id === 'string') push('arXiv', a.arxiv_id); break; case 'provider': if (Array.isArray(a.regions) && a.regions.length) push('regions', `${a.regions.length}`); break; case 'benchmark': if (typeof a.category === 'string') push('category', a.category); if (typeof a.metric === 'string') push('metric', a.metric); break; case 'hardware': case 'robot': if (typeof a.kind === 'string') push('kind', a.kind); if (num(a.memory_gb) !== null) push('memory', `${fmtInt(a.memory_gb)} GB`); if (num(a.memory_bandwidth_gbs) !== null) push('bandwidth', `${fmtInt(a.memory_bandwidth_gbs)} GB/s`); if (num(a.tdp_watts) !== null) push('TDP', `${fmtInt(a.tdp_watts)} W`); break; case 'framework': case 'library': case 'runtime': case 'repository': if (typeof a.latest_version === 'string') push('version', a.latest_version); if (typeof a.language === 'string') push('language', a.language); if (num(a['metric.stars']) !== null) push('stars', fmtInt(a['metric.stars'])); if (typeof a.license === 'string') push('license', a.license); break; case 'dataset': if (typeof a.modality === 'string') push('modality', a.modality); if (a.size) push('size', String(a.size)); if (typeof a.license === 'string') push('license', a.license); break; default: break; } return out.slice(0, 4); } export function cheapestPrice(e: EntitySummary): string | null { const a = e.attributes ?? {}; const v = num(a.min_input_per_mtok ?? a.best_input_per_mtok); return v === null ? null : fmtUsdPerM(v); } /** Dense list row: badge · name (link) · org · key attributes · quality. Used by search results, related, explore. */ export function EntityRow({ e, showType = true, trailing, className, showDescription = true }: { e: EntitySummary; showType?: boolean; trailing?: ReactNode; className?: string; showDescription?: boolean }) { const attrs = keyAttributes(e); const openness = typeof e.attributes?.openness === 'string' ? e.attributes.openness : null; return (
  • {showType && } {e.organization && ( {e.organization.name} )} {openness && }
    {showDescription && e.description &&

    {e.description}

    } {attrs.length > 0 && (

    {attrs.map((x) => ( {x.label} {x.value} ))}

    )}
    {trailing}
  • ); } /** Quality score 0–100 (how well AI Atlas knows the entity, not how good it is). */ export function QualityMark({ q, className, label = false }: { q: number | undefined | null; className?: string; label?: boolean }) { const n = num(q); if (n === null) return null; const tone = n >= 75 ? 'bg-positive' : n >= 45 ? 'bg-accent' : 'bg-warning'; return ( {label && data quality} {Math.round(n)} ); } /** Inline compact list of entity links "a, b, c +4". */ export function EntityInline({ items, max = 6, total }: { items: EntitySummary[]; max?: number; total?: number }) { const shown = items.slice(0, max); const rest = (total ?? items.length) - shown.length; return ( {shown.map((e, i) => ( {i > 0 && , } ))} {rest > 0 && +{rest}} ); } export function typeOf(e: { entity_type: string }): string { return typeLabel(e.entity_type); }