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.6 KB · 58 lines tsx
Raw Blame History
1import Link from "next/link";2import { RelativeTime } from "@/components/ui/freshness";3import { StatusBadge } from "@/components/ui/status-badge";4import { cx, EVENT_TYPE_LABEL, instrumentHref } from "@/lib/format";5import type { MarketEvent } from "@/lib/types";67const TYPE_TONE: Record<string, string> = {8  TRADING_HALT: "text-negative",9  SCHEMA_DRIFT: "text-negative",10  SOURCE_FAILURE: "text-warning",11  SOURCE_DIVERGENCE: "text-warning",12  VOLATILITY_SPIKE: "text-warning",13  MARKET_OPEN: "text-positive",14  TRADING_RESUME: "text-positive",15  SOURCE_RECOVERY: "text-positive",16  FILING_PUBLISHED: "text-accent",17  DOCUMENT_CHANGED: "text-accent",18};1920export function EventRow({ e, dense, className }: { e: MarketEvent; dense?: boolean; className?: string }) {21  const first = e.instruments?.[0];22  const url = typeof e.data?.url === "string" ? (e.data.url as string) : null;23  return (24    <li className={cx("flex gap-3 border-b border-rule py-2.5 last:border-0", dense && "py-1.5", className)}>25      <div className="w-[76px] shrink-0 pt-0.5 text-right">26        <RelativeTime value={e.timestamp} className="mono text-[11px] text-ink-3" />27      </div>28      <div className="min-w-0 flex-1">29        <div className="flex flex-wrap items-center gap-x-2 gap-y-1">30          <span className={cx("text-[10.5px] font-medium uppercase tracking-wide", TYPE_TONE[e.type] ?? "text-ink-3")}>{EVENT_TYPE_LABEL[e.type] ?? e.type.replace(/_/g, " ").toLowerCase()}</span>31          {(e.severity === "WARNING" || e.severity === "CRITICAL") && <StatusBadge status={e.severity} />}32          {first?.symbol && (33            <Link href={instrumentHref(first.id)} className="mono text-xs font-medium text-accent hover:underline">34              {first.symbol}35            </Link>36          )}37        </div>38        <Link href={`/events/${e.id}`} className="mt-0.5 block text-sm leading-snug hover:underline">39          {e.title}40        </Link>41        {!dense && e.summary && <div className="mt-0.5 truncate text-xs text-ink-3">{e.summary}</div>}42        <div className="mt-0.5 flex flex-wrap items-center gap-x-3 text-[11px] text-ink-3">43          <span>44            {e.source_count} source{e.source_count === 1 ? "" : "s"}45            {e.sources?.length ? ` · ${e.sources.slice(0, 3).join(", ")}` : ""}46          </span>47          <span className="mono">confidence {Math.round(e.confidence * 100)}%</span>48          {url && (49            <a href={url} target="_blank" rel="noopener noreferrer" className="text-accent hover:underline">50              document ↗51            </a>52          )}53        </div>54      </div>55    </li>56  );57}58