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.3 KB · 52 lines tsx
Raw Blame History
1'use client';2import Link from 'next/link';3import { usePathname } from 'next/navigation';4import { useEffect, useRef } from 'react';5import { t } from '@/i18n';6import { cn } from '@/lib/cn';7import { routes } from '@/lib/site';8import { TOPICS } from '@/lib/topics';910/**11 * Topic navigation for a country: horizontally scrollable chips on mobile, sticky sub-nav on desktop.12 * The active chip scrolls into view on mount. Counts (optional) show indicators with data per topic.13 */14export function TopicNav({ slug, counts, sticky = true, className }: { slug: string; counts?: Record<string, number>; sticky?: boolean; className?: string }) {15  const pathname = usePathname();16  const ref = useRef<HTMLElement>(null);17  useEffect(() => {18    const el = ref.current?.querySelector<HTMLElement>('[aria-current="page"]');19    if (el) el.scrollIntoView({ block: 'nearest', inline: 'center', behavior: 'instant' as ScrollBehavior });20  }, [pathname]);21  const items = [{ id: '', short: t('country.overview'), href: routes.country(slug) }, ...TOPICS.map((tp) => ({ id: tp.id, short: tp.short, href: routes.countryTopic(slug, tp.id) }))];22  return (23    <nav24      ref={ref}25      aria-label={t('country.topics.title', { name: '' }).trim()}26      className={cn(sticky && 'sticky top-[52px] z-20 md:top-[56px]', '-mx-4 border-b border-rule bg-paper/95 backdrop-blur supports-[backdrop-filter]:bg-paper/85 sm:-mx-6', className)}27    >28      <ul className="scrollbar-none flex snap-x gap-1 overflow-x-auto px-4 py-1 sm:px-6 md:py-1.5">29        {items.map((it) => {30          const active = pathname === it.href;31          const n = it.id ? counts?.[it.id] : undefined;32          return (33            <li key={it.href} className="snap-start">34              <Link35                href={it.href}36                aria-current={active ? 'page' : undefined}37                className={cn(38                  'inline-flex h-11 items-center gap-1.5 whitespace-nowrap rounded-sm px-3 text-sm md:h-9 md:px-2.5',39                  active ? 'bg-ink text-paper' : 'text-ink-2 hover:bg-surface-2 hover:text-ink',40                )}41              >42                {it.short}43                {n != null ? <span className={cn('tnum text-2xs', active ? 'text-paper/70' : 'text-ink-3')}>{n}</span> : null}44              </Link>45            </li>46          );47        })}48      </ul>49    </nav>50  );51}52