| |
| |
| |
| |
| |
| |
| |
| import { G } from "./state.js"; |
| import { sfx } from "./audio.js"; |
|
|
| let dismiss = null; |
|
|
| function escapeHtml(s) { |
| return String(s).replace(/[&<>"']/g, (c) => ({ |
| "&": "&", "<": "<", ">": ">", '"': """, "'": "'" }[c])); |
| } |
|
|
| export function isOpen() { |
| const el = G.els.comic; |
| return !!(el && !el.classList.contains("hidden")); |
| } |
|
|
| |
| |
| export function showComic(imageB64, caption, onDone) { |
| if (!imageB64) { onDone && onDone(); return; } |
| const el = G.els.comic; |
| const cap = caption && caption.trim() |
| ? `<div class="comic-caption">${escapeHtml(caption.trim())}</div>` : ""; |
| el.innerHTML = ` |
| <div class="comic-frame"> |
| ${cap} |
| <img class="comic-img" alt="" src="data:image/png;base64,${imageB64}"> |
| <div class="comic-hint">CLICK or SPACE ▶</div> |
| </div>`; |
| el.classList.remove("hidden"); |
| requestAnimationFrame(() => el.classList.add("comic-in")); |
| sfx.comic(); |
|
|
| let done = false; |
| const timer = setTimeout(() => dismiss && dismiss(), 7000); |
| dismiss = () => { |
| if (done) return; |
| done = true; |
| clearTimeout(timer); |
| el.classList.remove("comic-in"); |
| el.classList.add("hidden"); |
| el.innerHTML = ""; |
| el.removeEventListener("click", dismiss); |
| dismiss = null; |
| onDone && onDone(); |
| }; |
| el.addEventListener("click", dismiss); |
| } |
|
|
| |
| export function dismissComic() { |
| if (dismiss) { dismiss(); return true; } |
| return false; |
| } |
|
|