refactor: replace sidebar user footer with topbar dropdown menu

This commit is contained in:
2026-06-14 09:26:52 -04:00
parent b7bd4bfe92
commit 74cf9739d6
3 changed files with 94 additions and 37 deletions

View File

@@ -301,10 +301,7 @@ code, pre {
.sidebar.collapsed .nav-chevron,
.sidebar.collapsed .notification-badge,
.sidebar.collapsed .nav-divider,
.sidebar.collapsed .nav-section,
.sidebar.collapsed .user-details,
.sidebar.collapsed .user-menu,
.sidebar.collapsed .sidebar-footer {
.sidebar.collapsed .nav-section {
display: none;
}
@@ -317,10 +314,6 @@ code, pre {
padding: 0.65rem;
}
.sidebar.collapsed .user-info {
justify-content: center;
}
/* ==========================================================================
Main Content
========================================================================== */
@@ -374,6 +367,39 @@ code, pre {
font-size: 0.88rem;
color: var(--text-secondary);
white-space: nowrap;
cursor: pointer;
background: none;
border: none;
font-family: inherit;
padding: 0.4rem 0.6rem;
border-radius: var(--radius-sm);
transition: background var(--transition);
}
.topbar-user:hover {
background: var(--bg-hover);
}
.topbar-user-dropdown {
position: relative;
}
.dropdown-menu-right {
right: 0;
left: auto;
}
.dropdown-header {
padding: 0.55rem 1rem;
font-size: 0.88rem;
display: flex;
flex-direction: column;
gap: 2px;
}
.dropdown-header small {
font-size: 0.72rem;
color: var(--text-muted);
}
.btn-icon {
@@ -1056,7 +1082,8 @@ textarea.form-input {
box-shadow: var(--shadow-lg);
}
.dropdown.active .dropdown-menu {
.dropdown.active .dropdown-menu,
.dropdown-menu.open {
display: block;
}
@@ -2302,10 +2329,7 @@ textarea.form-input {
.sidebar.mobile-open.collapsed .nav-chevron,
.sidebar.mobile-open.collapsed .notification-badge,
.sidebar.mobile-open.collapsed .nav-divider,
.sidebar.mobile-open.collapsed .nav-section,
.sidebar.mobile-open.collapsed .user-details,
.sidebar.mobile-open.collapsed .user-menu,
.sidebar.mobile-open.collapsed .sidebar-footer {
.sidebar.mobile-open.collapsed .nav-section {
display: flex;
}
@@ -2318,10 +2342,6 @@ textarea.form-input {
padding: 0.65rem 1.25rem;
}
.sidebar.mobile-open.collapsed .user-info {
justify-content: flex-start;
}
.main-area {
margin-left: 0 !important;
}

View File

@@ -200,3 +200,31 @@ function toggleServerList(e) {
sub.style.maxHeight = sub.scrollHeight + 'px';
}
}
function toggleUserMenu(e) {
e.stopPropagation();
const menu = document.getElementById('userMenu');
if (!menu) return;
const isOpen = menu.classList.contains('open');
document.querySelectorAll('.dropdown-menu.open').forEach(function(m) {
if (m !== menu) m.classList.remove('open');
});
if (!isOpen) {
menu.classList.add('open');
setTimeout(function() {
document.addEventListener('click', closeUserMenu);
}, 0);
} else {
menu.classList.remove('open');
}
}
function closeUserMenu(e) {
const menu = document.getElementById('userMenu');
if (!menu) return;
const wrapper = menu.closest('.topbar-user-dropdown');
if (wrapper && !wrapper.contains(e.target)) {
menu.classList.remove('open');
document.removeEventListener('click', closeUserMenu);
}
}

View File

@@ -120,22 +120,7 @@ if (!isset($user) || $user === null) {
</a>
</nav>
<div class="sidebar-footer">
<div class="user-info">
<div class="user-avatar"><?= strtoupper(substr($user['username'] ?? '?', 0, 2)) ?></div>
<div class="user-details">
<span class="user-name"><?= htmlspecialchars($user['username'] ?? 'Guest') ?></span>
<span class="user-role"><?= htmlspecialchars(ucfirst(str_replace('_', ' ', $user['role'] ?? 'guest'))) ?></span>
</div>
<div class="user-menu">
<a href="/profile" title="Profile"><i class="fas fa-user-cog"></i></a>
<form method="POST" action="/logout" class="logout-form" style="display:inline">
<input type="hidden" name="_csrf_token" value="<?= $this->csrfToken() ?>">
<button type="submit" title="Logout" style="background:none;border:none;color:inherit;cursor:pointer;padding:0;font:inherit;line-height:1"><i class="fas fa-sign-out-alt"></i></button>
</form>
</div>
</div>
</div>
</aside>
<!-- Main Content -->
@@ -171,10 +156,34 @@ if (!isset($user) || $user === null) {
</div>
</div>
</div>
<span class="topbar-user">
<i class="fas fa-user-circle"></i>
<?= htmlspecialchars($user['username'] ?? 'Guest') ?>
</span>
<div class="dropdown topbar-user-dropdown">
<button class="topbar-user" onclick="toggleUserMenu(event)">
<i class="fas fa-user-circle"></i>
<?= htmlspecialchars($user['username'] ?? 'Guest') ?>
<i class="fas fa-chevron-down" style="font-size:0.7rem;margin-left:4px"></i>
</button>
<div class="dropdown-menu dropdown-menu-right" id="userMenu">
<div class="dropdown-header">
<strong><?= htmlspecialchars($user['username'] ?? 'Guest') ?></strong>
<small><?= htmlspecialchars(ucfirst(str_replace('_', ' ', $user['role'] ?? 'guest'))) ?></small>
</div>
<div class="dropdown-divider"></div>
<a href="/profile" class="dropdown-item"><i class="fas fa-user-cog"></i> My Account</a>
<a href="/notifications" class="dropdown-item"><i class="fas fa-bell"></i> Notifications</a>
<?php if (is_admin() || is_super_admin()): ?>
<div class="dropdown-divider"></div>
<a href="/admin/audit" class="dropdown-item"><i class="fas fa-history"></i> Audit Log</a>
<a href="/admin" class="dropdown-item"><i class="fas fa-cog"></i> Administration</a>
<?php endif; ?>
<div class="dropdown-divider"></div>
<form method="POST" action="/logout" style="padding:0;margin:0">
<input type="hidden" name="_csrf_token" value="<?= $this->csrfToken() ?>">
<button type="submit" class="dropdown-item" style="width:100%;text-align:left;border:none;background:none;cursor:pointer;font:inherit">
<i class="fas fa-sign-out-alt"></i> Log out
</button>
</form>
</div>
</div>
</div>
</header>