dr-sandbox/app/web/static/run-modal.js
Michael Pilosov bdbebaa7e8 compare: click to pin a point's highlight; hover temporarily overrides
Click a point in any panel to pin its id — highlight persists after the
cursor leaves, across all linked panels. Click the same pinned point (or
empty space) to unpin. Hover still shows the point under the cursor,
briefly overriding the pinned display. Canvas cursor is now crosshair to
hint at the interaction.
2026-04-22 17:00:29 -06:00

70 lines
2.5 KiB
JavaScript

// run-modal.js — homepage click-hijack for embedding links. Opens a
// <dialog id="run-modal"> that renders the run's embedding via panel-grid.js.
import { mountPanels } from './panel-grid.js?v=5';
const dialog = document.getElementById('run-modal');
const host = document.getElementById('modal-panel-host');
const controls = document.getElementById('modal-compare-controls');
const closeBtn = document.getElementById('run-modal-close');
const runsSlot = document.getElementById('runs-slot');
let active = null; // { destroy } returned by mountPanels
function openFor(stem) {
if (!dialog || !host || !controls) return;
if (active) { try { active.destroy(); } catch (_) {} active = null; }
active = mountPanels({ host, controls, stems: [stem] });
if (typeof dialog.showModal === 'function') dialog.showModal();
else dialog.setAttribute('open', '');
}
function closeModal() {
if (!dialog) return;
if (dialog.open) dialog.close();
if (active) { try { active.destroy(); } catch (_) {} active = null; }
}
function onRunsClick(ev) {
if (ev.defaultPrevented) return;
if (ev.button !== undefined && ev.button !== 0) return;
if (ev.metaKey || ev.ctrlKey || ev.shiftKey || ev.altKey) return;
const a = ev.target.closest('a[data-role="embedding-link"]');
if (!a) return;
if (!runsSlot || !runsSlot.contains(a)) return;
const stem = a.dataset.stem;
if (!stem) return;
ev.preventDefault();
openFor(stem);
}
function wire() {
if (!dialog) return;
if (runsSlot) runsSlot.addEventListener('click', onRunsClick);
if (closeBtn) closeBtn.addEventListener('click', closeModal);
dialog.addEventListener('close', () => {
if (active) { try { active.destroy(); } catch (_) {} active = null; }
});
// Clicking the backdrop (native behavior fires a click on the dialog
// itself, with target === dialog) closes the modal.
dialog.addEventListener('click', (ev) => {
if (ev.target === dialog) closeModal();
});
}
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', wire);
} else {
wire();
}
// htmx re-renders #runs-slot every 3s. Delegation on #runs-slot survives the
// swap (the slot element itself is stable), so we don't need to re-bind —
// but we keep the hook in case a consumer ever replaces the slot wholesale.
document.body.addEventListener('htmx:afterSwap', (ev) => {
if (ev.detail?.target?.id === 'runs-slot' && runsSlot && !runsSlot._runModalWired) {
runsSlot.addEventListener('click', onRunsClick);
runsSlot._runModalWired = true;
}
});