SPB Git forge

spb/countryatlas

Public
20commits 1branches 0releases
268.3 MBsize
maindefault branch
12 days agolast push
TypeScript 57% Python 38.6% JavaScript 3.6% CSS 0.6%
2.8 KB · 48 lines tsx
Raw Blame History
1'use client';2import Link from 'next/link';3import { t } from '@/i18n';4import { cn } from '@/lib/cn';5import { displayValue, formatPeriod } from '@/lib/format';6import { routes } from '@/lib/site';7import type { MetricValue } from '@/lib/types';8import { ChangeChip } from '@/components/data/change-chip';9import { payloadFor, type MetricCountry } from '@/components/data/metric';10import { useProvenance } from '@/components/data/provenance-context';11import { RankBadge } from '@/components/data/rank-badge';1213/**14 * Latest values of a subtopic, shown while its charts are collapsed on a long topic page: name · value · period15 * (highlighted when ≥ 2 years older than the newest value of the block) · change · world rank. Value → provenance.16 */17export function TopicCompact({ rows, country, regionName }: { rows: MetricValue[]; country: MetricCountry; regionName?: string | null }) {18  const { open } = useProvenance();19  const latestYear = Math.max(0, ...rows.map((m) => m.year ?? 0));20  return (21    <div className="min-w-0">22      <p className="mb-1 text-xs text-ink-3">{t('topic.collapsedHint')}</p>23      <ul className="divide-y divide-rule border-b border-rule text-sm">24        {rows.map((m) => {25          const stale = m.year != null && latestYear - m.year >= 2;26          return (27            <li key={m.indicator} className="grid grid-cols-[minmax(0,1fr)_auto] items-center gap-x-3 py-1 sm:grid-cols-[minmax(0,1fr)_auto_minmax(5rem,auto)_minmax(6rem,auto)]">28              <Link href={routes.indicator(m.indicator)} className="link-quiet inline-flex min-h-[44px] min-w-0 items-center text-ink md:min-h-[36px]">29                <span className="truncate">{m.indicator_name ?? m.indicator}</span>30              </Link>31              <button type="button" onClick={() => open(payloadFor(m, country))} className="tnum -mx-1 inline-flex min-h-[44px] items-baseline justify-end gap-1.5 rounded-sm px-1 text-right hover:bg-surface-2 md:min-h-[36px]" aria-label={`${m.indicator_name ?? m.indicator}: ${displayValue(m.value, m, m.formatted)} (${formatPeriod(m.period, m.frequency)}). ${t('common.openProvenance')}`}>32                <span className="font-medium text-ink">{displayValue(m.value, m, m.formatted)}</span>33                <span className={cn('text-2xs', stale ? 'rounded-xs bg-surface-2 px-1 text-ink-2' : 'text-ink-3')}>{formatPeriod(m.period, m.frequency)}</span>34              </button>35              <span className="hidden justify-end sm:flex">36                <ChangeChip change={m.change} spec={m} showVs={false} />37              </span>38              <span className="hidden min-w-0 justify-end truncate text-right sm:flex">39                <RankBadge rank={m} regionName={regionName} compact />40              </span>41            </li>42          );43        })}44      </ul>45    </div>46  );47}48