spb/market-atlas
Public
TypeScript 96.7%
SQL 1.6%
CSS 0.8%
JavaScript 0.5%
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