diff --git a/src/meshcore_hub/web/static/js/spa/pages/dashboard.js b/src/meshcore_hub/web/static/js/spa/pages/dashboard.js index 5e6110a..472a815 100644 --- a/src/meshcore_hub/web/static/js/spa/pages/dashboard.js +++ b/src/meshcore_hub/web/static/js/spa/pages/dashboard.js @@ -111,11 +111,11 @@ function renderChannelMessages(channelMessages, channelLabels) { `; } -/** Return a Tailwind grid-cols class for the given visible column count. */ +/** Return responsive Tailwind grid-cols classes for the given visible column count. */ function gridCols(count) { - if (count === 2) return 'md:grid-cols-2'; - if (count === 3) return 'md:grid-cols-3'; - if (count === 4) return 'md:grid-cols-4'; + if (count === 2) return 'sm:grid-cols-2'; + if (count === 3) return 'sm:grid-cols-2 lg:grid-cols-3'; + if (count === 4) return 'sm:grid-cols-2 lg:grid-cols-4'; return ''; } diff --git a/src/meshcore_hub/web/static/js/spa/pages/packet-group-detail.js b/src/meshcore_hub/web/static/js/spa/pages/packet-group-detail.js index 1044c48..2bb76f2 100644 --- a/src/meshcore_hub/web/static/js/spa/pages/packet-group-detail.js +++ b/src/meshcore_hub/web/static/js/spa/pages/packet-group-detail.js @@ -126,8 +126,9 @@ export async function render(container, params, router) { return tagName || n.name || truncateKey(n.public_key, 12); } - function positionPopover(rect) { + function positionPopover(badgeEl) { if (!popoverEl) return; + const rect = badgeEl.getBoundingClientRect(); const margin = 8; const pw = popoverEl.offsetWidth || 256; const ph = popoverEl.offsetHeight || 0; @@ -137,8 +138,9 @@ export async function render(container, params, router) { if (top + ph + margin > window.innerHeight && rect.top - ph - 4 > margin) { top = rect.top - ph - 4; } - popoverEl.style.left = `${left}px`; - popoverEl.style.top = `${top}px`; + // Anchor to the document (position: absolute) so the popover scrolls with the page. + popoverEl.style.left = `${left + window.scrollX}px`; + popoverEl.style.top = `${top + window.scrollY}px`; } function popoverShell(hashLabel, body) { @@ -153,15 +155,15 @@ export async function render(container, params, router) { async function openPathPopover(e, ph) { e.preventDefault(); e.stopPropagation(); - const rect = e.currentTarget.getBoundingClientRect(); + const badgeEl = e.currentTarget; closePopover(); popoverEl = document.createElement('div'); - popoverEl.className = 'path-node-popover fixed z-[1000] w-64 max-w-[90vw] max-h-[60vh] overflow-y-auto bg-base-100 rounded-box shadow-lg border border-base-300'; + popoverEl.className = 'path-node-popover absolute z-[1000] w-64 max-w-[90vw] max-h-[60vh] overflow-y-auto bg-base-100 rounded-box shadow-lg border border-base-300'; document.body.appendChild(popoverEl); litRender(popoverShell(ph, html`
${loading()}
`), popoverEl); - positionPopover(rect); + positionPopover(badgeEl); const onDocClick = (ev) => { if (popoverEl && !popoverEl.contains(ev.target)) closePopover(); }; const onKey = (ev) => { if (ev.key === 'Escape') closePopover(); }; @@ -194,11 +196,11 @@ export async function render(container, params, router) { ` : nothing} `; litRender(popoverShell(ph, body), popoverEl); - positionPopover(rect); + positionPopover(badgeEl); } catch (err) { if (isAbortError(err) || !popoverEl) return; litRender(popoverShell(ph, html`
${warningBadge(err.message)}
`), popoverEl); - positionPopover(rect); + positionPopover(badgeEl); } }