Archipelago — open-source initial import
This commit is contained in:
@@ -0,0 +1,91 @@
|
||||
<template>
|
||||
<Teleport to="body">
|
||||
<Transition name="modal">
|
||||
<div
|
||||
v-if="show"
|
||||
class="fixed inset-0 flex items-center justify-center p-4"
|
||||
:class="zClass"
|
||||
@click.self="close"
|
||||
>
|
||||
<div class="absolute inset-0 bg-black/60 backdrop-blur-md"></div>
|
||||
<div
|
||||
ref="modalRef"
|
||||
class="glass-card p-6 w-full relative z-10"
|
||||
:class="[maxWidth, contentClass]"
|
||||
role="dialog"
|
||||
aria-modal="true"
|
||||
@click.stop
|
||||
>
|
||||
<div class="flex items-start justify-between gap-4 mb-4 shrink-0">
|
||||
<h3 class="text-xl font-semibold text-white">{{ title }}</h3>
|
||||
<button
|
||||
@click="close"
|
||||
class="p-2 rounded-lg hover:bg-white/10 text-white/70 hover:text-white transition-colors"
|
||||
aria-label="Close"
|
||||
>
|
||||
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" />
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
<slot />
|
||||
<slot name="footer" />
|
||||
</div>
|
||||
</div>
|
||||
</Transition>
|
||||
</Teleport>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, computed } from 'vue'
|
||||
import { useModalKeyboard } from '@/composables/useModalKeyboard'
|
||||
import { useBodyScrollLock } from '@/composables/useBodyScrollLock'
|
||||
|
||||
const props = withDefaults(defineProps<{
|
||||
show: boolean
|
||||
title: string
|
||||
maxWidth?: string
|
||||
zIndex?: string
|
||||
contentClass?: string
|
||||
}>(), {
|
||||
maxWidth: 'max-w-md',
|
||||
zIndex: 'z-[3000]',
|
||||
contentClass: '',
|
||||
})
|
||||
|
||||
const emit = defineEmits<{
|
||||
close: []
|
||||
}>()
|
||||
|
||||
const modalRef = ref<HTMLElement | null>(null)
|
||||
|
||||
const zClass = computed(() => props.zIndex)
|
||||
|
||||
function close() {
|
||||
emit('close')
|
||||
}
|
||||
|
||||
useModalKeyboard(modalRef, computed(() => props.show), close)
|
||||
useBodyScrollLock(computed(() => props.show))
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.modal-enter-active,
|
||||
.modal-leave-active {
|
||||
transition: opacity 0.2s ease;
|
||||
}
|
||||
.modal-enter-from,
|
||||
.modal-leave-to {
|
||||
opacity: 0;
|
||||
}
|
||||
.modal-enter-active .glass-card,
|
||||
.modal-leave-active .glass-card {
|
||||
transition: transform 0.2s ease;
|
||||
}
|
||||
.modal-enter-from .glass-card {
|
||||
transform: scale(0.95);
|
||||
}
|
||||
.modal-leave-to .glass-card {
|
||||
transform: scale(0.95);
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user