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.6 KB · 87 lines tsx
Raw Blame History
1import type { FacilitySummary } from "@dci/core";2import Link from "next/link";3import { AiMark, EstimateMark, StatusBadge } from "@/components/ui/badge";4import { CountryFlag } from "@/components/ui/country-flag";5import { RowLink, TBody, THead, Table, Td, Th, Tr } from "@/components/ui/table";6import { HonestEmpty } from "@/components/intelligence/shared";7import { bestMw, fmtMw } from "@/lib/format";8import { AI_EVIDENCE_LABEL } from "@/lib/labels";9import { routes } from "@/lib/routes";1011/** AI / HPC facilities with the evidence level per row (confirmed / likely / associated / unknown). */12export function AiFacilitiesTable({ items }: { items: FacilitySummary[] }) {13  if (!items.length) return <HonestEmpty title="No facility with AI evidence yet" detail="a site is listed only when a source describes it as AI / HPC / GPU infrastructure (confirmed or likely)" />;14  return (15    <Table dense mobileCollapse={{ total: items.length, label: "facilities" }}>16      <THead>17        <tr>18          <Th>Facility</Th>19          <Th className="hidden sm:table-cell">Operator</Th>20          <Th className="hidden md:table-cell">Market</Th>21          <Th>Country</Th>22          <Th>Status</Th>23          <Th numeric>Capacity</Th>24          <Th>Evidence</Th>25        </tr>26      </THead>27      <TBody>28        {items.map((f) => {29          const { mw, kind } = bestMw(f);30          const ev = f.aiEvidence ?? "unknown";31          return (32            <Tr key={f.id}>33              <Td primary>34                <RowLink href={routes.facility(f.slug)}>{f.name}</RowLink>35                <div className="text-[11.5px] text-ink-3 sm:hidden">{f.operator?.name ?? "Operator unknown"}</div>36              </Td>37              <Td label="Operator" className="hidden sm:table-cell">38                {f.operator ? (39                  <Link href={routes.operator(f.operator.slug)} className="text-ink-2 hover:text-ink hover:underline">40                    {f.operator.name}41                  </Link>42                ) : (43                  <span className="text-ink-4">—</span>44                )}45              </Td>46              <Td label="Market" className="hidden md:table-cell" muted>47                {f.metro ? (48                  <Link href={routes.market(f.metro.slug)} className="hover:text-ink hover:underline">49                    {f.metro.name}50                  </Link>51                ) : (52                  (f.city ?? "—")53                )}54              </Td>55              <Td label="Country">56                <CountryFlag iso2={f.countryIso2} withName className="max-w-[140px] text-ink-2" />57              </Td>58              <Td label="Status">59                <StatusBadge status={f.status} short size="xs" />60              </Td>61              <Td label="Capacity" numeric lead>62                {mw === null ? (63                  <span className="text-ink-4">—</span>64                ) : (65                  <span title={kind === "it" ? "IT capacity" : kind === "total" ? "Total power" : "Planned power"}>66                    {(f.mwIsEstimate || kind === "planned") && <EstimateMark className="mr-0.5" />}67                    {fmtMw(mw)}68                  </span>69                )}70              </Td>71              <Td label="Evidence">72                {ev === "unknown" ? (73                  <span className="text-[11.5px] text-ink-4" title={AI_EVIDENCE_LABEL.unknown}>74                    flagged AI · evidence level unknown75                  </span>76                ) : (77                  <AiMark evidence={ev} />78                )}79              </Td>80            </Tr>81          );82        })}83      </TBody>84    </Table>85  );86}87