179 lines
4.9 KiB
Vue
179 lines
4.9 KiB
Vue
<script setup lang="ts">
|
|
import { SplideSlide } from '@splidejs/vue-splide'
|
|
import {
|
|
getComponentContainer,
|
|
getComponentGroupAry,
|
|
} from '#layers/utils/dataUtil'
|
|
import type { PageDataTemplateComponents } from '#layers/types/api/pageData'
|
|
|
|
interface Props {
|
|
components: PageDataTemplateComponents
|
|
pageVerTmplSeq: number
|
|
pageVerTmplNameEn: string
|
|
}
|
|
|
|
const props = defineProps<Props>()
|
|
|
|
const { locale } = useI18n()
|
|
const { sendLog } = useAnalytics()
|
|
|
|
const splideRef = ref<SplideSlide | null>(null)
|
|
const currentSlideIndex = ref<number | null>(null)
|
|
|
|
const slideData = computed(() => {
|
|
return getComponentContainer(props.components, 'group_sets', { maxLength: 5 })
|
|
})
|
|
const paginationData = computed(() => {
|
|
return getComponentGroupAry(props.components, 'pagination')
|
|
})
|
|
|
|
const goToSlide = (index: number, title: string) => {
|
|
const splide = splideRef.value?.splide
|
|
const analytics = {
|
|
action_type: 'click',
|
|
click_item: title,
|
|
click_sarea: props.pageVerTmplNameEn,
|
|
}
|
|
|
|
if (splide) {
|
|
splide.go(index)
|
|
sendLog(locale.value, analytics)
|
|
}
|
|
}
|
|
</script>
|
|
|
|
<template>
|
|
<section class="section-standard">
|
|
<WidgetsSlideFade
|
|
v-if="slideData"
|
|
ref="splideRef"
|
|
v-model:index="currentSlideIndex"
|
|
:autoplay="true"
|
|
:arrows="false"
|
|
:pagination="false"
|
|
class="h-full"
|
|
>
|
|
<SplideSlide v-for="(item, index) in slideData" :key="index">
|
|
<WidgetsBackground
|
|
v-if="hasComponentGroup(item, 'background')"
|
|
:resources-data="getComponentGroup(item, 'background')"
|
|
:video-play="currentSlideIndex === index"
|
|
/>
|
|
<div class="content-standard">
|
|
<WidgetsMainTitle
|
|
v-if="hasComponentGroup(item, 'mainTitle')"
|
|
:resources-data="getComponentGroup(item, 'mainTitle')"
|
|
class="title-lg max-w-[944px]"
|
|
/>
|
|
<WidgetsSubTitle
|
|
v-if="hasComponentGroup(item, 'subTitle')"
|
|
:resources-data="getComponentGroup(item, 'subTitle')"
|
|
class="title-md max-w-[944px] mt-0.5 line-clamp-3 md:mt-1 md:line-clamp-2"
|
|
/>
|
|
<WidgetsDescription
|
|
v-if="hasComponentGroup(item, 'description')"
|
|
:resources-data="getComponentGroup(item, 'description')"
|
|
class="max-w-[944px] mt-4 md:mt-6"
|
|
/>
|
|
</div>
|
|
</SplideSlide>
|
|
</WidgetsSlideFade>
|
|
<div
|
|
v-if="slideData && slideData.length > 1"
|
|
class="splide-pagination"
|
|
:style="getPaginationClass(paginationData)"
|
|
>
|
|
<div
|
|
v-for="(item, index) in slideData"
|
|
:key="index"
|
|
:class="[
|
|
'pagination-item',
|
|
{
|
|
'is-active': currentSlideIndex === index,
|
|
'is-completed': index < currentSlideIndex,
|
|
},
|
|
]"
|
|
>
|
|
<button
|
|
:class="[
|
|
'btn-pagination',
|
|
{ 'is-active': currentSlideIndex === index },
|
|
]"
|
|
@click="
|
|
goToSlide(
|
|
index,
|
|
getComponentGroup(item, 'pagenaviTitle')?.display?.text || ''
|
|
)
|
|
"
|
|
>
|
|
<span class="item-bullet"></span>
|
|
<span class="item-title">
|
|
{{ getComponentGroup(item, 'pagenaviTitle')?.display?.text || '' }}
|
|
</span>
|
|
</button>
|
|
<div v-if="index !== slideData.length - 1" class="progress-bar">
|
|
<span class="progress-fill"></span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
</template>
|
|
|
|
<style scoped>
|
|
.splide-pagination {
|
|
@apply flex items-center justify-center absolute bottom-10 left-1/2 max-w-full -translate-x-1/2 z-[5] md:bottom-[96px];
|
|
}
|
|
.btn-pagination {
|
|
@apply relative;
|
|
}
|
|
.pagination-item {
|
|
@apply flex items-center;
|
|
}
|
|
.item-bullet {
|
|
@apply block w-3 h-3 rounded-full transition-[background] duration-300 ease-in-out;
|
|
background-color: var(--pagination-disabled);
|
|
}
|
|
.item-title {
|
|
@apply hidden absolute -bottom-[46px] left-1/2 max-w-[184px] line-clamp-1 text-ellipsis whitespace-nowrap text-sm font-medium -translate-x-1/2 transition-[color] duration-300 ease-in-out md:block;
|
|
color: var(--pagination-disabled);
|
|
}
|
|
.progress-bar {
|
|
@apply relative w-[62px] h-[1px] overflow-hidden xs:w-[68px] md:w-[184px];
|
|
background-color: var(--pagination-disabled);
|
|
}
|
|
.progress-fill {
|
|
@apply absolute inset-y-0 left-0 w-[0];
|
|
background-color: var(--pagination-active);
|
|
}
|
|
|
|
/* 활성화 상태 (현재 슬라이드) */
|
|
.btn-pagination:hover .item-bullet,
|
|
.is-active .item-bullet {
|
|
background-color: var(--pagination-active);
|
|
}
|
|
.btn-pagination:hover .item-title,
|
|
.is-active .item-title {
|
|
color: var(--pagination-active);
|
|
}
|
|
.is-active .progress-fill {
|
|
animation: progressFill 5000ms linear forwards;
|
|
}
|
|
|
|
/* 완료 상태 (지나간 슬라이드) */
|
|
.is-completed .item-bullet {
|
|
background-color: var(--pagination-active);
|
|
}
|
|
.is-completed .progress-fill {
|
|
width: 100%;
|
|
}
|
|
|
|
@keyframes progressFill {
|
|
from {
|
|
width: 0%;
|
|
}
|
|
to {
|
|
width: 100%;
|
|
}
|
|
}
|
|
</style>
|