From 435586388eb3c6f9da9ab6db15de4d36dfaf9e4e Mon Sep 17 00:00:00 2001 From: Bryan Van Deusen Date: Thu, 23 Apr 2026 21:41:57 -0400 Subject: [PATCH] fix(modal): blocklist offer persists until user acts or image changes Drops the 8s auto-fade on the post-removal blocklist offer. User complained it closed too fast to be useful. The offer is already bounded by image switch (hideBlocklistOffer in updateImage) and modal close (hideBlocklistOffer in closeModal), so time-based fade was belt-and-suspenders. Keeps the 2.5s delay after a successful blocklist so the confirmation text shows before hiding. Co-Authored-By: Claude Opus 4.7 --- app/static/js/view-modal.js | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/app/static/js/view-modal.js b/app/static/js/view-modal.js index 5a4ceff..16b9ba1 100644 --- a/app/static/js/view-modal.js +++ b/app/static/js/view-modal.js @@ -845,10 +845,10 @@ document.addEventListener('DOMContentLoaded', () => { } // After a pill removal, offer an inline "Blocklist this everywhere" button. - // Fades after 8s; click escalates to blocklist (same endpoint + Celery sweep - // as the suggestion chip's ⊘ button). Covers the case where you remove a - // WD14 composition descriptor (e.g. '1girl', 'breasts') from this image and - // realize you also don't want it anywhere else. + // Persists until the user dismisses it (×), escalates (⊘), or navigates + // away (image switch / modal close). No time-based auto-fade — the user's + // explicit attention is worth more than the small layout cost of keeping + // the bar visible. function showBlocklistOffer(name) { const offer = document.getElementById('blocklistOffer'); if (!offer) return; @@ -863,9 +863,6 @@ document.addEventListener('DOMContentLoaded', () => { offer.setAttribute('aria-hidden', 'false'); btn.disabled = false; - clearTimeout(offer._fadeTimeout); - offer._fadeTimeout = setTimeout(() => hideBlocklistOffer(), 8000); - btn.onclick = async () => { btn.disabled = true; try { @@ -877,6 +874,7 @@ document.addEventListener('DOMContentLoaded', () => { const j = await r.json(); if (j.ok) { label.textContent = `Blocklisted '${name}'. Cleanup task enqueued.`; + // Short delay so the user sees the confirmation before it closes. setTimeout(() => hideBlocklistOffer(), 2500); } else { label.textContent = `Couldn't blocklist: ${j.error || 'error'}`; @@ -896,7 +894,6 @@ document.addEventListener('DOMContentLoaded', () => { if (!offer) return; offer.classList.remove('visible'); offer.setAttribute('aria-hidden', 'true'); - clearTimeout(offer._fadeTimeout); } // ---------------------------