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%
2.2 KB · 40 lines tsx
Raw Blame History
1"use client";23import Link from "next/link";4import { cx, formatClock, formatPercent, formatQuoteValue, instrumentHref } from "@/lib/format";5import { useMarketStream, useTape } from "@/lib/stream";6import { toneOf } from "@/components/ui/price";78/** Live tape: latest canonical price changes across everything the stream publishes (channel `tape`). */9export function LiveTape({ rows = 24, className }: { rows?: number; className?: string }) {10  const state = useMarketStream(["tape"]);11  const tape = useTape(rows);12  return (13    <div className={cx("mono overflow-hidden rounded-md border border-rule bg-surface text-[12px]", className)}>14      <div className="flex items-center justify-between border-b border-rule px-3 py-1.5 text-[10.5px] uppercase tracking-wide text-ink-3">15        <span>Live tape · canonical price changes</span>16        <span className={cx("inline-flex items-center gap-1.5", state === "open" ? "text-positive" : "text-warning")}>17          <span className={cx("inline-block h-1.5 w-1.5 rounded-full", state === "open" ? "bg-positive live-dot" : "bg-warning")} />18          {state === "open" ? "streaming" : state}19        </span>20      </div>21      {tape.length === 0 && <div className="px-3 py-6 text-center text-ink-3">Waiting for the first ticks…</div>}22      <ul className="max-h-[420px] overflow-y-auto">23        {tape.map((q, i) => (24          <li key={`${q.instrument_id}-${q.received}-${i}`} className={cx("flex items-center gap-3 border-b border-rule px-3 py-1 last:border-0", i === 0 && "bg-surface-2")}>25            <span className="w-[86px] shrink-0 text-ink-3" suppressHydrationWarning>26              {formatClock(q.timestamp)}27            </span>28            <Link href={instrumentHref(q.instrument_id)} className="w-[84px] shrink-0 truncate font-medium hover:text-accent">29              {q.symbol}30            </Link>31            <span className="flex-1 text-right tnum">{formatQuoteValue(q.price, undefined, q.currency)}</span>32            <span className={cx("w-[72px] shrink-0 text-right tnum", toneOf(q.change_pct))}>{formatPercent(q.change_pct)}</span>33            <span className="hidden w-12 shrink-0 text-right text-ink-3 sm:inline">{q.sources} src</span>34          </li>35        ))}36      </ul>37    </div>38  );39}40