// Atoms reused across screens
const Spark = ({ w = 60, h = 16, accent = false, seed = 1 }) => {
const pts = [];
let v = h * 0.5;
for (let i = 0; i < 14; i++) {
v += (Math.sin(seed * i * 1.7) + Math.cos(seed * i * 0.9)) * 2.5;
v = Math.max(2, Math.min(h - 2, v));
pts.push(`${(i / 13) * (typeof w === 'number' ? w : 100)},${v.toFixed(1)}`);
}
return (
<svg width={w} height={h} viewBox={`0 0 ${typeof w === 'number' ? w : 100} ${h}`}
preserveAspectRatio="none" style={{ display: 'block' }}>
<polyline points={pts.join(' ')} className={'spark' + (accent ? ' accent' : '')} />
</svg>
);
};
const ToolDot = ({ tool }) => (
<span className="tooldot" style={{ background: TOOL_COLORS[tool] || '#888' }} />
);
const ToolTag = ({ tool }) => (
<span className="tag"><ToolDot tool={tool} /> {tool}</span>
);
const HostTag = ({ host }) => <span className="tag host">{host}</span>;
const StatusDot = ({ status }) => <span className={'statusdot ' + status} />;
// Filter chip popover
const FilterPopover = ({ dim, value, onPick, onClose, anchor }) => {
const ref = React.useRef(null);
React.useEffect(() => {
const onDoc = (e) => { if (ref.current && !ref.current.contains(e.target)) onClose(); };
setTimeout(() => document.addEventListener('mousedown', onDoc), 0);
return () => document.removeEventListener('mousedown', onDoc);
}, [onClose]);
const opts = FILTER_DIMS[dim] || [];
const top = (anchor?.top || 30) + 4;
const left = anchor?.left || 14;
return (
<div ref={ref} className="popover" style={{ top, left }}>
<div className="ph">{dim}</div>
{opts.map(o => (
<div key={o} className="pi" onClick={() => { onPick(o); onClose(); }}>
<span style={{
width: 10, height: 10, borderRadius: 99,
border: '1px solid var(--ink-3)',
background: o === value ? 'var(--accent)' : 'transparent',
display: 'inline-block', flex: 'none'
}} />
<span className="mono">{o}</span>
</div>
))}
</div>
);
};
// Removable filter chip with click-through to popover
const FilterChip = ({ dim, value, onChange, onRemove }) => {
const [open, setOpen] = React.useState(false);
const [anchor, setAnchor] = React.useState(null);
const ref = React.useRef(null);
return (
<>
<span ref={ref} className={'tag click' + (value !== 'any' ? ' accent' : '')}
onClick={(e) => {
const r = ref.current.getBoundingClientRect();
const parent = ref.current.closest('.app').getBoundingClientRect();
setAnchor({ top: r.bottom - parent.top, left: r.left - parent.left });
setOpen(true);
}}>
{dim}: {value}
{onRemove && (
<span style={{ opacity: 0.6, marginLeft: 2 }}
onClick={(e) => { e.stopPropagation(); onRemove(); }}>×</span>
)}
</span>
{open && <FilterPopover dim={dim} value={value} anchor={anchor}
onPick={onChange} onClose={() => setOpen(false)} />}
</>
);
};
// Add-filter dashed chip + popover for which dim
const AddFilterChip = ({ availableDims, onAdd }) => {
const [open, setOpen] = React.useState(false);
const [anchor, setAnchor] = React.useState(null);
const ref = React.useRef(null);
return (
<>
<span ref={ref} className="tag dashed"
onClick={() => {
const r = ref.current.getBoundingClientRect();
const parent = ref.current.closest('.app').getBoundingClientRect();
setAnchor({ top: r.bottom - parent.top, left: r.left - parent.left });
setOpen(true);
}}>+ filter</span>
{open && (
<div className="popover" style={{ top: anchor.top + 4, left: anchor.left }}
onMouseLeave={() => setOpen(false)}>
<div className="ph">add filter</div>
{availableDims.map(d => (
<div key={d} className="pi" onClick={() => { onAdd(d); setOpen(false); }}>
<span className="mono">{d}</span>
</div>
))}
</div>
)}
</>
);
};
const Empty = ({ glyph = '∅', title, hint }) => (
<div className="empty">
<div className="glyph">{glyph}</div>
<div style={{ fontSize: 13, color: 'var(--ink-2)' }}>{title}</div>
{hint && <div style={{ marginTop: 4 }} className="muted mono">{hint}</div>}
</div>
);
Object.assign(window, {
Spark, ToolDot, ToolTag, HostTag, StatusDot,
FilterPopover, FilterChip, AddFilterChip, Empty,
});