diff --git a/app/app.vue b/app/app.vue index 5054488..00977ce 100644 --- a/app/app.vue +++ b/app/app.vue @@ -125,12 +125,13 @@ gtag('event', 'screen_view', { onMounted(() => { useEventListener('scroll', scrollStore.updateScrollValue) - if (gameData.value?.comm_img_json) { - gameData.value?.comm_img_json.groups.forEach(group => { - const cssVarName = `--${group.img_name}` - const imageUrl = `url(${getResolvedHost(group.img_path?.comm ?? '')})` - - document.documentElement.style.setProperty(cssVarName, imageUrl) + if (gameData.value?.comm_img_json?.groups) { + const groups = gameData.value.comm_img_json.groups + groups.forEach(({ img_name, img_path }) => { + document.documentElement.style.setProperty( + `--${img_name}`, + `url(${getResolvedHost(img_path?.comm ?? '')})` + ) }) } }) diff --git a/layers/assets/css/components/_layout.css b/layers/assets/css/components/_layout.css index ce44bca..dc920f1 100644 --- a/layers/assets/css/components/_layout.css +++ b/layers/assets/css/components/_layout.css @@ -25,6 +25,6 @@ @apply line-clamp-2 text-[16px] font-[500] leading-[24px] drop-shadow-[0_2px_2px_rgba(0,0,0,0.6)] md:line-clamp-1 md:text-[24px] md:leading-[34px]; } .title-xs { - @apply text-[14px] leading-[20px] tracking-[-0.42px] md:text-[18px] md:leading-[26px] md:tracking-[-0.54px]; + @apply text-[14px] font-[500] leading-[20px] tracking-[-0.42px] md:text-[18px] md:leading-[26px] md:tracking-[-0.54px]; } } diff --git a/layers/components/atoms/Video.vue b/layers/components/atoms/Video.vue index 2d60cc7..c792e95 100644 --- a/layers/components/atoms/Video.vue +++ b/layers/components/atoms/Video.vue @@ -2,15 +2,85 @@ interface Props { src: string type?: 'mp4' | 'webm' + play?: boolean + autoplay?: boolean + muted?: boolean + loop?: boolean + playsinline?: boolean + class?: ClassType } const props = withDefaults(defineProps(), { type: 'mp4', + play: false, + muted: true, + loop: true, + playsinline: true, }) + +const videoRef = ref(null) + +// autoplay prop 변경 시 재생/정지 제어 +watch( + () => props.play, + shouldPlay => { + if (!videoRef.value) return + + if (shouldPlay) { + videoRef.value.play().catch(err => { + console.warn('Video play failed:', err) + }) + } else { + setTimeout(() => { + videoRef.value.pause() + videoRef.value.currentTime = 0 + }, 200) + } + } +) + +// src 변경 시 비디오 다시 로드 +watch( + () => props.src, + () => { + if (!videoRef.value) return + + // 비디오 시간 초기화 및 새 소스 로드 + videoRef.value.currentTime = 0 + videoRef.value.load() + + // 재생 중이었다면 다시 재생 + if (props.play) { + nextTick(() => { + videoRef.value?.play().catch(err => { + console.warn('Video play failed:', err) + }) + }) + } + } +) + + diff --git a/layers/components/blocks/VisualContent.vue b/layers/components/blocks/VisualContent.vue index 26e9b77..ce19871 100644 --- a/layers/components/blocks/VisualContent.vue +++ b/layers/components/blocks/VisualContent.vue @@ -11,27 +11,20 @@ const props = withDefaults(defineProps(), { objectFit: 'contain', }) -const breakpoints = useResponsiveBreakpointsReliable() +const { getCurrentSrc } = useResponsiveSrc() +const imageSrc = computed(() => { + return getCurrentSrc(props.resourcesData?.res_path) +}) const displayText = computed(() => { return props.resourcesData?.display?.text || 'image' }) -const imageSrc = computed(() => { - return getResponsiveSrc(props.resourcesData?.res_path) -}) const colorName = computed(() => { return props.resourcesData?.display?.color_name }) const colorCode = computed(() => { return props.resourcesData?.display?.color_code }) -const currentImageSrc = computed(() => { - if (!imageSrc.value) return '' - - return breakpoints.value.isMobile - ? imageSrc.value.mobileSrc || '' - : imageSrc.value.pcSrc || '' -}) // HTML 콘텐츠 정리 (줄바꿈 처리) const sanitizedContent = computed(() => { @@ -42,8 +35,8 @@ const sanitizedContent = computed(() => {