diff --git a/public/app.js b/public/app.js index 00b9fd2..1fc115c 100755 --- a/public/app.js +++ b/public/app.js @@ -21,11 +21,13 @@ const loginBtn = document.getElementById("login-btn"); const loginSubmit = document.getElementById("login-submit"); const loginMsg = document.getElementById("login-msg"); const nav = document.getElementById("services"); +const estopBtn = document.getElementById("emergency-stop"); const usernameInput = document.getElementById("username"); const passwordInput = document.getElementById("password"); let loggedIn = false; +let armedPollInterval = null; // =========================== // Login anzeigen @@ -57,6 +59,8 @@ function switchToLogout() { // =========================== function performLocalLogout() { loggedIn = false; + stopArmedPolling(); + estopBtn.style.display = "none"; iframe.src = ""; iframe.style.display = "none"; nav.innerHTML = ""; @@ -64,6 +68,46 @@ function performLocalLogout() { switchToLogin(); } +// =========================== +// Armed-Status prüfen +// =========================== +async function updateArmedStatus() { + try { + const r = await fetch('https://robotDriver.server.schooltech.ch/api/power-status'); + if (r.ok) { + const data = await r.json(); + estopBtn.style.display = data.armed ? "block" : "none"; + } else { + estopBtn.style.display = "none"; + } + } catch (e) { + estopBtn.style.display = "none"; + } +} + +function startArmedPolling() { + updateArmedStatus(); + armedPollInterval = setInterval(updateArmedStatus, 5000); +} + +function stopArmedPolling() { + if (armedPollInterval) { + clearInterval(armedPollInterval); + armedPollInterval = null; + } +} + +// =========================== +// Emergency Stop +// =========================== +estopBtn.addEventListener("click", async () => { + try { + await fetch('https://robotDriver.server.schooltech.ch/api/emergency-stop', { method: 'POST' }); + } catch (e) { + console.error('E-Stop request failed:', e); + } +}); + // =========================== // Login-Logik // =========================== @@ -84,6 +128,7 @@ async function doLogin() { loginMsg.textContent = ""; setupServiceButtons(); switchToLogout(); + startArmedPolling(); } else { loginMsg.textContent = "Login fehlgeschlagen"; } @@ -156,6 +201,7 @@ function openService(svc) { loggedIn = true; setupServiceButtons(); switchToLogout(); + startArmedPolling(); } else { switchToLogin(); } diff --git a/public/index.html b/public/index.html index d1d024c..8bf96d3 100755 --- a/public/index.html +++ b/public/index.html @@ -10,8 +10,31 @@ diff --git a/public/style.css b/public/style.css index b5dcb9d..70cf131 100755 --- a/public/style.css +++ b/public/style.css @@ -10,24 +10,51 @@ body { header { - height: 48px; + height: 48px; display: flex; align-items: center; gap: 16px; padding: 0 20px; backdrop-filter: blur(6px); background: rgba(0,0,0,0.35); - - /* NEU – hochwertiger Shadow */ box-shadow: 0 4px 12px rgba(0,0,0,0.35); + overflow: visible; + position: relative; + z-index: 100; } .logo { font-weight: bold; } +.right-actions { + margin-left: auto; + display: flex; + align-items: center; + gap: 8px; +} + .user { - margin-left: auto; /* ⬅️ Login/Logout nach rechts */ + display: flex; + align-items: center; +} + +#emergency-stop { + display: none; + position: relative; + width: 78px; + height: 78px; + cursor: pointer; + flex-shrink: 0; + transition: transform 0.1s ease; +} + +#emergency-stop:hover svg { + filter: brightness(1.12); +} + +#emergency-stop:active { + transform: scale(0.93); } nav button {