(function(){ const host = document.getElementById("toastHost"); function iconFor(type){ if(type === "success") return "✅"; if(type === "error") return "⛔"; if(type === "info") return "🛰️"; return "🔔"; } window.toast = function(type="info", title="Notice", message="", ttl=3200){ if(!host) return; const el = document.createElement("div"); el.className = `toast toast-${type}`; el.innerHTML = `
${iconFor(type)}
${escapeHtml(title)}
${escapeHtml(message)}
`; const remove = () => { el.classList.add("out"); el.addEventListener("animationend", () => el.remove(), { once:true }); }; el.querySelector(".toast-x").addEventListener("click", remove); host.appendChild(el); if (ttl > 0) setTimeout(remove, ttl); }; function escapeHtml(s){ return String(s ?? "") .replaceAll("&","&") .replaceAll("<","<") .replaceAll(">",">") .replaceAll('"',""") .replaceAll("'","'"); } // Notifications dropdown (tiny JS) const notif = document.getElementById("notifPanel"); window.toggleNotif = function(){ if(!notif) return; const isHidden = notif.hasAttribute("hidden"); if(isHidden) notif.removeAttribute("hidden"); else notif.setAttribute("hidden",""); }; document.addEventListener("click", (e)=>{ if(!notif) return; const btn = e.target.closest(".iconbtn"); const inside = e.target.closest("#notifPanel"); if(inside || btn) return; notif.setAttribute("hidden",""); }); // Settings helpers: perf + alertpulse (no cookies) function setStorage(key, val, remember){ try{ if (remember) { localStorage.setItem(key, val); sessionStorage.removeItem(key); } else { sessionStorage.setItem(key, val); localStorage.removeItem(key); } }catch(e){} } function applyDataset(key, val){ document.documentElement.dataset[key] = val; if (key === "perf") { const label = document.getElementById("perfLabel"); if(label) label.textContent = val.toUpperCase(); } } window.applyPerfFromUI = function(){ const chosen = document.querySelector(".seg-btn.is-selected[data-perf]")?.dataset.perf; const remember = document.getElementById("rememberPerf")?.checked; const val = chosen || "auto"; setStorage("perf", val, remember); applyDataset("perf", val); toast("success","Performance", `Profil: ${val.toUpperCase()}`, 2200); if (val === "low") toast("info","Hint","Low deaktiviert Starfield", 1800); }; window.applyPulseFromUI = function(){ const chosen = document.querySelector(".seg-btn.is-selected[data-alertpulse]")?.dataset.alertpulse; const remember = document.getElementById("rememberPulse")?.checked; const val = chosen || "burst"; setStorage("alertpulse", val, remember); applyDataset("alertpulse", val); toast("success","Alerts", `Pulse: ${val.toUpperCase()}`, 2200); }; // Segment button selection behavior document.addEventListener("click", (e)=>{ const b = e.target.closest(".seg-btn"); if(!b) return; const parent = b.closest(".seg"); if(parent){ parent.querySelectorAll(".seg-btn").forEach(x=>x.classList.remove("is-selected")); b.classList.add("is-selected"); } }); // Pre-select in settings pages document.addEventListener("DOMContentLoaded", ()=>{ const perf = document.documentElement.dataset.perf || "auto"; document.querySelectorAll('.seg-btn[data-perf]').forEach(b=>{ if(b.dataset.perf === perf) b.classList.add("is-selected"); }); const pulse = document.documentElement.dataset.alertpulse || "burst"; document.querySelectorAll('.seg-btn[data-alertpulse]').forEach(b=>{ if(b.dataset.alertpulse === pulse) b.classList.add("is-selected"); }); }); function formatNumber(val){ const num = Number.isFinite(val) ? val : 0; return Math.round(num).toLocaleString("de-DE"); } const resourceMap = { "Metall": "metal", "Kristall": "crystals", "Deuterium": "deuterium", "Energie": "energy" }; function updateResourceBar(state){ const stats = document.querySelectorAll(".resource-row .stat"); stats.forEach((stat)=>{ const label = stat.querySelector(".stat-k")?.textContent?.trim(); const key = resourceMap[label]; if(!key) return; const value = state?.resources?.[key]; if(typeof value !== "number") return; const valueEl = stat.querySelector(".stat-v"); if(!valueEl) return; const dot = valueEl.querySelector(".dot"); const display = key === "energy" ? Math.round(value) : Math.floor(value); const prefix = key === "energy" && display >= 0 ? "+" : ""; valueEl.textContent = ""; if(dot) valueEl.appendChild(dot); valueEl.appendChild(document.createTextNode(` ${prefix}${formatNumber(display)}`)); }); } async function fetchState(){ try{ const res = await fetch("/api/state"); if(!res.ok) return null; return await res.json(); }catch(e){ return null; } } async function refreshState(){ const state = await fetchState(); if(state) updateResourceBar(state); } function ensureBuildButton(){ const content = document.getElementById("content"); if(!content || document.getElementById("buildOreMine")) return; const wrap = document.createElement("div"); wrap.className = "actions"; const btn = document.createElement("button"); btn.className = "btn btn-primary"; btn.id = "buildOreMine"; btn.type = "button"; btn.textContent = "Erzmine bauen"; btn.addEventListener("click", async ()=>{ try{ const res = await fetch("/api/build/start", { method: "POST", headers: {"Content-Type":"application/json"}, body: JSON.stringify({building_key:"ore_mine", amount:1}) }); const data = await res.json(); if(res.ok){ toast("success","Bau gestartet","Erzmine in Queue gelegt"); updateResourceBar({resources: data.resources}); }else{ toast("error","Bau fehlgeschlagen", data.message || "Aktion nicht möglich"); } }catch(e){ toast("error","Netzwerk","API nicht erreichbar"); } }); wrap.appendChild(btn); content.appendChild(wrap); } document.addEventListener("DOMContentLoaded", ()=>{ refreshState(); ensureBuildButton(); setInterval(refreshState, 30000); }); })();