spb/countryatlas
Public
TypeScript 57%
Python 38.6%
JavaScript 3.6%
CSS 0.6%
1import { t } from '@/i18n';2import type { CompareState } from '@/lib/compare-state';3import type { CompareSeries, CompareSnapshotRow, CountryLite } from '@/lib/types-compare';4import { subtopicAnchor } from '@/lib/anchors';5import { CollapsibleGroup, SubtopicJumpNav } from '@/components/data/collapsible-group';6import { CompareChart } from './compare-chart';7import { SnapshotCompact } from './snapshot-table';89/** Above this many charts a topic tab is split into collapsible subtopic blocks (first one expanded). */10const SECTION_THRESHOLD = 8;1112export function ChartGrid({ rows, countries, state, eager, maxYear }: { rows: CompareSnapshotRow[]; countries: CountryLite[]; state: CompareState; eager: Map<string, CompareSeries[]>; maxYear: number }) {13 return (14 <div className="grid gap-x-10 gap-y-8 lg:grid-cols-2">15 {rows.map((row) => (16 <CompareChart key={row.indicator.slug} indicator={row.indicator} countries={countries} state={state} initial={eager.get(row.indicator.slug)} snapshot={row.values} maxYear={maxYear} />17 ))}18 </div>19 );20}2122/** Group rows by `indicator.subtopic`, preserving first-seen order. */23export function groupBySubtopic<T extends { indicator: { subtopic: string | null } }>(rows: T[]): Array<{ subtopic: string; rows: T[] }> {24 const m = new Map<string, T[]>();25 for (const r of rows) {26 const k = r.indicator.subtopic ?? t('common.other');27 const cur = m.get(k);28 if (cur) cur.push(r);29 else m.set(k, [r]);30 }31 return Array.from(m, ([subtopic, rs]) => ({ subtopic, rows: rs }));32}3334/**35 * Charts of a compare topic tab. Short tabs → plain grid. Long tabs (> 8 charts, ≥ 2 subtopics) → a jump nav +36 * one CollapsibleGroup per subtopic: the first expanded (charts), the others collapsed showing the latest37 * values inline (SnapshotCompact) so nothing is hidden, just deferred. Charts still lazy-mount on scroll.38 */39export function ChartSections({ rows, countries, slugs, state, eager, maxYear, anchorPrefix }: { rows: CompareSnapshotRow[]; countries: CountryLite[]; slugs: string[]; state: CompareState; eager: Map<string, CompareSeries[]>; maxYear: number; anchorPrefix: string }) {40 const groups = groupBySubtopic(rows);41 if (rows.length <= SECTION_THRESHOLD || groups.length < 2) return <ChartGrid rows={rows} countries={countries} state={state} eager={eager} maxYear={maxYear} />;42 const items = groups.map((g) => ({ id: subtopicAnchor(anchorPrefix, g.subtopic), label: g.subtopic, count: g.rows.length }));43 return (44 <div className="min-w-0">45 <SubtopicJumpNav items={items} label={t('topic.jump')} className="mb-2" />46 {groups.map((g, i) => (47 <CollapsibleGroup key={g.subtopic} id={items[i]!.id} title={g.subtopic} count={g.rows.length} defaultOpen={i === 0} summary={<SnapshotCompact rows={g.rows} countries={countries} slugs={slugs} state={state} />}>48 <ChartGrid rows={g.rows} countries={countries} state={state} eager={eager} maxYear={maxYear} />49 </CollapsibleGroup>50 ))}51 </div>52 );53}54