From 665ca4e40bf1dfc6ebe08d5a404102e9c870a70b Mon Sep 17 00:00:00 2001 From: Boban Blaskovic Date: Sun, 31 May 2026 23:17:29 +0200 Subject: [PATCH] UI: sidebar fixed-header/scroll-mid/fixed-foot + mobile drawer + ChartJS Sidebar layout (per user request: header+footer fix, only nav scrollable): - Restructured clu-sidebar into 3 flex-children: clu-sidebar-head (brand + ws-switch fixed at top), clu-sidebar-scroll (nav, overflow-y:auto in middle), clu-sidebar-foot (plan-box fixed at bottom). Mobile sidebar (per user request: drawer + hamburger): - <920px: sidebar position fixed, translateX(-110%) hidden, .open class slides in. clu-sidebar-backdrop overlay dimms main + click-to-close. - New x-clu.burger component with hamburger icon, visible only <920px via display:grid in media query. Injected into all 9 topbars. - Alpine state sidebarOpen on , nav-item click closes drawer after navigation. Linking (per user request: sites detail unreachable): - Sites index table + dashboard top-sites table: domain cell now to route('sites.show', $site) with wire:navigate. Charts (per user request: chart.js): - composer/npm: chart.js ^4.5. - resources/js/app.js: register all chart.js plugins, expose window.Chart for inline page scripts. - Dashboard: added Traffic-24h line chart (Chart.js line+gradient fill) between metrics and 2-col row. Init re-runs on livewire:navigated for wire:navigate compatibility. Modal (per user request: wire-elements): - @livewire('wire-elements-modal') already in layouts/app.blade.php master layout per wire-elements/modal v3 docs (single mount). Open pattern: wire:click="$dispatch('openModal', { component: 'name' })". Full Pest regression: 47/47 green. --- app/package-lock.json | 19 ++++ app/package.json | 1 + app/resources/css/app.css | 43 +++++++- app/resources/js/app.js | 8 ++ .../views/components/clu/burger.blade.php | 9 ++ .../views/components/clu/sidebar.blade.php | 98 ++++++++++--------- app/resources/views/layouts/app.blade.php | 12 ++- .../livewire/pages/backups/index.blade.php | 1 + .../livewire/pages/clusters/create.blade.php | 1 + .../views/livewire/pages/dashboard.blade.php | 63 +++++++++++- .../livewire/pages/security/index.blade.php | 1 + .../livewire/pages/servers/index.blade.php | 1 + .../livewire/pages/settings/index.blade.php | 1 + .../livewire/pages/sites/index.blade.php | 5 +- .../views/livewire/pages/sites/show.blade.php | 1 + .../views/livewire/pages/team/index.blade.php | 1 + 16 files changed, 207 insertions(+), 58 deletions(-) create mode 100644 app/resources/views/components/clu/burger.blade.php diff --git a/app/package-lock.json b/app/package-lock.json index c9688b7..ae2e867 100644 --- a/app/package-lock.json +++ b/app/package-lock.json @@ -5,6 +5,7 @@ "packages": { "": { "dependencies": { + "chart.js": "^4.5.1", "laravel-echo": "^2.3.4", "pusher-js": "^8.5.0" }, @@ -512,6 +513,12 @@ "@jridgewell/sourcemap-codec": "^1.4.14" } }, + "node_modules/@kurkle/color": { + "version": "0.3.4", + "resolved": "https://registry.npmjs.org/@kurkle/color/-/color-0.3.4.tgz", + "integrity": "sha512-M5UknZPHRu3DEDWoipU6sE8PdkZ6Z/S+v4dD+Ke8IaNlpdSQah50lz1KtcFBa2vsdOnwbbnxJwVM4wty6udA5w==", + "license": "MIT" + }, "node_modules/@rollup/rollup-android-arm-eabi": { "version": "4.60.4", "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.60.4.tgz", @@ -1369,6 +1376,18 @@ "node": ">=8" } }, + "node_modules/chart.js": { + "version": "4.5.1", + "resolved": "https://registry.npmjs.org/chart.js/-/chart.js-4.5.1.tgz", + "integrity": "sha512-GIjfiT9dbmHRiYi6Nl2yFCq7kkwdkp1W/lp2J99rX0yo9tgJGn3lKQATztIjb5tVtevcBtIdICNWqlq5+E8/Pw==", + "license": "MIT", + "dependencies": { + "@kurkle/color": "^0.3.0" + }, + "engines": { + "pnpm": ">=8" + } + }, "node_modules/cliui": { "version": "8.0.1", "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", diff --git a/app/package.json b/app/package.json index 32e86e9..0df156a 100644 --- a/app/package.json +++ b/app/package.json @@ -18,6 +18,7 @@ "vite": "^7.0.7" }, "dependencies": { + "chart.js": "^4.5.1", "laravel-echo": "^2.3.4", "pusher-js": "^8.5.0" } diff --git a/app/resources/css/app.css b/app/resources/css/app.css index 0f233c2..4c38d4e 100644 --- a/app/resources/css/app.css +++ b/app/resources/css/app.css @@ -630,20 +630,55 @@ /* ───── App layout (sidebar + main) ───── */ .clu-app-grid { display: grid; grid-template-columns: 236px 1fr; min-height: 100vh; } - @media (max-width: 920px) { .clu-app-grid { grid-template-columns: 1fr; } .clu-sidebar { display: none; } } - /* Sidebar */ + /* Sidebar — fixed brand+ws-switch header, scrollable nav, fixed plan-box footer */ .clu-sidebar { - position: sticky; top: 0; height: 100vh; + position: sticky; top: 0; + height: 100vh; margin: 14px 0 14px 14px; border-radius: var(--radius); display: flex; flex-direction: column; - padding: 18px 14px; gap: 18px; + padding: 18px 14px; background: var(--color-glass-strong); backdrop-filter: blur(30px) saturate(180%); -webkit-backdrop-filter: blur(30px) saturate(180%); border: 1px solid var(--color-glass-border); box-shadow: var(--shadow-glass), var(--shadow-glass-inset); + z-index: 30; + } + .clu-sidebar-head { flex: none; display: flex; flex-direction: column; gap: 18px; } + .clu-sidebar-scroll { flex: 1; min-height: 0; overflow-y: auto; margin-top: 18px; padding-right: 4px; } + .clu-sidebar-scroll::-webkit-scrollbar { width: 6px; } + .clu-sidebar-scroll::-webkit-scrollbar-thumb { background: rgba(30,35,60,0.15); border-radius: 3px; } + .clu-sidebar-foot { flex: none; margin-top: 14px; } + + /* Sidebar backdrop (mobile only) */ + .clu-sidebar-backdrop { + position: fixed; inset: 0; + background: rgba(15,18,30,0.45); + backdrop-filter: blur(2px); + z-index: 28; + display: none; + } + + /* Hamburger button in topbar (mobile only) */ + .clu-burger { display: none; } + + @media (max-width: 920px) { + .clu-app-grid { grid-template-columns: 1fr; } + .clu-sidebar { + position: fixed; + top: 0; left: 0; + height: 100vh; + width: 256px; + margin: 0; + border-radius: 0 var(--radius) var(--radius) 0; + transform: translateX(-110%); + transition: transform .25s ease; + } + .clu-sidebar.open { transform: translateX(0); } + .clu-sidebar-backdrop.open { display: block; } + .clu-burger { display: grid; } } .clu-brand-row { display: flex; align-items: center; gap: 10px; padding: 2px 4px; } .clu-brand-name { font-weight: 600; font-size: 15px; letter-spacing: -0.01em; } diff --git a/app/resources/js/app.js b/app/resources/js/app.js index 4a70671..b819b7e 100644 --- a/app/resources/js/app.js +++ b/app/resources/js/app.js @@ -1,4 +1,12 @@ import './bootstrap'; import './login-effects'; import './register-effects'; +import { Chart, registerables } from 'chart.js'; + +Chart.register(...registerables); + +// Expose Chart globally so Blade inline + @endpush + {{-- ───── 2-col: Sites table + Activity feed ───── --}}
@@ -136,13 +195,13 @@ new #[Layout('layouts.app')] class extends Component { @foreach ($sites as $site) - + WP {{ $site->wp_version }} · PHP {{ $site->php_version }} {{ number_format($site->visitors_24h, 0, ',', '.') }} diff --git a/app/resources/views/livewire/pages/security/index.blade.php b/app/resources/views/livewire/pages/security/index.blade.php index 36c61f8..73a97ba 100644 --- a/app/resources/views/livewire/pages/security/index.blade.php +++ b/app/resources/views/livewire/pages/security/index.blade.php @@ -47,6 +47,7 @@ new #[Layout('layouts.app')] class extends Component {
+

Sicherheit

{{ $blockedCount }} blockiert / 24h · {{ $advisories->count() }} advisories
diff --git a/app/resources/views/livewire/pages/servers/index.blade.php b/app/resources/views/livewire/pages/servers/index.blade.php index 438dda7..4073053 100644 --- a/app/resources/views/livewire/pages/servers/index.blade.php +++ b/app/resources/views/livewire/pages/servers/index.blade.php @@ -46,6 +46,7 @@ new #[Layout('layouts.app')] class extends Component {
{{-- ───── Topbar ───── --}}
+

Server

{{ $totalServers }} nodes · cluster acme
diff --git a/app/resources/views/livewire/pages/settings/index.blade.php b/app/resources/views/livewire/pages/settings/index.blade.php index a998458..e2e0a82 100644 --- a/app/resources/views/livewire/pages/settings/index.blade.php +++ b/app/resources/views/livewire/pages/settings/index.blade.php @@ -34,6 +34,7 @@ new #[Layout('layouts.app')] class extends Component {
+

Einstellungen

workspace · benachrichtigungen · billing · api
diff --git a/app/resources/views/livewire/pages/sites/index.blade.php b/app/resources/views/livewire/pages/sites/index.blade.php index 615202e..f79797e 100644 --- a/app/resources/views/livewire/pages/sites/index.blade.php +++ b/app/resources/views/livewire/pages/sites/index.blade.php @@ -75,6 +75,7 @@ new #[Layout('layouts.app')] class extends Component {
{{-- ───── Topbar ───── --}}
+

Sites

{{ $totalSites }} wordpress-installationen
@@ -174,13 +175,13 @@ new #[Layout('layouts.app')] class extends Component { @forelse ($sites as $site) - + {{ $site->server->name }} WP {{ $site->wp_version }} diff --git a/app/resources/views/livewire/pages/sites/show.blade.php b/app/resources/views/livewire/pages/sites/show.blade.php index bb4eb5d..27b3142 100644 --- a/app/resources/views/livewire/pages/sites/show.blade.php +++ b/app/resources/views/livewire/pages/sites/show.blade.php @@ -72,6 +72,7 @@ new #[Layout('layouts.app')] class extends Component {