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.1 KB · 41 lines tsx
Raw Blame History
1import { t } from '@/i18n';2import { cn } from '@/lib/cn';3import { MAP_HEIGHT, MAP_WIDTH, isoLookupFromCountries, worldPaths } from '@/lib/map-geo';4import type { CountrySummary } from '@/lib/types';56/**7 * Server-rendered world map highlighting a group's members (accent) against the other countries (surface-2).8 * Static SVG — no hover layer needed, the members table below carries the detail.9 */10export function MemberMap({ members, countries, name, className }: { members: string[]; countries: CountrySummary[]; name: string; className?: string }) {11  const { paths, sphere } = worldPaths();12  const numeric = isoLookupFromCountries(countries as Array<{ id: string; iso_numeric?: string | null }>);13  const set = new Set(members);14  const summary = t('region.map.summary', { n: members.length, name });15  return (16    <figure className={cn('min-w-0', className)}>17      <div className="relative w-full" style={{ aspectRatio: `${MAP_WIDTH} / ${MAP_HEIGHT}` }}>18        <svg viewBox={`0 0 ${MAP_WIDTH} ${MAP_HEIGHT}`} className="h-full w-full" role="img" aria-label={summary}>19          <title>{summary}</title>20          <path d={sphere} fill="var(--surface)" stroke="var(--rule)" strokeWidth={1} />21          <g stroke="var(--surface)" strokeWidth={0.6} strokeLinejoin="round">22            {paths.map((p, i) => {23              const iso3 = p.iso3 ?? (p.numeric ? numeric.get(p.numeric) ?? null : null);24              const on = iso3 ? set.has(iso3) : false;25              return <path key={iso3 ?? `${p.name}-${i}`} d={p.d} fill={on ? 'var(--accent)' : 'var(--nodata)'} fillOpacity={on ? 0.9 : 0.55} />;26            })}27          </g>28        </svg>29      </div>30      <figcaption className="mt-2 flex flex-wrap items-center gap-x-3 text-2xs text-ink-2">31        <span className="inline-flex items-center gap-1">32          <span aria-hidden className="inline-block h-2.5 w-3.5 rounded-xs bg-accent" /> {name}33        </span>34        <span className="inline-flex items-center gap-1">35          <span aria-hidden className="inline-block h-2.5 w-3.5 rounded-xs bg-nodata" /> {t('chart.legend.noData')}36        </span>37      </figcaption>38    </figure>39  );40}41