Kopfleiste: Benutzer-Menü und gemeinsames Abmelden
- Benutzername und "Abmelden" im eigenen Header entfallen, nur noch Rückfall, wenn topbar.js nicht lädt - Sitzungsanzeige als slot="benutzer" im Benutzer-Menü der Leiste - hi-abmelden: POST /api/logout beendet die Timer-Sitzung, laufende Timer fragen vorher nach (Abbrechen stoppt das ganze Abmelden) - html data-theme="dark": die Leiste ist dunkel wie die App, auch bei hellem System - README/DEPLOY: Abmelden, Launch-URL /auth/login, CSP-Hinweis Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
8f5517a409
commit
0ee9b708a1
5 files changed
+94
-14
No files matched your search
+50
-7
@@ -161,28 +161,71 @@ async function enterApp() {
|
||||
startLoops();
|
||||
}
|
||||
|
||||
// Zeigt den angemeldeten Authentik-Nutzer oben rechts im Header.
|
||||
// Zeigt den angemeldeten Authentik-Nutzer: im Benutzer-Menue der
|
||||
// Portal-Kopfleiste, ohne Leiste oben rechts im eigenen Header.
|
||||
function renderCurrentUser() {
|
||||
const el = document.getElementById('currentUser');
|
||||
if (!el) return;
|
||||
const u = loggedInUser;
|
||||
el.textContent = u ? (u.displayName || u.username || '') : '';
|
||||
const name = u ? (u.displayName || u.username || '') : '';
|
||||
const el = document.getElementById('currentUser');
|
||||
el.textContent = name;
|
||||
el.title = u && u.email ? u.email : 'Angemeldet';
|
||||
renderTopbarSession(name);
|
||||
}
|
||||
|
||||
async function logout() {
|
||||
function confirmLogout() {
|
||||
const running = state.timers.filter(t => t.isRunning).length;
|
||||
if (running > 0 && !confirm(
|
||||
return running === 0 || confirm(
|
||||
`${running} Timer ${running === 1 ? 'läuft' : 'laufen'} noch.\n\n` +
|
||||
`Sie laufen serverseitig weiter und sind nach dem nächsten Anmelden wieder da. Trotzdem abmelden?`
|
||||
)) return;
|
||||
);
|
||||
}
|
||||
|
||||
// Eigener Abmelden-Knopf, nur sichtbar ohne Portal-Kopfleiste
|
||||
async function logout() {
|
||||
if (!confirmLogout()) return;
|
||||
stopLoops();
|
||||
state.timers = [];
|
||||
// GET-Navigation: beendet lokale Sitzung und – bei Authentik-Login – auch die SSO-Sitzung
|
||||
window.location.href = '/auth/logout';
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Portal-Kopfleiste
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
// topbar.js laeuft per defer erst nach diesem Skript, die Leiste steht also
|
||||
// fruehestens ab DOMContentLoaded im DOM. Die Sitzungsanzeige wird einmal
|
||||
// eingehaengt, sobald die Anmeldung steht, danach aendert sich nur ihr Text.
|
||||
const topbarSession = document.createElement('div');
|
||||
topbarSession.slot = 'benutzer';
|
||||
topbarSession.className = 'topbar-session';
|
||||
topbarSession.append(Object.assign(document.createElement('span'), { textContent: 'Timer – angemeldet als' }),
|
||||
document.createElement('strong'));
|
||||
let topbarSessionName = null; // null = (noch) nicht angemeldet
|
||||
|
||||
function renderTopbarSession(name) {
|
||||
topbarSessionName = name || 'Angemeldet';
|
||||
topbarSession.lastChild.textContent = topbarSessionName;
|
||||
if (!topbarSession.isConnected) document.querySelector('hi-topbar')?.append(topbarSession);
|
||||
}
|
||||
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
if (topbarSessionName !== null) renderTopbarSession(topbarSessionName);
|
||||
});
|
||||
|
||||
// "Abmelden" in der Leiste: erst die eigene Sitzung beenden, danach meldet
|
||||
// die Leiste bei Portal und Authentik ab. Abbrechen bei laufenden Timern
|
||||
// verhindert das ganze Abmelden.
|
||||
document.addEventListener('hi-abmelden', (e) => {
|
||||
if (!confirmLogout()) {
|
||||
e.preventDefault();
|
||||
return;
|
||||
}
|
||||
stopLoops();
|
||||
state.timers = [];
|
||||
e.detail.warten(fetch('/api/logout', { method: 'POST', credentials: 'same-origin' }));
|
||||
});
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Timer-Synchronisation
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
+13
-3
@@ -1,5 +1,6 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="de">
|
||||
<!-- data-theme: die App ist immer dunkel, die Portal-Kopfleiste soll es auch sein -->
|
||||
<html lang="de" data-theme="dark">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
@@ -795,6 +796,15 @@
|
||||
soll sie nicht erscheinen. */
|
||||
hi-topbar { flex-shrink: 0; }
|
||||
@media print { hi-topbar { display: none !important; } }
|
||||
|
||||
/* Benutzername und Abmelden sitzen im Benutzer-Menue der Leiste. Die
|
||||
eigenen bleiben nur als Rueckfall, wenn topbar.js nicht laedt. */
|
||||
hi-topbar ~ .container #currentUser,
|
||||
hi-topbar ~ .container #logoutBtn { display: none; }
|
||||
|
||||
/* Sitzungsanzeige im Benutzer-Menue (slot="benutzer"), Schriftfarbe kommt von der Leiste */
|
||||
.topbar-session { padding: 10px 16px; font-size: 13px; line-height: 1.4; }
|
||||
.topbar-session span { display: block; opacity: 0.7; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
@@ -806,7 +816,7 @@
|
||||
<button class="btn btn-secondary" onclick="showTimer()">⏱️ Timer</button>
|
||||
<button class="btn btn-secondary" onclick="showHistory()">📊 Historie</button>
|
||||
<button class="btn btn-secondary" onclick="showSettings()">⚙️ Einstellungen</button>
|
||||
<button class="btn btn-secondary" onclick="logout()">🚪 Abmelden</button>
|
||||
<button id="logoutBtn" class="btn btn-secondary" onclick="logout()">🚪 Abmelden</button>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
@@ -1019,6 +1029,6 @@
|
||||
|
||||
<div class="toast" id="toast"></div>
|
||||
|
||||
<script src="/app.js?v=20260912-devices"></script>
|
||||
<script src="/app.js?v=20261025-topbar"></script>
|
||||
</body>
|
||||
</html>
|
||||
Reference in new issue
Block a user