feat. videoPlay 컴포넌트 제작

This commit is contained in:
clkim
2025-09-18 15:18:53 +09:00
parent 0acc3b3eb8
commit 1a4c6b684d
10 changed files with 282 additions and 103 deletions

View File

@@ -1,67 +1,52 @@
<template>
<Teleport to="body">
<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"
<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="fixed inset-0 z-50 flex items-center justify-center bg-black bg-opacity-75"
@click="handleBackdropClick"
class="relative mx-4 my-4"
style="
width: min(896px, 90vw, calc((90vh - 2rem) * 16 / 9));
aspect-ratio: 16/9;
"
@click.stop
>
<Transition
enter-active-class="transition duration-300 ease-out"
enter-from-class="opacity-0 scale-95"
enter-to-class="opacity-100 scale-100"
leave-active-class="transition duration-200 ease-in"
leave-from-class="opacity-100 scale-100"
leave-to-class="opacity-0 scale-95"
>
<div v-if="isOpen" class="relative w-full max-w-4xl mx-4" @click.stop>
<!-- 헤더 -->
<div class="flex justify-end">
<button
class="p-1 text-white rounded-full transition-colors"
aria-label="모달 닫기"
@click="closeModal"
>
<svg
class="w-8 h-8"
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>
<!-- 헤더 -->
<div class="flex justify-end">
<button
class="p-1 text-white rounded-full transition-colors"
aria-label="모달 닫기"
@click="closeModal"
>
<AtomsIconsClose />
</button>
</div>
<!-- 유튜브 영상 컨테이너 -->
<div class="relative w-full" :style="{ paddingBottom: '56.25%' }">
<iframe
v-if="youtubeId"
:src="`https://www.youtube.com/embed/${youtubeId}?autoplay=1&rel=0`"
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>
</Transition>
<!-- 유튜브 영상 컨테이너 -->
<div class="relative w-full h-full">
<iframe
v-if="youtubeId"
:src="`https://www.youtube.com/embed/${youtubeId}?autoplay=1&rel=0`"
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>
</Transition>
</Teleport>
</div>
</Transition>
</template>
<script setup lang="ts">
@@ -74,11 +59,12 @@ interface Props {
}
interface Emits {
(e: 'close'): void
(e: 'update:isOpen', value: boolean): void
(e: 'closeButtonEvent'): void
}
const props = withDefaults(defineProps<Props>(), {
isOpen: false,
youtubeId: '',
title: '',
description: '',
closeOnBackdrop: true,
@@ -102,8 +88,7 @@ const handleBackdropClick = () => {
// 모달 닫기 함수
const closeModal = () => {
emit('close')
emit('update:isOpen', false)
emit('closeButtonEvent')
}
// 키보드 이벤트 리스너 등록/해제
@@ -114,21 +99,4 @@ onMounted(() => {
onUnmounted(() => {
document.removeEventListener('keydown', handleKeydown)
})
// 모달이 열릴 때 body 스크롤 방지
watch(
() => props.isOpen,
isOpen => {
if (isOpen) {
document.body.style.overflow = 'hidden'
} else {
document.body.style.overflow = ''
}
}
)
// 컴포넌트 언마운트 시 body 스크롤 복원
onUnmounted(() => {
document.body.style.overflow = ''
})
</script>