Skip to content

Instantly share code, notes, and snippets.

@claudsonm
Created July 25, 2020 17:51
Show Gist options
  • Save claudsonm/390ee8594a9bacf148398b75d02c3a75 to your computer and use it in GitHub Desktop.
Save claudsonm/390ee8594a9bacf148398b75d02c3a75 to your computer and use it in GitHub Desktop.
Global confirmation modal with AlpineJS and PHP
<!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/alpine@v2.x.x/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">tom@example.com</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">bernardlane@example.com</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">bernardlane@example.com</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">bernardlane@example.com</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">bernardlane@example.com</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