fix(bug-2): isCollapsed getter — sidebar auto-expands on mobile viewport
Add isMobile reactive property + resize listener to sidebar store. isCollapsed getter returns collapsed && !isMobile, so: - Desktop: collapse works as normal - Mobile: isCollapsed always false → sidebar always shows expanded state regardless of desktop-set collapsed value Replace all visual $store.sidebar.collapsed → isCollapsed in sidebar + layout. toggle() / _syncDataset() remain on raw `collapsed` (persisted to localStorage). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>main
parent
e0624b5d7c
commit
d3ad4b4740
|
|
@ -62,7 +62,12 @@ document.addEventListener('alpine:init', () => {
|
|||
Alpine.store('sidebar', {
|
||||
mobileOpen: false,
|
||||
collapsed: localStorage.getItem('sidebarCollapsed') === 'true',
|
||||
init() { this._syncDataset(); },
|
||||
isMobile: window.innerWidth < 768,
|
||||
get isCollapsed() { return this.collapsed && ! this.isMobile; },
|
||||
init() {
|
||||
this._syncDataset();
|
||||
window.addEventListener('resize', () => { this.isMobile = window.innerWidth < 768; });
|
||||
},
|
||||
_syncDataset() {
|
||||
if (this.collapsed) {
|
||||
document.documentElement.dataset.sidebarCollapsed = '1';
|
||||
|
|
|
|||
|
|
@ -98,21 +98,21 @@
|
|||
|
||||
<aside
|
||||
x-data="{ wsOpen: false }"
|
||||
:class="$store.sidebar.collapsed ? 'w-16' : 'w-60'"
|
||||
:class="$store.sidebar.isCollapsed ? 'w-16' : 'w-60'"
|
||||
class="fixed inset-y-0 left-0 h-screen flex flex-col bg-s1 border-r border-white/[.06] z-40 -translate-x-full md:translate-x-0 transition-[width,transform] duration-200 ease-in-out"
|
||||
:style="$store.sidebar?.mobileOpen ? 'translate: 0' : null"
|
||||
>
|
||||
<!-- Header: Logo + Workspace Switcher -->
|
||||
<div class="flex-shrink-0 relative" @click.outside="wsOpen = false">
|
||||
<!-- Collapsed state: centered logo acts as expand toggle -->
|
||||
<div x-show="$store.sidebar.collapsed" class="flex items-center justify-center py-4 border-b border-white/[.06]">
|
||||
<div x-show="$store.sidebar.isCollapsed" class="flex items-center justify-center py-4 border-b border-white/[.06]">
|
||||
<button @click="$store.sidebar.toggle()" title="Expand sidebar" class="flex items-center justify-center w-7 h-7 hover:opacity-75 transition-opacity">
|
||||
<img src="/brand/logo-mark.svg" alt="Nimuli" class="w-7 h-7">
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- Expanded state: full header with workspace switcher -->
|
||||
<div x-show="!$store.sidebar.collapsed">
|
||||
<div x-show="!$store.sidebar.isCollapsed">
|
||||
<div class="flex items-stretch border-b border-white/[.06]">
|
||||
<button
|
||||
@click="wsOpen = !wsOpen"
|
||||
|
|
@ -192,8 +192,8 @@
|
|||
wire:navigate
|
||||
data-nav-link="{{ $item['route'] }}"
|
||||
@if(in_array($item['route'], ['w.dashboard', 'dashboard'])) data-nav-exact="1" @endif
|
||||
:title="$store.sidebar.collapsed ? '{{ $item['label'] }}' : ''"
|
||||
:class="$store.sidebar.collapsed ? 'justify-center px-2 gap-0' : 'gap-3 px-3'"
|
||||
:title="$store.sidebar.isCollapsed ? '{{ $item['label'] }}' : ''"
|
||||
:class="$store.sidebar.isCollapsed ? 'justify-center px-2 gap-0' : 'gap-3 px-3'"
|
||||
class="flex items-center py-2 rounded-lg text-sm transition-colors group
|
||||
{{ $isActive
|
||||
? 'bg-blue/10 text-blue'
|
||||
|
|
@ -242,7 +242,7 @@
|
|||
</svg>
|
||||
@endif
|
||||
</span>
|
||||
<span x-show="!$store.sidebar.collapsed" class="truncate">{{ $item['label'] }}</span>
|
||||
<span x-show="!$store.sidebar.isCollapsed" class="truncate">{{ $item['label'] }}</span>
|
||||
</a>
|
||||
@endforeach
|
||||
</nav>
|
||||
|
|
@ -251,24 +251,24 @@
|
|||
<div class="max-md:hidden flex-shrink-0 border-t border-white/[.06] px-2 py-2">
|
||||
<button
|
||||
@click="$store.sidebar.toggle()"
|
||||
:title="$store.sidebar.collapsed ? 'Expand sidebar' : 'Collapse sidebar'"
|
||||
:title="$store.sidebar.isCollapsed ? 'Expand sidebar' : 'Collapse sidebar'"
|
||||
class="flex items-center gap-3 w-full px-3 py-2 rounded-lg text-t3 hover:text-t1 hover:bg-s2 transition-colors"
|
||||
>
|
||||
<span class="w-4 h-4 flex-shrink-0">
|
||||
<svg x-show="!$store.sidebar.collapsed" fill="none" viewBox="0 0 16 16" stroke="currentColor" stroke-width="1.5">
|
||||
<svg x-show="!$store.sidebar.isCollapsed" fill="none" viewBox="0 0 16 16" stroke="currentColor" stroke-width="1.5">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M10 3L5 8l5 5"/>
|
||||
</svg>
|
||||
<svg x-show="$store.sidebar.collapsed" x-cloak fill="none" viewBox="0 0 16 16" stroke="currentColor" stroke-width="1.5">
|
||||
<svg x-show="$store.sidebar.isCollapsed" x-cloak fill="none" viewBox="0 0 16 16" stroke="currentColor" stroke-width="1.5">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M6 3l5 5-5 5"/>
|
||||
</svg>
|
||||
</span>
|
||||
<span x-show="!$store.sidebar.collapsed" class="text-xs">Collapse</span>
|
||||
<span x-show="!$store.sidebar.isCollapsed" class="text-xs">Collapse</span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- Plan Usage Box -->
|
||||
@if($workspace && $plan)
|
||||
<div x-show="!$store.sidebar.collapsed" class="mx-3 mb-3 p-3 bg-s2 border border-white/[.06] rounded-lg">
|
||||
<div x-show="!$store.sidebar.isCollapsed" class="mx-3 mb-3 p-3 bg-s2 border border-white/[.06] rounded-lg">
|
||||
<div class="flex items-center justify-between mb-1.5">
|
||||
<span class="text-xs font-medium text-t2">{{ ucfirst($plan->name) }} Plan</span>
|
||||
@if(str_contains(strtolower($plan->name), 'free'))
|
||||
|
|
@ -291,11 +291,11 @@
|
|||
<div class="w-8 h-8 rounded-full bg-blue flex items-center justify-center text-white text-xs font-semibold flex-shrink-0">
|
||||
{{ $initials ?: strtoupper(substr(auth()->user()->email, 0, 2)) }}
|
||||
</div>
|
||||
<div x-show="!$store.sidebar.collapsed" class="flex-1 min-w-0">
|
||||
<div x-show="!$store.sidebar.isCollapsed" class="flex-1 min-w-0">
|
||||
<div class="text-xs font-medium text-t1 truncate">{{ auth()->user()->name }}</div>
|
||||
<div class="text-xs text-t3 truncate">{{ auth()->user()->email }}</div>
|
||||
</div>
|
||||
<form x-show="!$store.sidebar.collapsed" method="POST" action="{{ route('logout') }}">
|
||||
<form x-show="!$store.sidebar.isCollapsed" method="POST" action="{{ route('logout') }}">
|
||||
@csrf
|
||||
<button
|
||||
type="submit"
|
||||
|
|
|
|||
|
|
@ -132,7 +132,7 @@
|
|||
<!-- Main content area: shifts right based on sidebar width -->
|
||||
<div
|
||||
class="nim-content flex flex-col min-h-screen transition-[margin-left] duration-200 ease-in-out"
|
||||
:class="$store.sidebar?.collapsed ? 'md:ml-16' : 'md:ml-60'"
|
||||
:class="$store.sidebar?.isCollapsed ? 'md:ml-16' : 'md:ml-60'"
|
||||
>
|
||||
@persist('topbar')
|
||||
<x-topbar :title="$title ?? ''" />
|
||||
|
|
|
|||
Loading…
Reference in New Issue