From 046e5233524827449a2afe5be161698bcdcd4131 Mon Sep 17 00:00:00 2001 From: Kerim Atilgan Date: Sun, 25 Oct 2026 13:18:40 +0100 Subject: [PATCH] Kopfleiste: Timer, Historie und Einstellungen in die Leiste MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Die drei Knöpfe hängen als slot="aktionen" rechts in der Portal-Leiste, die aktuelle Ansicht ist hervorgehoben - Unter 600 px nur die Symbole, der Name steht im title - Der eigene Header (Logo + Knöpfe) entfällt, solange die Leiste da ist; lädt topbar.js nicht, bleibt er als Rückfall - Nach Ablauf der Sitzung (Anmeldeseite) sind Knöpfe und Sitzungsanzeige ausgeblendet Co-Authored-By: Claude Opus 5.5 --- frontend/app.js | 45 ++++++++++++++++++++++++++++++++++----------- frontend/index.html | 36 +++++++++++++++++++++++++++++++----- 2 files changed, 65 insertions(+), 16 deletions(-) diff --git a/frontend/app.js b/frontend/app.js index 0c451e6..40500f9 100644 --- a/frontend/app.js +++ b/frontend/app.js @@ -103,10 +103,13 @@ async function api(url, options = {}) { function switchView(id) { document.querySelectorAll('.view').forEach(v => v.classList.remove('active')); document.getElementById(id).classList.add('active'); + for (const btn of topbarNav.children) btn.classList.toggle('active', btn.dataset.view === id); } function showLogin() { document.getElementById('header').style.display = 'none'; + signedInName = null; + renderTopbar(); switchView('loginView'); applyLoginMode(); } @@ -169,7 +172,8 @@ function renderCurrentUser() { const el = document.getElementById('currentUser'); el.textContent = name; el.title = u && u.email ? u.email : 'Angemeldet'; - renderTopbarSession(name); + signedInName = name || 'Angemeldet'; + renderTopbar(); } function confirmLogout() { @@ -194,24 +198,43 @@ async function logout() { // --------------------------------------------------------------------------- // 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. +// fruehestens ab DOMContentLoaded im DOM. Navigation (slot="aktionen") und +// Sitzungsanzeige (slot="benutzer") werden einmal eingehaengt, sobald die +// Anmeldung steht. Danach aendern sich nur Text und Sichtbarkeit. Ist die +// Leiste da, blendet das CSS den eigenen Header aus. +const topbarNav = document.createElement('div'); +topbarNav.slot = 'aktionen'; +topbarNav.className = 'topbar-nav'; +for (const [view, icon, label, show] of [ + ['timerView', '⏱️', 'Timer', () => showTimer()], + ['historyView', '📊', 'Historie', () => showHistory()], + ['settingsView', '⚙️', 'Einstellungen', () => showSettings()], +]) { + const btn = document.createElement('button'); + btn.type = 'button'; + btn.dataset.view = view; + btn.title = label; + btn.append(icon, Object.assign(document.createElement('span'), { textContent: label })); + btn.addEventListener('click', show); + topbarNav.append(btn); +} + 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 +let signedInName = null; // null = nicht angemeldet -function renderTopbarSession(name) { - topbarSessionName = name || 'Angemeldet'; - topbarSession.lastChild.textContent = topbarSessionName; - if (!topbarSession.isConnected) document.querySelector('hi-topbar')?.append(topbarSession); +function renderTopbar() { + const signedIn = signedInName !== null; + topbarNav.hidden = topbarSession.hidden = !signedIn; + if (!signedIn) return; + topbarSession.lastChild.textContent = signedInName; + if (!topbarSession.isConnected) document.querySelector('hi-topbar')?.append(topbarNav, topbarSession); } -document.addEventListener('DOMContentLoaded', () => { - if (topbarSessionName !== null) renderTopbarSession(topbarSessionName); -}); +document.addEventListener('DOMContentLoaded', renderTopbar); // "Abmelden" in der Leiste: erst die eigene Sitzung beenden, danach meldet // die Leiste bei Portal und Authentik ab. Abbrechen bei laufenden Timern diff --git a/frontend/index.html b/frontend/index.html index 224b86b..9f01d4b 100644 --- a/frontend/index.html +++ b/frontend/index.html @@ -797,10 +797,36 @@ 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; } + /* Navigation, Benutzername und Abmelden sitzen in der Leiste. Der eigene + Header bleibt nur als Rueckfall, wenn topbar.js nicht laedt + (!important, weil app.js ihn per style.display einblendet). */ + hi-topbar ~ .container #header { display: none !important; } + + /* Navigation rechts in der Leiste (slot="aktionen"), Text erbt Weiss */ + .topbar-nav { display: flex; gap: 2px; } + .topbar-nav[hidden] { display: none; } + .topbar-nav button { + display: inline-flex; + align-items: center; + gap: 0.35rem; + height: 32px; + padding: 0 0.7rem; + border: 0; + border-radius: 8px; + background: none; + color: inherit; + font: inherit; + font-size: 13.5px; + cursor: pointer; + } + .topbar-nav button:hover { background: rgba(255, 255, 255, 0.14); } + .topbar-nav button.active { background: rgba(255, 255, 255, 0.22); } + .topbar-nav button:focus-visible { outline: 2px solid #cbbdf7; outline-offset: 1px; } + /* Schmal: nur die Symbole, der Name steht im title */ + @media (max-width: 600px) { + .topbar-nav button { padding: 0 0.55rem; font-size: 16px; } + .topbar-nav button span { 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; } @@ -1029,6 +1055,6 @@
- +