Merge branch 'feature/202501107-all' into feature/20251201-gil_qa

This commit is contained in:
“hyeonggkim”
2025-12-03 21:02:53 +09:00
28 changed files with 467 additions and 346 deletions

View File

@@ -57,7 +57,7 @@ onMounted(async () => {
class="btn-control"
@click="toggleEventNavigation"
>
<AtomsIconsArrowRightLine size="24" color="#ffffff" />
<AtomsIconsArrowRightLine color="#ffffff" />
</AtomsButtonCircle>
<ul class="navigation-list">
<li v-for="item in eventNavigationList" :key="item.banner_seq">

View File

@@ -1,4 +1,5 @@
<script setup lang="ts">
import { useThrottleFn } from '@vueuse/core'
import { useGameDataStore } from '#layers/stores/useGameDataStore'
import type {
GameDataMenu,
@@ -40,6 +41,13 @@ const officialItemWidths = ref<number[]>([])
const overflowNam = ref<number>(0)
const gnbData = computed(() => gameData.value?.gnb)
const hasGnbMenus = computed(() => {
const menus = gnbData.value?.menus
if (!menus) return false
if (typeof menus !== 'object') return false
return Object.keys(menus).length > 0
})
const gnb1depthButtonData = computed(
() => gnbData.value?.buttons[0]?.button_json as GameDataResourceGroup
)
@@ -81,6 +89,7 @@ const isNavItemActive = (gnbItem: GameDataMenu): boolean => {
// navAreaRef의 넓이를 구하는 함수
const calculateNavWidth = () => {
if (!import.meta.client) return
if (!navAreaRef.value || !gnbData.value) return 0
const navAreaWidth = navAreaRef.value.offsetWidth
@@ -89,6 +98,7 @@ const calculateNavWidth = () => {
// official 자식들의 넓이를 구하는 함수
const calculateOfficialItemWidths = () => {
if (!import.meta.client) return
if (!navAreaRef.value) return
const officialItems = navAreaRef.value.querySelectorAll('.official .nav-item')
@@ -107,6 +117,7 @@ const calculateOfficialItemWidths = () => {
// 오버플로우 계산 함수
const calculateOverflow = () => {
if (!import.meta.client) return
if (!navAreaRef.value || !startRef.value) return
if (breakpoints.value.isMobile) {
@@ -137,6 +148,11 @@ const calculateOverflow = () => {
}
}
// 100ms마다 최대 1회 실행
const throttledCalculateOverflow = useThrottleFn(() => {
calculateOverflow()
}, 100)
const handleMenuOpen = () => {
isMenuOpen.value = true
scrollStore.controlScrollLock(true)
@@ -200,26 +216,26 @@ const handleStartClick = () => {
window.open(url, '_blank')
}
watchEffect(() => {
if (!startWidth.value) return // 0, null, undefined면 스킵
calculateOverflow()
})
// 화면 크기 변경 시 오버플로우 재계산
watch(width, () => {
calculateOverflow()
})
onMounted(() => {
overflowNam.value = 0
isMounted.value = true
// 초기 계산 시도
// 초기 계산
nextTick(() => {
calculateNavWidth()
calculateOfficialItemWidths()
calculateOverflow()
})
watchEffect(() => {
if (!startWidth.value) return
throttledCalculateOverflow()
})
// 화면 크기 변경 시 오버플로우 재계산
watch(width, () => {
throttledCalculateOverflow()
})
})
</script>
@@ -256,89 +272,45 @@ onMounted(() => {
</AtomsLocaleLink>
</div>
<nav :class="['nav-list', { 'is-mounted': isMounted }]">
<div v-if="gnbData?.menus" class="official custom-theme-scrollbar">
<div
v-for="(gnbItem, key) in gnbData?.menus"
:key="key"
class="nav-item"
:class="{
'is-hidden':
overflowNam > 0 &&
Number(key) >=
Object.keys(gnbData?.menus).length - overflowNam,
}"
>
<AtomsLocaleLink
:to="isNotClickable(gnbItem) ? '#' : gnbItem.url_path"
:target="gnbItem.link_target"
:class="[
'nav-1depth',
{ 'has-link': !isNotClickable(gnbItem) },
{ active: isNavItemActive(gnbItem) },
]"
@click="handleMenuClose"
>
<span>{{ gnbItem.menu_name }}</span>
<AtomsIconsWebLinkLine
v-if="gnbItem.link_target === '_blank'"
/>
<AtomsIconsArrowDownFill
v-if="has2depthButton(gnbItem)"
class="hidden md:block"
/>
<AtomsIconsArrowRightLine
v-if="!has2depthButton(gnbItem)"
class="ml-auto md:hidden"
/>
</AtomsLocaleLink>
<Transition name="fade">
<div v-if="has2depthButton(gnbItem)" class="nav-2depth">
<ul>
<li
v-for="child in gnbItem.children"
:key="child.menu_name"
>
<AtomsLocaleLink
:to="child.url_path"
:target="child.link_target"
@click="handleMenuClose"
>
<span>{{ child.menu_name }}</span>
<AtomsIconsWebLinkLine
v-if="child.link_target === '_blank'"
/>
</AtomsLocaleLink>
</li>
</ul>
</div>
</Transition>
</div>
</div>
<div v-if="gnbData?.menus && overflowNam > 0" class="more">
<button class="btn-more">
<AtomsIconsOptionHorizontalFill class="mx-auto" />
<span class="sr-only">more</span>
</button>
<div class="more-list">
<div class="list-inner">
<div
v-for="(gnbItem, key) in gnbData?.menus"
:key="key"
:class="{
hidden:
Number(key) <
<template v-if="hasGnbMenus">
<div class="official custom-theme-scrollbar">
<div
v-for="(gnbItem, key) in gnbData?.menus"
:key="key"
class="nav-item"
:class="{
'is-hidden':
isMounted &&
overflowNam > 0 &&
Number(key) >=
Object.keys(gnbData?.menus).length - overflowNam,
}"
}"
>
<AtomsLocaleLink
:to="isNotClickable(gnbItem) ? '#' : gnbItem.url_path"
:target="gnbItem.link_target"
:class="[
'nav-1depth',
{ 'has-link': !isNotClickable(gnbItem) },
{ active: isNavItemActive(gnbItem) },
]"
@click="handleMenuClose"
>
<AtomsLocaleLink
:to="gnbItem.url_path"
:target="gnbItem.link_target"
:class="`${isNavItemActive(gnbItem) ? 'active' : ''}`"
@click="handleMenuClose"
>
<span>{{ gnbItem.menu_name }}</span>
</AtomsLocaleLink>
<div v-if="gnbItem.children">
<span>{{ gnbItem.menu_name }}</span>
<AtomsIconsWebLinkLine
v-if="gnbItem.link_target === '_blank'"
/>
<AtomsIconsArrowDownFill
v-if="has2depthButton(gnbItem)"
class="hidden md:block"
/>
<AtomsIconsArrowRightLine
v-if="!has2depthButton(gnbItem)"
class="ml-auto md:hidden"
/>
</AtomsLocaleLink>
<Transition name="fade">
<div v-if="has2depthButton(gnbItem)" class="nav-2depth">
<ul>
<li
v-for="child in gnbItem.children"
@@ -347,6 +319,7 @@ onMounted(() => {
<AtomsLocaleLink
:to="child.url_path"
:target="child.link_target"
@click="handleMenuClose"
>
<span>{{ child.menu_name }}</span>
<AtomsIconsWebLinkLine
@@ -356,16 +329,62 @@ onMounted(() => {
</li>
</ul>
</div>
</Transition>
</div>
</div>
<div v-if="isMounted && overflowNam > 0" class="more">
<button class="btn-more">
<AtomsIconsOptionHorizontalFill class="mx-auto" />
<span class="sr-only">more</span>
</button>
<div class="more-list">
<div class="list-inner">
<div
v-for="(gnbItem, key) in gnbData?.menus"
:key="key"
:class="{
hidden:
Number(key) <
Object.keys(gnbData?.menus).length - overflowNam,
}"
>
<AtomsLocaleLink
:to="gnbItem.url_path"
:target="gnbItem.link_target"
:class="`${isNavItemActive(gnbItem) ? 'active' : ''}`"
@click="handleMenuClose"
>
<span>{{ gnbItem.menu_name }}</span>
</AtomsLocaleLink>
<div v-if="gnbItem.children">
<ul>
<li
v-for="child in gnbItem.children"
:key="child.menu_name"
>
<AtomsLocaleLink
:to="child.url_path"
:target="child.link_target"
>
<span>{{ child.menu_name }}</span>
<AtomsIconsWebLinkLine
v-if="child.link_target === '_blank'"
/>
</AtomsLocaleLink>
</li>
</ul>
</div>
</div>
</div>
</div>
</div>
</div>
</template>
<div v-if="gameData?.event_banner" class="event">
<div class="nav-item">
<AtomsLocaleLink
:to="gameData.event_banner?.page_url"
:to="gameData?.event_banner?.page_url"
:target="
gameData.event_banner?.link_type === 1 ? '_self' : '_blank'
gameData?.event_banner?.link_type === 1 ? '_self' : '_blank'
"
class="nav-1depth text-gradient-pink"
@click="handleMenuClose"
@@ -560,11 +579,14 @@ onMounted(() => {
@apply px-6;
}
.event {
@apply relative pr-1 md:ml-[64px] md:pr-0
.official ~ .event {
@apply md:ml-[64px]
before:content-[''] before:block before:h-px before:mb-2 before:mx-3 before:bg-theme-foreground-reversal-8 md:before:hidden
after:content-[''] after:absolute md:after:top-[50%] md:after:left-[-32px] md:after:w-[1px] md:after:h-[16px] md:after:bg-theme-foreground-gray-750 md:after:translate-y-[-50%];
}
.event {
@apply relative pr-1 md:pr-0;
}
.is-hidden {
@apply hidden;