fuzzyworld

explodorama / files / src / ui / toast.ts

toast.ts

1.6 KB · history · blame

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 */
6const SHOW_MS = 2200
7
8let el: HTMLElement | null = null
9let 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 */
15export 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
19export 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}