From c5dad4a92eb1906ca6ed68cf66c829d54f9ce292 Mon Sep 17 00:00:00 2001 From: Aigars Silkalns Date: Fri, 20 Jun 2025 14:29:45 +0300 Subject: [PATCH] Major footer/navbar changes on mobile --- src/assets/scripts/app.js | 492 ++++++--- src/assets/styles/index.scss | 113 +++ .../styles/spec/components/pageContainer.scss | 161 ++- src/assets/styles/spec/components/topbar.scss | 241 +++++ src/assets/styles/utils/mobile.scss | 954 ++++++++++++++++++ 5 files changed, 1844 insertions(+), 117 deletions(-) create mode 100644 src/assets/styles/utils/mobile.scss diff --git a/src/assets/scripts/app.js b/src/assets/scripts/app.js index 1359a94..fd7b75b 100644 --- a/src/assets/scripts/app.js +++ b/src/assets/scripts/app.js @@ -1,6 +1,6 @@ /** * Modern Adminator Application - * Main application entry point - replaces jQuery-based initialization + * Main application entry point with enhanced mobile support */ import bootstrap from 'bootstrap'; @@ -24,7 +24,6 @@ import './vectorMaps'; import './chat'; import './email'; import './googleMaps'; -import './utils'; class AdminatorApp { constructor() { @@ -43,7 +42,7 @@ class AdminatorApp { init() { if (this.isInitialized) return; - console.log('๐Ÿš€ Initializing Adminator App (Modern Version)'); + console.log('๐Ÿš€ Initializing Adminator App (Mobile Optimized)'); try { // Initialize core components @@ -52,6 +51,7 @@ class AdminatorApp { this.initDataTables(); this.initDatePickers(); this.initTheme(); + this.initMobileEnhancements(); // Setup global event listeners this.setupGlobalEvents(); @@ -201,97 +201,107 @@ class AdminatorApp { try { picker.showPicker(); } catch (e) { - // Fallback for browsers that don't support showPicker console.log('๐Ÿ“… Date picker opened via icon click'); } } }); - - // Also make the entire icon container clickable - const iconContainer = inputGroup.querySelector('.input-group-text'); - if (iconContainer) { - iconContainer.style.cursor = 'pointer'; - DOM.on(iconContainer, 'click', (event) => { - event.preventDefault(); - event.stopPropagation(); - picker.focus(); - if (picker.showPicker && typeof picker.showPicker === 'function') { - try { - picker.showPicker(); - } catch (e) { - console.log('๐Ÿ“… Date picker opened via icon container click'); - } - } - }); - } } } }); - - // Add date validation - [...startDatePickers, ...endDatePickers].forEach(picker => { - DOM.on(picker, 'change', (event) => { - const isValid = DateUtils.form.validateDateInput(event.target.value); - if (!isValid) { - event.target.classList.add('is-invalid'); - console.warn('Invalid date format:', event.target.value); - } else { - event.target.classList.remove('is-invalid'); - console.log('Valid date selected:', DateUtils.formatters.shortDate(event.target.value)); - } - }); - - // Add focus/blur handlers for better UX - DOM.on(picker, 'focus', () => { - picker.classList.add('focus'); - }); - - DOM.on(picker, 'blur', () => { - picker.classList.remove('focus'); - }); - }); } /** - * Initialize theme + * Initialize theme system with toggle */ initTheme() { + console.log('๐ŸŒ™ Initializing theme system'); + + // Initialize theme system first Theme.init(); - - // inject toggle switch if missing - const navRight = document.querySelector('.nav-right'); - if (navRight && !document.getElementById('theme-toggle')) { + + // Inject theme toggle if missing - with retry mechanism + setTimeout(() => { + const navRight = DOM.select('.nav-right'); + console.log('๐Ÿ” nav-right found:', !!navRight); + console.log('๐Ÿ” navRight element:', navRight); + console.log('๐Ÿ” theme-toggle exists:', DOM.exists('#theme-toggle')); + console.log('๐Ÿ” All nav-right li elements:', navRight ? navRight.querySelectorAll('li').length : 0); + + // Debug the DOM structure + if (navRight) { + console.log('๐Ÿ” navRight children:', Array.from(navRight.children).map(child => ({ + tagName: child.tagName, + className: child.className, + id: child.id + }))); + } + + if (navRight && !DOM.exists('#theme-toggle')) { const li = document.createElement('li'); li.className = 'theme-toggle d-flex ai-c'; li.innerHTML = `
`; - navRight.insertBefore(li, navRight.firstElementChild); - - const toggleInput = li.querySelector('#theme-toggle'); - - const updateSwitch = () => { - toggleInput.checked = Theme.current() === 'dark'; - }; - updateSwitch(); - - toggleInput.addEventListener('change', (e) => { - Theme.apply(e.target.checked ? 'dark' : 'light'); - }); + + // Insert before user dropdown (last item) - safer approach + const lastItem = navRight.querySelector('li:last-child'); + console.log('๐Ÿ” lastItem found:', !!lastItem); + console.log('๐Ÿ” lastItem parent:', lastItem ? lastItem.parentNode : null); + console.log('๐Ÿ” navRight:', navRight); + + if (lastItem && lastItem.parentNode === navRight) { + navRight.insertBefore(li, lastItem); + console.log('โœ… Theme toggle inserted before last item'); + } else { + navRight.appendChild(li); + console.log('โœ… Theme toggle appended to nav-right (safer approach)'); + } + + // Add toggle functionality + const toggle = DOM.select('#theme-toggle'); + if (toggle) { + // Set initial state + const currentTheme = Theme.current(); + toggle.checked = currentTheme === 'dark'; + + DOM.on(toggle, 'change', () => { + Theme.apply(toggle.checked ? 'dark' : 'light'); + }); + + // Listen for theme changes from other sources + window.addEventListener('adminator:themeChanged', (event) => { + toggle.checked = event.detail.theme === 'dark'; + + // Update charts when theme changes + const charts = this.components.get('charts'); + if (charts) charts.redrawCharts(); + }); + } + } else { + console.log('โŒ No nav-right found or theme-toggle already exists'); + } + }, 100); // Wait 100ms for DOM to be fully ready + } - window.addEventListener('adminator:themeChanged', () => { - updateSwitch(); - const charts = this.components.get('charts'); - if (charts) charts.redrawCharts(); - }); + /** + * Initialize mobile-specific enhancements + */ + initMobileEnhancements() { + console.log('๐Ÿ“ฑ Initializing mobile enhancements'); + this.enhanceMobileDropdowns(); + this.enhanceMobileSearch(); + + // Prevent horizontal scroll on mobile + if (this.isMobile()) { + document.body.style.overflowX = 'hidden'; } } @@ -299,55 +309,312 @@ class AdminatorApp { * Setup global event listeners */ setupGlobalEvents() { - // Global resize handler - let resizeTimer; - window.addEventListener('resize', () => { - clearTimeout(resizeTimer); - resizeTimer = setTimeout(() => { - this.handleResize(); - }, 150); - }); - - // Global click handler for dynamic content - document.addEventListener('click', (e) => { - this.handleGlobalClick(e); + // Global click handler + DOM.on(document, 'click', (event) => this.handleGlobalClick(event)); + + // Window resize handler with debouncing + let resizeTimeout; + DOM.on(window, 'resize', () => { + clearTimeout(resizeTimeout); + resizeTimeout = setTimeout(() => this.handleResize(), 250); }); - - // Custom event for masonry recalculation - window.EVENT = new Event('resize'); + + console.log('๐ŸŒ Global event listeners set up'); } /** - * Handle window resize + * Handle window resize events */ handleResize() { - // Notify charts to resize - const charts = this.components.get('charts'); - if (charts) { - charts.redrawCharts(); + console.log('๐Ÿ“ Window resized, updating mobile features'); + + // Close all mobile-specific overlays when switching to desktop + if (!this.isMobile()) { + document.body.style.overflow = ''; + document.body.style.overflowX = ''; + + // Close dropdowns + const dropdowns = DOM.selectAll('.nav-right .dropdown'); + dropdowns.forEach(dropdown => { + dropdown.classList.remove('show'); + const menu = dropdown.querySelector('.dropdown-menu'); + if (menu) menu.classList.remove('show'); + }); + + // Close search + const searchBox = DOM.select('.search-box'); + const searchInput = DOM.select('.search-input'); + if (searchBox && searchInput) { + searchBox.classList.remove('active'); + searchInput.classList.remove('active'); + } + } else { + // Re-enable mobile overflow protection + document.body.style.overflowX = 'hidden'; } - - // Dispatch resize event for other components - window.dispatchEvent(new CustomEvent('adminator:resize')); + + // Re-apply mobile enhancements + this.enhanceMobileDropdowns(); + this.enhanceMobileSearch(); } /** - * Handle global clicks + * Handle global click events */ handleGlobalClick(event) { - // Handle any global click events here - // This can be used for analytics, debugging, etc. + // Close mobile dropdowns when clicking outside + if (!event.target.closest('.dropdown')) { + const dropdowns = DOM.selectAll('.nav-right .dropdown'); + dropdowns.forEach(dropdown => { + dropdown.classList.remove('show'); + const menu = dropdown.querySelector('.dropdown-menu'); + if (menu) menu.classList.remove('show'); + }); + document.body.style.overflow = ''; + } + + // Close search when clicking outside + if (!event.target.closest('.search-box') && !event.target.closest('.search-input')) { + const searchBox = DOM.select('.search-box'); + const searchInput = DOM.select('.search-input'); + if (searchBox && searchInput) { + searchBox.classList.remove('active'); + searchInput.classList.remove('active'); + document.body.style.overflow = ''; + document.body.classList.remove('mobile-menu-open'); + } + } + } + + /** + * Check if we're on a mobile device + */ + isMobile() { + return window.innerWidth <= 768; } /** - * Get component instance + * Enhanced mobile dropdown handling with improved email layout + */ + enhanceMobileDropdowns() { + if (!this.isMobile()) return; + + const dropdowns = DOM.selectAll('.nav-right .dropdown'); + + dropdowns.forEach(dropdown => { + const toggle = dropdown.querySelector('.dropdown-toggle'); + const menu = dropdown.querySelector('.dropdown-menu'); + + if (toggle && menu) { + // Remove existing listeners to prevent duplicates + const newToggle = toggle.cloneNode(true); + toggle.replaceWith(newToggle); + + // Add click functionality for mobile dropdowns + DOM.on(newToggle, 'click', (e) => { + e.preventDefault(); + e.stopPropagation(); + + // Close search if open + const searchBox = DOM.select('.search-box'); + const searchInput = DOM.select('.search-input'); + if (searchBox && searchInput) { + searchBox.classList.remove('active'); + searchInput.classList.remove('active'); + } + + // Close other dropdowns first + dropdowns.forEach(otherDropdown => { + if (otherDropdown !== dropdown) { + otherDropdown.classList.remove('show'); + const otherMenu = otherDropdown.querySelector('.dropdown-menu'); + if (otherMenu) otherMenu.classList.remove('show'); + } + }); + + // Toggle current dropdown + const isOpen = dropdown.classList.contains('show'); + if (isOpen) { + dropdown.classList.remove('show'); + menu.classList.remove('show'); + document.body.style.overflow = ''; + document.body.classList.remove('mobile-menu-open'); + } else { + dropdown.classList.add('show'); + menu.classList.add('show'); + document.body.style.overflow = 'hidden'; + document.body.classList.add('mobile-menu-open'); + } + }); + + // Enhanced mobile close button functionality + DOM.on(menu, 'click', (e) => { + // Check if clicked on the close area (::before pseudo-element area) + const rect = menu.getBoundingClientRect(); + const clickY = e.clientY - rect.top; + + // If clicked in top 50px (close button area) + if (clickY <= 50) { + dropdown.classList.remove('show'); + menu.classList.remove('show'); + document.body.style.overflow = ''; + document.body.classList.remove('mobile-menu-open'); + e.preventDefault(); + e.stopPropagation(); + } + }); + } + }); + + // Close dropdowns on escape key + DOM.on(document, 'keydown', (e) => { + if (e.key === 'Escape') { + dropdowns.forEach(dropdown => { + dropdown.classList.remove('show'); + const menu = dropdown.querySelector('.dropdown-menu'); + if (menu) menu.classList.remove('show'); + }); + document.body.style.overflow = ''; + document.body.classList.remove('mobile-menu-open'); + } + }); + } + + /** + * Enhanced mobile search handling - Full-width search bar + */ + enhanceMobileSearch() { + const searchBox = DOM.select('.search-box'); + const searchInput = DOM.select('.search-input'); + + if (searchBox && searchInput) { + const searchToggle = searchBox.querySelector('a'); + const searchField = searchInput.querySelector('input'); + + if (searchToggle && searchField) { + console.log('๐Ÿ” Setting up full-width search functionality'); + + // Remove existing listeners to prevent duplication + const newSearchToggle = searchToggle.cloneNode(true); + searchToggle.replaceWith(newSearchToggle); + + DOM.on(newSearchToggle, 'click', (e) => { + e.preventDefault(); + e.stopPropagation(); + + console.log('๐Ÿ” Full-width search toggle clicked'); + + // Close any open dropdowns first + const dropdowns = DOM.selectAll('.nav-right .dropdown'); + dropdowns.forEach(dropdown => { + dropdown.classList.remove('show'); + const menu = dropdown.querySelector('.dropdown-menu'); + if (menu) menu.classList.remove('show'); + }); + + // Toggle search state + const isActive = searchInput.classList.contains('active'); + const searchIcon = newSearchToggle.querySelector('i'); + + if (isActive) { + // Close search + searchInput.classList.remove('active'); + document.body.classList.remove('search-open'); + + // Change icon back to search + if (searchIcon) { + searchIcon.className = 'ti-search'; + } + + // Clear input + if (searchField) { + searchField.value = ''; + searchField.blur(); + } + + console.log('๐Ÿ” Full-width search closed'); + } else { + // Open search + searchInput.classList.add('active'); + document.body.classList.add('search-open'); + + // Change icon to close + if (searchIcon) { + searchIcon.className = 'ti-close'; + } + + // Focus the input after a short delay + setTimeout(() => { + if (searchField) { + searchField.focus(); + console.log('๐Ÿ” Search field focused'); + } + }, 100); + + console.log('๐Ÿ” Full-width search opened'); + } + }); + + // Close search on escape + DOM.on(document, 'keydown', (e) => { + if (e.key === 'Escape' && searchInput.classList.contains('active')) { + searchInput.classList.remove('active'); + document.body.classList.remove('search-open'); + + // Reset icon + const searchIcon = newSearchToggle.querySelector('i'); + if (searchIcon) { + searchIcon.className = 'ti-search'; + } + + // Clear input + if (searchField) { + searchField.value = ''; + searchField.blur(); + } + + console.log('๐Ÿ” Full-width search closed via escape'); + } + }); + + // Handle search input + DOM.on(searchField, 'keypress', (e) => { + if (e.key === 'Enter') { + e.preventDefault(); + const query = searchField.value.trim(); + if (query) { + console.log('๐Ÿ” Search query:', query); + // Implement your search logic here + + // For demo, close search after "searching" + searchInput.classList.remove('active'); + document.body.classList.remove('search-open'); + + const searchIcon = newSearchToggle.querySelector('i'); + if (searchIcon) { + searchIcon.className = 'ti-search'; + } + + searchField.value = ''; + searchField.blur(); + } + } + }); + + console.log('๐Ÿ” Full-width search functionality initialized'); + } + } + } + + /** + * Get a component by name */ getComponent(name) { return this.components.get(name); } /** - * Check if app is initialized + * Check if app is ready */ isReady() { return this.isInitialized; @@ -357,45 +624,42 @@ class AdminatorApp { * Destroy the application */ destroy() { + console.log('๐Ÿ—‘๏ธ Destroying Adminator App'); + // Destroy all components this.components.forEach((component, name) => { if (typeof component.destroy === 'function') { component.destroy(); } + console.log(`๐Ÿ—‘๏ธ ${name} component destroyed`); }); this.components.clear(); this.isInitialized = false; - - console.log('๐Ÿงน Adminator App destroyed'); } /** - * Refresh all components (useful for dynamic content) + * Refresh/reinitialize the application */ refresh() { console.log('๐Ÿ”„ Refreshing Adminator App'); - // Refresh sidebar active links - const sidebar = this.components.get('sidebar'); - if (sidebar) { - sidebar.refreshActiveLink(); - } - - // Reinitialize charts if needed - const charts = this.components.get('charts'); - if (charts) { - charts.redrawCharts(); + if (this.isInitialized) { + this.destroy(); } + + setTimeout(() => { + this.init(); + }, 100); } - - } -// Create global app instance +// Initialize the application +console.log('๐Ÿ“ฑ Starting Adminator (Mobile Optimized)'); const app = new AdminatorApp(); -// Export for external access +// Make app globally available for debugging window.AdminatorApp = app; +// Export for module usage export default app; \ No newline at end of file diff --git a/src/assets/styles/index.scss b/src/assets/styles/index.scss index dee00cf..bd01c1d 100755 --- a/src/assets/styles/index.scss +++ b/src/assets/styles/index.scss @@ -4,6 +4,7 @@ @use 'spec/index' as *; @use 'vendor/index' as *; @import "utils/theme.css"; +@import "utils/mobile.scss"; body { background: var(--c-bkg-body); @@ -83,6 +84,118 @@ body { } } } + + // Mobile theme toggle adjustments + @media (max-width: 991px) { + padding: 0 6px; + height: 65px; + + .form-check { + .form-check-label { + font-size: 10px; + + &:first-child { + margin-right: 4px; + } + + &:last-child { + margin-left: 4px; + } + } + + .form-check-input { + width: 2rem; + height: 1rem; + } + } + } + + // Very small mobile adjustments + @media (max-width: 480px) { + padding: 0 4px; + + .form-check { + flex-direction: column; + align-items: center; + text-align: center; + + .form-check-label { + font-size: 8px; + margin: 1px 0; + white-space: nowrap; + + i { + margin: 0 2px; + } + } + + .form-check-input { + width: 1.5rem; + height: 0.8rem; + margin: 2px 0; + } + } + } + } +} + +// Mobile dropdown menu improvements +@media (max-width: 767px) { + .header { + .nav-right { + .dropdown-menu { + position: fixed !important; + top: 65px !important; + left: 5px !important; + right: 5px !important; + width: auto !important; + max-width: none !important; + min-width: auto !important; + transform: none !important; + z-index: 1050; + border-radius: 8px; + box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15); + max-height: calc(100vh - 85px); + overflow-y: auto; + } + + .notifications .dropdown-menu { + max-height: calc(100vh - 85px); + overflow-y: auto; + } + } + } +} + +// Mobile search input overlay +@media (max-width: 480px) { + .header { + .search-input { + &.active { + position: absolute; + top: 65px; + left: 0; + right: 0; + background: var(--c-bkg-card); + border-top: 1px solid var(--c-border); + padding: 10px; + z-index: 999; + + input { + margin-top: 0; + width: 100%; + padding: 10px; + border: 1px solid var(--c-border); + border-radius: 4px; + background: var(--c-bkg-card); + color: var(--c-text-base); + + &::placeholder { + color: var(--c-text-muted); + } + } + } + } } } diff --git a/src/assets/styles/spec/components/pageContainer.scss b/src/assets/styles/spec/components/pageContainer.scss index 44159f0..4589d47 100755 --- a/src/assets/styles/spec/components/pageContainer.scss +++ b/src/assets/styles/spec/components/pageContainer.scss @@ -10,15 +10,20 @@ // + @Main Content // + @Full Container // + @Collapsed State +// + @Mobile Layout Fixes // --------------------------------------------------------- -// @Page Container +// @Page Container - MODERN LAYOUT APPROACH // --------------------------------------------------------- .page-container { min-height: 100vh; padding-left: $offscreen-size; transition: all 0.2s ease; + + // Modern flexbox layout to prevent footer overlap + display: flex; + flex-direction: column; @include between($breakpoint-md, $breakpoint-xl) { padding-left: $collapsed-size; @@ -30,16 +35,30 @@ } // --------------------------------------------------------- -// @Main Content +// @Main Content - FLEXIBLE LAYOUT // --------------------------------------------------------- .main-content { padding: 85px 20px 20px; - min-height: calc(100vh - 61px); + + // Flex-grow to push footer to bottom + flex: 1 0 auto; + min-height: 0; // Allow flex shrinking + + // Ensure content doesn't overflow + overflow-x: hidden; @include to($breakpoint-md) { padding: 85px 5px 5px; } + + @include to($breakpoint-sm) { + padding: 85px 10px 30px; // Extra bottom padding on mobile + } + + @include to(400px) { + padding: 85px 5px 40px; // Even more bottom padding on tiny screens + } } .remain-height { @@ -68,6 +87,142 @@ } } +// --------------------------------------------------------- +// @Mobile Layout Fixes - AGGRESSIVE FOOTER SOLUTION +// --------------------------------------------------------- + +// Footer - completely redesigned for mobile +footer { + // Flex-shrink: 0 to prevent compression + flex: 0 0 auto; + + // Positioning + position: relative; + z-index: 1; + + // Styling + margin-top: auto; + padding: 20px; + text-align: center; + border-top: 1px solid var(--c-border); + background: var(--c-bkg-card); + color: var(--c-text-muted); + font-size: 12px; + line-height: 1.4; + + // Prevent any potential overflow + word-wrap: break-word; + overflow-wrap: break-word; + + // Tablet footer adjustments + @include to($breakpoint-md) { + padding: 18px 15px; + font-size: 11px; + } + + // Mobile footer adjustments + @include to($breakpoint-sm) { + padding: 15px 10px; + font-size: 10px; + line-height: 1.3; + + span { + display: inline-block; + max-width: 100%; + + a { + color: var(--c-primary); + text-decoration: none; + word-break: break-word; + + &:hover { + text-decoration: underline; + } + } + } + } + + // Tiny screen footer adjustments + @include to(400px) { + padding: 12px 8px; + font-size: 9px; + line-height: 1.2; + + span { + display: block; + + // Break long text on new lines for readability + &::after { + content: ""; + display: block; + height: 2px; + } + } + } +} + +// Ensure body and html take full height for flex layout +html, body { + height: 100%; + margin: 0; + padding: 0; +} + +// Global mobile overflow prevention +@include to($breakpoint-sm) { + body { + overflow-x: hidden; + } + + // Prevent any element from causing horizontal scroll + * { + max-width: 100%; + box-sizing: border-box; + } +} + +// Additional mobile content spacing +@include to($breakpoint-sm) { + .page-container { + .main-content { + // Extra margin-bottom to ensure footer never overlaps + margin-bottom: 20px; + + // Responsive content adjustments + .row { + margin-left: 0; + margin-right: 0; + } + + .col-md-6, .col-md-3, .col-md-12 { + padding-left: 5px; + padding-right: 5px; + } + } + } +} + +// Emergency footer overlap prevention +@include to(480px) { + .page-container { + // Force minimum height that accounts for content + min-height: calc(100vh - 80px); + + .main-content { + // Ensure there's always space for footer + padding-bottom: 60px !important; + margin-bottom: 20px !important; + } + } + + footer { + // Stick to bottom on very small screens + position: relative; + margin-top: auto; + clear: both; + } +} + // --------------------------------------------------------- // @Collapsed State // --------------------------------------------------------- diff --git a/src/assets/styles/spec/components/topbar.scss b/src/assets/styles/spec/components/topbar.scss index 25d3b80..9183b8c 100755 --- a/src/assets/styles/spec/components/topbar.scss +++ b/src/assets/styles/spec/components/topbar.scss @@ -10,6 +10,7 @@ // + @Topbar // + @Collapsed State +// + @Mobile Responsive Fixes // --------------------------------------------------------- // @Topbar @@ -195,6 +196,244 @@ } } +// --------------------------------------------------------- +// @Mobile Responsive Fixes - AGGRESSIVE APPROACH +// --------------------------------------------------------- + +// Tablet mobile fixes (768px to 991px) +@include to($breakpoint-md) { + .header { + .header-container { + padding: 0 10px; + + .nav-left { + margin-left: 5px; + + > li > a { + padding: 0 8px !important; + } + } + + .nav-right { + margin-right: 5px; + + > li { + > a { + padding: 0 8px !important; + + // Hide text in user dropdown on tablet + .peer:last-child { + display: none; + } + } + } + + // Make theme toggle more compact + .theme-toggle { + padding: 0 5px !important; + + .form-check-label { + font-size: 9px !important; + margin: 0 3px !important; + } + + .form-check-input { + width: 1.8rem !important; + height: 1rem !important; + } + } + } + } + } +} + +// Small mobile phones (576px to 767px) +@include to($breakpoint-sm) { + .header { + .header-container { + height: auto; + min-height: $header-height; + padding: 0 5px; + + .nav-left { + margin-left: 2px; + + > li > a { + padding: 0 5px !important; + } + + // Hide search toggle on small mobile - make it icon only when active + .search-box:not(.active) { + display: none; + } + } + + .nav-right { + margin-right: 2px; + + > li { + > a { + padding: 0 4px !important; + + // Hide all text content, keep only icons + span { + display: none; + } + + .peer:last-child { + display: none; + } + } + } + + // Ultra-compact theme toggle + .theme-toggle { + padding: 0 3px !important; + + .form-check { + flex-direction: column; + align-items: center; + + .form-check-label { + font-size: 7px !important; + margin: 0 !important; + line-height: 1 !important; + + span { + display: none !important; + } + } + + .form-check-input { + width: 1.5rem !important; + height: 0.8rem !important; + margin: 1px 0 !important; + } + } + } + } + + // Full-screen mobile dropdowns + .nav-right .dropdown-menu { + position: fixed !important; + top: $header-height !important; + left: 0 !important; + right: 0 !important; + bottom: 0 !important; + width: 100vw !important; + height: calc(100vh - #{$header-height}) !important; + max-width: none !important; + min-width: auto !important; + transform: none !important; + border-radius: 0 !important; + z-index: 9999; + overflow-y: auto; + + // Close button for mobile dropdowns + &::before { + content: "โœ• Close"; + position: sticky; + top: 0; + display: block; + background: var(--c-primary); + color: white; + text-align: center; + padding: 10px; + cursor: pointer; + font-weight: bold; + z-index: 10000; + } + } + } + } +} + +// Extra small mobile phones (less than 576px) +@include to(480px) { + .header { + .header-container { + display: flex; + align-items: center; + justify-content: space-between; + flex-wrap: nowrap; + padding: 0 2px; + + .nav-left { + flex: 0 0 auto; + margin: 0; + + > li { + float: none; + display: inline-block; + + > a { + padding: 0 3px !important; + font-size: 14px !important; + } + } + + // Search overlay for tiny screens + .search-input.active { + position: fixed; + top: $header-height; + left: 0; + right: 0; + background: var(--c-bkg-card); + border-top: 1px solid var(--c-border); + padding: 15px; + z-index: 9998; + + input { + width: 100%; + padding: 12px; + font-size: 16px; + border: 1px solid var(--c-border); + border-radius: 6px; + background: var(--c-bkg-card); + color: var(--c-text-base); + margin-top: 0; + + &::placeholder { + color: var(--c-text-muted); + } + } + } + } + + .nav-right { + flex: 0 0 auto; + margin: 0; + + > li { + float: none; + display: inline-block; + + > a { + padding: 0 2px !important; + font-size: 12px !important; + } + } + + // Minimal theme toggle + .theme-toggle { + padding: 0 1px !important; + + .form-check { + .form-check-label { + display: none !important; + } + + .form-check-input { + width: 1.2rem !important; + height: 0.7rem !important; + } + } + } + } + } + } +} + // --------------------------------------------------------- // @Collapsed State // --------------------------------------------------------- @@ -212,3 +451,5 @@ } } } + + diff --git a/src/assets/styles/utils/mobile.scss b/src/assets/styles/utils/mobile.scss new file mode 100644 index 0000000..14d4352 --- /dev/null +++ b/src/assets/styles/utils/mobile.scss @@ -0,0 +1,954 @@ +// Mobile Utility Classes and Fixes +// This file contains mobile-specific utility classes and responsive fixes + +// Mobile text utilities - Only hide theme labels on very small screens +@media (max-width: 480px) { + .theme-toggle .form-check-label { + display: none !important; + } + + .theme-toggle { + padding: 0 6px !important; + height: 60px !important; // Match header height + justify-content: center !important; + min-height: 60px !important; + + .form-check { + height: 100% !important; + + .form-check-label { + font-size: 11px !important; // Slightly smaller for very small screens + font-weight: 500 !important; + + i { + font-size: 14px !important; // Still reasonable for tiny screens + } + } + + .form-check-input { + margin: 0 6px !important; + width: 38px !important; // Bigger than before but not huge for tiny screens + height: 22px !important; // Bigger than before but not huge for tiny screens + border-radius: 11px !important; + border-width: 2px !important; + } + } + } + + // Very small screen adjustments + .d-none-xs { + display: none !important; + } + + .fs-xs { + font-size: 10px !important; + } + + .p-xs { + padding: 5px !important; + } + + .m-xs { + margin: 5px !important; + } +} + +// Mobile dropdown improvements +@media (max-width: 767px) { + .dropdown-menu { + // Ensure all dropdowns are mobile-friendly + &.show { + position: fixed !important; + top: 65px !important; + left: 5px !important; + right: 5px !important; + width: auto !important; + transform: none !important; + z-index: 1050; + max-height: calc(100vh - 85px); + overflow-y: auto; + } + } + + // Mobile notification improvements + .notifications .dropdown-menu { + .scrollable { + max-height: 300px; + overflow-y: auto; + } + } +} + +// Mobile header compact mode +@media (max-width: 991px) { + .header .nav-right > li > a { + padding: 0 6px !important; + } + + .header .nav-left > li > a { + padding: 0 8px !important; + } +} + +// Ultra-compact mode for very small screens +@media (max-width: 480px) { + .header .nav-right > li > a { + padding: 0 4px !important; + font-size: 14px !important; + } + + .header .nav-left > li > a { + padding: 0 6px !important; + } + + // Hide search on very small screens when not active + .search-box:not(.active) { + display: none !important; + } +} + +// Mobile-specific spacing utilities +.mobile-compact { + @media (max-width: 767px) { + padding: 5px !important; + margin: 2px !important; + } +} + +.mobile-hidden { + @media (max-width: 767px) { + display: none !important; + } +} + +.mobile-only { + display: none !important; + + @media (max-width: 767px) { + display: block !important; + } +} + +// Prevent horizontal scroll on mobile +.mobile-no-scroll { + @media (max-width: 767px) { + overflow-x: hidden !important; + } +} + +// COMPREHENSIVE Mobile Header Fixes +// Better layout, bigger icons, full-width search, and desktop fixes + +// ============================================================================= +// DESKTOP FIXES - Remove top spacing issue +// ============================================================================= + +@media screen and (min-width: 768px) { + .header { + margin-top: 0 !important; + top: 0 !important; + } + + .page-container { + padding-top: 61px !important; // Standard header height + 1px border + } + + .main-content { + margin-top: 0 !important; + padding-top: 20px !important; + } + + // DESKTOP THEME TOGGLE - Make sure it's fully visible + .theme-toggle { + display: flex !important; + align-items: center !important; + height: 65px !important; + padding: 0 15px !important; + + .form-check { + margin: 0 !important; + display: flex !important; + align-items: center !important; + + .form-check-label { + color: var(--c-text-muted) !important; + font-size: 11px !important; + font-weight: 500 !important; + text-transform: uppercase !important; + letter-spacing: 0.5px !important; + display: inline !important; + + i { + font-size: 12px !important; + } + } + + .form-check-input { + width: 2.5rem !important; + height: 1.25rem !important; + background-color: var(--c-border) !important; + border: 1px solid var(--c-border) !important; + cursor: pointer !important; + margin: 0 8px !important; + + &:checked { + background-color: var(--c-primary) !important; + border-color: var(--c-primary) !important; + } + + &:focus { + box-shadow: 0 0 0 0.2rem color-mix(in srgb, var(--c-primary) 25%, transparent) !important; + border-color: var(--c-primary) !important; + } + } + } + } +} + +// ============================================================================= +// HEADER NAVIGATION MOBILE FIXES - ENHANCED LAYOUT +// ============================================================================= + +// Mobile header fixes with improved spacing and layout +@media screen and (max-width: 767px) { + + // Force header to be fixed and proper height + .header { + position: fixed !important; + top: 0 !important; + left: 0 !important; + right: 0 !important; + z-index: 1000 !important; + width: 100% !important; + height: auto !important; + min-height: 60px !important; + padding: 0 !important; + margin: 0 !important; + margin-top: 0 !important; // Ensure no top margin on mobile + } + + // Header container - IMPROVED EDGE-TO-EDGE LAYOUT + .header .header-container { + display: flex !important; + align-items: center !important; + justify-content: space-between !important; + flex-wrap: nowrap !important; + padding: 8px 8px !important; // Reduced side padding for more space + height: auto !important; + min-height: 60px !important; + max-height: 60px !important; + overflow: visible !important; + gap: 12px !important; // Larger gap to push items apart + } + + // LEFT SECTION: Logo + Hamburger + Search - PUSHED MORE LEFT + .header .nav-left { + display: flex !important; + align-items: center !important; + flex: 1 1 auto !important; + margin: 0 !important; + padding: 0 !important; + float: none !important; + max-width: 65% !important; // Increased width + gap: 4px !important; // Tighter spacing between left items + justify-content: flex-start !important; // Push to left edge + + // Logo first - positioned at far left + &::before { + content: "A" !important; + display: inline-flex !important; + align-items: center !important; + justify-content: center !important; + width: 32px !important; + height: 32px !important; + background: #007bff !important; + color: white !important; + border-radius: 6px !important; + font-weight: bold !important; + font-size: 18px !important; + flex-shrink: 0 !important; + order: -1 !important; + margin-right: 6px !important; // Small margin to separate from hamburger + } + + > li { + display: inline-flex !important; + align-items: center !important; + margin: 0 !important; + float: none !important; + + > a { + padding: 8px 6px !important; // Reduced padding for tighter spacing + margin: 0 !important; + min-height: auto !important; + line-height: 1 !important; + display: flex !important; + align-items: center !important; + border-radius: 4px !important; + + i { + font-size: 20px !important; + margin: 0 !important; + } + + // Hover state for better UX + &:hover { + background: rgba(0, 0, 0, 0.05) !important; + } + } + + // Sidebar toggle (hamburger) + &:first-child > a { + padding: 8px 6px !important; + + i { + font-size: 22px !important; + } + } + + // Search toggle + &.search-box > a { + padding: 8px 6px !important; + + i { + font-size: 20px !important; + } + } + } + + // FULL-WIDTH SEARCH BAR - CLEANER DESIGN + .search-input { + display: none !important; // Hidden by default + position: fixed !important; // Fixed positioning for full control + top: 60px !important; // Right below header + left: 0 !important; + right: 0 !important; + background: var(--c-bkg-card) !important; + border-bottom: 1px solid var(--c-border) !important; + padding: 15px 20px !important; // More padding for better appearance + z-index: 9999 !important; + box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1) !important; // Subtle shadow + + &.active { + display: block !important; + } + + input { + width: 100% !important; + padding: 12px 16px !important; // Better padding + font-size: 16px !important; + border: 1px solid var(--c-border) !important; + border-radius: 8px !important; // Rounded corners + background: var(--c-bkg-body) !important; + color: var(--c-text-base) !important; + margin: 0 !important; + outline: none !important; + + &::placeholder { + color: var(--c-text-muted) !important; + } + + &:focus { + outline: none !important; + border-color: var(--c-primary) !important; + box-shadow: 0 0 0 2px rgba(0, 123, 255, 0.25) !important; + } + } + } + } + + // RIGHT SECTION: Notifications + Messages + Theme Toggle + Profile - PERFECT ALIGNMENT + .header .nav-right { + display: flex !important; + align-items: center !important; + flex: 0 0 auto !important; + margin: 0 !important; + padding: 0 !important; + float: none !important; + flex-wrap: nowrap !important; + gap: 4px !important; // Consistent spacing + justify-content: flex-end !important; // Push to right edge + height: 60px !important; // Match header height exactly + + > li { + display: flex !important; + align-items: center !important; + justify-content: center !important; + margin: 0 !important; + padding: 0 !important; + float: none !important; + flex: 0 0 auto !important; + position: relative !important; + height: 60px !important; // Force exact height for all items + min-height: 60px !important; // Ensure minimum height + + > a { + padding: 0 !important; // NO padding for perfect alignment + margin: 0 !important; + width: 44px !important; // Fixed width for all nav items + height: 44px !important; // Fixed height for all nav items + line-height: 1 !important; + display: flex !important; + align-items: center !important; // Perfect vertical centering + justify-content: center !important; // Perfect horizontal centering + position: relative !important; + border-radius: 50% !important; // Circular touch targets + background: transparent !important; + transition: all 0.2s ease !important; // Smooth transitions + + i { + font-size: 20px !important; // Consistent icon size for all nav items + margin: 0 !important; + display: block !important; + line-height: 1 !important; + text-align: center !important; + } + + // Hide text content, keep only icons + span:not(.counter) { + display: none !important; + } + + // Hide user avatar text + .peer:last-child { + display: none !important; + } + + // Hover state - subtle and theme-consistent + &:hover { + background: var(--c-grey-100) !important; + transform: scale(1.05) !important; + transition: all 0.2s ease !important; + } + } + + // User dropdown - special styling for avatar + &:last-child > a { + .peer { + &:first-child { + margin-right: 0 !important; + display: flex !important; + align-items: center !important; + justify-content: center !important; + } + + img { + width: 36px !important; + height: 36px !important; + max-width: 36px !important; + max-height: 36px !important; + border-radius: 50% !important; + object-fit: cover !important; + } + } + } + } + + // NOTIFICATION COUNTERS - CORRECTLY ANCHORED + > li { + position: relative !important; // This is the anchor + + .counter { + position: absolute !important; + top: 10px !important; + right: 10px !important; + z-index: 10 !important; + + // The design of the counter itself is inherited + } + } + + // Theme toggle - perfectly aligned with other nav icons + .theme-toggle { + padding: 0 !important; + display: flex !important; + align-items: center !important; + justify-content: center !important; + height: 60px !important; // Match header height exactly + min-height: 60px !important; // Force exact height + width: 44px !important; // Same width as other nav items + + .form-check { + margin: 0 !important; + padding: 0 !important; + align-items: center !important; + justify-content: center !important; + display: flex !important; + height: 44px !important; // Same height as other nav items + width: 44px !important; // Same width as other nav items + border-radius: 50% !important; // Match other nav items + position: relative !important; + + .form-check-label { + display: none !important; // Hide labels on mobile for consistency + } + + .form-check-input { + width: 28px !important; // Smaller switch to fit in circular area + height: 16px !important; // Smaller switch to fit in circular area + margin: 0 !important; // No margin for perfect centering + flex-shrink: 0 !important; + border-radius: 8px !important; // Proportional border radius + border-width: 1px !important; // Standard border + position: absolute !important; + top: 50% !important; + left: 50% !important; + transform: translate(-50%, -50%) !important; // Perfect centering + } + + // Hover state to match other nav items + &:hover { + background: var(--c-grey-100) !important; + transform: scale(1.05) !important; + transition: all 0.2s ease !important; + } + } + } + } + + // Full-screen mobile dropdowns + .header .nav-right .dropdown-menu { + position: fixed !important; + top: 60px !important; + left: 0 !important; + right: 0 !important; + bottom: 0 !important; + width: 100vw !important; + height: calc(100vh - 60px) !important; + max-width: none !important; + min-width: auto !important; + transform: none !important; + border-radius: 0 !important; + z-index: 9999 !important; + overflow-y: auto !important; + border: none !important; + margin: 0 !important; + padding: 0 !important; + + // Mobile close button + &::before { + content: "โœ• Close" !important; + position: sticky !important; + top: 0 !important; + display: block !important; + background: var(--c-primary) !important; + color: white !important; + text-align: center !important; + padding: 15px !important; + cursor: pointer !important; + font-weight: bold !important; + z-index: 10000 !important; + font-size: 16px !important; + } + + // UNIFIED EMAIL/NOTIFICATION MOBILE LAYOUT + .peers { + padding: 15px 20px !important; + flex-wrap: wrap !important; + align-items: flex-start !important; + + .peer { + max-width: 100% !important; + + img { + width: 40px !important; + height: 40px !important; + margin-right: 12px !important; + flex-shrink: 0 !important; + } + + &.peer-greed { + flex: 1 !important; + min-width: 0 !important; + + // NOTIFICATIONS STYLE - Direct content (span > fw-500 + c-grey-600, then p > small) + > span { + display: block !important; + margin-bottom: 4px !important; + + .fw-500 { + font-size: 14px !important; + font-weight: 600 !important; + margin: 0 !important; + color: var(--c-text-base) !important; + display: inline !important; + } + + .c-grey-600 { + font-size: 13px !important; + color: var(--c-text-muted) !important; + line-height: 1.4 !important; + display: inline !important; + } + } + + > p { + margin: 0 !important; + + small { + font-size: 12px !important; + color: var(--c-text-muted) !important; + } + } + + // EMAILS STYLE - Match notifications exactly + > div { + // Completely restructure emails to match notification layout + display: block !important; + + .peers { + display: inline !important; // Make name and action on same line + margin: 0 !important; + + .peer { + &:first-child { + // Name section + p { + font-size: 14px !important; + font-weight: 600 !important; + margin: 0 !important; + color: var(--c-text-base) !important; + display: inline !important; + } + + // Add action text after name + &::after { + content: " sent you a message" !important; + font-size: 13px !important; + color: var(--c-text-muted) !important; + font-weight: normal !important; + } + } + + &:last-child { + // Move timestamp to its own line below (like notifications) + display: block !important; + margin-top: 2px !important; + + small { + font-size: 12px !important; + color: var(--c-text-muted) !important; + display: block !important; + } + } + } + } + + // Hide the email preview text completely to match notifications + > .c-grey-600, + .c-grey-600.fsz-sm { + display: none !important; + } + } + } + } + } + + // Header items in dropdown + .pX-20 { + padding-left: 20px !important; + padding-right: 20px !important; + + .fw-600 { + font-size: 16px !important; + font-weight: 600 !important; + } + } + + // Footer links in dropdown + .ta-c { + padding: 15px 20px !important; + + a { + font-size: 14px !important; + font-weight: 500 !important; + } + } + } +} + +// Extra small screens - refined adjustments +@media screen and (max-width: 479px) { + .header .header-container { + padding: 8px 5px !important; // Even less padding for tiny screens + gap: 8px !important; + } + + .header .nav-left { + max-width: 60% !important; + gap: 2px !important; // Even tighter spacing + + &::before { + width: 28px !important; + height: 28px !important; + font-size: 16px !important; + margin-right: 4px !important; + } + + > li > a { + padding: 8px 4px !important; + + i { + font-size: 18px !important; + } + } + } + + .header .nav-right { + gap: 1px !important; // Minimal spacing + + > li > a { + padding: 8px 4px !important; + + i { + font-size: 18px !important; // Slightly smaller for tiny screens + } + } + + .theme-toggle .form-check-input { + width: 28px !important; + height: 16px !important; + } + } + + // Full-width search bar on tiny screens + .header .nav-left .search-input { + padding: 12px 15px !important; + + input { + padding: 10px 12px !important; + font-size: 16px !important; // Prevent zoom on iOS + } + } +} + +// ============================================================================= +// FOOTER OVERLAP FIXES - MAINTAINING PREVIOUS FIXES +// ============================================================================= + +// Global layout fixes +html, body { + height: 100% !important; + margin: 0 !important; + padding: 0 !important; + overflow-x: hidden !important; +} + +// Page container - force flexbox layout +.page-container { + display: flex !important; + flex-direction: column !important; + min-height: 100vh !important; + margin: 0 !important; + padding-top: 60px !important; +} + +// Main content - flexible +.main-content { + flex: 1 0 auto !important; + padding: 20px 10px 40px !important; + margin: 0 !important; + min-height: 0 !important; + overflow-x: hidden !important; +} + +// Footer - fixed to bottom +footer { + flex: 0 0 auto !important; + margin-top: auto !important; + padding: 15px 10px !important; + background: var(--c-bkg-card) !important; + border-top: 1px solid var(--c-border) !important; + text-align: center !important; + font-size: 11px !important; + line-height: 1.3 !important; + z-index: 10 !important; + position: relative !important; + width: 100% !important; + clear: both !important; + + // CRITICAL: Override lh-0 class that causes overlap + &.lh-0 { + line-height: 1.3 !important; // Force proper line height + } +} + +@media screen and (max-width: 767px) { + .page-container { + padding-left: 0 !important; + min-height: 100vh !important; // Ensure full height + position: relative !important; // Ensure positioning context + } + + .main-content { + padding: 15px 8px 60px !important; // Increased bottom padding for footer space + margin-bottom: 0 !important; + width: 100% !important; + box-sizing: border-box !important; + } + + footer { + position: relative !important; // Ensure footer stays in flow + width: 100% !important; + padding: 15px 10px !important; // Increased padding for better spacing + font-size: 11px !important; // Slightly larger for readability + line-height: 1.4 !important; // Better line height for mobile + background: var(--c-bkg-card) !important; + border-top: 1px solid var(--c-border) !important; + margin-top: auto !important; + box-sizing: border-box !important; + + // CRITICAL MOBILE FIXES: Override all conflicting utility classes + &.lh-0 { + line-height: 1.4 !important; // Override line-height: 0 that causes overlap + } + + &.p-30 { + padding: 15px 10px !important; // Override desktop padding + } + + &.fsz-sm { + font-size: 11px !important; // Ensure readable font size on mobile + } + + span { + display: block !important; // Force block for better wrapping + word-wrap: break-word !important; + max-width: 100% !important; + text-align: center !important; + line-height: 1.4 !important; + + // Handle long text better + hyphens: auto !important; + word-break: break-word !important; + + a { + color: var(--c-primary) !important; + text-decoration: none !important; + display: inline !important; // Keep link inline within text + + &:hover { + text-decoration: underline !important; + } + } + } + } +} + +@media screen and (max-width: 479px) { + .main-content { + padding: 10px 8px 50px !important; // Adequate bottom space for footer + } + + footer { + padding: 12px 8px !important; + font-size: 10px !important; + line-height: 1.5 !important; // Better readability on small screens + + // Override utility classes for small screens + &.lh-0 { + line-height: 1.5 !important; // Override line-height: 0 + } + + &.p-30 { + padding: 12px 8px !important; // Override desktop padding + } + + &.fsz-sm { + font-size: 10px !important; // Ensure readable font size + } + + span { + display: block !important; + margin: 0 !important; // Remove extra margins + padding: 0 !important; + text-align: center !important; + + // Split long copyright text into multiple lines if needed + word-spacing: normal !important; + letter-spacing: normal !important; + + // Ensure links are readable + a { + display: inline !important; + white-space: nowrap !important; // Keep "Colorlib" as one word + } + } + } +} + +// Additional mobile footer fixes +@media screen and (max-width: 360px) { + footer { + font-size: 9px !important; + padding: 10px 5px !important; + + // Override utility classes for extra small screens + &.lh-0 { + line-height: 1.6 !important; // Even better line height for tiny screens + } + + &.p-30 { + padding: 10px 5px !important; // Override desktop padding + } + + &.fsz-sm { + font-size: 9px !important; // Readable font size for tiny screens + } + + span { + line-height: 1.6 !important; // Ensure good readability + + // For very small screens, ensure text doesn't overlap + word-break: break-word !important; + overflow-wrap: break-word !important; + + // Ensure links are readable + a { + font-weight: bold !important; + color: var(--c-primary) !important; + } + } + } +} + +// ============================================================================= +// UTILITY CLASSES FOR MOBILE +// ============================================================================= + +// Prevent body scroll when mobile menus are open +body.mobile-menu-open { + overflow: hidden !important; + position: fixed !important; + width: 100% !important; +} + +// Emergency fixes for any remaining issues +@media screen and (max-width: 767px) { + // Ensure dropdowns don't break layout + .dropdown-menu.show { + position: fixed !important; + } + + // Prevent content overflow + .row { + margin-left: 0 !important; + margin-right: 0 !important; + } + + [class*="col-"] { + padding-left: 5px !important; + padding-right: 5px !important; + } + + // Hide on mobile utility + .d-none-mobile { + display: none !important; + } + + // Force no horizontal scroll + * { + max-width: 100% !important; + box-sizing: border-box !important; + } +} \ No newline at end of file