SPB Git forge
38commits 1branches 0releases
338.7 MBsize
maindefault branch
6 h agolast push
HTML 53.9% TypeScript 44.5% JavaScript 0.6% SQL 0.5%
3.2 KB · 49 lines tsx
Raw Blame History
1import type { DashboardStats } from "@dci/core";2import Link from "next/link";3import { cn } from "@/components/ui/cn";4import { fmtInt, fmtPct, splitMw } from "@/lib/format";5import { routes } from "@/lib/routes";67interface Cell {8  label: string;9  value: string | null;10  unit?: string;11  caveat: string;12  href: string;13  accent?: boolean;14}1516/**17 * Global ticker (§16): FACILITIES · KNOWN OPERATIONAL CAPACITY · UNDER CONSTRUCTION · PROJECTS · COUNTRIES · NEW EVENTS 24 H.18 * Every figure carries its coverage caveat on the line below — totals are lower bounds computed from published figures.19 */20export function GlobalTicker({ stats, className }: { stats: DashboardStats | null; className?: string }) {21  const s = stats;22  const op = splitMw(s?.knownOperationalMw);23  const uc = splitMw(s?.constructionMw);24  const cells: Cell[] = [25    { label: "Facilities", value: s ? fmtInt(s.facilities) : null, caveat: s ? `${fmtInt(s.operational)} operational · ${fmtInt(s.metros)} markets` : "indexed records", href: routes.datacenters() },26    { label: "Known operational capacity", value: op?.value ?? null, unit: op?.unit ?? "MW", caveat: s ? `MW published for ${fmtPct(s.mwCoverage)} of facilities — lower bound` : "published figures only", href: routes.datacenters("has_mw=1&status=operational&sort=mw") },27    { label: "Under construction", value: uc?.value ?? null, unit: uc?.unit ?? "MW", caveat: s ? `${fmtInt(s.underConstruction)} facilities · published MW only` : "published MW only", href: routes.datacenters("status=under_construction"), accent: true },28    { label: "Projects", value: s ? fmtInt(s.projects) : null, caveat: s ? `${fmtInt(s.planned)} planned facilities` : "pipeline records", href: routes.projects() },29    { label: "Countries", value: s ? fmtInt(s.countries) : null, caveat: s ? `${fmtInt(s.operators)} operators` : "with ≥ 1 indexed facility", href: routes.countries() },30    { label: "New events · 24 h", value: s ? fmtInt(s.events24h) : null, caveat: s ? `${fmtInt(s.events7d)} in 7 days · deduplicated` : "detected changes", href: routes.live(), accent: true },31  ];32  return (33    <div className={cn("grid grid-cols-2 border-y border-hair sm:grid-cols-3 xl:grid-cols-6 [&>*]:min-w-0 max-sm:[&>*:nth-child(even)]:border-l max-sm:[&>*:nth-child(n+3)]:border-t sm:max-xl:[&>*:nth-child(n+4)]:border-t sm:max-xl:[&>*:not(:nth-child(3n+1))]:border-l xl:[&>*+*]:border-l [&>*]:border-hair", className)} aria-label="Global ticker">34      {cells.map((c) => (35        <Link key={c.label} href={c.href} className="group block px-3 py-3 hover:bg-surface-2/60 sm:px-4">36          <div className="label-caps mb-1 truncate">{c.label}</div>37          <div className="flex items-baseline gap-1 leading-none">38            <span className={cn("figure text-[22px] font-medium tracking-[-0.03em] sm:text-[26px]", c.value === null ? "text-ink-4" : c.accent ? "text-accent-ink group-hover:text-accent" : "text-ink group-hover:text-accent")}>{c.value ?? "—"}</span>39            {c.unit && c.value !== null && <span className="text-[12px] font-medium text-ink-3">{c.unit}</span>}40          </div>41          <div className="mt-1 truncate text-[11px] leading-tight text-ink-3" title={c.caveat}>42            {c.caveat}43          </div>44        </Link>45      ))}46    </div>47  );48}49