89 lines
2.9 KiB
TypeScript
89 lines
2.9 KiB
TypeScript
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 = "";
|
|
});
|
|
});
|