// 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 (
);
};
const ToolDot = ({ tool }) => (
);
const ToolTag = ({ tool }) => (
{tool}
);
const HostTag = ({ host }) => {host};
const 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 (
{dim}
{opts.map(o => (
{ onPick(o); onClose(); }}>
{o}
))}
);
};
// 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 (
<>
{
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 && (
{ e.stopPropagation(); onRemove(); }}>×
)}
{open && 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 (
<>
{
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
{open && (
setOpen(false)}>
add filter
{availableDims.map(d => (
{ onAdd(d); setOpen(false); }}>
{d}
))}
)}
>
);
};
const Empty = ({ glyph = '∅', title, hint }) => (
{glyph}
{title}
{hint &&
{hint}
}
);
Object.assign(window, {
Spark, ToolDot, ToolTag, HostTag, StatusDot,
FilterPopover, FilterChip, AddFilterChip, Empty,
});