206 lines
6.6 KiB
JavaScript
206 lines
6.6 KiB
JavaScript
(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 = `
|
|
<div class="toast-icon">${iconFor(type)}</div>
|
|
<div class="toast-body">
|
|
<div class="toast-title">${escapeHtml(title)}</div>
|
|
<div class="toast-msg">${escapeHtml(message)}</div>
|
|
</div>
|
|
<button class="toast-x" aria-label="Close">✕</button>
|
|
`;
|
|
|
|
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);
|
|
});
|
|
})();
|