spb/datacenterindex
Public
HTML 53.9%
TypeScript 44.5%
JavaScript 0.6%
SQL 0.5%
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