'use client'; import { ArrowRight, ExternalLink, Scale, X } from 'lucide-react'; import Link from 'next/link'; import { t } from '@/i18n'; import { cn } from '@/lib/cn'; import { formatValue, grouped, ordinal } from '@/lib/format'; import { regionShort } from '@/lib/regions'; import { routes } from '@/lib/site'; import type { FormatSpec, Provenance } from '@/lib/types'; import type { PointCountry } from '@/lib/types-analytics'; import { seqVar } from '@/components/charts/palette'; import { Sparkline } from '@/components/charts/sparkline'; import type { SeriesPoint } from '@/components/charts/scales'; import { useProvenance } from '@/components/data/provenance-context'; import { stepFor } from './geo'; export interface CountryYearInfo { country: PointCountry; value: number | null; year: number; rankWorld: number | null; nWorld: number; rankRegion: number | null; nRegion: number; series: SeriesPoint[]; firstYear: number | null; lastYear: number | null; latestValue: number | null; latestYear: number | null; } /** Legend for the pooled quantile classes (stable while scrubbing). */ export function ClassLegend({ breaks, min, max, spec, k, compact, className }: { breaks: number[]; min: number | null; max: number | null; spec: FormatSpec; k: number; compact?: boolean; className?: string }) { const items = Array.from({ length: k }, (_, i) => { const lo = i === 0 ? min : breaks[i - 1]!; const hi = i === k - 1 ? max : breaks[i]!; return { cls: i, lo, hi }; }); return (
    {items.map((it) => (
  1. {compact ? (it.cls === 0 ? formatValue(it.lo, spec) : it.cls === k - 1 ? formatValue(it.hi, spec) : '') : `${formatValue(it.lo, spec)} – ${formatValue(it.hi, spec)}`}
  2. ))}
  3. {t('chart.legend.noData')}
); } /** Floating hover label on the map: country · value · year · world / regional rank. */ export function MapTooltip({ info, spec, x, y, sticky, onOpen }: { info: CountryYearInfo; spec: FormatSpec; x: number; y: number; sticky: boolean; onOpen: () => void }) { return (
{info.country.flag ? {info.country.flag} : null} {info.country.name}
{formatValue(info.value, spec)} · {info.year}
{info.value != null && info.rankWorld != null ? (
{t('explorer.rank.world', { rank: ordinal(info.rankWorld), n: grouped(info.nWorld) })} {info.rankRegion != null && info.country.region ? ` · ${t('explorer.rank.region', { rank: ordinal(info.rankRegion), region: regionShort(info.country.region) ?? info.country.region })}` : ''}
) : info.value == null ? (
{t('explorer.noValueYear', { year: info.year })}
) : null} {sticky ? ( ) : null}
); } /** Country drawer content (right panel on desktop, bottom sheet on phones). */ export function CountryPanel({ info, spec, indicatorSlug, indicatorName, provenance, onClose, onCompareHref, trajectoriesHref, closeClassName }: { info: CountryYearInfo; spec: FormatSpec; indicatorSlug: string; indicatorName: string; provenance: Provenance | null; onClose: () => void; onCompareHref: string; trajectoriesHref: string; closeClassName?: string }) { const { open } = useProvenance(); const c = info.country; const slug = c.slug ?? c.id.toLowerCase(); const dir = info.series.length >= 2 ? Math.sign((info.series[info.series.length - 1]!.value ?? 0) - (info.series[info.series.length - 2]!.value ?? 0)) : 0; return (
{c.flag}

{c.name}

{regionShort(c.region) ?? c.region ?? ''} {c.income ? ` · ${c.income}` : ''}

{indicatorName}
{info.value != null && info.rankWorld != null ? (

{t('explorer.rank.world', { rank: ordinal(info.rankWorld), n: grouped(info.nWorld) })} {info.rankRegion != null && c.region ? · {t('explorer.rank.region', { rank: ordinal(info.rankRegion), region: regionShort(c.region) ?? c.region })} : null}

) : null} {info.series.length >= 2 ? (
{t('explorer.drawer.history', { y0: info.firstYear ?? '', y1: info.lastYear ?? '' })}
0 ? 'up' : dir < 0 ? 'down' : 'flat'} ariaLabel={t('explorer.drawer.sparkAria', { name: c.name ?? c.id, indicator: indicatorName })} />
{info.firstYear} {info.lastYear}
) : null}
{t('explorer.drawer.open')} {t('explorer.drawer.compare')} {t('explorer.drawer.trajectories')} {t('explorer.drawer.series')} →
); } /** Best-effort topic for the country topic page link (falls back to the indicator page when unknown). */ function topicOf(slug: string): string { return TOPIC_HINT[slug] ?? 'economy'; } const TOPIC_HINT: Record = { population: 'population', 'population-growth': 'population', 'median-age': 'population', 'fertility-rate': 'population', 'urban-population-share': 'population', gdp: 'economy', 'gdp-per-capita': 'economy', 'gdp-per-capita-ppp': 'economy', 'gdp-growth': 'economy', inflation: 'economy', 'unemployment-rate': 'labor', 'life-expectancy': 'health', 'infant-mortality-rate': 'health', 'general-government-gross-debt-pct-gdp': 'government', 'co2-per-capita': 'climate', 'co2-emissions': 'climate', 'renewable-electricity-share': 'energy', 'energy-use-per-capita': 'energy', 'internet-users': 'digital', };