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%
4.1 KB · 95 lines tsx
Raw Blame History
1import Link from 'next/link';2import { t } from '@/i18n';3import { formatDate } from '@/lib/format';4import { routes } from '@/lib/site';5import { Logo } from '@/components/brand/Logo';67/**8 * Site footer: explore/reference link columns, licence note, credits ("Made by … · contact", "Hosted on MacLustr").9 * `builtAt`/`runId` (optional) come from the API `meta` of the page that renders it. Reuse `<FooterCredits />`10 * on /sources and /api pages for the contact line.11 */12export function SiteFooter({ builtAt, runId }: { builtAt?: string | null; runId?: string | null }) {13  const explore = [14    { href: routes.explore(), label: t('nav.explore') },15    { href: routes.countries(), label: t('nav.countries') },16    { href: routes.compare(), label: t('nav.compare') },17    { href: routes.rankings(), label: t('nav.rankings') },18    { href: routes.indicators(), label: t('nav.indicators') },19    { href: routes.regions(), label: t('nav.regions') },20    { href: routes.changes(), label: t('site.footer.changes') },21    { href: routes.trajectories(), label: t('nav.trajectories') },22    { href: routes.scatter(), label: t('nav.scatter') },23    { href: routes.finder(), label: t('nav.finder') },24    { href: routes.extremes(), label: t('nav.extremes') },25    { href: routes.stories(), label: t('nav.stories') },26  ];27  const reference = [28    { href: routes.sources(), label: t('site.footer.sources') },29    { href: routes.methodology(), label: t('site.footer.methodology') },30    { href: routes.api(), label: t('site.footer.api') },31    { href: routes.download(), label: t('site.footer.data') },32    { href: routes.updates(), label: t('nav.updates') },33    { href: routes.peers(), label: t('nav.peers') },34  ];35  return (36    <footer className="mt-16 border-t border-rule bg-surface-2/40 text-sm">37      <div className="container-x mx-auto max-w-[1400px] py-10">38        <div className="grid gap-8 md:grid-cols-[1.4fr_1.2fr_1fr]">39          <div className="max-w-md">40            <Logo variant="full" />41            <p className="mt-3 text-ink-2">{t('site.tagline')}</p>42            <p className="mt-3 text-xs leading-relaxed text-ink-3">{t('site.licence')}</p>43            {builtAt ? (44              <p className="tnum mt-3 text-xs text-ink-3">45                {t('site.footer.refreshed', { date: formatDate(builtAt) })}46                {runId ? ` · ${t('site.footer.build', { run: runId })}` : ''}47              </p>48            ) : null}49          </div>50          <FooterColumn title={t('site.footer.explore')} items={explore} />51          <FooterColumn title={t('site.footer.reference')} items={reference} />52        </div>53        <div className="mt-8 flex flex-col gap-2 border-t border-rule pt-5 text-xs text-ink-2 md:flex-row md:items-center md:justify-between">54          <FooterCredits />55          <p className="text-ink-3">{t('site.footer.made')}</p>56        </div>57      </div>58    </footer>59  );60}6162function FooterColumn({ title, items }: { title: string; items: Array<{ href: string; label: string }> }) {63  return (64    <div>65      <div className="eyebrow mb-2">{title}</div>66      <ul className="grid grid-cols-2 gap-x-4 gap-y-1 sm:grid-cols-1">67        {items.map((it) => (68          <li key={it.href}>69            <Link href={it.href} className="inline-flex min-h-[44px] items-center text-ink-2 hover:text-accent md:min-h-[32px]">70              {it.label}71            </Link>72          </li>73        ))}74      </ul>75    </div>76  );77}7879/** "Made by Simon-Pierre Boucher · contact@spboucher.ai" + "Hosted on MacLustr". */80export function FooterCredits({ className }: { className?: string }) {81  return (82    <p className={className}>83      {t('site.footer.madeBy')} <span className="text-ink">{t('site.footer.author')}</span> ·{' '}84      <a href={`mailto:${t('site.footer.contact')}`} className="text-accent hover:underline">85        {t('site.footer.contact')}86      </a>87      <span className="mx-2 text-ink-3">·</span>88      {t('site.footer.hostedOn')}{' '}89      <a href="https://www.maclustr.io" target="_blank" rel="noopener noreferrer" className="text-accent hover:underline">90        {t('site.footer.host')}91      </a>92    </p>93  );94}95