From 1d5c9571b7b511fc502523b3871b7e9fcc32e70a Mon Sep 17 00:00:00 2001 From: clkim Date: Thu, 11 Dec 2025 13:38:25 +0900 Subject: [PATCH] =?UTF-8?q?feat.=20=EC=9D=BC=EB=B0=98=20=ED=85=9C=ED=94=8C?= =?UTF-8?q?=EB=A6=BF=20=EB=A1=9C=EA=B7=B8=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- layers/assets/css/components/_splide.css | 16 +- layers/components/atoms/Button/Play.vue | 19 +- layers/components/blocks/CardNews.vue | 16 +- layers/components/blocks/slide/Arrows.vue | 37 ++ layers/components/layouts/Header.vue | 79 ++-- layers/components/layouts/Main.vue | 3 +- layers/components/widgets/ButtonList.vue | 6 +- layers/components/widgets/VideoPlay.vue | 13 +- .../{blocks => widgets}/slide/CenterFocus.vue | 32 +- .../slide/CenterHighlight.vue | 31 +- .../{blocks => widgets}/slide/Default.vue | 25 +- .../{blocks => widgets}/slide/Fade.vue | 25 +- .../{blocks => widgets}/slide/Thumbnail.vue | 78 ++-- layers/composables/useAnalytics.ts | 376 ++++++++++-------- layers/composables/useSplideArrow.ts | 83 ---- layers/templates/FxCoupon01/index.vue | 8 +- layers/templates/FxDownload01/index.vue | 4 +- layers/templates/FxPreregist01/index.vue | 5 +- layers/templates/FxSecure01/index.vue | 326 +++++++-------- layers/templates/FxVideo01/index.vue | 36 +- layers/templates/GrBoard01/index.vue | 34 +- layers/templates/GrContents01/index.vue | 2 +- layers/templates/GrDetail01/index.vue | 28 +- layers/templates/GrDetail02/index.vue | 10 +- layers/templates/GrDetail03/index.vue | 10 +- layers/templates/GrGallery01/index.vue | 50 +-- layers/templates/GrGallery02/index.vue | 18 +- layers/templates/GrGallery03/index.vue | 19 +- layers/templates/GrVisual01/index.vue | 8 +- layers/templates/GrVisual02/index.vue | 24 +- layers/templates/GrVisual03/index.vue | 22 +- layers/types/AnalyticsType.ts | 8 +- layers/types/api/common.ts | 6 + layers/types/api/gameData.ts | 13 +- layers/types/api/pageData.ts | 14 +- tailwind.config.ts | 1 + 36 files changed, 750 insertions(+), 735 deletions(-) create mode 100644 layers/components/blocks/slide/Arrows.vue rename layers/components/{blocks => widgets}/slide/CenterFocus.vue (87%) rename layers/components/{blocks => widgets}/slide/CenterHighlight.vue (87%) rename layers/components/{blocks => widgets}/slide/Default.vue (79%) rename layers/components/{blocks => widgets}/slide/Fade.vue (76%) rename layers/components/{blocks => widgets}/slide/Thumbnail.vue (80%) delete mode 100644 layers/composables/useSplideArrow.ts diff --git a/layers/assets/css/components/_splide.css b/layers/assets/css/components/_splide.css index dbda97b..f1147fb 100644 --- a/layers/assets/css/components/_splide.css +++ b/layers/assets/css/components/_splide.css @@ -18,27 +18,25 @@ background-color: var(--pagination-active); } - .splide-arrows { + .splide__arrows { @apply hidden md:block; } - .splide-arrow { + .splide__arrows .splide-arrow.btn-circle { @apply absolute top-1/2 w-[40px] h-[40px] bg-cover bg-center bg-no-repeat -translate-y-1/2 cursor-pointer z-[5] - md:w-[48px] md:h-[48px] - after:content-[''] after:absolute after:top-0 after:left-0 after:w-full after:h-full after:rounded-full after:bg-white after:transition-opacity after:duration-300 after:ease-in-out after:opacity-0 - hover:after:opacity-10; + md:w-[48px] md:h-[48px]; } - .arrow-prev { + .splide__arrow--prev { @apply bg-[image:var(--arrow-prev)]; } - .arrow-next { + .splide__arrow--next { @apply bg-[image:var(--arrow-next)]; } - .type-full .arrow-prev { + .type-full .splide__arrow--prev { @apply left-10; } - .type-full .arrow-next { + .type-full .splide__arrow--next { @apply right-10; } diff --git a/layers/components/atoms/Button/Play.vue b/layers/components/atoms/Button/Play.vue index fd9ffdb..65f85ab 100644 --- a/layers/components/atoms/Button/Play.vue +++ b/layers/components/atoms/Button/Play.vue @@ -1,11 +1,22 @@ diff --git a/layers/components/blocks/CardNews.vue b/layers/components/blocks/CardNews.vue index b1f7b40..e663eea 100644 --- a/layers/components/blocks/CardNews.vue +++ b/layers/components/blocks/CardNews.vue @@ -3,6 +3,7 @@ interface Props { title: string description: string | number imgPath: string | null + analyticsSarea: string linkTarget?: '_blank' | '_self' url?: string alt?: string @@ -10,8 +11,9 @@ interface Props { } const props = defineProps() + const { locale } = useI18n() -const { sendLog, useAnalyticsLogDataDirect } = useAnalytics() +const { sendLog, useAnalyticsData } = useAnalytics() const isNoImage = computed(() => { return !props.imgPath || props.imgPath === null @@ -21,14 +23,12 @@ const isShowOverlay = computed(() => { }) const handleLinkClick = (title: string) => { - const trackingData = { - tracking: { - click_item: title, - action_type: 'click', - click_sarea: '', - }, + const analytics = { + click_item: title, + action_type: 'click', + click_sarea: props.analyticsSarea, } - sendLog(locale.value, useAnalyticsLogDataDirect(trackingData, 1)) + sendLog(locale.value, useAnalyticsData(analytics)) } diff --git a/layers/components/blocks/slide/Arrows.vue b/layers/components/blocks/slide/Arrows.vue new file mode 100644 index 0000000..704575a --- /dev/null +++ b/layers/components/blocks/slide/Arrows.vue @@ -0,0 +1,37 @@ + + + diff --git a/layers/components/layouts/Header.vue b/layers/components/layouts/Header.vue index 9bb5291..f7e1a3d 100644 --- a/layers/components/layouts/Header.vue +++ b/layers/components/layouts/Header.vue @@ -9,15 +9,16 @@ import type { } from '#layers/types/api/gameData' const MORE_WIDTH = 72 -const START_WIDTH_MARGIN = 40 +const START_MARGIN = 40 const route = useRoute() -const { tm } = useI18n() +const { locale, tm } = useI18n() const { width } = useWindowSize() const gameDataStore = useGameDataStore() const pageDataStore = usePageDataStore() const scrollStore = useScrollStore() const breakpoints = useResponsiveBreakpoints() +const { sendLog, useAnalyticsData } = useAnalytics() const { gameData } = storeToRefs(gameDataStore) const { pageLayoutType } = storeToRefs(pageDataStore) @@ -95,7 +96,7 @@ const calculateOverflow = () => { } const screenWidth = width.value - const totalNavWidth = navWidth.value + startWidth.value + START_WIDTH_MARGIN + const totalNavWidth = navWidth.value + startWidth.value + START_MARGIN // 해상도가 navWidth + startWidth보다 작은 경우 if (screenWidth < totalNavWidth) { @@ -120,18 +121,6 @@ const calculateOverflow = () => { // 100ms마다 최대 1회 실행 const throttledCalculateOverflow = useThrottleFn(calculateOverflow, 100) -const handleMenuOpen = () => { - isMenuOpen.value = true - scrollStore.controlScrollLock(true) -} - -const handleMenuClose = (isPassing: boolean = false) => { - if (isPassing) return - - isMenuOpen.value = false - scrollStore.controlScrollLock(false) -} - const isNotClickable = (gnbItem: GameDataMenu) => { return gnbItem.click_action_type === 0 } @@ -140,6 +129,32 @@ const has2depthButton = (gnbItem: GameDataMenu) => { return gnbItem.children && Object.keys(gnbItem.children).length > 0 } +const handleMenuOpen = () => { + isMenuOpen.value = true + scrollStore.controlScrollLock(true) +} + +const handleMenuClose = () => { + isMenuOpen.value = false + scrollStore.controlScrollLock(false) +} + +const handleSendLog = (item: string) => { + const analytics = { + action_type: 'click', + click_item: item, + click_sarea: 'GNB', + } + sendLog(locale.value, useAnalyticsData(analytics)) +} + +const handleGnbItemClick = (gnbItem: GameDataMenu) => { + if (isNotClickable(gnbItem)) return + + handleMenuClose() + sendLog(locale.value, useAnalyticsData(gnbItem.tracking_json)) +} + onMounted(() => { overflowCount.value = 0 isMounted.value = true @@ -170,7 +185,11 @@ onMounted(() => { v-if="gnbData" :class="['game-wrap', { 'is-fixed': isPassedStoveGnb }]" > - + {
diff --git a/layers/components/widgets/ButtonList.vue b/layers/components/widgets/ButtonList.vue index 92c7eb5..31d65bc 100644 --- a/layers/components/widgets/ButtonList.vue +++ b/layers/components/widgets/ButtonList.vue @@ -7,7 +7,6 @@ import type { ButtonType } from '#layers/types/components/button' interface Props { resourcesData: PageDataResourceGroup[] - pageVerTmplSeq: number } const props = defineProps() @@ -16,7 +15,7 @@ const { locale } = useI18n() const modalStore = useModalStore() const scrollStore = useScrollStore() const breakpoints = useResponsiveBreakpoints() -const { sendLog, useAnalyticsLogDataDirect } = useAnalytics() +const { sendLog, useAnalyticsData } = useAnalytics() const { tm } = useI18n() const device = useDevice() @@ -92,8 +91,7 @@ const downloadFile = async (url: string = '', osType: number = 0) => { } const handleButtonClick = (button: PageDataResourceGroup) => { - // 로그 - sendLog(locale.value, useAnalyticsLogDataDirect(button, props.pageVerTmplSeq)) + sendLog(locale.value, useAnalyticsData(button.tracking)) const btnDetail = button.btn_info?.detail diff --git a/layers/components/widgets/VideoPlay.vue b/layers/components/widgets/VideoPlay.vue index 6baddc8..c43fbad 100644 --- a/layers/components/widgets/VideoPlay.vue +++ b/layers/components/widgets/VideoPlay.vue @@ -3,27 +3,22 @@ import type { PageDataResourceGroup } from '#layers/types/api/pageData' const props = defineProps<{ resourcesData: PageDataResourceGroup - pageVerTmplSeq: number }>() const modalStore = useModalStore() -const { locale } = useI18n() -const { sendLog, useAnalyticsLogDataDirect } = useAnalytics() // 비디오 플레이 버튼 클릭 핸들러 const handleVideoPlayClick = () => { const youtubeUrl = props.resourcesData?.display?.text ?? '' if (youtubeUrl) { modalStore.handleOpenYoutube({ youtubeUrl }) - - sendLog( - locale.value, - useAnalyticsLogDataDirect(props.resourcesData, props.pageVerTmplSeq) - ) } } diff --git a/layers/components/blocks/slide/CenterFocus.vue b/layers/components/widgets/slide/CenterFocus.vue similarity index 87% rename from layers/components/blocks/slide/CenterFocus.vue rename to layers/components/widgets/slide/CenterFocus.vue index e1382d7..9ffa7a8 100644 --- a/layers/components/blocks/slide/CenterFocus.vue +++ b/layers/components/widgets/slide/CenterFocus.vue @@ -1,8 +1,8 @@