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