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 <noreply@anthropic.com>
This commit is contained in:
2026-04-23 21:41:57 -04:00
parent e76e94a635
commit 435586388e
+5 -8
View File
@@ -845,10 +845,10 @@ document.addEventListener('DOMContentLoaded', () => {
} }
// After a pill removal, offer an inline "Blocklist this everywhere" button. // After a pill removal, offer an inline "Blocklist this everywhere" button.
// Fades after 8s; click escalates to blocklist (same endpoint + Celery sweep // Persists until the user dismisses it (×), escalates (⊘), or navigates
// as the suggestion chip's ⊘ button). Covers the case where you remove a // away (image switch / modal close). No time-based auto-fade — the user's
// WD14 composition descriptor (e.g. '1girl', 'breasts') from this image and // explicit attention is worth more than the small layout cost of keeping
// realize you also don't want it anywhere else. // the bar visible.
function showBlocklistOffer(name) { function showBlocklistOffer(name) {
const offer = document.getElementById('blocklistOffer'); const offer = document.getElementById('blocklistOffer');
if (!offer) return; if (!offer) return;
@@ -863,9 +863,6 @@ document.addEventListener('DOMContentLoaded', () => {
offer.setAttribute('aria-hidden', 'false'); offer.setAttribute('aria-hidden', 'false');
btn.disabled = false; btn.disabled = false;
clearTimeout(offer._fadeTimeout);
offer._fadeTimeout = setTimeout(() => hideBlocklistOffer(), 8000);
btn.onclick = async () => { btn.onclick = async () => {
btn.disabled = true; btn.disabled = true;
try { try {
@@ -877,6 +874,7 @@ document.addEventListener('DOMContentLoaded', () => {
const j = await r.json(); const j = await r.json();
if (j.ok) { if (j.ok) {
label.textContent = `Blocklisted '${name}'. Cleanup task enqueued.`; label.textContent = `Blocklisted '${name}'. Cleanup task enqueued.`;
// Short delay so the user sees the confirmation before it closes.
setTimeout(() => hideBlocklistOffer(), 2500); setTimeout(() => hideBlocklistOffer(), 2500);
} else { } else {
label.textContent = `Couldn't blocklist: ${j.error || 'error'}`; label.textContent = `Couldn't blocklist: ${j.error || 'error'}`;
@@ -896,7 +894,6 @@ document.addEventListener('DOMContentLoaded', () => {
if (!offer) return; if (!offer) return;
offer.classList.remove('visible'); offer.classList.remove('visible');
offer.setAttribute('aria-hidden', 'true'); offer.setAttribute('aria-hidden', 'true');
clearTimeout(offer._fadeTimeout);
} }
// --------------------------- // ---------------------------