[object Object]

← back to Wallco Ai

color-dots: bind dot strips + Save toolbar only to VISIBLE images (isVisible gate)

6c667735b3da2b2f1e5305b229328421d02f04ef · 2026-06-02 08:58:45 -0700 · Steve Abrams

Test surfaced that the toolbar could attach to a hidden modal image (edit-modal
preview / colorway-fullscreen), rendering the Save pill invisible. clientWidth
alone missed display:none-ancestor/opacity:0/visibility:hidden cases. New
isVisible() checks computed display/visibility/opacity + offsetParent + rect
size. Verified headless: save pill now visible + a real (non-forced) click saves.

Files touched

Diff

commit 6c667735b3da2b2f1e5305b229328421d02f04ef
Author: Steve Abrams <steve@designerwallcoverings.com>
Date:   Tue Jun 2 08:58:45 2026 -0700

    color-dots: bind dot strips + Save toolbar only to VISIBLE images (isVisible gate)
    
    Test surfaced that the toolbar could attach to a hidden modal image (edit-modal
    preview / colorway-fullscreen), rendering the Save pill invisible. clientWidth
    alone missed display:none-ancestor/opacity:0/visibility:hidden cases. New
    isVisible() checks computed display/visibility/opacity + offsetParent + rect
    size. Verified headless: save pill now visible + a real (non-forced) click saves.
---
 public/js/color-dots.js | 14 +++++++++++++-
 1 file changed, 13 insertions(+), 1 deletion(-)

diff --git a/public/js/color-dots.js b/public/js/color-dots.js
index 3a545c1..c609013 100644
--- a/public/js/color-dots.js
+++ b/public/js/color-dots.js
@@ -139,10 +139,22 @@
     sw.style.background = hex(curRGB[0], curRGB[1], curRGB[2]);
   }
 
+  // Visible = laid out, on-screen-sized, not inside a display:none / hidden /
+  // opacity:0 modal. clientWidth alone missed the edit-modal preview img and the
+  // colorway-fullscreen img, so the 💾 Save toolbar could bind to a HIDDEN host
+  // and render invisibly. offsetParent===null catches a display:none ancestor.
+  function isVisible(el) {
+    if (!el) return false;
+    var cs = getComputedStyle(el);
+    if (cs.display === 'none' || cs.visibility === 'hidden' || parseFloat(cs.opacity || '1') < 0.05) return false;
+    if (el.offsetParent === null && cs.position !== 'fixed') return false;
+    var r = el.getBoundingClientRect();
+    return r.width >= MIN_W && r.height >= 8;
+  }
   function addDots(img) {
     if (img.dataset.cdDone) return;
     if ((img.naturalWidth || 0) < 8) return;
-    if ((img.clientWidth || img.width || 0) < MIN_W) return;
+    if (!isVisible(img)) return;
     var st = buildState(img); if (!st) return;
     img.dataset.cdDone = '1'; state.set(img, st);
     var host = img.parentElement; if (!host) return;

← bc1d6d8 hires: cache TIF-lookup HITS only, never misses  ·  back to Wallco Ai  ·  Add nightly TIF backfill cron wrapper (cron-build-tifs.sh) bce674c →