Merge branch 'feature/20251001-gil' into feature/20250910-all
This commit is contained in:
@@ -10,12 +10,28 @@ interface Props {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const props = defineProps<Props>()
|
const props = defineProps<Props>()
|
||||||
|
const {locale} = useI18n()
|
||||||
|
const { sendLog, useAnalyticsLogDataDirect } = useAnalytics()
|
||||||
|
|
||||||
|
const handleLinkClick = (title) => {
|
||||||
|
const trackingData = {
|
||||||
|
tracking: {
|
||||||
|
click_item: title,
|
||||||
|
action_type: 'click',
|
||||||
|
click_sarea: ''
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sendLog(locale.value, useAnalyticsLogDataDirect(trackingData, 1))
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div
|
<div
|
||||||
v-if="props.title || props.description"
|
v-if="props.title || props.description"
|
||||||
:class="`card-news ${props.class || ''}`"
|
:class="`card-news ${props.class || ''}`"
|
||||||
|
@click="handleLinkClick(props.title)"
|
||||||
>
|
>
|
||||||
<img
|
<img
|
||||||
:src="props.imgPath"
|
:src="props.imgPath"
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
import { Splide } from '@splidejs/vue-splide'
|
import { Splide } from '@splidejs/vue-splide'
|
||||||
import type { Splide as SplideType, ResponsiveOptions } from '@splidejs/splide'
|
import type { Splide as SplideType, ResponsiveOptions } from '@splidejs/splide'
|
||||||
import type { SlideItemSize } from '#layers/types/components/slide'
|
import type { SlideItemSize } from '#layers/types/components/slide'
|
||||||
|
import { useSplideArrow } from '#layers/composables/useSplideArrow'
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
slideItemSize: SlideItemSize
|
slideItemSize: SlideItemSize
|
||||||
@@ -20,6 +21,9 @@ const props = withDefaults(defineProps<Props>(), {
|
|||||||
|
|
||||||
const emit = defineEmits(['mounted', 'move', 'moved', 'arrowClick'])
|
const emit = defineEmits(['mounted', 'move', 'moved', 'arrowClick'])
|
||||||
|
|
||||||
|
// Splide 화살표 로직을 위한 composable 사용
|
||||||
|
const { addArrowClickListeners } = useSplideArrow()
|
||||||
|
|
||||||
const isMultipleItems = computed(() => {
|
const isMultipleItems = computed(() => {
|
||||||
return props.slideItemLength > 1
|
return props.slideItemLength > 1
|
||||||
})
|
})
|
||||||
@@ -85,7 +89,9 @@ const handleSplideMounted = (splide: SplideType) => {
|
|||||||
|
|
||||||
// 화살표 버튼 클릭 이벤트 리스너 추가
|
// 화살표 버튼 클릭 이벤트 리스너 추가
|
||||||
nextTick(() => {
|
nextTick(() => {
|
||||||
addArrowClickListeners(splide)
|
addArrowClickListeners(splide, (direction, targetIndex) => {
|
||||||
|
emit('arrowClick', direction, targetIndex)
|
||||||
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -107,34 +113,6 @@ const handleMoved = (
|
|||||||
emit('moved', splide, newIndex, oldIndex, destIndex)
|
emit('moved', splide, newIndex, oldIndex, destIndex)
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleArrowClick = (direction: 'prev' | 'next', splide: SplideType) => {
|
|
||||||
const currentIndex = splide.index
|
|
||||||
const totalSlides = splide.length
|
|
||||||
|
|
||||||
// 이동할 슬라이드 인덱스 계산
|
|
||||||
let targetIndex: number
|
|
||||||
if (direction === 'next') {
|
|
||||||
targetIndex = currentIndex + 1 >= totalSlides ? 0 : currentIndex + 1
|
|
||||||
} else {
|
|
||||||
targetIndex = currentIndex - 1 < 0 ? totalSlides - 1 : currentIndex - 1
|
|
||||||
}
|
|
||||||
|
|
||||||
emit('arrowClick', direction, targetIndex)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 화살표 버튼에 클릭 이벤트 리스너 추가
|
|
||||||
const addArrowClickListeners = (splide: SplideType) => {
|
|
||||||
const prevArrow = splide.root.querySelector('.arrow-prev')
|
|
||||||
const nextArrow = splide.root.querySelector('.arrow-next')
|
|
||||||
|
|
||||||
if (prevArrow) {
|
|
||||||
prevArrow.addEventListener('click', () => handleArrowClick('prev', splide))
|
|
||||||
}
|
|
||||||
|
|
||||||
if (nextArrow) {
|
|
||||||
nextArrow.addEventListener('click', () => handleArrowClick('next', splide))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -18,7 +18,10 @@ const props = withDefaults(defineProps<Props>(), {
|
|||||||
pagination: true,
|
pagination: true,
|
||||||
})
|
})
|
||||||
|
|
||||||
const emit = defineEmits(['mounted', 'move', 'moved'])
|
const emit = defineEmits(['mounted', 'move', 'moved', 'arrowClick'])
|
||||||
|
|
||||||
|
// Splide 화살표 로직을 위한 composable 사용
|
||||||
|
const { addArrowClickListeners } = useSplideArrow()
|
||||||
|
|
||||||
const isMultipleItems = computed(() => {
|
const isMultipleItems = computed(() => {
|
||||||
return props.slideItemLength > 1
|
return props.slideItemLength > 1
|
||||||
@@ -85,6 +88,13 @@ const style = computed(() => {
|
|||||||
const handleSplideMounted = (splide: SplideType) => {
|
const handleSplideMounted = (splide: SplideType) => {
|
||||||
emit('mounted', splide)
|
emit('mounted', splide)
|
||||||
splide.refresh()
|
splide.refresh()
|
||||||
|
|
||||||
|
// 화살표 버튼 클릭 이벤트 리스너 추가
|
||||||
|
nextTick(() => {
|
||||||
|
addArrowClickListeners(splide, (direction, targetIndex) => {
|
||||||
|
emit('arrowClick', direction, targetIndex)
|
||||||
|
})
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleMove = (
|
const handleMove = (
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { Splide } from '@splidejs/vue-splide'
|
import { Splide } from '@splidejs/vue-splide'
|
||||||
import type { Splide as SplideType, ResponsiveOptions } from '@splidejs/splide'
|
import type { Splide as SplideType, ResponsiveOptions } from '@splidejs/splide'
|
||||||
|
import { useSplideArrow } from '#layers/composables/useSplideArrow'
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
autoplay?: boolean | string
|
autoplay?: boolean | string
|
||||||
@@ -18,6 +19,8 @@ const props = withDefaults(defineProps<Props>(), {
|
|||||||
const emit = defineEmits(['mounted', 'move', 'moved', 'arrowClick'])
|
const emit = defineEmits(['mounted', 'move', 'moved', 'arrowClick'])
|
||||||
|
|
||||||
const splideRef = ref()
|
const splideRef = ref()
|
||||||
|
// Splide 화살표 로직을 위한 composable 사용
|
||||||
|
const { addArrowClickListeners } = useSplideArrow()
|
||||||
|
|
||||||
const options = computed((): ResponsiveOptions => {
|
const options = computed((): ResponsiveOptions => {
|
||||||
return {
|
return {
|
||||||
@@ -53,7 +56,9 @@ const handleSplideMounted = (splide: SplideType) => {
|
|||||||
|
|
||||||
// 화살표 버튼 클릭 이벤트 리스너 추가
|
// 화살표 버튼 클릭 이벤트 리스너 추가
|
||||||
nextTick(() => {
|
nextTick(() => {
|
||||||
addArrowClickListeners(splide)
|
addArrowClickListeners(splide, (direction, targetIndex) => {
|
||||||
|
emit('arrowClick', direction, targetIndex)
|
||||||
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -74,35 +79,6 @@ const handleMoved = (
|
|||||||
) => {
|
) => {
|
||||||
emit('moved', splide, newIndex, oldIndex, destIndex)
|
emit('moved', splide, newIndex, oldIndex, destIndex)
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleArrowClick = (direction: 'prev' | 'next', splide: SplideType) => {
|
|
||||||
const currentIndex = splide.index
|
|
||||||
const totalSlides = splide.length
|
|
||||||
|
|
||||||
// 이동할 슬라이드 인덱스 계산
|
|
||||||
let targetIndex: number
|
|
||||||
if (direction === 'next') {
|
|
||||||
targetIndex = currentIndex + 1 >= totalSlides ? 0 : currentIndex + 1
|
|
||||||
} else {
|
|
||||||
targetIndex = currentIndex - 1 < 0 ? totalSlides - 1 : currentIndex - 1
|
|
||||||
}
|
|
||||||
|
|
||||||
emit('arrowClick', direction, targetIndex)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 화살표 버튼에 클릭 이벤트 리스너 추가
|
|
||||||
const addArrowClickListeners = (splide: SplideType) => {
|
|
||||||
const prevArrow = splide.root.querySelector('.arrow-prev')
|
|
||||||
const nextArrow = splide.root.querySelector('.arrow-next')
|
|
||||||
|
|
||||||
if (prevArrow) {
|
|
||||||
prevArrow.addEventListener('click', () => handleArrowClick('prev', splide))
|
|
||||||
}
|
|
||||||
|
|
||||||
if (nextArrow) {
|
|
||||||
nextArrow.addEventListener('click', () => handleArrowClick('next', splide))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import type {
|
|||||||
PageDataTemplateComponentSet,
|
PageDataTemplateComponentSet,
|
||||||
PageDataResourceGroups,
|
PageDataResourceGroups,
|
||||||
} from '#layers/types/api/pageData'
|
} from '#layers/types/api/pageData'
|
||||||
|
import { useSplideArrow } from '#layers/composables/useSplideArrow'
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
slideData: PageDataTemplateComponentSet[]
|
slideData: PageDataTemplateComponentSet[]
|
||||||
@@ -18,6 +19,11 @@ const props = withDefaults(defineProps<Props>(), {
|
|||||||
drag: true,
|
drag: true,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const emit = defineEmits(['arrowClick'])
|
||||||
|
|
||||||
|
// Splide 화살표 로직을 위한 composable 사용
|
||||||
|
const { addArrowClickListeners } = useSplideArrow()
|
||||||
|
|
||||||
let mainInst: SplideType | null = null
|
let mainInst: SplideType | null = null
|
||||||
let thumbsInst: SplideType | null = null
|
let thumbsInst: SplideType | null = null
|
||||||
|
|
||||||
@@ -85,6 +91,13 @@ onMounted(() => {
|
|||||||
|
|
||||||
if (mainInst && thumbsInst) {
|
if (mainInst && thumbsInst) {
|
||||||
mainInst.sync(thumbsInst)
|
mainInst.sync(thumbsInst)
|
||||||
|
|
||||||
|
// 썸네일 슬라이드의 화살표 버튼에 이벤트 리스너 추가
|
||||||
|
nextTick(() => {
|
||||||
|
addArrowClickListeners(thumbsInst, (direction, targetIndex) => {
|
||||||
|
emit('arrowClick', direction, targetIndex)
|
||||||
|
})
|
||||||
|
})
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@@ -5,22 +5,25 @@ const props = defineProps<{
|
|||||||
resourcesData: PageDataResourceGroup
|
resourcesData: PageDataResourceGroup
|
||||||
pageVerTmplSeq: number
|
pageVerTmplSeq: number
|
||||||
}>()
|
}>()
|
||||||
const { useAnalyticsLogDataDirect } = useAnalytics()
|
|
||||||
const logData = useAnalyticsLogDataDirect(props.resourcesData, props.pageVerTmplSeq)
|
|
||||||
|
|
||||||
// YouTube 모달 스토어 사용
|
// YouTube 모달 스토어 사용
|
||||||
const modalStore = useModalStore()
|
const modalStore = useModalStore()
|
||||||
|
|
||||||
|
const {locale} = useI18n()
|
||||||
|
const { sendLog, useAnalyticsLogDataDirect } = useAnalytics()
|
||||||
|
|
||||||
|
|
||||||
// 비디오 플레이 버튼 클릭 핸들러
|
// 비디오 플레이 버튼 클릭 핸들러
|
||||||
const handleVideoPlayClick = () => {
|
const handleVideoPlayClick = () => {
|
||||||
const youtubeUrl = props.resourcesData?.display?.text ?? ''
|
const youtubeUrl = props.resourcesData?.display?.text ?? ''
|
||||||
modalStore.handleOpenYoutube({ youtubeUrl })
|
modalStore.handleOpenYoutube({ youtubeUrl })
|
||||||
|
|
||||||
|
sendLog(locale.value, useAnalyticsLogDataDirect(props.resourcesData, props.pageVerTmplSeq))
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<AtomsButtonPlay
|
<AtomsButtonPlay
|
||||||
v-analytics="logData"
|
|
||||||
:resources-data="resourcesData"
|
:resources-data="resourcesData"
|
||||||
@click="handleVideoPlayClick"
|
@click="handleVideoPlayClick"
|
||||||
/>
|
/>
|
||||||
|
|||||||
68
layers/composables/useSplideArrow.ts
Normal file
68
layers/composables/useSplideArrow.ts
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
import type { Splide as SplideType } from '@splidejs/splide'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Splide 슬라이더의 화살표 클릭 로직을 처리하는 composable
|
||||||
|
*/
|
||||||
|
export const useSplideArrow = () => {
|
||||||
|
/**
|
||||||
|
* 화살표 클릭 시 슬라이드 인덱스를 계산하는 함수
|
||||||
|
* @param direction - 이동 방향 ('prev' | 'next')
|
||||||
|
* @param splide - Splide 인스턴스
|
||||||
|
* @returns 다음 슬라이드 인덱스
|
||||||
|
*/
|
||||||
|
const calculateTargetIndex = (direction: 'prev' | 'next', splide: SplideType): number => {
|
||||||
|
const currentIndex = splide.index
|
||||||
|
const totalSlides = splide.length
|
||||||
|
|
||||||
|
if (direction === 'next') {
|
||||||
|
return currentIndex + 1 >= totalSlides ? 0 : currentIndex + 1
|
||||||
|
} else {
|
||||||
|
return currentIndex - 1 < 0 ? totalSlides - 1 : currentIndex - 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 화살표 클릭 핸들러
|
||||||
|
* @param direction - 이동 방향
|
||||||
|
* @param splide - Splide 인스턴스
|
||||||
|
* @param onArrowClick - 화살표 클릭 시 실행될 콜백 함수
|
||||||
|
*/
|
||||||
|
const handleArrowClick = (
|
||||||
|
direction: 'prev' | 'next',
|
||||||
|
splide: SplideType,
|
||||||
|
onArrowClick?: (direction: 'prev' | 'next', targetIndex: number) => void
|
||||||
|
) => {
|
||||||
|
const targetIndex = calculateTargetIndex(direction, splide)
|
||||||
|
|
||||||
|
if (onArrowClick) {
|
||||||
|
onArrowClick(direction, targetIndex)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 화살표 버튼에 클릭 이벤트 리스너를 추가하는 함수
|
||||||
|
* @param splide - Splide 인스턴스
|
||||||
|
* @param onArrowClick - 화살표 클릭 시 실행될 콜백 함수
|
||||||
|
*/
|
||||||
|
const addArrowClickListeners = (
|
||||||
|
splide: SplideType,
|
||||||
|
onArrowClick?: (direction: 'prev' | 'next', targetIndex: number) => void
|
||||||
|
) => {
|
||||||
|
const prevArrow = splide.root.querySelector('.arrow-prev')
|
||||||
|
const nextArrow = splide.root.querySelector('.arrow-next')
|
||||||
|
|
||||||
|
if (prevArrow) {
|
||||||
|
prevArrow.addEventListener('click', () => handleArrowClick('prev', splide, onArrowClick))
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nextArrow) {
|
||||||
|
nextArrow.addEventListener('click', () => handleArrowClick('next', splide, onArrowClick))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
calculateTargetIndex,
|
||||||
|
handleArrowClick,
|
||||||
|
addArrowClickListeners
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -60,6 +60,12 @@ const handleChange = (
|
|||||||
'buttonList'
|
'buttonList'
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
const {locale} = useI18n()
|
||||||
|
const { sendLog, useAnalyticsLogDataDirect } = useAnalytics()
|
||||||
|
const onArrowClick = (direction, targetIndex) => {
|
||||||
|
const logTraking = direction == 'prev' ? props.components.arrow.groups[0] : props.components.arrow.groups[1];
|
||||||
|
sendLog(locale.value, useAnalyticsLogDataDirect(logTraking, 1))
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
@@ -78,6 +84,7 @@ const handleChange = (
|
|||||||
:pagination="false"
|
:pagination="false"
|
||||||
class="mt-[24px] md:mt-[48px]"
|
class="mt-[24px] md:mt-[48px]"
|
||||||
@move="handleChange"
|
@move="handleChange"
|
||||||
|
@arrow-click="onArrowClick"
|
||||||
>
|
>
|
||||||
<SplideSlide v-for="(item, index) in slideData" :key="index">
|
<SplideSlide v-for="(item, index) in slideData" :key="index">
|
||||||
<div class="slide-inner border-line">
|
<div class="slide-inner border-line">
|
||||||
|
|||||||
@@ -71,6 +71,14 @@ const slideItemSize = {
|
|||||||
gap: 32,
|
gap: 32,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
const {locale} = useI18n()
|
||||||
|
const { sendLog, useAnalyticsLogDataDirect } = useAnalytics()
|
||||||
|
const onArrowClick = (direction, targetIndex) => {
|
||||||
|
const logTraking = direction == 'prev' ? props.components.arrow.groups[0] : props.components.arrow.groups[1];
|
||||||
|
sendLog(locale.value, useAnalyticsLogDataDirect(logTraking, 1))
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('resourcesData.value===', resourcesData.value)
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
@@ -96,6 +104,7 @@ const slideItemSize = {
|
|||||||
:resources-data="videoPlayData"
|
:resources-data="videoPlayData"
|
||||||
:page-ver-tmpl-seq="Number(props.pageVerTmplSeq)"
|
:page-ver-tmpl-seq="Number(props.pageVerTmplSeq)"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<WidgetsButtonList
|
<WidgetsButtonList
|
||||||
v-if="buttonListData.length > 0"
|
v-if="buttonListData.length > 0"
|
||||||
:resources-data="buttonListData"
|
:resources-data="buttonListData"
|
||||||
@@ -108,6 +117,7 @@ const slideItemSize = {
|
|||||||
:slide-item-length="slideData?.length"
|
:slide-item-length="slideData?.length"
|
||||||
:pagination="false"
|
:pagination="false"
|
||||||
class="mt-[36px] md:mt-[60px]"
|
class="mt-[36px] md:mt-[60px]"
|
||||||
|
@arrow-click="onArrowClick"
|
||||||
>
|
>
|
||||||
<SplideSlide v-for="(item, index) in slideData" :key="index">
|
<SplideSlide v-for="(item, index) in slideData" :key="index">
|
||||||
<BlocksCardNews
|
<BlocksCardNews
|
||||||
|
|||||||
Reference in New Issue
Block a user