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); } // ---------------------------