feat: reusable dynamic confirmation modal
This commit is contained in:
103
resources/views/components/bento/confirm-modal.blade.php
Normal file
103
resources/views/components/bento/confirm-modal.blade.php
Normal file
@@ -0,0 +1,103 @@
|
||||
@props([
|
||||
'name' => 'confirm-modal',
|
||||
])
|
||||
|
||||
<div x-show="show"
|
||||
x-data="{
|
||||
show: false,
|
||||
title: '',
|
||||
message: '',
|
||||
confirmLabel: 'Confirm',
|
||||
type: 'danger',
|
||||
action: null,
|
||||
open(data) {
|
||||
this.title = data.title || 'Are you sure?';
|
||||
this.message = data.message || 'This action cannot be undone.';
|
||||
this.confirmLabel = data.confirmLabel || 'Confirm';
|
||||
this.type = data.type || 'danger';
|
||||
this.action = data.action || null;
|
||||
this.show = true;
|
||||
},
|
||||
confirm() {
|
||||
if (this.action) {
|
||||
this.action();
|
||||
}
|
||||
this.show = false;
|
||||
}
|
||||
}"
|
||||
x-on:open-{{ $name }}.window="open($event.detail)"
|
||||
class="fixed inset-0 z-[110] flex items-center justify-center p-4 lg:p-8"
|
||||
style="display: none;"
|
||||
x-cloak>
|
||||
|
||||
<!-- Backdrop -->
|
||||
<div x-show="show"
|
||||
x-transition:enter="transition ease-out duration-300"
|
||||
x-transition:enter-start="opacity-0"
|
||||
x-transition:enter-end="opacity-100"
|
||||
x-transition:leave="transition ease-in duration-200"
|
||||
x-transition:leave-start="opacity-100"
|
||||
x-transition:leave-end="opacity-0"
|
||||
@click="show = false"
|
||||
class="absolute inset-0 bg-zinc-950/80 backdrop-blur-xl"></div>
|
||||
|
||||
<!-- Modal Card -->
|
||||
<div x-show="show"
|
||||
x-transition:enter="transition ease-out duration-500"
|
||||
x-transition:enter-start="opacity-0 scale-95 translate-y-8"
|
||||
x-transition:enter-end="opacity-100 scale-100 translate-y-0"
|
||||
x-transition:leave="transition ease-in duration-300"
|
||||
x-transition:leave-start="opacity-100 scale-100 translate-y-0"
|
||||
x-transition:leave-end="opacity-0 scale-95 translate-y-8"
|
||||
class="w-full max-w-[400px] bg-zinc-900 border border-white/10 rounded-[32px] p-8 relative overflow-hidden shadow-2xl">
|
||||
|
||||
<!-- Background Glow based on type -->
|
||||
<div class="absolute top-0 left-1/2 -translate-x-1/2 w-64 h-64 rounded-full blur-[80px] -z-10 opacity-20"
|
||||
:class="{
|
||||
'bg-rose-500': type === 'danger',
|
||||
'bg-blue-500': type === 'info',
|
||||
'bg-amber-500': type === 'warning',
|
||||
'bg-emerald-500': type === 'success'
|
||||
}"></div>
|
||||
|
||||
<div class="text-center">
|
||||
<!-- Icon -->
|
||||
<div class="w-16 h-16 rounded-2xl flex items-center justify-center mx-auto mb-6 shadow-xl"
|
||||
:class="{
|
||||
'bg-rose-500/10 text-rose-500': type === 'danger',
|
||||
'bg-blue-500/10 text-blue-500': type === 'info',
|
||||
'bg-amber-500/10 text-amber-500': type === 'warning',
|
||||
'bg-emerald-500/10 text-emerald-500': type === 'success'
|
||||
}">
|
||||
<!-- Danger Icon -->
|
||||
<svg x-show="type === 'danger'" class="w-8 h-8" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16" /></svg>
|
||||
<!-- Warning Icon -->
|
||||
<svg x-show="type === 'warning'" class="w-8 h-8" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z" /></svg>
|
||||
<!-- Info Icon -->
|
||||
<svg x-show="type === 'info'" class="w-8 h-8" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" /></svg>
|
||||
<!-- Success Icon -->
|
||||
<svg x-show="type === 'success'" class="w-8 h-8" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7" /></svg>
|
||||
</div>
|
||||
|
||||
<h3 class="text-2xl font-black text-white mb-2 tracking-tight uppercase italic" x-text="title"></h3>
|
||||
<p class="text-xs font-bold text-zinc-500 uppercase tracking-widest leading-relaxed mb-8 px-4" x-text="message"></p>
|
||||
|
||||
<div class="grid grid-cols-2 gap-4">
|
||||
<button @click="show = false"
|
||||
class="py-4 rounded-2xl bg-white/5 border border-white/10 text-zinc-400 font-black text-[10px] uppercase tracking-[0.2em] hover:bg-white/10 hover:text-white transition-all">
|
||||
Cancel
|
||||
</button>
|
||||
<button @click="confirm()"
|
||||
class="py-4 rounded-2xl font-black text-[10px] uppercase tracking-[0.2em] shadow-xl transition-all"
|
||||
:class="{
|
||||
'bg-rose-600 text-white hover:bg-rose-500 shadow-rose-900/20': type === 'danger',
|
||||
'bg-blue-600 text-white hover:bg-blue-500 shadow-blue-900/20': type === 'info',
|
||||
'bg-amber-600 text-white hover:bg-amber-500 shadow-amber-900/20': type === 'warning',
|
||||
'bg-emerald-600 text-white hover:bg-emerald-500 shadow-emerald-900/20': type === 'success'
|
||||
}"
|
||||
x-text="confirmLabel">
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
Reference in New Issue
Block a user