explodorama / files / src / ui / toast.ts
toast.ts
| 1 | /** |
| 2 | * A toast (user request, 2026-11-01): a short note over the board that fades by itself, for what |
| 3 | * the player got when no dialog explains it (a charge picked up for the second time in a run; the |
| 4 | * icons in the top bar are small). One at a time; a new one replaces the one showing. |
| 5 | */ |
| 6 | const SHOW_MS = 2200 |
| 7 | |
| 8 | let el: HTMLElement | null = null |
| 9 | let timer = 0 |
| 10 | |
| 11 | /** |
| 12 | * What a charge pickup says: `n` picked up, and the total held when that is more (2 held and 3 |
| 13 | * picked up: "Picked up 3 × Nuke", "5 charges in all"; user request, 2026-11-01). |
| 14 | */ |
| 15 | export function chargeToast(name: string, n: number, total: number): { title: string; text: string } { |
| 16 | return { title: n > 1 ? `Picked up ${n} × ${name}` : `Picked up ${name}`, text: total > n ? `${total} charges in all` : '' } |
| 17 | } |
| 18 | |
| 19 | export function showToast(icon: string, title: string, text: string): void { |
| 20 | if (!el) { |
| 21 | el = document.createElement('div') |
| 22 | el.id = 'toast' |
| 23 | el.setAttribute('role', 'status') |
| 24 | // In the top layer, so it also shows over a dialog (the almanac's samples). |
| 25 | el.popover = 'manual' |
| 26 | document.body.append(el) |
| 27 | } |
| 28 | el.innerHTML = `<img src="${icon}" alt="" draggable="false"><div><strong>${title}</strong>${text ? `<span>${text}</span>` : ''}</div>` |
| 29 | el.classList.remove('show') |
| 30 | if (!el.matches(':popover-open')) el.showPopover?.() |
| 31 | // Restarts the fade when one replaces another. |
| 32 | void el.offsetWidth |
| 33 | el.classList.add('show') |
| 34 | window.clearTimeout(timer) |
| 35 | timer = window.setTimeout(() => { |
| 36 | el?.classList.remove('show') |
| 37 | // Hidden once the fade is done. |
| 38 | window.setTimeout(() => !el?.classList.contains('show') && el?.hidePopover?.(), 300) |
| 39 | }, SHOW_MS) |
| 40 | } |