Created
July 25, 2020 17:51
-
-
Save claudsonm/390ee8594a9bacf148398b75d02c3a75 to your computer and use it in GitHub Desktop.
Global confirmation modal with AlpineJS and PHP
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<html lang="en"> | |
<head> | |
<meta charset="UTF-8"> | |
<meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
<title>Cool Modal</title> | |
<link href="https://unpkg.com/tailwindcss@^1.0/dist/tailwind.min.css" rel="stylesheet"> | |
<script src="https://cdn.jsdelivr.net/gh/alpinejs/[email protected]/dist/alpine.min.js" defer></script> | |
</head> | |
<body> | |
<div> | |
<nav class="bg-gray-800" x-data="{ mobileMenuOpen: false}"> | |
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8"> | |
<div class="flex items-center justify-between h-16"> | |
<div class="flex items-center"> | |
<div class="flex-shrink-0"> | |
<img class="h-8 w-8" src="https://tailwindui.com/img/logos/workflow-mark-on-dark.svg" alt="Workflow logo"> | |
</div> | |
<div class="hidden md:block"> | |
<div class="ml-10 flex items-baseline"> | |
<a href="#" class="px-3 py-2 rounded-md text-sm font-medium text-white bg-gray-900 focus:outline-none focus:text-white focus:bg-gray-700">Dashboard</a> | |
<a href="#" class="ml-4 px-3 py-2 rounded-md text-sm font-medium text-gray-300 hover:text-white hover:bg-gray-700 focus:outline-none focus:text-white focus:bg-gray-700">Team</a> | |
<a href="#" class="ml-4 px-3 py-2 rounded-md text-sm font-medium text-gray-300 hover:text-white hover:bg-gray-700 focus:outline-none focus:text-white focus:bg-gray-700">Projects</a> | |
<a href="#" class="ml-4 px-3 py-2 rounded-md text-sm font-medium text-gray-300 hover:text-white hover:bg-gray-700 focus:outline-none focus:text-white focus:bg-gray-700">Calendar</a> | |
<a href="#" class="ml-4 px-3 py-2 rounded-md text-sm font-medium text-gray-300 hover:text-white hover:bg-gray-700 focus:outline-none focus:text-white focus:bg-gray-700">Reports</a> | |
</div> | |
</div> | |
</div> | |
<div class="hidden md:block"> | |
<div class="ml-4 flex items-center md:ml-6"> | |
<!-- Profile dropdown --> | |
<div x-data="{ open: false }" class="ml-3 relative"> | |
<div> | |
<button @click="open = ! open" class="max-w-xs flex items-center text-sm rounded-full text-white focus:outline-none focus:shadow-solid" id="user-menu" aria-label="User menu" aria-haspopup="true"> | |
<img class="h-8 w-8 rounded-full" src="https://images.unsplash.com/photo-1472099645785-5658abf4ff4e?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=facearea&facepad=2&w=256&h=256&q=80" alt=""> | |
</button> | |
</div> | |
<div x-show="open" @click.away="open = false" x-transition:enter="transition ease-out duration-100" x-transition:enter-start="transform opacity-0 scale-95" x-transition:enter-end="transform opacity-100 scale-100" x-transition:leave="transition ease-in duration-75" x-transition:leave-start="transform opacity-100 scale-100" x-transition:leave-end="transform opacity-0 scale-95" class="origin-top-right absolute right-0 mt-2 w-48 rounded-md shadow-lg"> | |
<div class="py-1 rounded-md bg-white shadow-xs" role="menu" aria-orientation="vertical" aria-labelledby="user-menu"> | |
<a href="#" class="block px-4 py-2 text-sm text-gray-700 hover:bg-gray-100" role="menuitem">Your Profile</a> | |
<a href="#" class="block px-4 py-2 text-sm text-gray-700 hover:bg-gray-100" role="menuitem">Settings</a> | |
<a href="#" class="block px-4 py-2 text-sm text-gray-700 hover:bg-gray-100" role="menuitem">Sign out</a> | |
</div> | |
</div> | |
</div> | |
</div> | |
</div> | |
<div class="-mr-2 flex md:hidden"> | |
<!-- Mobile menu button --> | |
<button @click="mobileMenuOpen = !mobileMenuOpen" class="inline-flex items-center justify-center p-2 rounded-md text-gray-400 hover:text-white hover:bg-gray-700 focus:outline-none focus:bg-gray-700 focus:text-white"> | |
<!-- Menu open: "hidden", Menu closed: "block" --> | |
<svg class="block h-6 w-6" :class="{ 'hidden': mobileMenuOpen, 'block': ! mobileMenuOpen }" stroke="currentColor" fill="none" viewBox="0 0 24 24"> | |
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6h16M4 12h16M4 18h16" /> | |
</svg> | |
<!-- Menu open: "block", Menu closed: "hidden" --> | |
<svg class="h-6 w-6" :class="{ 'block': mobileMenuOpen, 'hidden': ! mobileMenuOpen }" stroke="currentColor" fill="none" viewBox="0 0 24 24"> | |
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" /> | |
</svg> | |
</button> | |
</div> | |
</div> | |
</div> | |
<!-- | |
Mobile menu, toggle classes based on menu state. | |
Open: "block", closed: "hidden" | |
--> | |
<div class="md:hidden" :class="{ | |
'block': mobileMenuOpen, | |
'hidden': ! mobileMenuOpen | |
}"> | |
<div class="px-2 pt-2 pb-3 sm:px-3"> | |
<a href="#" class="block px-3 py-2 rounded-md text-base font-medium text-white bg-gray-900 focus:outline-none focus:text-white focus:bg-gray-700">Dashboard</a> | |
<a href="#" class="mt-1 block px-3 py-2 rounded-md text-base font-medium text-gray-300 hover:text-white hover:bg-gray-700 focus:outline-none focus:text-white focus:bg-gray-700">Team</a> | |
<a href="#" class="mt-1 block px-3 py-2 rounded-md text-base font-medium text-gray-300 hover:text-white hover:bg-gray-700 focus:outline-none focus:text-white focus:bg-gray-700">Projects</a> | |
<a href="#" class="mt-1 block px-3 py-2 rounded-md text-base font-medium text-gray-300 hover:text-white hover:bg-gray-700 focus:outline-none focus:text-white focus:bg-gray-700">Calendar</a> | |
<a href="#" class="mt-1 block px-3 py-2 rounded-md text-base font-medium text-gray-300 hover:text-white hover:bg-gray-700 focus:outline-none focus:text-white focus:bg-gray-700">Reports</a> | |
</div> | |
<div class="pt-4 pb-3 border-t border-gray-700"> | |
<div class="flex items-center px-5"> | |
<div class="flex-shrink-0"> | |
<img class="h-10 w-10 rounded-full" src="https://images.unsplash.com/photo-1472099645785-5658abf4ff4e?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=facearea&facepad=2&w=256&h=256&q=80" alt=""> | |
</div> | |
<div class="ml-3"> | |
<div class="text-base font-medium leading-none text-white">Tom Cook</div> | |
<div class="mt-1 text-sm font-medium leading-none text-gray-400">[email protected]</div> | |
</div> | |
</div> | |
<div class="mt-3 px-2"> | |
<a href="#" class="block px-3 py-2 rounded-md text-base font-medium text-gray-400 hover:text-white hover:bg-gray-700 focus:outline-none focus:text-white focus:bg-gray-700">Your | |
Profile</a> | |
<a href="#" class="mt-1 block px-3 py-2 rounded-md text-base font-medium text-gray-400 hover:text-white hover:bg-gray-700 focus:outline-none focus:text-white focus:bg-gray-700">Settings</a> | |
<a href="#" class="mt-1 block px-3 py-2 rounded-md text-base font-medium text-gray-400 hover:text-white hover:bg-gray-700 focus:outline-none focus:text-white focus:bg-gray-700">Sign | |
out</a> | |
</div> | |
</div> | |
</div> | |
</nav> | |
<header class="bg-white shadow"> | |
<div class="max-w-7xl mx-auto py-6 px-4 sm:px-6 lg:px-8"> | |
<h1 class="text-3xl font-bold leading-tight text-gray-900"> | |
Dashboard | |
</h1> | |
</div> | |
</header> | |
<main> | |
<div class="max-w-7xl mx-auto py-6 sm:px-6 lg:px-8"> | |
<!-- Replace with your content --> | |
<div class="flex flex-col"> | |
<div class="-my-2 py-2 overflow-x-auto sm:-mx-6 sm:px-6 lg:-mx-8 lg:px-8"> | |
<div class="align-middle inline-block min-w-full shadow overflow-hidden sm:rounded-lg border-b border-gray-200"> | |
<table class="min-w-full"> | |
<thead> | |
<tr> | |
<th class="px-6 py-3 border-b border-gray-200 bg-gray-50 text-left text-xs leading-4 font-medium text-gray-500 uppercase tracking-wider"> | |
Name | |
</th> | |
<th class="px-6 py-3 border-b border-gray-200 bg-gray-50 text-left text-xs leading-4 font-medium text-gray-500 uppercase tracking-wider"> | |
Title | |
</th> | |
<th class="px-6 py-3 border-b border-gray-200 bg-gray-50 text-left text-xs leading-4 font-medium text-gray-500 uppercase tracking-wider"> | |
Status | |
</th> | |
<th class="px-6 py-3 border-b border-gray-200 bg-gray-50 text-left text-xs leading-4 font-medium text-gray-500 uppercase tracking-wider"> | |
Role | |
</th> | |
<th class="px-6 py-3 border-b border-gray-200 bg-gray-50"></th> | |
</tr> | |
</thead> | |
<tbody class="bg-white"> | |
<tr> | |
<td class="px-6 py-4 whitespace-no-wrap border-b border-gray-200"> | |
<div class="flex items-center"> | |
<div class="flex-shrink-0 h-10 w-10"> | |
<img class="h-10 w-10 rounded-full" src="https://images.unsplash.com/photo-1472099645785-5658abf4ff4e?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=facearea&facepad=2&w=256&h=256&q=80" alt=""> | |
</div> | |
<div class="ml-4"> | |
<div class="text-sm leading-5 font-medium text-gray-900">Bernard Lane</div> | |
<div class="text-sm leading-5 text-gray-500">[email protected]</div> | |
</div> | |
</div> | |
</td> | |
<td class="px-6 py-4 whitespace-no-wrap border-b border-gray-200"> | |
<div class="text-sm leading-5 text-gray-900">Director</div> | |
<div class="text-sm leading-5 text-gray-500">Human Resources</div> | |
</td> | |
<td class="px-6 py-4 whitespace-no-wrap border-b border-gray-200"> | |
<span class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full bg-green-100 text-green-800"> | |
Active | |
</span> | |
</td> | |
<td class="px-6 py-4 whitespace-no-wrap border-b border-gray-200 text-sm leading-5 text-gray-500"> | |
Owner | |
</td> | |
<td class="px-6 py-4 whitespace-no-wrap text-right border-b border-gray-200 text-sm leading-5 font-medium"> | |
<a href="#" class="text-indigo-600 hover:text-indigo-900">Delete</a> | |
</td> | |
</tr> | |
<tr> | |
<td class="px-6 py-4 whitespace-no-wrap border-b border-gray-200"> | |
<div class="flex items-center"> | |
<div class="flex-shrink-0 h-10 w-10"> | |
<img class="h-10 w-10 rounded-full" src="https://images.unsplash.com/photo-1532910404247-7ee9488d7292?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=facearea&facepad=2&w=256&h=256&q=80" alt=""> | |
</div> | |
<div class="ml-4"> | |
<div class="text-sm leading-5 font-medium text-gray-900">Bernard Lane</div> | |
<div class="text-sm leading-5 text-gray-500">[email protected]</div> | |
</div> | |
</div> | |
</td> | |
<td class="px-6 py-4 whitespace-no-wrap border-b border-gray-200"> | |
<div class="text-sm leading-5 text-gray-900">Director</div> | |
<div class="text-sm leading-5 text-gray-500">Human Resources</div> | |
</td> | |
<td class="px-6 py-4 whitespace-no-wrap border-b border-gray-200"> | |
<span class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full bg-green-100 text-green-800"> | |
Active | |
</span> | |
</td> | |
<td class="px-6 py-4 whitespace-no-wrap border-b border-gray-200 text-sm leading-5 text-gray-500"> | |
Owner | |
</td> | |
<td class="px-6 py-4 whitespace-no-wrap text-right border-b border-gray-200 text-sm leading-5 font-medium"> | |
<a href="#" class="text-indigo-600 hover:text-indigo-900">Delete</a> | |
</td> | |
</tr> | |
<?php | |
$model = new stdClass(); | |
$model->id = 1; | |
$model->name = 'Upper Record'; | |
$model->destination = 'https://jsonplaceholder.typicode.com/users/1'; | |
$encoded = json_encode($model); | |
?> | |
<tr x-data='{ "model": <?php echo $encoded; ?> }' @removed.window="$event.detail.id == model.id && $el.remove()"> | |
<td class="px-6 py-4 whitespace-no-wrap border-b border-gray-200"> | |
<div class="flex items-center"> | |
<div class="flex-shrink-0 h-10 w-10"> | |
<img class="h-10 w-10 rounded-full" src="https://images.unsplash.com/photo-1505503693641-1926193e8d57?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=facearea&facepad=2&w=256&h=256&q=80" alt=""> | |
</div> | |
<div class="ml-4"> | |
<div class="text-sm leading-5 font-medium text-gray-900">Bernard Lane</div> | |
<div class="text-sm leading-5 text-gray-500">[email protected]</div> | |
</div> | |
</div> | |
</td> | |
<td class="px-6 py-4 whitespace-no-wrap border-b border-gray-200"> | |
<div class="text-sm leading-5 text-gray-900">Director</div> | |
<div class="text-sm leading-5 text-gray-500">Human Resources</div> | |
</td> | |
<td class="px-6 py-4 whitespace-no-wrap border-b border-gray-200"> | |
<span class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full bg-red-100 text-red-800"> | |
Inactive | |
</span> | |
</td> | |
<td class="px-6 py-4 whitespace-no-wrap border-b border-gray-200 text-sm leading-5 text-gray-500"> | |
Owner | |
</td> | |
<td class="px-6 py-4 whitespace-no-wrap text-right border-b border-gray-200 text-sm leading-5 font-medium"> | |
<a href="#" class="text-indigo-600 hover:text-indigo-900" @click.prevent='$dispatch("confirm-exclusion", model)'>Delete</a> | |
</td> | |
</tr> | |
<?php | |
$model = new stdClass(); | |
$model->id = 2; | |
$model->name = 'Awesome Record'; | |
$model->destination = 'https://jsonplaceholder.typicode.com/users/2'; | |
$encoded = json_encode($model); | |
?> | |
<tr x-data='{ "model": <?php echo $encoded; ?> }' @removed.window="$event.detail.id == model.id && $el.remove()"> | |
<td class="px-6 py-4 whitespace-no-wrap"> | |
<div class="flex items-center"> | |
<div class="flex-shrink-0 h-10 w-10"> | |
<img class="h-10 w-10 rounded-full" src="https://images.unsplash.com/photo-1463453091185-61582044d556?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=facearea&facepad=2&w=256&h=256&q=80" alt=""> | |
</div> | |
<div class="ml-4"> | |
<div class="text-sm leading-5 font-medium text-gray-900">Bernard Lane</div> | |
<div class="text-sm leading-5 text-gray-500">[email protected]</div> | |
</div> | |
</div> | |
</td> | |
<td class="px-6 py-4 whitespace-no-wrap"> | |
<div class="text-sm leading-5 text-gray-900">Director</div> | |
<div class="text-sm leading-5 text-gray-500">Human Resources</div> | |
</td> | |
<td class="px-6 py-4 whitespace-no-wrap"> | |
<span class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full bg-red-100 text-red-800"> | |
Inactive | |
</span> | |
</td> | |
<td class="px-6 py-4 whitespace-no-wrap text-sm leading-5 text-gray-500"> | |
Owner | |
</td> | |
<td class="px-6 py-4 whitespace-no-wrap text-right text-sm leading-5 font-medium"> | |
<a href="#" class="text-indigo-600 hover:text-indigo-900" @click.prevent='$dispatch("confirm-exclusion", model)'>Delete</a> | |
</td> | |
</tr> | |
</tbody> | |
</table> | |
</div> | |
</div> | |
</div> | |
<div | |
x-data="myModal()" | |
x-show="modalOpen" | |
@confirm-exclusion.window="modalOpen = true; modelResource = $event.detail" | |
@keydown.escape.window="modalOpen = false" | |
class="fixed bottom-0 inset-x-0 px-4 pb-4 sm:inset-0 sm:flex sm:items-center sm:justify-center"> | |
<div | |
x-show="modalOpen" | |
x-transition:enter="ease-out duration-300" | |
x-transition:enter-start="opacity-0" | |
x-transition:enter-end="opacity-100" | |
x-transition:leave="ease-in duration-200" | |
x-transition:leave-start="opacity-100" | |
x-transition:leave-end="opacity-0" | |
class="fixed inset-0 transition-opacity"> | |
<div class="absolute inset-0 bg-gray-500 opacity-75"></div> | |
</div> | |
<div | |
x-show="modalOpen" | |
@click.away="modalOpen = false" | |
x-transition:enter="ease-out duration-300" | |
x-transition:enter-start="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95" | |
x-transition:enter-end="opacity-100 translate-y-0 sm:scale-100" | |
x-transition:leave="ease-in duration-200" | |
x-transition:leave-start="opacity-100 translate-y-0 sm:scale-100" | |
x-transition:leave-end="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95" | |
class="bg-white rounded-lg overflow-hidden shadow-xl transform transition-all sm:max-w-lg sm:w-full" role="dialog" aria-modal="true" aria-labelledby="modal-headline"> | |
<div class="bg-white px-4 pt-5 pb-4 sm:p-6 sm:pb-4"> | |
<div class="sm:flex sm:items-start"> | |
<div class="mx-auto flex-shrink-0 flex items-center justify-center h-12 w-12 rounded-full bg-red-100 sm:mx-0 sm:h-10 sm:w-10"> | |
<svg class="h-6 w-6 text-red-600" 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> | |
</div> | |
<div class="mt-3 text-center sm:mt-0 sm:ml-4 sm:text-left"> | |
<h3 class="text-lg leading-6 font-medium text-gray-900" id="modal-headline"> | |
Deactivate <span x-text="modelResource.name + ' #' + modelResource.id"></span> | |
</h3> | |
<div class="mt-2"> | |
<p class="text-sm leading-5 text-gray-500"> | |
Are you sure you want to deactivate your account? All of your data will be permanently | |
removed. This action cannot be undone. | |
</p> | |
</div> | |
</div> | |
</div> | |
</div> | |
<div class="bg-gray-50 px-4 py-3 sm:px-6 sm:flex sm:flex-row-reverse"> | |
<span class="flex w-full rounded-md shadow-sm sm:ml-3 sm:w-auto"> | |
<button @click="removeAction($dispatch)" type="button" class="inline-flex justify-center w-full rounded-md border border-transparent px-4 py-2 bg-red-600 text-base leading-6 font-medium text-white shadow-sm hover:bg-red-500 focus:outline-none focus:border-red-700 focus:shadow-outline-red transition ease-in-out duration-150 sm:text-sm sm:leading-5"> | |
Deactivate | |
</button> | |
</span> | |
<span class="mt-3 flex w-full rounded-md shadow-sm sm:mt-0 sm:w-auto"> | |
<button @click="modalOpen = false" type="button" class="inline-flex justify-center w-full rounded-md border border-gray-300 px-4 py-2 bg-white text-base leading-6 font-medium text-gray-700 shadow-sm hover:text-gray-500 focus:outline-none focus:border-blue-300 focus:shadow-outline-blue transition ease-in-out duration-150 sm:text-sm sm:leading-5"> | |
Cancel | |
</button> | |
</span> | |
</div> | |
</div> | |
</div> | |
<!-- /End replace --> | |
</div> | |
</main> | |
</div> | |
<script> | |
function myModal() { | |
return { | |
modalOpen: false, | |
modelResource: {}, | |
removeAction($dispatch) { | |
this.modalOpen = false; | |
$dispatch('removed', this.modelResource) | |
} | |
} | |
} | |
</script> | |
</body> | |
</html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment