From da90b39085a77bfbf83dd97a2984f466ebc8a766 Mon Sep 17 00:00:00 2001 From: Boban Blaskovic Date: Sun, 31 May 2026 23:33:07 +0200 Subject: [PATCH] Fix: chart.js race, burger desktop visibility, modal glass-themed MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit User-reported issues + browser-verified: 1. **Chart.js race condition** — inline @push('scripts') ran before the @vite type=module script that imports Chart. Wrapped Chart init in a poll loop that retries every 30ms until window.Chart resolves. Re-fires on livewire:navigated for SPA navigation. 2. **Hamburger always visible on desktop** — .clu-icon-btn defined display:grid AFTER .clu-burger {display:none}. Chained selector '.clu-burger.clu-icon-btn' (specificity 0,2,0) now wins both at default and inside the <920px media query. 3. **Modal in CluPilot glass style** — - app/Livewire/Modals/ConfirmDelete.php (class extends ModalComponent) with title/message/confirmLabel/confirmEvent/payload props, confirm() dispatches the named event + closes the modal. - resources/views/livewire/modals/confirm-delete.blade.php renders clu-modal-card with icon + title/message head + foot containing cancel (clu-ghost-btn) + delete (clu-btn-primary clu-btn-danger with red gradient). - CSS overrides for the wire-elements default Tailwind v2 markup: bg-gray-500 backdrop dimmer, transparent modal-container, z-index bumped to 100 so it sits above sticky topbar + sidebar. - @source hints in app.css so Tailwind v4 scans vendor/wire-elements/modal blade templates and generates the sm:inline-block / sm:h-screen utilities the modal needs to center. - Demo: Settings → Danger Zone → 'Workspace löschen' opens modal. 4. **AppServiceProvider Vite::usePreloadTagAttributes(false)** kept. 5. Browser console clean across dashboard / sites / sites/{id} / settings + open modal (verified via Chrome MCP). --- app/app/Livewire/Modals/ConfirmDelete.php | 49 +++++++++++++ app/resources/css/app.css | 72 ++++++++++++++++++- app/resources/css/safelist-tailwindcss.txt | 5 ++ .../livewire/modals/confirm-delete.blade.php | 25 +++++++ .../views/livewire/pages/dashboard.blade.php | 70 +++++++++--------- .../livewire/pages/settings/index.blade.php | 15 +++- 6 files changed, 195 insertions(+), 41 deletions(-) create mode 100644 app/app/Livewire/Modals/ConfirmDelete.php create mode 100644 app/resources/css/safelist-tailwindcss.txt create mode 100644 app/resources/views/livewire/modals/confirm-delete.blade.php diff --git a/app/app/Livewire/Modals/ConfirmDelete.php b/app/app/Livewire/Modals/ConfirmDelete.php new file mode 100644 index 0000000..78c85ec --- /dev/null +++ b/app/app/Livewire/Modals/ConfirmDelete.php @@ -0,0 +1,49 @@ +id }} + * } + * })">Löschen + * + * Catch the result in the parent Livewire component: + * #[On('site-delete-confirmed')] + * public function handleDelete(int $id): void { ... } + */ +class ConfirmDelete extends ModalComponent +{ + public string $title = 'Wirklich löschen?'; + public string $message = 'Diese Aktion kann nicht rückgängig gemacht werden.'; + public string $confirmLabel = 'Löschen'; + public string $cancelLabel = 'Abbrechen'; + public string $confirmEvent = 'confirmed'; + public mixed $payload = null; + + public function confirm(): void + { + $this->dispatch($this->confirmEvent, payload: $this->payload); + $this->closeModal(); + } + + public static function modalMaxWidth(): string + { + return 'md'; // sm | md | lg | xl | 2xl | 3xl | ... + } + + public function render() + { + return view('livewire.modals.confirm-delete'); + } +} diff --git a/app/resources/css/app.css b/app/resources/css/app.css index 4c38d4e..dd964e7 100644 --- a/app/resources/css/app.css +++ b/app/resources/css/app.css @@ -1,5 +1,10 @@ @import "tailwindcss"; +/* Pull Tailwind utilities used by 3rd-party Blade templates so Tailwind v4 + generates them. Without these @source hints the scanner skips vendor/. */ +@source "../../vendor/wire-elements/modal/resources/views/**/*.blade.php"; +@source "../../vendor/livewire/livewire/src/**/*.blade.php"; + /* ──────────────────────────────────────────────────────────────────────── CluPilot design tokens — sourced from templates/akutell/* (light glass). ──────────────────────────────────────────────────────────────────────── */ @@ -661,8 +666,9 @@ display: none; } - /* Hamburger button in topbar (mobile only) */ - .clu-burger { display: none; } + /* Hamburger button in topbar (mobile only). + Chained selector to outrank .clu-icon-btn {display:grid}. */ + .clu-burger.clu-icon-btn { display: none; } @media (max-width: 920px) { .clu-app-grid { grid-template-columns: 1fr; } @@ -678,7 +684,7 @@ } .clu-sidebar.open { transform: translateX(0); } .clu-sidebar-backdrop.open { display: block; } - .clu-burger { display: grid; } + .clu-burger.clu-icon-btn { 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; } @@ -1137,6 +1143,66 @@ .clu-log-level.error { color: #f05252; } .clu-log-msg { color: #cccddd; flex: 1; word-break: break-all; } + /* ───── Modal (wire-elements/modal v3) ───── */ + /* The package's modal.blade.php uses Tailwind v2 classes (bg-gray-500, + bg-white, opacity-75) that don't render with our custom v4 theme. + Override the structural pieces so the modal sits on a dim backdrop + with our glass-themed card body. */ + + /* Backdrop dimmer (.fixed.inset-0.transition-all.transform > .absolute.inset-0) */ + body > [wire\:id] .fixed.inset-0.transition-all.transform > .absolute.inset-0, + body > [wire\:id] .fixed.inset-0.transition-all.transform > .bg-gray-500 { + background-color: rgba(20,22,35,0.55) !important; + opacity: 1 !important; + } + + /* Modal container chrome — strip white bg/shadow, let clu-modal-card + drive its own glass look. */ + #modal-container { + background-color: transparent !important; + box-shadow: none !important; + border-radius: var(--radius) !important; + overflow: visible !important; + } + /* Lift modal wrapper above sticky topbar (z:20) + sidebar (z:30) */ + body > [wire\:id] > .fixed.inset-0.z-10 { z-index: 100 !important; } + + /* Our actual styled card */ + .clu-modal-card { + background: var(--color-glass-strong); + backdrop-filter: blur(28px) saturate(175%); + -webkit-backdrop-filter: blur(28px) saturate(175%); + border: 1px solid var(--color-glass-border); + border-radius: var(--radius); + box-shadow: var(--shadow-glass), var(--shadow-glass-inset); + padding: 22px 24px 18px; + color: var(--color-fg); + display: flex; flex-direction: column; gap: 18px; + } + .clu-modal-head { display: flex; gap: 14px; align-items: flex-start; } + .clu-modal-ico { + width: 40px; height: 40px; + border-radius: 12px; + background: var(--color-danger-soft); + color: var(--color-danger); + display: grid; place-items: center; + flex: none; + border: 1px solid rgba(219,59,59,0.25); + } + .clu-modal-title { margin: 0; font-size: 16px; font-weight: 600; letter-spacing: -0.01em; } + .clu-modal-msg { margin: 4px 0 0; font-size: 13px; color: var(--color-muted); line-height: 1.5; } + .clu-modal-foot { + display: flex; gap: 8px; justify-content: flex-end; + padding-top: 14px; + border-top: 1px solid var(--color-hairline); + } + /* Danger variant of primary button */ + .clu-btn-danger { + background: linear-gradient(180deg, #e25555, #db3b3b); + box-shadow: 0 1px 0 rgba(255,255,255,0.3) inset, 0 6px 16px -5px rgba(219,59,59,0.55); + } + .clu-btn-danger:hover { filter: brightness(1.05); } + /* File tree */ .clu-file-tree { font-family: var(--font-mono); diff --git a/app/resources/css/safelist-tailwindcss.txt b/app/resources/css/safelist-tailwindcss.txt new file mode 100644 index 0000000..c99c89b --- /dev/null +++ b/app/resources/css/safelist-tailwindcss.txt @@ -0,0 +1,5 @@ +sm:max-w-md +md:max-w-xl +lg:max-w-3xl +xl:max-w-5xl +2xl:max-w-7xl diff --git a/app/resources/views/livewire/modals/confirm-delete.blade.php b/app/resources/views/livewire/modals/confirm-delete.blade.php new file mode 100644 index 0000000..7b3d54a --- /dev/null +++ b/app/resources/views/livewire/modals/confirm-delete.blade.php @@ -0,0 +1,25 @@ +{{-- Confirm-delete modal in CluPilot glass style. --}} +
+
+
+ +
+
+

{{ $title }}

+

{{ $message }}

+
+
+ +
+ + +
+
diff --git a/app/resources/views/livewire/pages/dashboard.blade.php b/app/resources/views/livewire/pages/dashboard.blade.php index 615822b..d8dabad 100644 --- a/app/resources/views/livewire/pages/dashboard.blade.php +++ b/app/resources/views/livewire/pages/dashboard.blade.php @@ -125,49 +125,45 @@ new #[Layout('layouts.app')] class extends Component { @push('scripts') @endpush diff --git a/app/resources/views/livewire/pages/settings/index.blade.php b/app/resources/views/livewire/pages/settings/index.blade.php index e2e0a82..7ea8fea 100644 --- a/app/resources/views/livewire/pages/settings/index.blade.php +++ b/app/resources/views/livewire/pages/settings/index.blade.php @@ -165,7 +165,20 @@ new #[Layout('layouts.app')] class extends Component {

Danger Zone

Workspace löschen entfernt alle Sites, Server-Verbindungen und Backups unwiderruflich.

- +
@endif