aboutsummaryrefslogtreecommitdiff
path: root/src/ui/c-modal/c-modal.vue
diff options
context:
space:
mode:
Diffstat (limited to 'src/ui/c-modal/c-modal.vue')
-rw-r--r--src/ui/c-modal/c-modal.vue74
1 files changed, 74 insertions, 0 deletions
diff --git a/src/ui/c-modal/c-modal.vue b/src/ui/c-modal/c-modal.vue
new file mode 100644
index 0000000..af92f01
--- /dev/null
+++ b/src/ui/c-modal/c-modal.vue
@@ -0,0 +1,74 @@
+<script setup lang="ts">
+import { useTheme } from './c-modal.theme';
+
+const props = withDefaults(defineProps<{ open?: boolean; centered?: boolean }>(), {
+ open: false,
+ centered: true,
+});
+const emit = defineEmits(['update:open']);
+const isOpen = useVModel(props, 'open', emit, { passive: true });
+
+const { centered } = toRefs(props);
+
+function close() {
+ isOpen.value = false;
+}
+
+function open() {
+ isOpen.value = true;
+}
+
+function toggle() {
+ isOpen.value = !isOpen.value;
+}
+
+defineExpose({
+ close,
+ open,
+ toggle,
+ isOpen,
+});
+
+defineOptions({
+ inheritAttrs: false,
+});
+
+const theme = useTheme();
+const modal = ref();
+
+onClickOutside(modal, () => {
+ if (isOpen.value) {
+ close();
+ }
+});
+</script>
+
+<template>
+ <transition>
+ <div v-if="isOpen" class="c-modal--overlay" fixed left-0 top-0 z-10 h-full w-full flex justify-center px-2 :class="{ 'items-center': centered }">
+ <div ref="modal" class="c-modal--container" v-bind="$attrs" max-w-xl w-full flex-grow rounded-md pa-24px>
+ <slot />
+ </div>
+ </div>
+ </transition>
+</template>
+
+<style scoped lang="less">
+.c-modal--overlay {
+ background-color: rgba(0, 0, 0, 0.5);
+}
+
+.c-modal--container {
+ background-color: v-bind('theme.background');
+}
+
+.v-enter-active,
+.v-leave-active {
+ transition: opacity 0.3s ease-in-out;
+}
+
+.v-enter-from,
+.v-leave-to {
+ opacity: 0;
+}
+</style>