mirror of
https://github.com/ipnet-mesh/meshcore-hub.git
synced 2026-08-06 17:02:59 +02:00
fix(web): path-node popover follows page scroll
The popover used position: fixed with viewport-relative coordinates, so it stayed pinned to the viewport while the page scrolled away beneath it. Switch to absolute positioning anchored to the document (adding scrollX/scrollY) and read the badge's live rect on each reposition so it tracks the anchor after the async node fetch resolves. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -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`<div class="p-3">${loading()}</div>`), 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) {
|
||||
</a></li>` : nothing}
|
||||
</ul>`;
|
||||
litRender(popoverShell(ph, body), popoverEl);
|
||||
positionPopover(rect);
|
||||
positionPopover(badgeEl);
|
||||
} catch (err) {
|
||||
if (isAbortError(err) || !popoverEl) return;
|
||||
litRender(popoverShell(ph, html`<div class="p-3">${warningBadge(err.message)}</div>`), popoverEl);
|
||||
positionPopover(rect);
|
||||
positionPopover(badgeEl);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user