diff --git a/assets/app_auth.js b/assets/app_auth.js index 749e45f..6070f3b 100644 --- a/assets/app_auth.js +++ b/assets/app_auth.js @@ -333,7 +333,7 @@ const loggedIn = this.isLoggedIn(); const user = this.getUser(); - // Topbar Elemente in index.html + // Topbar Elemente in index.html & dashboard.html const userSpan = document.getElementById('nav-auth-user'); const loginBtn = document.getElementById('nav-btn-login'); const registerBtn = document.getElementById('nav-btn-register'); @@ -341,6 +341,24 @@ const teacherLink = document.getElementById('nav-teacher-link'); const heroPrimaryCta = document.getElementById('hero-primary-cta'); + // Modern User Avatar Dropdown Elemente + const userDropdown = document.getElementById('portal-user-dropdown'); + const userAvatar = document.getElementById('portal-user-avatar'); + const userNameEl = document.getElementById('portal-user-name'); + const ddFullName = document.getElementById('portal-dropdown-user-fullname'); + const ddEmail = document.getElementById('portal-dropdown-user-email'); + const ddBadge = document.getElementById('portal-dropdown-user-badge'); + const ddTeacher = document.getElementById('dropdown-link-teacher'); + const ddAdmin = document.getElementById('dropdown-link-admin'); + const ddMgmtTitle = document.getElementById('dropdown-mgmt-title'); + const ddMgmtDivider = document.getElementById('dropdown-teacher-divider'); + + // Mobile Drawer User Header + const mobUserBox = document.getElementById('mobile-drawer-user-info'); + const mobAvatar = document.getElementById('mobile-drawer-avatar'); + const mobUsername = document.getElementById('mobile-drawer-username'); + const mobRole = document.getElementById('mobile-drawer-role'); + // Dashboard Links auf index.html / impressum / datenschutz const navDashLink = document.getElementById('nav-dashboard-link'); const mobDashLink = document.getElementById('mobile-drawer-dash-link'); @@ -349,37 +367,72 @@ if (guestBtn) guestBtn.style.display = 'none'; // Gast-Button permanent ausblenden + function computeInitials(str) { + if (!str) return 'IT'; + const parts = str.trim().split(/\s+/); + if (parts.length >= 2) { + return (parts[0][0] + parts[1][0]).toUpperCase(); + } + return str.substring(0, 2).toUpperCase(); + } + + const roleLabels = { + 'admin': 'Administrator', + 'teacher': 'Dozent / Ausbilder', + 'student': 'Auszubildender', + 'solo': 'Professional' + }; + if (loggedIn && user) { document.body.classList.add('logged-in'); + const displayName = user.name || user.email.split('@')[0]; + const initials = computeInitials(displayName); + const roleLabel = roleLabels[user.role] || 'Teilnehmer'; + const profStr = user.profession ? ` • ${user.profession}` : ''; + + // 1. User Dropdown befüllen + if (userDropdown) { + userDropdown.style.display = 'inline-block'; + } + if (userAvatar) userAvatar.innerText = initials; + if (userNameEl) userNameEl.innerText = displayName; + if (ddFullName) ddFullName.innerText = displayName; + if (ddEmail) ddEmail.innerText = user.email || ''; + if (ddBadge) { + ddBadge.innerText = `${roleLabel}${profStr}`; + } + + // Mobile Drawer User Header + if (mobUserBox) mobUserBox.style.display = 'flex'; + if (mobAvatar) mobAvatar.innerText = initials; + if (mobUsername) mobUsername.innerText = displayName; + if (mobRole) mobRole.innerText = `${roleLabel}${profStr}`; + + // Dozent / Admin im Dropdown + const hasTeacher = (user.role === 'teacher' || user.role === 'admin'); + const hasAdmin = (user.role === 'admin'); + if (ddTeacher) ddTeacher.style.display = hasTeacher ? 'flex' : 'none'; + if (ddAdmin) ddAdmin.style.display = hasAdmin ? 'flex' : 'none'; + if (ddMgmtTitle) ddMgmtTitle.style.display = hasTeacher ? 'block' : 'none'; + if (ddMgmtDivider) ddMgmtDivider.style.display = hasTeacher ? 'block' : 'none'; + + const mobMgmtTitle = document.getElementById('mobile-drawer-mgmt-title'); + const mobMgmtDivider = document.getElementById('mobile-drawer-mgmt-divider'); + if (mobMgmtTitle) mobMgmtTitle.style.display = hasTeacher ? 'block' : 'none'; + if (mobMgmtDivider) mobMgmtDivider.style.display = hasTeacher ? 'block' : 'none'; + if (userSpan) { userSpan.style.display = 'inline-flex'; - userSpan.innerHTML = `${escapeHtml(user.name || user.email)}`; + userSpan.innerHTML = `${escapeHtml(displayName)}`; userSpan.style.cursor = 'pointer'; userSpan.title = 'Zum Kurs-Dashboard wechseln'; userSpan.onclick = () => { window.location.href = 'dashboard.html'; }; } if (loginBtn) { - loginBtn.style.display = 'inline-flex'; - loginBtn.innerText = 'Abmelden'; - loginBtn.style.background = 'rgba(239, 68, 68, 0.15)'; - loginBtn.style.color = '#f87171'; - loginBtn.style.borderColor = 'rgba(239, 68, 68, 0.3)'; - loginBtn.removeAttribute('onclick'); - loginBtn.onclick = () => { - if (confirm('Möchtest du dich wirklich abmelden?')) { - this.logout(); - } - }; + loginBtn.style.display = 'none'; // Bei aktivem User-Dropdown wird der separate Login-Btn ausgeblendet } if (registerBtn) { - registerBtn.style.display = 'inline-flex'; - registerBtn.innerHTML = 'Zum Kurs-DashboardDashboard'; - registerBtn.style.background = '#10b981'; - registerBtn.removeAttribute('onclick'); - registerBtn.onclick = (e) => { - e.preventDefault(); - window.location.href = 'dashboard.html'; - }; + registerBtn.style.display = 'none'; // Ebenso } if (heroPrimaryCta) { heroPrimaryCta.innerHTML = 'Zum Dashboard & Kurse wählen →'; @@ -408,10 +461,10 @@ if (landingBanner) { landingBanner.style.display = 'flex'; if (landingUserName) { - landingUserName.innerText = user.name || user.email.split('@')[0]; + landingUserName.innerText = displayName; } } - if (navDashLink) navDashLink.style.display = 'none'; // Keine doppelte Schaltfläche in Desktop-Leiste + if (navDashLink) navDashLink.style.display = 'none'; if (mobDashLink) mobDashLink.style.display = 'flex'; const mobLogoutBtn = document.getElementById('mobile-drawer-logout-btn'); if (mobLogoutBtn) mobLogoutBtn.style.display = 'flex'; @@ -419,6 +472,9 @@ if (mobDrawerAuthActions) mobDrawerAuthActions.style.display = 'none'; } else { document.body.classList.remove('logged-in'); + if (userDropdown) userDropdown.style.display = 'none'; + if (mobUserBox) mobUserBox.style.display = 'none'; + if (userSpan) { userSpan.style.display = 'none'; userSpan.onclick = null; @@ -744,6 +800,50 @@ } } + // Globales User Avatar Dropdown Handling + window.toggleUserDropdown = function (event) { + if (event) { + event.preventDefault(); + event.stopPropagation(); + } + const menu = document.getElementById('portal-dropdown-menu'); + const btn = document.getElementById('portal-user-btn'); + if (!menu) return; + const isShown = menu.classList.contains('show'); + if (isShown) { + menu.classList.remove('show'); + if (btn) btn.setAttribute('aria-expanded', 'false'); + } else { + menu.classList.add('show'); + if (btn) btn.setAttribute('aria-expanded', 'true'); + } + }; + + // Klick außerhalb schließt das Dropdown + document.addEventListener('click', (e) => { + const dd = document.getElementById('portal-user-dropdown'); + const menu = document.getElementById('portal-dropdown-menu'); + const btn = document.getElementById('portal-user-btn'); + if (menu && menu.classList.contains('show')) { + if (!dd || !dd.contains(e.target)) { + menu.classList.remove('show'); + if (btn) btn.setAttribute('aria-expanded', 'false'); + } + } + }); + + // Escape-Taste schließt das Dropdown + document.addEventListener('keydown', (e) => { + if (e.key === 'Escape') { + const menu = document.getElementById('portal-dropdown-menu'); + const btn = document.getElementById('portal-user-btn'); + if (menu && menu.classList.contains('show')) { + menu.classList.remove('show'); + if (btn) btn.setAttribute('aria-expanded', 'false'); + } + } + }); + if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', initAuth); } else { diff --git a/assets/style.css b/assets/style.css index daa230d..136dad3 100644 --- a/assets/style.css +++ b/assets/style.css @@ -2901,3 +2901,214 @@ tbody tr:hover { } } +/* ========================================================================== + 👤 MODERN USER AVATAR & DROPDOWN MENU (EDTECH & DEV STANDARD) + ========================================================================== */ + +.portal-user-dropdown { + position: relative; + display: inline-block; +} + +.portal-user-btn { + display: inline-flex; + align-items: center; + gap: 8px; + background: #1e293b; + border: 1px solid #334155; + color: #f8fafc; + padding: 5px 12px 5px 6px; + border-radius: 99px; + font-size: 0.84rem; + font-weight: 600; + cursor: pointer; + transition: all 0.15s ease; + user-select: none; + outline: none; +} + +.portal-user-btn:hover, +.portal-user-btn:focus-visible, +.portal-user-btn[aria-expanded="true"] { + background: #334155; + border-color: #475569; + box-shadow: 0 4px 12px rgba(0, 0, 0, 0.2); +} + +.portal-user-avatar { + width: 28px; + height: 28px; + border-radius: 50%; + background: linear-gradient(135deg, #0284c7, #1d4ed8); + color: white; + display: flex; + align-items: center; + justify-content: center; + font-size: 0.74rem; + font-weight: 800; + text-transform: uppercase; + letter-spacing: 0.5px; + flex-shrink: 0; +} + +.portal-user-name { + max-width: 110px; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + font-size: 0.84rem; + color: #f8fafc; +} + +.portal-user-caret { + font-size: 0.65rem; + color: #94a3b8; + transition: transform 0.2s ease; +} + +.portal-user-btn[aria-expanded="true"] .portal-user-caret { + transform: rotate(180deg); +} + +.portal-dropdown-menu { + position: absolute; + top: calc(100% + 8px); + right: 0; + min-width: 270px; + background: #0f172a; + border: 1px solid #334155; + border-radius: 12px; + box-shadow: 0 16px 36px -4px rgba(0, 0, 0, 0.5), 0 0 0 1px rgba(255, 255, 255, 0.05); + padding: 8px; + z-index: 1050; + display: none; + animation: portalFadeSlide 0.18s cubic-bezier(0.16, 1, 0.3, 1); +} + +.portal-dropdown-menu.show { + display: block; +} + +@keyframes portalFadeSlide { + from { + opacity: 0; + transform: translateY(-6px); + } + to { + opacity: 1; + transform: translateY(0); + } +} + +.portal-dropdown-header { + padding: 10px 12px 12px 12px; + border-bottom: 1px solid #1e293b; + margin-bottom: 6px; +} + +.portal-dropdown-name { + font-size: 0.92rem; + font-weight: 700; + color: #ffffff; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} + +.portal-dropdown-meta { + font-size: 0.76rem; + color: #94a3b8; + margin-top: 2px; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} + +.portal-dropdown-badge { + display: inline-flex; + align-items: center; + gap: 4px; + font-size: 0.68rem; + font-weight: 700; + text-transform: uppercase; + padding: 2px 7px; + border-radius: 4px; + background: rgba(56, 189, 248, 0.15); + color: #38bdf8; + border: 1px solid rgba(56, 189, 248, 0.3); + margin-top: 6px; +} + +.portal-dropdown-item { + display: flex; + align-items: center; + gap: 10px; + padding: 8px 12px; + color: #cbd5e1; + text-decoration: none; + font-size: 0.84rem; + font-weight: 500; + border-radius: 8px; + transition: all 0.12s ease; + border: none; + background: transparent; + width: 100%; + text-align: left; + cursor: pointer; + box-sizing: border-box; +} + +.portal-dropdown-item:hover, +.portal-dropdown-item:focus-visible { + background: #1e293b; + color: #ffffff; + outline: none; +} + +.portal-dropdown-item.danger { + color: #f87171; +} + +.portal-dropdown-item.danger:hover, +.portal-dropdown-item.danger:focus-visible { + background: rgba(239, 68, 68, 0.12); + color: #ef4444; +} + +.portal-dropdown-divider { + height: 1px; + background: #1e293b; + margin: 6px 0; +} + +.portal-dropdown-section-title { + font-size: 0.68rem; + font-weight: 700; + text-transform: uppercase; + letter-spacing: 0.6px; + color: #64748b; + padding: 6px 12px 4px 12px; +} + +/* Mobile Drawer Grouping Styles */ +.mobile-drawer-section-title { + font-size: 0.7rem; + font-weight: 700; + text-transform: uppercase; + letter-spacing: 0.6px; + color: #94a3b8; + padding: 6px 12px 2px 12px; +} + +.mobile-drawer-divider { + height: 1px; + background: rgba(255, 255, 255, 0.08); + margin: 4px 0; +} + +.mobile-drawer-link.danger-link:hover { + background: rgba(239, 68, 68, 0.15) !important; + color: #fca5a5 !important; +} + + diff --git a/dashboard.html b/dashboard.html index b794b4e..fe8a012 100644 --- a/dashboard.html +++ b/dashboard.html @@ -229,10 +229,10 @@
- +