From b98207b1186724cf2a0eeb68f270487d65c150f1 Mon Sep 17 00:00:00 2001 From: admin Date: Thu, 17 Jul 2025 19:40:31 -0600 Subject: [PATCH] Fixed some menu bugs --- map/app/public/admin.html | 37 +++- map/app/public/css/admin.css | 377 ++++++++++++++++++++++++++++++++++ map/app/public/css/shifts.css | 72 +++++++ map/app/public/js/admin.js | 92 ++++++++- 4 files changed, 568 insertions(+), 10 deletions(-) diff --git a/map/app/public/admin.html b/map/app/public/admin.html index f1dbd3a..1698fd9 100644 --- a/map/app/public/admin.html +++ b/map/app/public/admin.html @@ -23,23 +23,46 @@
+

Admin Panel

-
-

Admin Panel

+
diff --git a/map/app/public/css/admin.css b/map/app/public/css/admin.css index 18c487e..17b2a76 100644 --- a/map/app/public/css/admin.css +++ b/map/app/public/css/admin.css @@ -189,6 +189,53 @@ right: 20px; z-index: 10000; max-width: 400px; + pointer-events: none; /* Allow clicks to pass through container */ +} + +/* Mobile status container - center horizontally at top */ +@media (max-width: 768px) { + .status-container { + left: 10px; + right: 10px; + top: 10px; + width: auto; + max-width: 100%; + transform: none; + display: flex; + flex-direction: column; + align-items: center; + } + + .status-message { + width: auto; + max-width: 90vw; + box-sizing: border-box; + font-size: 13px; + text-align: center; + } +} + +/* Very small screens - adjust positioning and sizing */ +@media (max-width: 480px) { + .status-container { + top: 70px; /* Smaller header on mobile */ + max-width: calc(100vw - 20px); + min-width: 260px; + } +} + +/* Extra small screens */ +@media (max-width: 360px) { + .status-container { + top: 65px; + max-width: calc(100vw - 15px); + min-width: auto; + } + + .status-message { + padding: 10px 12px; + font-size: 13px; + } } .status-message { @@ -197,6 +244,8 @@ border-radius: var(--border-radius); font-size: 14px; animation: slideIn 0.3s ease-out; + pointer-events: auto; /* Allow interaction with individual messages */ + cursor: pointer; /* Show it's clickable for dismissal */ } .status-message.success { @@ -897,6 +946,8 @@ padding: 10px 12px; max-width: 90%; text-align: center; + width: fit-content; + margin: 0 auto 10px auto; } } @@ -1271,3 +1322,329 @@ font-size: 10px; } } + +/* Mobile Menu Toggle */ +.mobile-menu-toggle { + display: none; + background: none; + border: none; + padding: 8px; + cursor: pointer; + position: relative; + width: 40px; + height: 40px; +} + +.mobile-menu-toggle span { + display: block; + width: 24px; + height: 3px; + background: white; + margin: 5px auto; + transition: all 0.3s ease; + border-radius: 2px; +} + +.mobile-menu-toggle.active span:nth-child(1) { + transform: rotate(45deg) translate(5px, 5px); +} + +.mobile-menu-toggle.active span:nth-child(2) { + opacity: 0; +} + +.mobile-menu-toggle.active span:nth-child(3) { + transform: rotate(-45deg) translate(7px, -6px); +} + +/* Sidebar Header (mobile) */ +.sidebar-header { + display: none; + justify-content: space-between; + align-items: center; + padding-bottom: 20px; + border-bottom: 1px solid #e0e0e0; + margin-bottom: 20px; +} + +.close-sidebar { + background: none; + border: none; + font-size: 24px; + cursor: pointer; + color: var(--dark-color); + padding: 0; + width: 30px; + height: 30px; + display: flex; + align-items: center; + justify-content: center; +} + +/* Sidebar Footer (mobile) */ +.sidebar-footer { + display: none; + margin-top: auto; + padding-top: 20px; + border-top: 1px solid #e0e0e0; +} + +.mobile-admin-info { + margin-top: 15px; + font-size: 14px; + color: #666; + text-align: center; +} + +/* Navigation Icons */ +.nav-icon { + margin-right: 10px; + font-size: 18px; +} + +/* Utility Classes */ +.desktop-only { + display: flex; +} + +.mobile-only { + display: none; +} + +.btn-block { + width: 100%; + justify-content: center; +} + +/* Mobile Styles */ +@media (max-width: 768px) { + /* Show mobile menu toggle */ + .mobile-menu-toggle { + display: block; + } + + /* Header adjustments */ + .header { + padding: 10px 15px; + display: flex; + align-items: center; + gap: 15px; + } + + .header h1 { + flex: 1; + text-align: center; + margin: 0; + font-size: 18px; + } + + /* Hide desktop elements */ + .desktop-only { + display: none !important; + } + + .mobile-only { + display: flex; + } + + /* Admin container becomes full width */ + .admin-container { + flex-direction: column; + height: calc(100vh - 50px); /* Reduced header height */ + } + + /* Sidebar as overlay */ + .admin-sidebar { + position: fixed; + top: 0; + left: -280px; + width: 280px; + height: 100vh; + background: white; + z-index: 9999; /* Increased from 1000 */ + transition: left 0.3s ease; + box-shadow: 2px 0 10px rgba(0, 0, 0, 0.1); + display: flex; + flex-direction: column; + padding: 20px; + } + + .admin-sidebar.active { + left: 0; + } + + /* Show sidebar header and footer on mobile */ + .sidebar-header { + display: flex; + } + + .sidebar-footer { + display: block; + } + + /* Admin nav mobile styling */ + .admin-nav { + flex: 1; + display: flex; + flex-direction: column; + gap: 8px; + margin: 20px 0; + } + + .admin-nav a { + display: flex; + align-items: center; + padding: 10px 12px; + font-size: 14px; + border-radius: 6px; + background-color: #f5f5f5; + border: 1px solid #e0e0e0; + transition: all 0.2s ease; + } + + .admin-nav a:active { + background-color: #e0e0e0; + transform: scale(0.98); + } + + .admin-nav a.active { + background-color: var(--primary-color); + color: white; + border-color: var(--primary-color); + } + + .admin-nav a:hover { + background-color: #ebebeb; + border-color: #d0d0d0; + } + + .admin-nav a.active:hover { + background-color: #0056b3; + border-color: #0056b3; + } + + /* Smaller nav icons and text */ + .nav-icon { + font-size: 16px; + margin-right: 8px; + flex-shrink: 0; + } + + .nav-text { + font-size: 14px; + font-weight: 500; + } + + /* Compact sidebar header */ + .sidebar-header { + display: flex; + padding-bottom: 15px; + margin-bottom: 0; + } + + .sidebar-header h2 { + font-size: 18px; + margin: 0; + } + + /* Compact sidebar footer */ + .sidebar-footer { + display: block; + margin-top: auto; + padding-top: 15px; + border-top: 1px solid #e0e0e0; + } + + .sidebar-footer .btn { + padding: 10px 12px; + font-size: 14px; + } + + .mobile-admin-info { + margin-top: 10px; + font-size: 13px; + color: #666; + text-align: center; + } + + /* Ensure sidebar fits content without scroll */ + .admin-sidebar { + position: fixed; + top: 0; + left: -280px; + width: 280px; + height: 100vh; + background: white; + z-index: 9999; /* Increased from 1000 */ + transition: left 0.3s ease; + box-shadow: 2px 0 10px rgba(0, 0, 0, 0.1); + display: flex; + flex-direction: column; + padding: 15px; + overflow-y: auto; /* Just in case for very small screens */ + } +} + +/* Small mobile devices */ +@media (max-width: 480px) { + .admin-sidebar { + width: 260px; + left: -260px; + padding: 12px; + } + + .admin-nav { + gap: 6px; + margin: 15px 0; + } + + .admin-nav a { + padding: 8px 10px; + font-size: 13px; + } + + .nav-icon { + font-size: 14px; + margin-right: 6px; + } + + .nav-text { + font-size: 13px; + } + + .sidebar-header h2 { + font-size: 16px; + } + + .sidebar-footer .btn { + padding: 8px 10px; + font-size: 13px; + } + + .mobile-admin-info { + font-size: 12px; + margin-top: 8px; + } +} + +/* Very small screens (under 360px) */ +@media (max-width: 360px) { + .admin-sidebar { + width: 240px; + left: -240px; + } + + .admin-nav a { + padding: 8px; + font-size: 12px; + } + + .nav-icon { + font-size: 13px; + margin-right: 5px; + } + + .nav-text { + font-size: 12px; + } +} diff --git a/map/app/public/css/shifts.css b/map/app/public/css/shifts.css index 834a64e..871f4a0 100644 --- a/map/app/public/css/shifts.css +++ b/map/app/public/css/shifts.css @@ -1,3 +1,75 @@ +/* Header styles - matching admin.css for consistency */ +.header { + background-color: var(--primary-color); + color: white; + padding: 15px 30px; + display: flex; + justify-content: space-between; + align-items: center; + box-shadow: 0 2px 4px rgba(0,0,0,0.1); + position: sticky; + top: 0; + z-index: 100; +} + +.header h1 { + margin: 0; + font-size: 1.5em; + font-weight: 600; +} + +.header-actions { + display: flex; + align-items: center; + gap: 20px; +} + +.user-info { + display: flex; + align-items: center; + gap: 10px; + color: rgba(255,255,255,0.9); + font-size: 14px; +} + +.user-email { + font-weight: 500; +} + +/* Mobile header adjustments */ +@media (max-width: 768px) { + .header { + padding: 12px 15px; + } + + .header h1 { + font-size: 1.2em; + } + + .header-actions { + gap: 10px; + } + + .user-info { + display: none; /* Hide user info on mobile to save space */ + } +} + +@media (max-width: 480px) { + .header { + padding: 10px 15px; + } + + .header h1 { + font-size: 1.1em; + } + + .header-actions .btn { + padding: 6px 12px; + font-size: 13px; + } +} + .shifts-container { max-width: 1200px; margin: 0 auto; diff --git a/map/app/public/js/admin.js b/map/app/public/js/admin.js index a389dc5..f13177c 100644 --- a/map/app/public/js/admin.js +++ b/map/app/public/js/admin.js @@ -10,6 +10,7 @@ document.addEventListener('DOMContentLoaded', () => { loadCurrentStartLocation(); setupEventListeners(); setupNavigation(); + setupMobileMenu(); // Add this line // Check if URL has a hash to show specific section const hash = window.location.hash; @@ -42,6 +43,54 @@ document.addEventListener('DOMContentLoaded', () => { } }); +// Add mobile menu functionality +function setupMobileMenu() { + const menuToggle = document.getElementById('mobile-menu-toggle'); + const sidebar = document.getElementById('admin-sidebar'); + const closeSidebar = document.getElementById('close-sidebar'); + const adminNavLinks = document.querySelectorAll('.admin-nav a'); + + if (menuToggle && sidebar) { + // Toggle menu + menuToggle.addEventListener('click', () => { + sidebar.classList.toggle('active'); + menuToggle.classList.toggle('active'); + document.body.classList.toggle('sidebar-open'); // This line already exists + }); + + // Close sidebar button + if (closeSidebar) { + closeSidebar.addEventListener('click', () => { + sidebar.classList.remove('active'); + menuToggle.classList.remove('active'); + document.body.classList.remove('sidebar-open'); + }); + } + + // Close sidebar when clicking outside + document.addEventListener('click', (e) => { + if (sidebar.classList.contains('active') && + !sidebar.contains(e.target) && + !menuToggle.contains(e.target)) { + sidebar.classList.remove('active'); + menuToggle.classList.remove('active'); + document.body.classList.remove('sidebar-open'); + } + }); + + // Close sidebar when navigation link is clicked on mobile + adminNavLinks.forEach(link => { + link.addEventListener('click', () => { + if (window.innerWidth <= 768) { + sidebar.classList.remove('active'); + menuToggle.classList.remove('active'); + document.body.classList.remove('sidebar-open'); + } + }); + }); + } +} + // Check if user is authenticated as admin async function checkAdminAuth() { try { @@ -53,12 +102,24 @@ async function checkAdminAuth() { return; } - // Display admin info + // Display admin info (desktop) document.getElementById('admin-info').innerHTML = ` 👤 ${escapeHtml(data.user.email)} `; + // Display admin info (mobile) + const mobileAdminInfo = document.getElementById('mobile-admin-info'); + if (mobileAdminInfo) { + mobileAdminInfo.innerHTML = ` +
👤 ${escapeHtml(data.user.email)}
+ + `; + + // Add logout listener for mobile button + document.getElementById('mobile-logout-btn')?.addEventListener('click', handleLogout); + } + document.getElementById('logout-btn').addEventListener('click', handleLogout); } catch (error) { @@ -881,17 +942,42 @@ async function handleLogout() { // Show status message function showStatus(message, type = 'info') { - const container = document.getElementById('status-container'); + let container = document.getElementById('status-container'); + + // Create container if it doesn't exist + if (!container) { + container = document.createElement('div'); + container.id = 'status-container'; + container.className = 'status-container'; + document.body.appendChild(container); + } const messageDiv = document.createElement('div'); messageDiv.className = `status-message ${type}`; messageDiv.textContent = message; + // Add click to dismiss functionality + messageDiv.addEventListener('click', () => { + messageDiv.remove(); + }); + + // Add a small close button for better UX + const closeBtn = document.createElement('span'); + closeBtn.innerHTML = ' ×'; + closeBtn.style.float = 'right'; + closeBtn.style.fontWeight = 'bold'; + closeBtn.style.marginLeft = '10px'; + closeBtn.style.cursor = 'pointer'; + closeBtn.setAttribute('title', 'Click to dismiss'); + messageDiv.appendChild(closeBtn); + container.appendChild(messageDiv); // Auto-remove after 5 seconds setTimeout(() => { - messageDiv.remove(); + if (messageDiv.parentNode) { + messageDiv.remove(); + } }, 5000); }