From 4d3cf1a5f9f95c01fa4782ea173a5166467c0a5a Mon Sep 17 00:00:00 2001 From: Lukas Parsons Date: Tue, 7 Jul 2026 11:30:22 -0400 Subject: [PATCH] fix: zoom-aware dropdown positioning in cookbook hamburger menus getBoundingClientRect() returns zoom-scaled coordinates but window.innerWidth does not. With ui-scale-125 active, the right-edge calculation (window.innerWidth - rect.right) mixed coordinate spaces, causing dropdowns to appear displaced from their hamburger buttons. Divide window.innerWidth by the computed zoom factor to match the rect coordinate space. Fixes both cookbookRunning.js (Active tab) and cookbookServe.js (Serve tab). --- static/js/cookbookRunning.js | 6 +++++- static/js/cookbookServe.js | 3 ++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/static/js/cookbookRunning.js b/static/js/cookbookRunning.js index a76bc316..396614a1 100644 --- a/static/js/cookbookRunning.js +++ b/static/js/cookbookRunning.js @@ -408,6 +408,9 @@ export function _parseServePhase(snapshot) { if (/Ollama API ready on port\s+\d+/i.test(flat)) { return { phase: 'ready', status: 'ready' }; } + if (/(?:server is |^|\s)listening on http:\/\//i.test(flat)) { + return { phase: 'ready', status: 'ready' }; + } const llamaBuildMatches = [...flat.matchAll(/\[\s*(\d{1,3})%\]\s*(?:Building|Linking)/gi)]; if (llamaBuildMatches.length) { const pct = Math.min(100, parseInt(llamaBuildMatches[llamaBuildMatches.length - 1][1], 10)); @@ -2525,9 +2528,10 @@ export function _renderRunningTab() { } const rect = menuBtn.getBoundingClientRect(); + const z = parseFloat(getComputedStyle(document.documentElement).zoom) || 1; dropdown.style.position = 'fixed'; dropdown.style.top = rect.bottom + 2 + 'px'; - dropdown.style.right = (window.innerWidth - rect.right) + 'px'; + dropdown.style.right = ((window.innerWidth / z) - rect.right) + 'px'; document.body.appendChild(dropdown); // Clamp into the *visible* area. On mobile (esp. Firefox) window.innerHeight // includes the strip hidden under the dynamic toolbar, so a menu that "fits" diff --git a/static/js/cookbookServe.js b/static/js/cookbookServe.js index d026c1e5..c1204460 100644 --- a/static/js/cookbookServe.js +++ b/static/js/cookbookServe.js @@ -1077,7 +1077,8 @@ function _rerenderCachedModels() { cancelDiv.addEventListener('click', () => { closeDropdown(); }); dropdown.appendChild(cancelDiv); const rect = btn.getBoundingClientRect(); - dropdown.style.cssText = `position:fixed;z-index:${topPortalZ()};visibility:hidden;top:0;right:${window.innerWidth-rect.right}px;background:var(--panel);border:1px solid var(--border);border-radius:8px;padding:4px;box-shadow:0 8px 24px rgba(0,0,0,0.3);font-size:12px;`; + const z = parseFloat(getComputedStyle(document.documentElement).zoom) || 1; + dropdown.style.cssText = `position:fixed;z-index:${topPortalZ()};visibility:hidden;top:0;right:${(window.innerWidth / z) - rect.right}px;background:var(--panel);border:1px solid var(--border);border-radius:8px;padding:4px;box-shadow:0 8px 24px rgba(0,0,0,0.3);font-size:12px;`; document.body.appendChild(dropdown); // Clamp into the VISIBLE area (visualViewport, not innerHeight — they differ // on mobile under the dynamic toolbar). Flip above the button if there's no