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. --}} +
{{ $message }}
+Workspace löschen entfernt alle Sites, Server-Verbindungen und Backups unwiderruflich.
- +