From 666b64e748ee2ce7bcf0e885625fb1ed438818e3 Mon Sep 17 00:00:00 2001 From: Fredrik Johansson Date: Sat, 1 Aug 2026 22:23:42 +0200 Subject: [PATCH] Modals close on Escape, not just the X button MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Characters modal was missing an Escape handler entirely (click-outside already worked). Consolidated the Escape handling into one listener that closes whichever overlay is topmost — lightbox first, then characters, then help — so dismissing the lightbox with Escape doesn't also close the characters modal underneath it. Deliberately left the event-choice modal alone: that one represents a decision with real game consequences, not just a "look at content" overlay, so it should require an explicit choice rather than being dismissible. Verified via headless browser: Escape and click-outside both close help, characters, and the lightbox correctly, with the lightbox/ characters layering behaving as expected. Co-Authored-By: Claude Sonnet 5 --- src/ui.ts | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/ui.ts b/src/ui.ts index 98270ed..5c0b3a1 100644 --- a/src/ui.ts +++ b/src/ui.ts @@ -212,7 +212,7 @@ export function initUI( document.getElementById('help-btn')!.addEventListener('click', () => helpModal.classList.toggle('visible')); document.getElementById('help-close')!.addEventListener('click', () => helpModal.classList.remove('visible')); helpModal.addEventListener('click', (e) => { if (!helpInner.contains(e.target as Node)) helpModal.classList.remove('visible'); }); - document.addEventListener('keydown', (e) => { if (e.key === '?' || (e.key === 'Escape' && helpModal.classList.contains('visible'))) helpModal.classList.toggle('visible'); }); + document.addEventListener('keydown', (e) => { if (e.key === '?') helpModal.classList.toggle('visible'); }); const charactersModal = document.getElementById('characters-modal')!; const charactersInner = document.getElementById('characters-modal-inner')!; @@ -252,7 +252,16 @@ export function initUI( }); document.getElementById('lightbox-close')!.addEventListener('click', () => lightbox.classList.remove('visible')); lightbox.addEventListener('click', (e) => { if (e.target === lightbox) lightbox.classList.remove('visible'); }); - document.addEventListener('keydown', (e) => { if (e.key === 'Escape') lightbox.classList.remove('visible'); }); + + // Escape closes whichever overlay is topmost — lightbox sits on top of + // the characters modal, which can sit on top of help, so check in that + // order and stop at the first one actually open. + document.addEventListener('keydown', (e) => { + if (e.key !== 'Escape') return; + if (lightbox.classList.contains('visible')) { lightbox.classList.remove('visible'); return; } + if (charactersModal.classList.contains('visible')) { charactersModal.classList.remove('visible'); return; } + if (helpModal.classList.contains('visible')) { helpModal.classList.remove('visible'); return; } + }); // Split the map container: map on top, log below const mapContainer = document.getElementById('map-container')!;