| 296 | } |
| 297 | |
| 298 | function OBRow({ level, side, maxCum }: { level: OrderBookLevel; side: "bid" | "ask"; maxCum: number }) { |
| 299 | const pct = maxCum > 0 ? (level.cumSize / maxCum) * 100 : 0; |
| 300 | const bid = side === "bid"; |
| 301 | return ( |
| 302 | <div className="ob-row flex items-center text-[10px] tabular-nums px-2 relative" style={{ height: 18 }}> |
| 303 | <div className="absolute inset-y-0 right-0" style={{ width: `${pct}%`, background: bid ? BID_BAR : ASK_BAR }} /> |
| 304 | <span className="w-[52px] font-medium relative z-[1]" style={{ color: bid ? BID_COLOR : ASK_COLOR }}> |
| 305 | {level.price.toFixed(3)} |
| 306 | </span> |
| 307 | <span className="w-[52px] text-right text-[var(--text-secondary)] relative z-[1]"> |
| 308 | {fmtK(level.size)} |
| 309 | </span> |
| 310 | <span className="flex-1 text-right text-[var(--text-dim)] text-[10px] relative z-[1]"> |
| 311 | {fmtK(level.cumSize)} |
| 312 | </span> |
| 313 | </div> |
| 314 | ); |
| 315 | } |
| 316 | |
| 317 | function fmtK(n: number): string { |
| 318 | if (n >= 1_000_000) return `${(n / 1_000_000).toFixed(1)}M`; |