Merge branch 'feature/20250930_cl_GR_GALLERY' into feature/20250910-all

This commit is contained in:
clkim
2025-09-25 10:07:06 +09:00
48 changed files with 1853 additions and 354 deletions

View File

@@ -2,10 +2,14 @@
import { getResponsiveClass, getResponsiveSrc } from '#layers/utils/dataUtil'
import type { PageDataResourceGroup } from '#layers/types/api/pageData'
const props = defineProps<{
interface Props {
resourcesData: PageDataResourceGroup
gradientClass?: string
}>()
gradient?: boolean
}
const props = withDefaults(defineProps<Props>(), {
gradient: false,
})
const resPath = computed(() => {
return props.resourcesData?.res_path
@@ -37,10 +41,10 @@ const posterSrc = computed(() => {
<!-- 비디오 타입 -->
<template v-else-if="resourcesData?.group_type === 'video'">
<!-- 모바일 비디오 (sm 미만) -->
<!-- 모바일 비디오 (md 미만) -->
<video
v-if="videoSrc?.mobileSrc"
class="w-full h-full object-cover sm:hidden"
class="w-full h-full object-cover md:hidden"
:poster="posterSrc?.mobileSrc"
autoplay
muted
@@ -50,10 +54,10 @@ const posterSrc = computed(() => {
<source :src="videoSrc.mobileSrc" type="video/mp4" />
<source :src="videoSrc.mobileSrc" type="video/webm" />
</video>
<!-- PC 비디오 (sm 이상) -->
<!-- PC 비디오 (md 이상) -->
<video
v-if="videoSrc?.pcSrc"
class="w-full h-full object-cover hidden sm:block"
class="w-full h-full object-cover hidden md:block"
:poster="posterSrc?.pcSrc"
autoplay
muted
@@ -65,6 +69,10 @@ const posterSrc = computed(() => {
</video>
</template>
<div class="absolute inset-0" :class="gradientClass" />
<!-- 그라디언트 오버레이 (gradient가 true일 때만) -->
<div
v-if="props.gradient"
class="absolute bottom-0 left-0 right-0 h-[342px] md:h-[720px] bg-gradient-to-b from-[#100d0f]/0 to-[#100d0f]"
/>
</div>
</template>

View File

@@ -0,0 +1,77 @@
<script setup lang="ts">
import { SplideSlide } from '@splidejs/vue-splide'
import type { ListOperateGroupItem } from '#layers/types/api/resourcesData'
import type { SlideItemSize } from '#layers/types/components/slide'
interface BannerListProps {
slideItemList: ListOperateGroupItem[]
slideItemSize: SlideItemSize
arrows?: boolean
pagination?: boolean
class?: string
}
const props = withDefaults(defineProps<BannerListProps>(), {
arrows: true,
pagination: true,
})
const isMultipleItems = computed(() => {
return props.slideItemList.length > 1
})
</script>
<template>
<BlocksSlideCenterHighlight
:slide-item-size="props.slideItemSize"
:type="isMultipleItems ? 'loop' : 'slide'"
:arrows="isMultipleItems ? true : false"
:pagination="false"
class="mt-[36px] md:mt-[60px]"
>
<SplideSlide
v-for="(item, index) in props.slideItemList"
:key="index"
class="splide-slide"
>
<BlocksCardNews
:title="item.title"
:description="item.option01"
:img-path="getResolvedHost(item.img_path)"
:url="item.url"
:link-target="item.link_target"
class="news-center-highlight"
/>
</SplideSlide>
</BlocksSlideCenterHighlight>
</template>
<style scoped>
.center-highlight:deep(.splide__slide.is-active .news-center-highlight) {
width: var(--banner-width-mo-active);
height: var(--banner-height-mo-active);
}
.center-highlight:deep(.splide__slide.is-active .card-link) {
pointer-events: auto;
}
.news-center-highlight {
width: var(--banner-width-mo);
height: var(--banner-height-mo);
transition: all 0.4s cubic-bezier(0.4, 0, 0.2, 1);
}
.center-highlight:deep(.splide__slide .card-link) {
pointer-events: none;
}
/* PC 스타일 */
@media (min-width: 1024px) {
.center-highlight:deep(.splide__slide.is-active .news-center-highlight) {
width: var(--banner-width-pc-active);
height: var(--banner-height-pc-active);
}
.news-center-highlight {
width: var(--banner-width-pc);
height: var(--banner-height-pc);
}
}
</style>

View File

@@ -3,19 +3,25 @@ import type { PageDataResourceGroup } from '#layers/types/api/pageData'
const props = defineProps<{
groupsData: PageDataResourceGroup[]
buttonType?: string
}>()
</script>
<template>
<template v-if="props.groupsData">
<div
v-if="props.groupsData"
class="flex flex-wrap justify-center gap-3 md:gap-4"
>
<AtomsButton
v-for="button in props.groupsData"
:key="button.group_code"
:button-type="props.buttonType"
class="size-extra-small md:size-medium"
:background-color="button.btn_info?.color_code_btn"
:text-color="button.btn_info?.color_code_txt"
:disabled="button.btn_info?.disabled"
>
{{ button.btn_info?.txt_btn_name }}
</AtomsButton>
</template>
</div>
</template>

View File

@@ -1,17 +1,13 @@
<script setup lang="ts">
import { getResponsiveSrc } from '#layers/utils/dataUtil'
import type { PageDataResourceGroup } from '#layers/types/api/pageData'
const props = defineProps<{
resourcesData: PageDataResourceGroup
}>()
const displayText = props.resourcesData?.display?.text
const imageSrc = getResponsiveSrc(props.resourcesData?.res_path)
</script>
<template>
<p>
<BlocksVisualContent :text="displayText" :image-src="imageSrc" />
<BlocksVisualContent :resources-data="props.resourcesData" />
</p>
</template>

View File

@@ -1,17 +1,13 @@
<script setup lang="ts">
import { getResponsiveSrc } from '#layers/utils/dataUtil'
import type { PageDataResourceGroup } from '#layers/types/api/pageData'
const props = defineProps<{
resourcesData: PageDataResourceGroup
}>()
const displayText = props.resourcesData?.display?.text
const imageSrc = getResponsiveSrc(props.resourcesData?.res_path)
</script>
<template>
<h2>
<BlocksVisualContent :text="displayText" :image-src="imageSrc" />
<BlocksVisualContent :resources-data="props.resourcesData" />
</h2>
</template>

View File

@@ -1,17 +1,13 @@
<script setup lang="ts">
import { getResponsiveSrc } from '#layers/utils/dataUtil'
import type { PageDataResourceGroup } from '#layers/types/api/pageData'
const props = defineProps<{
resourcesData: PageDataResourceGroup
}>()
const displayText = props.resourcesData?.display?.text
const imageSrc = getResponsiveSrc(props.resourcesData?.res_path)
</script>
<template>
<h3>
<BlocksVisualContent :text="displayText" :image-src="imageSrc" />
<BlocksVisualContent :resources-data="props.resourcesData" />
</h3>
</template>

View File

@@ -1,51 +1,26 @@
<script setup lang="ts">
import { getResponsiveSrc, getResponsiveClass } from '#layers/utils/dataUtil'
import type { PageDataResourceGroup } from '#layers/types/api/pageData'
const props = defineProps<{ resourcesData: PageDataResourceGroup, pageVerTmplSeq: number }>()
const props = defineProps<{
resourcesData: PageDataResourceGroup
pageVerTmplSeq: number
}>()
const { useAnalyticsLogData } = useAnalytics()
const logData = useAnalyticsLogData(props.resourcesData, props.pageVerTmplSeq)
const bgStyles = getResponsiveSrc(props.resourcesData?.res_path, {
resourcesType: 'bg',
})
// YouTube 모달 상태 관리
const isYouTubeModalOpen = ref(false)
const youtubeVideoId = ref('')
// YouTube 모달 스토어 사용
const modalStore = useModalStore()
// 비디오 플레이 버튼 클릭 핸들러
const handleVideoPlayClick = () => {
// TODO: 실제 YouTube 비디오 ID를 설정해야 합니다
// 예시: 'dQw4w9WgXcQ' (Rick Astley - Never Gonna Give You Up)
youtubeVideoId.value = 'UKVsZYHxYTc' // 임시로 설정
isYouTubeModalOpen.value = true
}
// 모달 닫기 핸들러
const handleCloseModal = () => {
isYouTubeModalOpen.value = false
youtubeVideoId.value = ''
const youtubeUrl = props.resourcesData?.display?.text ?? ''
modalStore.handleOpenYoutube({ youtubeUrl })
}
</script>
<template>
<button
v-if="resourcesData"
v-analytics="logData"
class="bg-cover bg-center bg-no-repeat w-[66px] h-[66px] lg:w-[100px] lg:h-[100px]"
:class="getResponsiveClass()"
:style="bgStyles"
@click="handleVideoPlayClick()"
>
<span class="sr-only">videoPlay</span>
</button>
<!-- YouTube 모달 -->
<BlocksModalYouTube
:is-open="isYouTubeModalOpen"
:youtube-id="youtubeVideoId"
@close="handleCloseModal"
@update:is-open="(value: boolean) => (isYouTubeModalOpen = value)"
<AtomsButtonPlay
:resources-data="resourcesData"
@click="handleVideoPlayClick"
/>
</template>