spb/datacenterindex
Public
HTML 53.9%
TypeScript 44.5%
JavaScript 0.6%
SQL 0.5%
1import type { ReactNode } from "react";2import { cn } from "@/components/ui/cn";34export interface KvItem {5 label: ReactNode;6 value: ReactNode;7 /** hide the row when the value is unknown (default) or show “—” */8 keepEmpty?: boolean;9}1011/**12 * Compact definition list for entity facts (address, tier, cooling, website…). Rows with null / undefined / "" / "—"13 * values are dropped unless `keepEmpty`, so pages never show a wall of dashes.14 */15export function KeyValueList({ items, className, columns = 1 }: { items: KvItem[]; className?: string; columns?: 1 | 2 }) {16 const rows = items.filter((it) => it.keepEmpty || (it.value !== null && it.value !== undefined && it.value !== "" && it.value !== "—"));17 if (!rows.length) return null;18 return (19 <dl className={cn("grid gap-x-6", columns === 2 ? "sm:grid-cols-2" : "", className)}>20 {rows.map((it, i) => (21 <div key={i} className="grid grid-cols-[minmax(96px,120px)_minmax(0,1fr)] gap-x-3 border-b border-hair py-2 text-[13px] last:border-b-0 sm:grid-cols-[minmax(120px,160px)_minmax(0,1fr)]">22 <dt className="text-[12px] text-ink-3">{it.label}</dt>23 <dd className="min-w-0 break-words text-ink">{it.value ?? <span className="text-ink-4">—</span>}</dd>24 </div>25 ))}26 </dl>27 );28}2930/** Honest placeholder for a section whose data the source does not publish. */31export function NotPublished({ what, className }: { what: string; className?: string }) {32 return <p className={cn("rounded-sm border border-dashed border-hair-2 px-3 py-2.5 text-[12.5px] text-ink-3", className)}>{what} — not published by the sources indexed so far.</p>;33}3435/** External link with safe rel and host-only label by default. */36export function ExtLink({ href, children, className }: { href: string; children?: ReactNode; className?: string }) {37 let label: ReactNode = children;38 if (!label) {39 try {40 label = new URL(href).host.replace(/^www\./, "");41 } catch {42 label = href;43 }44 }45 return (46 <a href={href} target="_blank" rel="noopener noreferrer" className={cn("break-all text-ink underline decoration-hair-2 underline-offset-2 hover:text-accent", className)}>47 {label}48 </a>49 );50}51