109 lines
2.5 KiB
Vue
109 lines
2.5 KiB
Vue
<template>
|
|
<Transition
|
|
enter-active-class="transition duration-300 ease-out"
|
|
enter-from-class="opacity-0"
|
|
enter-to-class="opacity-100"
|
|
leave-active-class="transition duration-200 ease-in"
|
|
leave-from-class="opacity-100"
|
|
leave-to-class="opacity-0"
|
|
>
|
|
<div
|
|
v-if="isOpen"
|
|
class="fixed inset-0 z-50 flex items-center justify-center bg-black bg-opacity-75"
|
|
@click="handleBackdropClick"
|
|
>
|
|
<div
|
|
v-if="isOpen"
|
|
class="relative mx-4 my-4"
|
|
style="
|
|
width: min(896px, 90vw, calc((90vh - 2rem) * 16 / 9));
|
|
aspect-ratio: 16/9;
|
|
"
|
|
@click.stop
|
|
>
|
|
<!-- 헤더 -->
|
|
<div class="flex justify-end mb-3 md:mb-4">
|
|
<button
|
|
class="text-white rounded-full transition-colors"
|
|
aria-label="모달 닫기"
|
|
@click="closeModal"
|
|
>
|
|
<AtomsIconsCloseLine />
|
|
</button>
|
|
</div>
|
|
|
|
<!-- 유튜브 영상 컨테이너 -->
|
|
<div class="relative w-full h-full">
|
|
<iframe
|
|
v-if="embedUrl"
|
|
:src="embedUrl"
|
|
class="absolute top-0 left-0 w-full h-full"
|
|
frameborder="0"
|
|
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
|
|
allowfullscreen
|
|
title="YouTube video player"
|
|
/>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</Transition>
|
|
</template>
|
|
|
|
<script setup lang="ts">
|
|
import { getYouTubeEmbedUrl } from '#layers/utils/youtube'
|
|
|
|
interface Props {
|
|
isOpen: boolean
|
|
youtubeUrl: string
|
|
title?: string
|
|
description?: string
|
|
closeOnBackdrop?: boolean
|
|
}
|
|
|
|
interface Emits {
|
|
(e: 'closeButtonEvent'): void
|
|
}
|
|
|
|
const props = withDefaults(defineProps<Props>(), {
|
|
isOpen: false,
|
|
youtubeUrl: '',
|
|
title: '',
|
|
description: '',
|
|
closeOnBackdrop: true,
|
|
})
|
|
|
|
const emit = defineEmits<Emits>()
|
|
|
|
const embedUrl = computed(() => {
|
|
return getYouTubeEmbedUrl(props.youtubeUrl)
|
|
})
|
|
|
|
// ESC 키로 모달 닫기
|
|
const handleKeydown = (event: KeyboardEvent) => {
|
|
if (event.key === 'Escape' && props.isOpen) {
|
|
closeModal()
|
|
}
|
|
}
|
|
|
|
// 배경 클릭으로 모달 닫기
|
|
const handleBackdropClick = () => {
|
|
if (props.closeOnBackdrop) {
|
|
closeModal()
|
|
}
|
|
}
|
|
|
|
// 모달 닫기 함수
|
|
const closeModal = () => {
|
|
emit('closeButtonEvent')
|
|
}
|
|
|
|
// 키보드 이벤트 리스너 등록/해제
|
|
onMounted(() => {
|
|
document.addEventListener('keydown', handleKeydown)
|
|
})
|
|
|
|
onUnmounted(() => {
|
|
document.removeEventListener('keydown', handleKeydown)
|
|
})
|
|
</script>
|