spb/countryatlas
Public
TypeScript 57%
Python 38.6%
JavaScript 3.6%
CSS 0.6%
1import type { Metadata } from 'next';2import { t } from '@/i18n';3import { isNotBuilt, safe } from '@/lib/api';4import { apiCompare } from '@/lib/api-compare';5import { routes } from '@/lib/site';6import type { RankingRow } from '@/lib/types';7import { NotBuiltState } from '@/components/data/empty-state';8import { RankingsDirectory } from '@/components/rankings/rankings-directory';910export const revalidate = 900;1112export const metadata: Metadata = {13 title: t('rankings.metaTitle'),14 description: t('rankings.description', { n: 230 }),15 alternates: { canonical: routes.rankings() },16 openGraph: { title: `${t('rankings.metaTitle')} — ${t('site.name')}`, description: t('rankings.description', { n: 230 }), url: routes.rankings(), type: 'website' },17};1819/**20 * /rankings — every rankable indicator grouped by topic (featured first). Top-3 previews are fetched21 * server-side for the featured ones (≈ 27 requests, under the API's 120 req/min budget); the others load22 * client-side on scroll.23 */24export default async function RankingsPage() {25 let list;26 try {27 list = await apiCompare.rankings();28 } catch (e) {29 if (isNotBuilt(e)) return <NotBuiltState />;30 throw e;31 }32 const featured = list.items.filter((i) => i.featured).slice(0, 30);33 const tops = await Promise.all(featured.map((i) => safe(apiCompare.ranking(i.slug, { limit: 3, sparkline: false }))));34 const previews: Record<string, RankingRow[] | null> = {};35 featured.forEach((i, k) => {36 previews[i.slug] = tops[k]?.rows ?? null;37 });3839 return (40 <>41 <header className="pb-2 pt-6 md:pt-10">42 <h1 className="display text-3xl leading-tight text-ink md:text-5xl">{t('rankings.title')}</h1>43 <p className="mt-2 max-w-prose text-sm text-ink-2 md:text-base">{t('rankings.sub', { n: list.n })}</p>44 </header>45 <RankingsDirectory items={list.items} previews={previews} />46 </>47 );48}49