import "./styles/main.css"; import { getDB, initApp } from "./app"; import { initAudioOnInteraction, startAmbientSound, setAmbientMuted } from "./audio/sounds"; import { getSettings, saveSettings } from "./storage/db"; window.addEventListener("error", (event) => { console.error("Global error:", event.error); const overlay = document.getElementById("error-overlay"); if (overlay) overlay.style.display = "flex"; }); window.addEventListener("unhandledrejection", (event) => { console.error("Unhandled rejection:", event.reason); const overlay = document.getElementById("error-overlay"); if (overlay) overlay.style.display = "flex"; }); document.addEventListener("DOMContentLoaded", async () => { await initApp(); const db = getDB(); // Wire mute button const muteBtn = document.getElementById("mute-btn"); const muteIcon = document.getElementById("mute-icon"); if (muteBtn && muteIcon) { // Set initial state from settings const settings = await getSettings(db); const audioEnabled = settings?.audioEnabled !== false; muteIcon.textContent = audioEnabled ? "\u{1F50A}" : "\u{1F507}"; if (!audioEnabled) { muteBtn.classList.add("mute-btn--muted"); } muteBtn.onclick = async () => { // Initialize AudioContext on first click (autoplay policy) initAudioOnInteraction(); const current = await getSettings(db); const nowEnabled = !(current?.audioEnabled !== false); const updated = current ?? { id: 1 as const, audioEnabled: false, speechEnabled: false, apiKey: "", }; updated.audioEnabled = nowEnabled; await saveSettings(db, updated); muteIcon.textContent = nowEnabled ? "\u{1F50A}" : "\u{1F507}"; muteBtn.classList.toggle("mute-btn--muted", !nowEnabled); setAmbientMuted(!nowEnabled); }; } // Initialize AudioContext + ambient sound on first user interaction (autoplay policy D-02) const initAudioOnce = () => { initAudioOnInteraction(); startAmbientSound(); document.removeEventListener("click", initAudioOnce); document.removeEventListener("keydown", initAudioOnce); }; document.addEventListener("click", initAudioOnce); document.addEventListener("keydown", initAudioOnce); // Lightbox: click on forest/reward images to view fullscreen const lightbox = document.getElementById("image-lightbox")!; const lightboxImg = document.getElementById("lightbox-img") as HTMLImageElement; document.addEventListener("click", (e) => { const target = e.target as HTMLElement; // Open lightbox when clicking forest element or reward image if ( (target.tagName === "IMG" && target.closest(".forest__element")) || (target.tagName === "IMG" && target.closest(".reward__image-area")) ) { lightboxImg.src = (target as HTMLImageElement).src; lightboxImg.alt = (target as HTMLImageElement).alt; lightbox.style.display = "flex"; } }); // Close lightbox on click lightbox.addEventListener("click", () => { lightbox.style.display = "none"; lightboxImg.src = ""; }); });