fix. 템플릿 수정

This commit is contained in:
clkim
2025-10-30 16:23:12 +09:00
parent 7a4dfd9790
commit 74ce5a0714
15 changed files with 422 additions and 79 deletions

View File

@@ -116,7 +116,7 @@ const handleClick = () => {
<ClientOnly>
<Teleport to="#teleports">
<BlocksModalClient />
<WidgetsModalClient />
</Teleport>
</ClientOnly>
</template>

View File

@@ -72,7 +72,7 @@ const handleLinkClick = (title: string) => {
@apply absolute bottom-0 left-0 w-full pt-[14px] px-[18px] pb-[16px] flex flex-col justify-end border-t border-white/10 bg-black/40 shadow-[0_-10px_10px_0_rgba(0,0,0,0.25)] backdrop-blur-[25px] md:pt-[20px] text-left md:px-[26px] md:pb-[26px];
}
.card-title {
@apply text-[14px] leading-[20px] font-medium text-white md:text-[18px] md:leading-[26px];
@apply text-[14px] leading-[20px] font-medium text-white line-clamp-1 md:text-[18px] md:leading-[26px];
}
.card-description {
@apply mt-[6px] text-[12px] leading-[18px] text-white/50 md:mt-1 md:text-[14px] md:leading-[24px];

View File

@@ -0,0 +1,65 @@
<script setup lang="ts">
interface props {
isShowDimmed?: boolean
contentText?: string
confirmButtonText?: string
isOutsideClose?: boolean
modalName?: string
}
const props = withDefaults(defineProps<props>(), {
isShowDimmed: false,
isOutsideClose: false,
})
const emit = defineEmits(['confirmButtonEvent'])
const isOpen = defineModel<boolean>('isOpen', { default: false })
const setButtonEvent = (event?: () => void | void) => {
if (typeof event === 'function') {
return event()
}
isOpen.value = false
}
const handleOutsideClick = () => {
if (props.isOutsideClose) {
isOpen.value = false
}
}
</script>
<template>
<Transition name="fade">
<div
v-if="isOpen"
:class="['modal-wrap', { dimmed: props.isShowDimmed }, props.modalName]"
@click="handleOutsideClick"
>
<div class="modal-area" @click.stop>
<div class="modal-content">
<p
v-if="props.contentText"
v-dompurify-html="props.contentText"
class="content-text"
></p>
<slot></slot>
<div class="content-btns">
<AtomsButtonVariant
@click="setButtonEvent(() => emit('confirmButtonEvent'))"
>
{{ props.confirmButtonText || '확인' }}
</AtomsButtonVariant>
</div>
</div>
</div>
</div>
</Transition>
</template>
<style scoped>
.modal-area {
@apply max-w-[312px] p-6 bg-white rounded-[20px];
}
</style>

View File

@@ -0,0 +1,72 @@
<script setup lang="ts">
interface props {
isShowDimmed?: boolean
contentText?: string
confirmButtonText?: string
cancelButtonText?: string
isOutsideClose?: boolean
modalName?: string
}
const props = withDefaults(defineProps<props>(), {
isShowDimmed: false,
isOutsideClose: false,
})
const emit = defineEmits(['cancelButtonEvent', 'confirmButtonEvent'])
const isOpen = defineModel<boolean>('isOpen', { default: false })
const setButtonEvent = (event?: () => void) => {
if (event) {
event()
}
isOpen.value = false
}
const handleOutsideClick = () => {
if (props.isOutsideClose) {
isOpen.value = false
}
}
</script>
<template>
<Transition name="fade">
<div
v-if="isOpen"
:class="['modal-wrap', { dimmed: props.isShowDimmed }, props.modalName]"
@click="handleOutsideClick"
>
<div class="modal-area" @click.stop>
<div class="modal-content">
<p
v-if="props.contentText"
v-dompurify-html="props.contentText"
class="content-text"
></p>
<slot></slot>
<div class="content-btns">
<AtomsButtonVariant
variant="outlined"
@click="setButtonEvent(() => emit('cancelButtonEvent'))"
>
{{ props.cancelButtonText || '취소' }}
</AtomsButtonVariant>
<AtomsButtonVariant
@click="setButtonEvent(() => emit('confirmButtonEvent'))"
>
{{ props.confirmButtonText || '확인' }}
</AtomsButtonVariant>
</div>
</div>
</div>
</div>
</Transition>
</template>
<style scoped>
.modal-area {
@apply max-w-[312px] p-6 bg-white rounded-[20px];
}
</style>

View File

@@ -0,0 +1,50 @@
<script setup lang="ts">
interface props {
isShowDimmed?: boolean
isOutsideClose?: boolean
modalName?: string
areaClass?: string
closeClass?: string
}
const props = withDefaults(defineProps<props>(), {
isShowDimmed: false,
isOutsideClose: false,
})
const isOpen = defineModel<boolean>('isOpen', { default: false })
const handleCloseModal = () => {
isOpen.value = false
}
const handleOutsideClick = () => {
if (props.isOutsideClose) {
handleCloseModal()
}
}
</script>
<template>
<Transition name="fade">
<div
v-if="isOpen"
:class="['modal-wrap', { dimmed: props.isShowDimmed }, props.modalName]"
@click="handleOutsideClick"
>
<div :class="['modal-area', props.areaClass]" @click.stop>
<div class="modal-content">
<slot></slot>
</div>
<button
type="button"
:class="['modal-close', props.closeClass]"
@click="handleCloseModal"
>
<span class="sr-only">close</span>
<AtomsIconsCloseLine size="24" color="#333333" />
</button>
</div>
</div>
</Transition>
</template>

View File

@@ -0,0 +1,88 @@
<script setup lang="ts">
import { getYouTubeEmbedUrl } from '@/layers/utils/youtubeUtil'
interface Props {
youtubeUrl: string
isOutsideClose?: boolean
modalName?: string
}
const props = withDefaults(defineProps<Props>(), {
youtubeUrl: '',
isOutsideClose: false,
})
const emit = defineEmits(['closeButtonEvent'])
const isOpen = defineModel<boolean>('isOpen', { default: false })
const embedUrl = computed(() => {
return getYouTubeEmbedUrl(props.youtubeUrl)
})
const handleCloseModal = () => {
isOpen.value = false
emit('closeButtonEvent')
}
const handleKeydown = (event: KeyboardEvent) => {
if (event.key === 'Escape' && isOpen.value) {
handleCloseModal()
}
}
const handleOutsideClick = () => {
if (props.isOutsideClose) {
handleCloseModal()
}
}
// 키보드 이벤트 리스너 등록/해제
onMounted(() => {
document.addEventListener('keydown', handleKeydown)
})
onUnmounted(() => {
document.removeEventListener('keydown', handleKeydown)
})
</script>
<template>
<Transition name="fade">
<div
v-if="isOpen"
class="fixed inset-0 flex items-center justify-center bg-black bg-opacity-75 z-[800]"
:class="props.modalName"
@click="handleOutsideClick"
>
<div
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 type="button" @click="handleCloseModal">
<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>

View File

@@ -6,6 +6,7 @@ import type { PageDataResourceGroups } from '#layers/types/api/pageData'
interface Props {
type?: ResponsiveOptions['type']
slideItemLength?: number
gap?: number
autoplay?: boolean
perPage?: number
drag?: boolean
@@ -16,6 +17,7 @@ interface Props {
}
const props = withDefaults(defineProps<Props>(), {
gap: 0,
autoplay: false,
perPage: 1,
drag: true,
@@ -39,6 +41,7 @@ const options = computed((): ResponsiveOptions => {
type: slideType.value,
autoWidth: true,
autoHeight: true,
gap: props.gap,
perPage: props.perPage,
speed: 500,
updateOnMove: true,