diff --git a/backend/workflows/static/workflows/css/app_chrome.css b/backend/workflows/static/workflows/css/app_chrome.css index 2d461e5..d7880b9 100644 --- a/backend/workflows/static/workflows/css/app_chrome.css +++ b/backend/workflows/static/workflows/css/app_chrome.css @@ -322,6 +322,114 @@ background: linear-gradient(180deg, rgba(249, 252, 255, 0.96), rgba(243, 248, 255, 0.92)); } +.session-warning-dialog { + position: relative; + overflow: hidden; + padding-top: 28px; + background: + radial-gradient(circle at top right, rgba(201, 37, 37, 0.12), transparent 30%), + radial-gradient(circle at top left, rgba(255, 191, 120, 0.2), transparent 36%), + linear-gradient(180deg, rgba(255,255,255,0.98), rgba(249,251,255,0.98)); +} + +.session-warning-orb { + position: absolute; + top: 18px; + right: 18px; + width: 62px; + height: 62px; + display: grid; + place-items: center; +} + +.session-warning-orb-ring, +.session-warning-orb-core { + position: absolute; + border-radius: 999px; +} + +.session-warning-orb-ring { + inset: 0; + background: + radial-gradient(circle, rgba(255,255,255,0.92) 38%, rgba(255,255,255,0) 39%), + conic-gradient(from 0deg, rgba(201,37,37,0.16), rgba(255,191,120,0.64), rgba(201,37,37,0.2)); + box-shadow: 0 12px 24px rgba(128, 46, 18, 0.12); +} + +.session-warning-orb-core { + inset: 9px; + display: grid; + place-items: center; + background: linear-gradient(180deg, #fff5ef, #ffe5d7); + color: #a53b17; + font-size: 24px; + font-weight: 900; + line-height: 1; +} + +.session-warning-kicker { + color: #9a4a1e; +} + +.session-warning-panels { + display: grid; + grid-template-columns: repeat(2, minmax(0, 1fr)); + gap: 12px; + margin-bottom: 6px; +} + +.session-warning-panel { + display: grid; + gap: 4px; + padding: 12px 14px; + border: 1px solid rgba(217, 227, 238, 0.92); + border-radius: 16px; + background: rgba(255,255,255,0.82); + box-shadow: inset 0 1px 0 rgba(255,255,255,0.88); +} + +.session-warning-panel strong { + color: #152743; + font-size: 12px; + line-height: 1.25; +} + +.session-warning-panel span { + color: #53657e; + font-size: 12px; + line-height: 1.5; +} + +.session-warning-countdown { + margin-bottom: 2px; + color: #9a3c1d; + font-weight: 700; +} + +.session-warning-status { + margin: 0 0 4px; + color: #0f6b45; + font-size: 12px; + font-weight: 700; +} + +@media (max-width: 760px) { + .session-warning-panels { + grid-template-columns: 1fr; + } + + .session-warning-dialog { + padding-top: 74px; + } + + .session-warning-orb { + top: 14px; + left: 50%; + right: auto; + transform: translateX(-50%); + } +} + .app-notification-item.is-unread { border-color: rgba(0, 0, 120, 0.22); box-shadow: inset 3px 0 0 rgba(0, 0, 120, 0.9); diff --git a/backend/workflows/static/workflows/js/session_warning.js b/backend/workflows/static/workflows/js/session_warning.js index 736acd4..bac59c7 100644 --- a/backend/workflows/static/workflows/js/session_warning.js +++ b/backend/workflows/static/workflows/js/session_warning.js @@ -5,8 +5,9 @@ const warningLeadSeconds = Math.min(300, Math.max(60, Math.floor(config.idleTimeoutSeconds / 6))); const modal = document.getElementById("app-session-warning-modal"); const countdown = document.getElementById("app-session-warning-countdown"); + const status = document.getElementById("app-session-warning-status"); const extendButton = document.getElementById("app-session-warning-extend"); - if (!modal || !countdown || !extendButton) return; + if (!modal || !countdown || !extendButton || !status) return; let lastConfirmedAt = Date.now(); let warningVisible = false; @@ -27,8 +28,19 @@ warningVisible = false; } + function showStatus(message) { + status.textContent = message; + status.hidden = false; + } + + function hideStatus() { + status.hidden = true; + status.textContent = ""; + } + function showWarning(secondsLeft) { countdown.textContent = `Noch etwa ${secondsLeft} Sekunden bis zur automatischen Abmeldung.`; + hideStatus(); if (warningVisible) return; modal.hidden = false; modal.setAttribute("aria-hidden", "false"); @@ -54,7 +66,11 @@ return; } lastConfirmedAt = Date.now(); - hideWarning(); + showStatus("Sitzung erfolgreich verlängert."); + window.setTimeout(function () { + hideWarning(); + hideStatus(); + }, 1200); } catch (_error) { window.location.href = config.loginUrl; } finally { @@ -75,7 +91,11 @@ } extendButton.addEventListener("click", function () { + extendButton.disabled = true; sendKeepalive(); + setTimeout(function () { + extendButton.disabled = false; + }, 800); }); setInterval(tick, 1000); diff --git a/backend/workflows/templates/workflows/base_shell.html b/backend/workflows/templates/workflows/base_shell.html index 8d4bf40..57e82ab 100644 --- a/backend/workflows/templates/workflows/base_shell.html +++ b/backend/workflows/templates/workflows/base_shell.html @@ -105,15 +105,30 @@