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%
3.7 KB · 71 lines tsx
Raw Blame History
1import Link from "next/link";2import { cx } from "@/lib/format";3import type { CoverageSummary } from "@/lib/types";45/** Source Redundancy block (server component). Numbers come from the coverage engine, never hard-coded. */6export function RedundancyPanel({ coverage: c, className, prominent }: { coverage: CoverageSummary; className?: string; prominent?: boolean }) {7  const f = c.byFamilies;8  const bars: Array<[string, number, string]> = [9    ["≥ 5 sources", f[">=5"], "bg-positive"],10    ["≥ 3", f[">=3"] - f[">=5"], "bg-accent"],11    ["2", f[">=2"] - f[">=3"], "bg-warning"],12    ["single source", f["1"], "bg-stale"],13  ];14  const pct = (n: number) => (c.quoted ? (n / c.quoted) * 100 : 0);15  const tierA = c.tiers.A;16  return (17    <div className={cx("rounded-md border border-rule bg-surface p-4", className)}>18      <div className="flex items-baseline justify-between gap-3">19        <h3 className="text-[11px] font-medium uppercase tracking-wide text-ink-3">Source redundancy</h3>20        <Link href="/coverage" className="text-xs text-accent hover:underline">21          Source coverage →22        </Link>23      </div>24      <div className={cx("mt-1 flex flex-wrap items-baseline gap-x-2", prominent && "gap-x-3")}>25        <span className={cx("mono font-semibold tnum", prominent ? "text-3xl" : "text-2xl")}>{c.multiSource}</span>26        <span className="text-sm text-ink-2">27          of <span className="mono tnum">{c.quoted}</span> quoted instruments observed through ≥ 2 independent source families28        </span>29      </div>30      <div className="mt-3 flex h-2 overflow-hidden rounded-full bg-surface-3" aria-hidden>31        {bars.map(([label, n, cls]) => (n > 0 ? <span key={label} className={cls} style={{ width: `${pct(n)}%` }} title={`${n} ${label}`} /> : null))}32      </div>33      <div className="mt-2 grid grid-cols-2 gap-x-4 gap-y-1 text-[11.5px] sm:grid-cols-4">34        {bars.map(([label, n, cls]) => (35          <span key={label} className="inline-flex items-center gap-1.5 text-ink-2">36            <span className={cx("inline-block h-1.5 w-1.5 rounded-full", cls)} />37            <span className="mono tnum">{n}</span> {label}38          </span>39        ))}40      </div>41      <div className="mt-3 border-t border-rule pt-3">42        <div className="flex items-baseline justify-between text-xs">43          <span className="text-ink-3">Weighted redundancy score</span>44          <span className="mono tnum font-medium">{c.weightedScore.toFixed(1)}%</span>45        </div>46        <div className="mt-1 h-1.5 overflow-hidden rounded-full bg-surface-3">47          <span className="block h-full rounded-full bg-accent" style={{ width: `${Math.min(100, c.weightedScore)}%` }} />48        </div>49        <dl className="mt-2 grid grid-cols-2 gap-x-4 text-xs">50          <Row k="Tier A majors covered" v={`${tierA.covered} / ${tierA.instruments}`} sub={`${tierA.attainment.toFixed(0)}% · target ≥ 3 families`} />51          <Row k="Tier B liquid covered" v={`${c.tiers.B.covered} / ${c.tiers.B.instruments}`} sub={`${c.tiers.B.attainment.toFixed(0)}% · target ≥ 2 families`} />52          <Row k="Proxies confirming" v={`${c.proxiesConfirming}`} sub="stablecoin markets, crosses" />53          <Row k="Validators confirming" v={`${c.validatorsConfirming}`} sub="restricted-rights cross-checks" />54        </dl>55      </div>56    </div>57  );58}5960function Row({ k, v, sub }: { k: string; v: string; sub?: string }) {61  return (62    <div className="border-b border-rule py-1">63      <div className="flex items-baseline justify-between">64        <dt className="text-ink-3">{k}</dt>65        <dd className="mono tnum">{v}</dd>66      </div>67      {sub && <div className="text-[10.5px] text-ink-3">{sub}</div>}68    </div>69  );70}71