diff --git a/app/resources/css/app.css b/app/resources/css/app.css index bd05ae6..1cdcfdc 100644 --- a/app/resources/css/app.css +++ b/app/resources/css/app.css @@ -634,6 +634,48 @@ } .clu-top-link a { color: var(--color-accent); font-weight: 600; } + /* Workspace switcher dropdown */ + .clu-ws-dropdown { + position: absolute; + top: 100%; left: 0; right: 0; + margin-top: 6px; + background: rgba(255,255,255,0.98); + border: 1px solid var(--color-glass-border); + border-radius: var(--radius-sm); + box-shadow: 0 18px 50px -8px rgba(40,52,92,0.35), 0 4px 12px -4px rgba(40,52,92,0.15); + backdrop-filter: blur(28px) saturate(170%); + -webkit-backdrop-filter: blur(28px) saturate(170%); + z-index: 60; + padding: 6px; + max-height: 480px; + overflow-y: auto; + } + [x-cloak] { display: none !important; } + .clu-ws-section { + font-size: 10px; + text-transform: uppercase; + letter-spacing: 0.09em; + color: var(--color-muted-2); + font-weight: 600; + padding: 10px 10px 4px; + } + .clu-ws-item { + display: flex; align-items: center; gap: 9px; + padding: 7px 10px; + border-radius: var(--radius-xs); + color: var(--color-fg); + transition: background .12s; + text-decoration: none !important; + cursor: pointer; + } + .clu-ws-item:hover { background: rgba(255,255,255,0.7); } + .clu-ws-item.active { background: var(--color-accent-soft); } + .clu-ws-divider { + height: 1px; + background: var(--color-hairline); + margin: 6px 4px; + } + /* ───── App layout (sidebar fixed + main offset by padding) ───── */ .clu-app-grid { position: relative; diff --git a/app/resources/views/components/clu/sidebar.blade.php b/app/resources/views/components/clu/sidebar.blade.php index dcdede9..51b52df 100644 --- a/app/resources/views/components/clu/sidebar.blade.php +++ b/app/resources/views/components/clu/sidebar.blade.php @@ -1,8 +1,33 @@ @props(['active' => null]) @php - $ws = auth()->user()?->currentWorkspace; - $wsInitials = $ws ? mb_strtoupper(mb_substr(preg_replace('/[^A-Za-z\s]/', '', $ws->name), 0, 2)) : '—'; + $user = auth()->user(); + $ws = $user?->currentWorkspace; + $wsInitials = $ws ? mb_strtoupper(mb_substr(preg_replace('/[^A-Za-z\s]/', '', $ws->name), 0, 2)) : '—'; + $userInit = $user ? mb_strtoupper(mb_substr($user->name, 0, 1) . mb_substr(explode(' ', $user->name)[1] ?? '', 0, 1)) : '?'; + + // All workspaces the user can access: owned + via TeamMember. + $workspaces = collect(); + if ($user) { + $workspaces = $workspaces->merge($user->ownedWorkspaces); + if (method_exists($user, 'teamMemberships')) { + $workspaces = $workspaces->merge($user->teamMemberships->pluck('workspace')); + } else { + // Fallback via TeamMember model + $memberWsIds = \App\Models\TeamMember::where('user_id', $user->id)->pluck('workspace_id'); + $workspaces = $workspaces->merge(\App\Models\Workspace::whereIn('id', $memberWsIds)->get()); + } + $workspaces = $workspaces->unique('id')->values(); + // Fallback: at least the currently-active workspace. + if ($workspaces->isEmpty() && $ws) { + $workspaces = collect([$ws]); + } + } + + $sitesUsed = $ws ? \App\Models\Site::count() : 0; + $sitesQuota = $ws?->quotas['sites'] ?? 0; + $planPct = $sitesQuota ? min(100, round($sitesUsed / $sitesQuota * 100)) : 0; + $items = [ ['name' => 'dashboard', 'label' => 'Dashboard', 'route' => 'dashboard', 'svg' => ''], @@ -31,22 +56,76 @@
CluPilotv2.4
-
-
{{ $wsInitials }}
-
-
{{ $ws?->name ?? 'Workspace wählen' }}
-
{{ strtoupper($ws?->plan ?? 'free') }} · {{ \App\Models\Site::count() }}/{{ $ws?->quotas['sites'] ?? 0 }} sites
+ {{-- Workspace switcher (Alpine dropdown) --}} +
+ + + -
{{-- Scrollable nav --}}