diff --git a/web/index.html b/web/index.html index 53275ac..3e32556 100644 --- a/web/index.html +++ b/web/index.html @@ -54,22 +54,47 @@ - - - - - - - Mailing List Manager - - - - - User - role - - Logout + + + + + + Mailing List Manager + + + + + + + + User + role + + + + + + + + + + + User + role + + + + + + + User Management + + + + + Sign Out + @@ -88,10 +113,6 @@ Members - - - Users - @@ -134,13 +155,7 @@ - - Members - - - Click the "Lists" button next to any member to manage their subscriptions - - + Members diff --git a/web/static/css/style.css b/web/static/css/style.css index edcafb0..2dccf89 100644 --- a/web/static/css/style.css +++ b/web/static/css/style.css @@ -285,7 +285,8 @@ body { } /* Header */ -.header { +/* Menu Bar Header */ +.menu-bar { background: var(--white); border-bottom: 1px solid var(--gray-200); box-shadow: var(--shadow-sm); @@ -294,24 +295,29 @@ body { z-index: 100; } -.header-content { +.menu-bar-content { display: flex; - justify-content: space-between; align-items: center; - padding: var(--space-4) 0; + justify-content: space-between; + padding: var(--space-2) var(--space-4); + min-height: 56px; } -.logo { - font-size: var(--font-size-xl); - font-weight: 700; - color: var(--primary-color); +.app-title { display: flex; align-items: center; gap: var(--space-2); + font-size: var(--font-size-lg); + font-weight: 600; + color: var(--primary-color); } -.logo i { - font-size: var(--font-size-2xl); +.app-title i { + font-size: var(--font-size-xl); +} + +.menu-spacer { + flex: 1; } /* Authentication */ @@ -342,31 +348,185 @@ body { box-shadow: 0 0 0 3px rgb(37 99 235 / 0.1); } -.user-info { +/* User Dropdown - Menu Bar Style */ +.user-dropdown { + position: relative; +} + +.user-dropdown-trigger { display: flex; align-items: center; - gap: var(--space-3); + gap: var(--space-2); + padding: var(--space-2) var(--space-3); + background: transparent; + border: 1px solid var(--gray-200); + border-radius: var(--radius); + cursor: pointer; + transition: var(--transition); + font-size: var(--font-size-sm); + height: 40px; + position: relative; + z-index: 10; + pointer-events: auto; +} + +.user-dropdown-trigger:hover { + background: var(--gray-50); + border-color: var(--gray-300); +} + +.user-dropdown-trigger.active { + background: var(--gray-50); + border-color: var(--primary-color); + box-shadow: 0 0 0 3px rgb(37 99 235 / 0.1); +} + +.user-avatar { + width: 24px; + height: 24px; + background: var(--primary-color); + color: var(--white); + border-radius: 50%; + display: flex; + align-items: center; + justify-content: center; + font-size: var(--font-size-xs); + flex-shrink: 0; } .user-details { display: flex; flex-direction: column; - align-items: flex-end; - gap: var(--space-1); + align-items: flex-start; + gap: 1px; + min-width: 0; } .user-name { font-weight: 500; + font-size: var(--font-size-xs); + color: var(--gray-900); + line-height: 1.2; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + max-width: 100px; +} + +.user-role { + font-size: 10px; + color: var(--gray-500); + text-transform: capitalize; + line-height: 1; + white-space: nowrap; +} + +.dropdown-arrow { + color: var(--gray-400); + font-size: 10px; + transition: var(--transition); + flex-shrink: 0; +} + +.user-dropdown-trigger.active .dropdown-arrow { + transform: rotate(180deg); +} + +.user-dropdown-menu { + position: absolute; + top: 100%; + right: 0; + min-width: 220px; + background: var(--white); + border: 1px solid var(--gray-200); + border-radius: var(--radius); + box-shadow: var(--shadow-lg); + z-index: 1000; + opacity: 0; + visibility: hidden; + transform: translateY(-8px); + transition: all 0.2s ease; + margin-top: var(--space-1); +} + +.user-dropdown.active .user-dropdown-menu { + opacity: 1; + visibility: visible; + transform: translateY(0); +} + +.dropdown-header { + padding: var(--space-3); + border-bottom: 1px solid var(--gray-100); +} + +.dropdown-user-info { + display: flex; + align-items: center; + gap: var(--space-3); +} + +.dropdown-avatar { + width: 40px; + height: 40px; + background: var(--primary-color); + color: var(--white); + border-radius: 50%; + display: flex; + align-items: center; + justify-content: center; + font-size: var(--font-size-base); +} + +.dropdown-details { + display: flex; + flex-direction: column; + gap: var(--space-1); +} + +.dropdown-name { + font-weight: 600; font-size: var(--font-size-sm); color: var(--gray-900); } -.user-role { +.dropdown-role { font-size: var(--font-size-xs); color: var(--gray-500); text-transform: capitalize; } +.dropdown-divider { + height: 1px; + background: var(--gray-100); + margin: 0; +} + +.dropdown-item { + display: flex; + align-items: center; + gap: var(--space-3); + width: 100%; + padding: var(--space-3); + background: transparent; + border: none; + text-align: left; + font-size: var(--font-size-sm); + color: var(--gray-700); + cursor: pointer; + transition: var(--transition); +} + +.dropdown-item:hover { + background: var(--gray-50); + color: var(--gray-900); +} + +.dropdown-item i { + width: 16px; + color: var(--gray-400); +} + .status-indicator { display: flex; align-items: center; @@ -945,11 +1105,35 @@ body { padding: 0 var(--space-3); } - .header-content { + .menu-bar-content { flex-direction: column; - gap: var(--space-4); + gap: var(--space-2); + padding: var(--space-2) var(--space-3); align-items: stretch; } + + .app-title { + order: 1; + justify-content: center; + font-size: var(--font-size-base); + } + + .user-dropdown { + order: 2; + align-self: flex-end; + width: auto; + } + + .menu-spacer { + display: none; + } + + .user-dropdown-menu { + right: 0; + left: auto; + width: auto; + min-width: 200px; + } .auth-controls { flex-direction: column; diff --git a/web/static/js/app.js b/web/static/js/app.js index b01e03f..771aafd 100644 --- a/web/static/js/app.js +++ b/web/static/js/app.js @@ -52,6 +52,33 @@ class MailingListApp { this.logout(); }); + // User dropdown functionality + const userDropdownTrigger = document.getElementById('userDropdownTrigger'); + const userDropdown = document.getElementById('userDropdown'); + + userDropdownTrigger.addEventListener('click', (e) => { + e.preventDefault(); + e.stopPropagation(); + userDropdown.classList.toggle('active'); + userDropdownTrigger.classList.toggle('active'); + }); + + // Close dropdown when clicking outside + document.addEventListener('click', (e) => { + if (!userDropdown.contains(e.target)) { + userDropdown.classList.remove('active'); + userDropdownTrigger.classList.remove('active'); + } + }); + + // Close dropdown on escape key + document.addEventListener('keydown', (e) => { + if (e.key === 'Escape') { + userDropdown.classList.remove('active'); + userDropdownTrigger.classList.remove('active'); + } + }); + // Bulk import button document.getElementById('showBulkImportBtn').addEventListener('click', () => { uiManager.showBulkImportModal(); @@ -61,6 +88,15 @@ class MailingListApp { document.getElementById('addUserBtn').addEventListener('click', () => { uiManager.showUserModal(); }); + + // User management dropdown item + document.getElementById('userManagementBtn').addEventListener('click', () => { + // Close the dropdown + userDropdown.classList.remove('active'); + userDropdownTrigger.classList.remove('active'); + // Switch to users tab + this.switchToUsersTab(); + }); } /** @@ -214,10 +250,13 @@ class MailingListApp { if (this.currentUser) { document.getElementById('currentUsername').textContent = this.currentUser.username; document.getElementById('currentUserRole').textContent = this.currentUser.role; + document.getElementById('dropdownUsername').textContent = this.currentUser.username; + document.getElementById('dropdownUserRole').textContent = this.currentUser.role; // Show/hide admin-only features const isAdmin = this.currentUser.role === 'administrator'; - document.getElementById('usersTab').style.display = isAdmin ? 'block' : 'none'; + document.getElementById('userManagementBtn').style.display = isAdmin ? 'block' : 'none'; + document.getElementById('userManagementDivider').style.display = isAdmin ? 'block' : 'none'; // Show/hide write access features const hasWriteAccess = this.currentUser.role === 'administrator' || this.currentUser.role === 'operator'; @@ -250,6 +289,28 @@ class MailingListApp { document.getElementById('showBulkImportBtn').setAttribute('data-requires-write', ''); } + /** + * Switch to users tab (triggered from user dropdown) + */ + switchToUsersTab() { + // Switch to users tab programmatically + const tabButtons = document.querySelectorAll('.tab-btn'); + const tabContents = document.querySelectorAll('.tab-content'); + + // Remove active class from all tabs and contents + tabButtons.forEach(btn => btn.classList.remove('active')); + tabContents.forEach(content => content.classList.remove('active')); + + // Show users tab content + const usersTab = document.getElementById('users-tab'); + if (usersTab) { + usersTab.classList.add('active'); + } + + // Load users data if needed + this.loadUsers(); + } + /** * Load all data from API */