feat(ui): add responsive sidebar with mobile toggle and overlay

Implement responsive sidebar functionality that auto-opens on desktop (≥1024px) and auto-closes on mobile, with a toggle button for mobile users. Added overlay for mobile sidebar dismissal and CSS for collapsed state on desktop. Minor adjustments to dashboard chart borders and grid layouts.
This commit is contained in:
jgor20
2026-01-11 11:26:37 +00:00
parent ed4231310b
commit f9dd71f411
6 changed files with 148 additions and 72 deletions

View File

@@ -57,9 +57,33 @@ document.addEventListener('alpine:init', () => {
return Alpine.store('data')?.loading || false; return Alpine.store('data')?.loading || false;
}, },
sidebarOpen: window.innerWidth >= 1024,
toggleSidebar() {
this.sidebarOpen = !this.sidebarOpen;
},
init() { init() {
console.log('App controller initialized'); console.log('App controller initialized');
// Handle responsive sidebar transitions
let lastWidth = window.innerWidth;
window.addEventListener('resize', () => {
const currentWidth = window.innerWidth;
const lgBreakpoint = 1024;
// Desktop -> Mobile: Auto-close sidebar to prevent overlay blocking screen
if (lastWidth >= lgBreakpoint && currentWidth < lgBreakpoint) {
this.sidebarOpen = false;
}
// Mobile -> Desktop: Auto-open sidebar (restore standard desktop layout)
if (lastWidth < lgBreakpoint && currentWidth >= lgBreakpoint) {
this.sidebarOpen = true;
}
lastWidth = currentWidth;
});
// Theme setup // Theme setup
document.documentElement.setAttribute('data-theme', 'black'); document.documentElement.setAttribute('data-theme', 'black');
document.documentElement.classList.add('dark'); document.documentElement.classList.add('dark');

View File

@@ -489,3 +489,12 @@
.skeleton-table-row { .skeleton-table-row {
@apply skeleton h-12 w-full mb-2; @apply skeleton h-12 w-full mb-2;
} }
/* Desktop Sidebar Collapsed State */
@media (min-width: 1024px) {
.sidebar-collapsed {
width: 0 !important;
padding: 0 !important;
border: none !important;
}
}

2
public/css/style.css generated

File diff suppressed because one or more lines are too long

View File

@@ -62,8 +62,15 @@
<!-- Navbar --> <!-- Navbar -->
<div <div
class="h-14 border-b border-space-border flex items-center px-6 justify-between bg-space-900/50 backdrop-blur-md z-50"> class="h-14 border-b border-space-border flex items-center px-4 lg:px-6 justify-between bg-space-900/50 backdrop-blur-md z-50 relative">
<div class="flex items-center gap-3"> <div class="flex items-center gap-3">
<!-- Mobile Menu Button -->
<button @click="toggleSidebar()" class="text-gray-400 hover:text-white focus:outline-none p-1 transition-colors">
<svg class="w-6 h-6" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6h16M4 12h16M4 18h16" />
</svg>
</button>
<div <div
class="w-8 h-8 rounded bg-gradient-to-br from-neon-purple to-blue-600 flex items-center justify-center text-white font-bold shadow-[0_0_15px_rgba(168,85,247,0.4)]"> class="w-8 h-8 rounded bg-gradient-to-br from-neon-purple to-blue-600 flex items-center justify-center text-white font-bold shadow-[0_0_15px_rgba(168,85,247,0.4)]">
AG</div> AG</div>
@@ -103,12 +110,47 @@
</div> </div>
<!-- Layout --> <!-- Layout -->
<div class="flex h-[calc(100vh-56px)]"> <div class="flex h-[calc(100vh-56px)] relative">
<!-- Mobile Sidebar Overlay -->
<div x-show="sidebarOpen"
x-transition:enter="transition-opacity ease-linear duration-300"
x-transition:enter-start="opacity-0"
x-transition:enter-end="opacity-100"
x-transition:leave="transition-opacity ease-linear duration-300"
x-transition:leave-start="opacity-100"
x-transition:leave-end="opacity-0"
@click="sidebarOpen = false"
class="fixed inset-0 bg-black/50 z-40 lg:hidden"
style="display: none;"></div>
<!-- Sidebar --> <!-- Sidebar -->
<div class="w-64 bg-space-900 border-r border-space-border flex flex-col pt-6 pb-4"> <div class="fixed top-14 bottom-0 left-0 z-40 bg-space-900 border-r border-space-border transition-all duration-300 shadow-2xl overflow-hidden lg:static lg:h-auto lg:shadow-none lg:flex-shrink-0"
<div class="px-4 mb-2 text-xs font-bold text-gray-600 uppercase tracking-widest" :class="{
'translate-x-0': sidebarOpen,
'-translate-x-full': !sidebarOpen,
'w-64': true,
'lg:translate-x-0': true,
'lg:w-64': sidebarOpen,
'sidebar-collapsed': !sidebarOpen
}">
<!-- Inner Sidebar Content (Fixed Width to prevent squashing) -->
<div class="w-64 flex flex-col h-full pt-6 pb-4 flex-shrink-0">
<!-- Mobile Menu Header -->
<div class="flex items-center justify-between px-4 mb-6 lg:hidden">
<span class="text-sm font-bold text-white">Menu</span>
<button @click="sidebarOpen = false" class="text-gray-400 hover:text-white">
<svg class="w-5 h-5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" />
</svg>
</button>
</div>
<!-- Desktop Header (Main) -->
<div class="px-4 mb-2 text-xs font-bold text-gray-600 uppercase tracking-widest hidden lg:block"
x-text="$store.global.t('main')">Main</div> x-text="$store.global.t('main')">Main</div>
<nav class="flex flex-col gap-1"> <nav class="flex flex-col gap-1">
<button <button
class="nav-item flex items-center gap-3 px-6 py-3 text-sm font-medium text-gray-400 hover:text-white hover:bg-white/5" class="nav-item flex items-center gap-3 px-6 py-3 text-sm font-medium text-gray-400 hover:text-white hover:bg-white/5"
@@ -177,6 +219,7 @@
</div> </div>
</div> </div>
</div> </div>
</div>
<!-- Main Content --> <!-- Main Content -->
<div class="flex-1 overflow-auto bg-space-950 relative custom-scrollbar"> <div class="flex-1 overflow-auto bg-space-950 relative custom-scrollbar">

View File

@@ -260,7 +260,7 @@ window.DashboardCharts.updateCharts = function (component) {
data: data, data: data,
backgroundColor: colors, backgroundColor: colors,
borderColor: getThemeColor("--color-space-950"), borderColor: getThemeColor("--color-space-950"),
borderWidth: 2, borderWidth: 0,
hoverOffset: 0, hoverOffset: 0,
borderRadius: 0, borderRadius: 0,
}, },

View File

@@ -34,7 +34,7 @@
<div class="skeleton-stat-card"></div> <div class="skeleton-stat-card"></div>
<div class="skeleton-stat-card"></div> <div class="skeleton-stat-card"></div>
<div class="skeleton-stat-card"></div> <div class="skeleton-stat-card"></div>
<div class="skeleton-stat-card"></div> <div class="skeleton-stat-card col-span-2 sm:col-span-1"></div>
</div> </div>
<!-- Skeleton Charts --> <!-- Skeleton Charts -->
@@ -155,7 +155,7 @@
<!-- Global Quota Chart --> <!-- Global Quota Chart -->
<div <div
class="stat bg-space-900/40 border border-space-border/30 rounded-xl p-6 h-full flex items-center justify-between gap-3 overflow-hidden relative group hover:border-space-border/60 transition-colors"> class="stat bg-space-900/40 border border-space-border/30 rounded-xl p-6 h-full flex items-center justify-between gap-3 overflow-hidden relative group hover:border-space-border/60 transition-colors col-span-2 sm:col-span-1">
<!-- Chart Container --> <!-- Chart Container -->
<div class="h-14 w-14 lg:h-16 lg:w-16 relative flex-shrink-0"> <div class="h-14 w-14 lg:h-16 lg:w-16 relative flex-shrink-0">
<canvas id="quotaChart"></canvas> <canvas id="quotaChart"></canvas>