171 lines
5.1 KiB
Vue
171 lines
5.1 KiB
Vue
<script setup lang="ts">
|
|
import type { TrackingObject } from '#layers/types/api/common'
|
|
import type {
|
|
EventNavigationResponse,
|
|
EventNavigation,
|
|
} from '#layers/types/api/eventNavigation'
|
|
|
|
const { locale } = useI18n()
|
|
const { sendLog } = useAnalytics()
|
|
const gameDomain = getGameDomain()
|
|
const breakpoints = useResponsiveBreakpoints()
|
|
|
|
const analytics = {
|
|
action_type: 'click',
|
|
click_sarea: 'EventNavigation',
|
|
}
|
|
|
|
const isEventNavigationOpen = ref(true)
|
|
const eventNavigationList = ref<Record<string, EventNavigation>>({})
|
|
|
|
const getEventNavigation = async (): Promise<Record<
|
|
string,
|
|
EventNavigation
|
|
> | null> => {
|
|
const runtimeConfig = useRuntimeConfig()
|
|
const stoveApiBaseUrl = runtimeConfig.public.stoveApiUrl
|
|
const apiUrl = `${stoveApiBaseUrl}/pub-comm/v1.0/template/eventBanners`
|
|
|
|
const queryParams: Record<string, string> = {
|
|
game_domain: gameDomain,
|
|
lang_code: locale.value,
|
|
_t: Date.now().toString(),
|
|
}
|
|
|
|
const response = (await commonFetch('GET', apiUrl, {
|
|
query: queryParams,
|
|
})) as EventNavigationResponse | null
|
|
if (response?.code === 0 && 'value' in response) {
|
|
return response.value
|
|
}
|
|
|
|
return null
|
|
}
|
|
|
|
const toggleEventNavigation = () => {
|
|
isEventNavigationOpen.value = !isEventNavigationOpen.value
|
|
|
|
const navigationAnalytics = {
|
|
...analytics,
|
|
click_item: isEventNavigationOpen.value ? '열기' : '닫기',
|
|
} as TrackingObject
|
|
sendLog(locale.value, navigationAnalytics)
|
|
}
|
|
|
|
onMounted(async () => {
|
|
eventNavigationList.value = await getEventNavigation()
|
|
if (breakpoints.value.isMobile) {
|
|
isEventNavigationOpen.value = false
|
|
}
|
|
})
|
|
</script>
|
|
|
|
<template>
|
|
<div
|
|
v-if="Object.keys(eventNavigationList).length > 1"
|
|
class="navigation-wrap"
|
|
:class="{
|
|
'is-closed': !isEventNavigationOpen,
|
|
}"
|
|
>
|
|
<div class="navigation-container">
|
|
<AtomsButtonCircle
|
|
sr-only="event navigation control"
|
|
class="btn-control"
|
|
@click="toggleEventNavigation"
|
|
>
|
|
<AtomsIconsArrowRightLine color="#ffffff" />
|
|
</AtomsButtonCircle>
|
|
<ul class="navigation-list">
|
|
<li v-for="item in eventNavigationList" :key="item.banner_seq">
|
|
<AtomsLocaleLink
|
|
:to="item.page_url"
|
|
:target="item.link_type === 2 ? '_blank' : '_self'"
|
|
:rel="item.link_type === 2 ? 'noopener noreferrer' : undefined"
|
|
class="item-link"
|
|
@click="
|
|
sendLog(locale, {
|
|
...analytics,
|
|
click_item: item.banner_title || item.promotion_name,
|
|
})
|
|
"
|
|
>
|
|
<div class="item-thumbnail">
|
|
<img
|
|
v-if="item.thumbnail"
|
|
:src="item.thumbnail"
|
|
:alt="item.banner_title || item.promotion_name"
|
|
class="w-full h-full object-cover"
|
|
/>
|
|
</div>
|
|
<span class="item-title">
|
|
{{ item.banner_title || item.promotion_name }}
|
|
</span>
|
|
</AtomsLocaleLink>
|
|
</li>
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<style scoped>
|
|
.empty-game + main .navigation-wrap {
|
|
@apply mt-[var(--scroll-position,48px)];
|
|
}
|
|
.sns-wrap ~ .navigation-wrap {
|
|
@apply pb-[78px];
|
|
}
|
|
|
|
.navigation-wrap {
|
|
@apply fixed top-0 left-0 bottom-0 mt-[calc(var(--scroll-position,48px)+48px)] md:mt-[calc(var(--scroll-position,64px)+64px)] z-[90] transition-transform duration-300 ease-in-out;
|
|
}
|
|
.navigation-container {
|
|
@apply relative h-full p-3 sm:p-5 sm:pr-3
|
|
md:p-8 md:pt-6 md:pr-4;
|
|
}
|
|
.navigation-list {
|
|
@apply flex flex-col gap-4 w-[180px] h-full overflow-y-scroll rounded-[20px] p-4 pr-1 bg-[rgba(25,25,25,0.5)] shadow-[0_2px_4px_0_rgba(0,0,0,0.06)] backdrop-blur-[25px] transition-opacity duration-300 ease-in-out;
|
|
}
|
|
.item-thumbnail {
|
|
@apply overflow-hidden relative w-[148px] h-[75px] rounded-[10px] bg-[#333333]
|
|
after:content-[''] after:absolute after:top-0 after:left-0 after:w-full after:h-full after:rounded-[10px] after:border-[1px] after:border-white/[0.08] after:transition-all after:duration-300 after:ease-in-out;
|
|
}
|
|
.item-thumbnail img {
|
|
@apply opacity-50 transition-opacity duration-300 ease-in-out;
|
|
}
|
|
.item-title {
|
|
@apply block mt-2 text-center text-[#FFF] text-[14px] font-normal leading-[20px] tracking-[-0.42px] opacity-50 transition-opacity duration-300 ease-in-out;
|
|
}
|
|
.btn-control {
|
|
@apply absolute top-3 right-[-40px] bg-black/20 shadow-[0_1.667px_3.333px_0_rgba(0,0,0,0.06)] backdrop-blur-[12.5px] rotate-180
|
|
sm:top-5 md:top-6 md:right-[-48px];
|
|
}
|
|
.btn-control:hover :deep(.icon) {
|
|
@apply translate-x-[3px];
|
|
}
|
|
|
|
.navigation-wrap.is-closed {
|
|
@apply translate-x-[calc(-100%+20px)] sm:translate-x-[calc(-100%+40px)];
|
|
}
|
|
.navigation-wrap.is-closed .btn-control {
|
|
@apply rotate-0;
|
|
}
|
|
.navigation-wrap.is-closed .navigation-list {
|
|
@apply pointer-events-none opacity-0;
|
|
}
|
|
|
|
.router-link-active .item-thumbnail {
|
|
@apply after:border-[var(--primary)];
|
|
}
|
|
.router-link-active .item-thumbnail img,
|
|
.item-link:hover .item-thumbnail img {
|
|
@apply opacity-100;
|
|
}
|
|
.item-link:hover .item-title {
|
|
@apply opacity-100;
|
|
}
|
|
.router-link-active .item-title {
|
|
@apply text-[var(--primary)] opacity-100;
|
|
}
|
|
</style>
|