homemanager-fe/src/components/Modal.vue

97 lines
2.5 KiB
Vue

<template>
<TransitionRoot appear :show="isOpen" as="template">
<Dialog as="div" @close="closeModal" class="relative z-10">
<TransitionChild
as="template"
enter="duration-300 ease-out"
enter-from="opacity-0"
enter-to="opacity-100"
leave="duration-200 ease-in"
leave-from="opacity-100"
leave-to="opacity-0"
>
<div class="fixed inset-0 bg-black bg-opacity-25" />
</TransitionChild>
<div class="fixed inset-0 overflow-y-auto">
<div
class="flex min-h-full items-center justify-center p-4 text-center"
>
<TransitionChild
as="template"
enter="duration-300 ease-out"
enter-from="opacity-0 scale-95"
enter-to="opacity-100 scale-100"
leave="duration-200 ease-in"
leave-from="opacity-100 scale-100"
leave-to="opacity-0 scale-95"
>
<DialogPanel
:class="`w-full ${maxWidth} transform overflow-hidden rounded-2xl bg-white p-6 text-left align-middle shadow-xl transition-all`"
>
<DialogTitle
as="h3"
class="text-lg font-bold leading-6 text-gray-900"
>
<div class="mb-4 flex items-center justify-between">
<slot name="title" />
<button v-if="closeButton" @click="closeModal">
<XMarkIcon class="h-6 w-6" />
</button>
</div>
</DialogTitle>
<slot :closeModal="closeModal" />
</DialogPanel>
</TransitionChild>
</div>
</div>
</Dialog>
</TransitionRoot>
</template>
<script setup lang="ts">
import { computed, ref } from 'vue';
import {
TransitionRoot,
TransitionChild,
Dialog,
DialogPanel,
DialogTitle,
} from '@headlessui/vue';
import { XMarkIcon } from '@heroicons/vue/24/outline';
const isOpen = ref(false);
const props = withDefaults(
defineProps<{
closeButton?: boolean;
size?: 'sm' | 'md' | 'lg' | 'xl';
}>(),
{
closeButton: true,
size: 'sm',
}
);
function closeModal() {
isOpen.value = false;
}
function openModal() {
isOpen.value = true;
}
const maxWidth = computed(() => {
if (props.size === 'sm') return 'max-w-md';
if (props.size === 'md') return 'max-w-xl';
if (props.size === 'lg') return 'max-w-2xl';
return 'max-w-4xl';
});
defineExpose({
openModal,
closeModal,
isOpen,
});
</script>