SPB Git

spb/rareindex

Public
2.4 KB · 49 lines tsx
1import Link from 'next/link';2import type { IndexRow } from '@/lib/queries/indices';3import { fmtNum, cn, fmtPct, deltaClass } from '@/lib/format';45/**6 * Live tape (§163): a terminal-style ticker of the indices. Published indices show value + daily change;7 * indices still building show their constituent progress. Pauses on hover/focus; static under reduced motion.8 */9export function IndexTape({ indices, className }: { indices: IndexRow[]; className?: string }) {10  if (!indices.length) return null;11  const ordered = [...indices].sort((a, b) => Number(Boolean(b.latest)) - Number(Boolean(a.latest)) || (a.isFlagship ? -1 : 0) - (b.isFlagship ? -1 : 0));12  const items = ordered.map((i) => {13    const up = (i.change1d ?? 0) > 0;14    const down = (i.change1d ?? 0) < 0;15    return (16      <Link key={i.ticker} href={`/rareindex/${i.ticker}`} className="mono-num flex h-9 shrink-0 items-center gap-2.5 border-r border-border px-4 text-[12px] hover:bg-inset" aria-label={`${i.ticker}${i.latest ? ` ${fmtNum(i.latest.value, { digits: 2 })} ${fmtPct(i.change1d)}` : ' building'}`}>17        <span className="inline-block h-2 w-2 rounded-[2px]" style={{ background: i.color ?? 'var(--ri-index)' }} aria-hidden />18        <span className="font-semibold tracking-wide text-fg">{i.ticker}</span>19        {i.latest ? (20          <>21            <span className="text-muted">{fmtNum(i.latest.value, { digits: 2 })}</span>22            <span className={cn('font-medium', deltaClass(i.change1d))}>23              {up ? '▲' : down ? '▼' : '■'} {fmtPct(i.change1d)}24            </span>25          </>26        ) : (27          <span className="text-subtle">28            building {i.pricedAssets}/{i.minConstituents}29          </span>30        )}31      </Link>32    );33  });34  return (35    <div className={cn('relative overflow-hidden border-y border-border bg-elevated', className)} aria-label="Index tape" role="marquee">36      <div className="pointer-events-none absolute inset-y-0 left-0 z-10 w-8 bg-gradient-to-r from-elevated to-transparent" aria-hidden />37      <div className="pointer-events-none absolute inset-y-0 right-0 z-10 w-8 bg-gradient-to-l from-elevated to-transparent" aria-hidden />38      <div className="tape-track flex w-max">39        {items}40        {items.map((it, k) => (41          <span key={`dup-${k}`} aria-hidden className="contents">42            {it}43          </span>44        ))}45      </div>46    </div>47  );48}49
Files · d732f70ce5489245a263ca6bcf09fbebc0d2be77
Menu

Theme