SPB Git forge

spb/market-atlas

Public
12commits 1branches 0releases
1.1 MBsize
maindefault branch
10 days agolast push
TypeScript 96.7% SQL 1.6% CSS 0.8% JavaScript 0.5%
2.6 KB · 50 lines tsx
Raw Blame History
1import type { Metadata } from "next";2import Link from "next/link";3import { Page, PageHeader, Section } from "@/components/ui/section";4import { StatusBadge } from "@/components/ui/status-badge";5import { api } from "@/lib/api";6import type { Country } from "@/lib/types";78type Row = Country & { exchanges: Array<{ id: string; name: string; status: string }>; instruments_tracked: number };910export const metadata: Metadata = { title: "Countries", description: "Market atlas by country: exchanges, indices, rates and currencies observed by Market Atlas.", alternates: { canonical: "/countries" } };11export const dynamic = "force-dynamic";1213export default async function CountriesPage() {14  const rows = await api<Row[]>("/v1/countries");15  const regions = [...new Set(rows.map((r) => r.region))].sort();16  return (17    <Page wide>18      <PageHeader kicker="World" title="Countries" lead="Every country in the atlas with its venues and what Market Atlas currently tracks there. Coverage is a measure of Market Atlas observation, not of market size." />19      {regions.map((region) => (20        <Section key={region} title={region}>21          <ul className="grid grid-cols-1 [&>*]:min-w-0 gap-2 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4">22            {rows23              .filter((r) => r.region === region)24              .sort((a, b) => b.instruments_tracked - a.instruments_tracked || a.name.localeCompare(b.name))25              .map((r) => (26                <li key={r.code} className="rounded-md border border-rule bg-surface px-3 py-2.5 hover:border-rule-strong">27                  <Link href={`/countries/${r.code}`} className="flex items-baseline justify-between gap-2">28                    <span className="font-medium">{r.name}</span>29                    <span className="mono text-xs text-ink-3">30                      {r.code} · {r.currency ?? "—"}31                    </span>32                  </Link>33                  <div className="mt-1 flex flex-wrap items-center gap-1.5 text-[11px] text-ink-3">34                    {r.exchanges.slice(0, 3).map((e) => (35                      <span key={e.id} className="inline-flex items-center gap-1">36                        <StatusBadge status={e.status} label={e.status.toLowerCase()} /> {e.name}37                      </span>38                    ))}39                    {!r.exchanges.length && <span>no venue in the atlas</span>}40                  </div>41                  <div className="mono mt-1 text-[11px] text-ink-3">{r.instruments_tracked.toLocaleString("en-US")} instruments tracked</div>42                </li>43              ))}44          </ul>45        </Section>46      ))}47    </Page>48  );49}50