// uiComponents.jsx — shared UI atoms const PnLValue = ({ value, size = 'md' }) => { if (value == null) return React.createElement('span', { style: { color: 'var(--muted)', fontFamily: 'JetBrains Mono, monospace' } }, '—'); const isPos = value >= 0; const color = isPos ? '#00d27a' : '#f04060'; const sizes = { sm: '12px', md: '14px', lg: '18px', xl: '24px', xxl: '32px' }; return React.createElement('span', { style: { color, fontFamily: 'JetBrains Mono, monospace', fontSize: sizes[size] || sizes.md, fontWeight: 500 } }, fmtPnL(value)); }; const RValue = ({ value }) => { if (value == null) return React.createElement('span', { style: { color: 'var(--muted)', fontFamily: 'JetBrains Mono, monospace' } }, '—'); const isPos = value >= 0; const color = isPos ? '#00d27a' : '#f04060'; return React.createElement('span', { style: { color, fontFamily: 'JetBrains Mono, monospace', fontSize: '13px', fontWeight: 500 } }, fmtR(value)); }; const Badge = ({ children, color = 'default', size = 'sm' }) => { const palettes = { default: { bg: 'var(--border)', text: 'var(--text2)', border: '#283060' }, green: { bg: 'rgba(0,210,122,0.10)', text: '#00d27a', border: 'rgba(0,210,122,0.25)' }, red: { bg: 'rgba(240,64,96,0.10)', text: '#f04060', border: 'rgba(240,64,96,0.25)' }, blue: { bg: 'rgba(85,136,255,0.10)', text: '#5588ff', border: 'rgba(85,136,255,0.25)' }, yellow: { bg: 'rgba(255,184,63,0.10)', text: '#ffb83f', border: 'rgba(255,184,63,0.25)' }, purple: { bg: 'rgba(160,100,255,0.10)', text: '#a064ff', border: 'rgba(160,100,255,0.25)' }, }; const p = palettes[color] || palettes.default; return React.createElement('span', { style: { display: 'inline-flex', alignItems: 'center', background: p.bg, color: p.text, border: `1px solid ${p.border}`, borderRadius: '4px', padding: size === 'sm' ? '2px 7px' : '4px 10px', fontSize: size === 'sm' ? '11px' : '12px', fontWeight: 500, letterSpacing: '0.02em', whiteSpace: 'nowrap' } }, children); }; const DirectionBadge = ({ direction }) => React.createElement(Badge, { color: direction === 'long' ? 'green' : 'red' }, direction.toUpperCase()); const TypeBadge = ({ type, optionType, strategy }) => { if (type === 'stock') return React.createElement(Badge, { color: 'blue' }, 'STOCK'); if (!strategy || strategy === 'single') { const label = optionType === 'call' ? 'CALL' : 'PUT'; const color = optionType === 'call' ? 'green' : 'red'; return React.createElement(Badge, { color }, `OPT ${label}`); } const strat = OPTION_STRATEGIES.find(s => s.id === strategy); const shortLabel = strat ? strat.shortLabel : 'COMBO'; return React.createElement(Badge, { color: 'purple' }, shortLabel); }; const StatusDot = ({ status }) => { const color = status === 'open' ? '#ffb83f' : status === 'closed' ? '#5588ff' : 'var(--muted)'; const label = status === 'open' ? 'Open' : 'Closed'; return React.createElement('span', { style: { display: 'inline-flex', alignItems: 'center', gap: '5px', fontSize: '12px', color: 'var(--text2)' } }, [ React.createElement('span', { key: 'dot', style: { width: '6px', height: '6px', borderRadius: '50%', background: color, boxShadow: status === 'open' ? `0 0 6px ${color}` : 'none' } }), label ]); }; const SignalTag = ({ label, active, onClick }) => React.createElement('button', { onClick, style: { background: active ? 'rgba(85,136,255,0.15)' : 'rgba(30,36,64,0.5)', color: active ? '#5588ff' : 'var(--muted)', border: `1px solid ${active ? 'rgba(85,136,255,0.4)' : 'var(--border)'}`, borderRadius: '4px', padding: '3px 9px', fontSize: '12px', cursor: 'pointer', fontFamily: 'Space Grotesk, sans-serif', transition: 'all 0.15s' } }, label); const SymbolCell = ({ symbol }) => React.createElement('span', { style: { fontFamily: 'JetBrains Mono, monospace', fontWeight: 600, fontSize: '13px', color: 'var(--text)', letterSpacing: '0.04em' } }, symbol); const StatCard = ({ label, value, sub, accent, icon }) => { const accentColors = { green: '#00d27a', red: '#f04060', blue: '#5588ff', yellow: '#ffb83f', default: '#5588ff' }; const ac = accentColors[accent] || accentColors.default; return React.createElement('div', { style: { background: 'var(--surface)', border: '1px solid var(--border)', borderRadius: '10px', padding: '20px 22px', display: 'flex', flexDirection: 'column', gap: '8px', borderTop: `2px solid ${ac}`, flex: 1 } }, [ React.createElement('div', { key: 'label', style: { fontSize: '11px', color: 'var(--muted)', fontWeight: 600, textTransform: 'uppercase', letterSpacing: '0.08em' } }, label), React.createElement('div', { key: 'value', style: { fontSize: '28px', fontWeight: 700, color: 'var(--text)', fontFamily: 'JetBrains Mono, monospace', lineHeight: 1 } }, value), sub && React.createElement('div', { key: 'sub', style: { fontSize: '12px', color: 'var(--muted)' } }, sub) ]); }; // Simple SVG sparkline const Sparkline = ({ data, width = 80, height = 28, color = '#5588ff' }) => { if (!data || data.length < 2) return null; const min = Math.min(...data); const max = Math.max(...data); const range = max - min || 1; const pts = data.map((v, i) => { const x = (i / (data.length - 1)) * width; const y = height - ((v - min) / range) * height; return `${x},${y}`; }).join(' '); return React.createElement('svg', { width, height, style: { overflow: 'visible' } }, [ React.createElement('polyline', { key: 'line', points: pts, fill: 'none', stroke: color, strokeWidth: 1.5, strokeLinejoin: 'round' }) ]); }; const LabelBadge = ({ label }) => React.createElement('span', { style: { display: 'inline-flex', alignItems: 'center', background: 'rgba(255,184,63,0.10)', color: '#ffb83f', border: '1px solid rgba(255,184,63,0.25)', borderRadius: '4px', padding: '2px 7px', fontSize: '11px', fontWeight: 500, letterSpacing: '0.02em', whiteSpace: 'nowrap' } }, label); const LabelTag = ({ label, active, onClick }) => React.createElement('button', { onClick, style: { background: active ? 'rgba(255,184,63,0.15)' : 'rgba(30,36,64,0.5)', color: active ? '#ffb83f' : 'var(--muted)', border: `1px solid ${active ? 'rgba(255,184,63,0.4)' : 'var(--border)'}`, borderRadius: '4px', padding: '3px 9px', fontSize: '12px', cursor: 'pointer', fontFamily: 'Space Grotesk, sans-serif', transition: 'all 0.15s' } }, label); const Divider = () => React.createElement('div', { style: { height: '1px', background: 'var(--border)', margin: '0 -1px' } }); const EmptyState = ({ message = 'No data' }) => React.createElement('div', { style: { display: 'flex', flexDirection: 'column', alignItems: 'center', justifyContent: 'center', padding: '60px 20px', color: 'var(--muted)', gap: '8px' } }, [ React.createElement('div', { key: 'icon', style: { fontSize: '32px', opacity: 0.3 } }, '◈'), React.createElement('div', { key: 'msg', style: { fontSize: '14px' } }, message) ]); Object.assign(window, { PnLValue, RValue, Badge, DirectionBadge, TypeBadge, StatusDot, SignalTag, LabelTag, LabelBadge, SymbolCell, StatCard, Sparkline, Divider, EmptyState });