Merge branch 'feature/202501107-all' into feature/20251001-gil
This commit is contained in:
@@ -6,9 +6,6 @@ import type {
|
||||
|
||||
const { locale } = useI18n()
|
||||
const gameDomain = useGetGameDomain()
|
||||
const scrollStore = useScrollStore()
|
||||
|
||||
const { isPassedStoveGnb } = storeToRefs(scrollStore)
|
||||
|
||||
const isEventNavigationOpen = ref(true)
|
||||
const eventNavigationList = ref<Record<string, EventNavigation>>({})
|
||||
@@ -52,7 +49,6 @@ onMounted(async () => {
|
||||
class="event-navigation"
|
||||
:class="{
|
||||
'is-closed': !isEventNavigationOpen,
|
||||
'is-fixed': isPassedStoveGnb,
|
||||
}"
|
||||
>
|
||||
<div class="navigation-wrapper">
|
||||
@@ -90,10 +86,7 @@ onMounted(async () => {
|
||||
|
||||
<style scoped>
|
||||
.event-navigation {
|
||||
@apply absolute top-0 left-0 bottom-0 mt-[48px] md:mt-[64px] z-[100] transition-transform duration-300 ease-in-out;
|
||||
}
|
||||
.event-navigation.is-fixed {
|
||||
@apply fixed;
|
||||
@apply fixed top-0 left-0 bottom-0 mt-[calc(var(--scroll-position,48px)+48px)] md:mt-[calc(var(--scroll-position,64px)+64px)] z-[100] transition-transform duration-300 ease-in-out;
|
||||
}
|
||||
.navigation-wrapper {
|
||||
@apply relative h-full p-3 sm:p-5 sm:pr-3
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
<script setup lang="ts">
|
||||
import { onClickOutside, useWindowSize } from '@vueuse/core'
|
||||
import { useGameDataStore } from '#layers/stores/useGameDataStore'
|
||||
import type {
|
||||
GameDataMenu,
|
||||
@@ -9,6 +8,14 @@ import type {
|
||||
PlatformTransformType,
|
||||
} from '#layers/types/api/gameData'
|
||||
|
||||
const MORE_WIDTH = 72
|
||||
const START_WIDTH_MARGIN = 40
|
||||
const PLATFORM_LABEL_KEY: Record<PlatformTransformType, string> = {
|
||||
pc: 'PC',
|
||||
google_play: 'Google Play',
|
||||
app_store: 'App Store',
|
||||
}
|
||||
|
||||
const route = useRoute()
|
||||
const { tm } = useI18n()
|
||||
const { width } = useWindowSize()
|
||||
@@ -21,21 +28,23 @@ const modalStore = useModalStore()
|
||||
const { gameData } = storeToRefs(gameDataStore)
|
||||
const { isPassedStoveGnb } = storeToRefs(scrollStore)
|
||||
|
||||
const navAreaRef = ref<HTMLElement>()
|
||||
const startRef = ref<HTMLElement>()
|
||||
const navAreaRef = ref<HTMLElement | null>(null)
|
||||
const startRef = ref<HTMLElement | null>(null)
|
||||
|
||||
const gnbData = gameData.value?.gnb
|
||||
const { width: startWidth } = useElementSize(startRef)
|
||||
|
||||
const isMounted = ref(false)
|
||||
const isMenuOpen = ref(false)
|
||||
const navWidth = ref(0)
|
||||
const startWidth = ref(0)
|
||||
const officialItemWidths = ref<number[]>([])
|
||||
const overflowNam = ref<number>(0)
|
||||
|
||||
const gnbData = computed(() => gameData.value?.gnb)
|
||||
const gnb1depthButtonData = computed(
|
||||
() => gnbData?.buttons[0]?.button_json as GameDataResourceGroup
|
||||
() => gnbData.value?.buttons[0]?.button_json as GameDataResourceGroup
|
||||
)
|
||||
const gnb2depthButtonData = computed(
|
||||
() => gnbData?.buttons[1]?.button_json as GameDataResourceGroupSet
|
||||
() => gnbData.value?.buttons[1]?.button_json as GameDataResourceGroupSet
|
||||
)
|
||||
const currentPath = computed(() => formatPathWithoutLocale(route.path))
|
||||
const supportedPlatforms = computed(
|
||||
@@ -47,7 +56,7 @@ const supportedPlatforms = computed(
|
||||
|
||||
const pathMatches = (base: string, current: string) => {
|
||||
if (!base || base === '/') return current === '/'
|
||||
return current === base || current.startsWith(base + '/')
|
||||
return current === base
|
||||
}
|
||||
|
||||
/** 자식 중 활성 링크 존재 여부 */
|
||||
@@ -76,20 +85,10 @@ const isNavItemActive = (gnbItem: GameDataMenu): boolean => {
|
||||
|
||||
// navAreaRef의 넓이를 구하는 함수
|
||||
const calculateNavWidth = () => {
|
||||
if (!navAreaRef.value || !gnbData) return 0
|
||||
if (!navAreaRef.value || !gnbData.value) return 0
|
||||
|
||||
const navAreaWidth = navAreaRef.value.offsetWidth
|
||||
const moreWidth = 72 // 더보기 버튼 넓이 + 마진
|
||||
return navAreaWidth + moreWidth
|
||||
}
|
||||
|
||||
// startRef의 넓이를 구하는 함수
|
||||
const calculateStartWidth = () => {
|
||||
if (!startRef.value || !gnbData) return 0
|
||||
|
||||
const startWidth = startRef.value.offsetWidth
|
||||
const headerRightPadding = 40 // 헤더 오른쪽 마진
|
||||
return startWidth + headerRightPadding
|
||||
navWidth.value = navAreaWidth + MORE_WIDTH
|
||||
}
|
||||
|
||||
// official 자식들의 넓이를 구하는 함수
|
||||
@@ -108,24 +107,20 @@ const calculateOfficialItemWidths = () => {
|
||||
}
|
||||
|
||||
officialItemWidths.value = widths
|
||||
|
||||
// 해상도 체크 및 오버플로우 계산
|
||||
calculateOverflow()
|
||||
}
|
||||
|
||||
// 오버플로우 계산 함수
|
||||
const calculateOverflow = () => {
|
||||
if (!navAreaRef.value || !startRef.value) return
|
||||
|
||||
const totalNavWidth = navWidth.value + startWidth.value
|
||||
const screenWidth = width.value
|
||||
|
||||
// 모바일(1024px 미만)에서는 overflowNam을 0으로 설정
|
||||
if (screenWidth < 1024) {
|
||||
if (breakpoints.value.isMobile) {
|
||||
overflowNam.value = 0
|
||||
return
|
||||
}
|
||||
|
||||
const screenWidth = width.value
|
||||
const totalNavWidth = navWidth.value + startWidth.value + START_WIDTH_MARGIN
|
||||
|
||||
// 해상도가 navWidth + startWidth보다 작은 경우
|
||||
if (screenWidth < totalNavWidth) {
|
||||
let removedCount = 0
|
||||
@@ -166,12 +161,6 @@ const has2depthButton = (gnbItem: GameDataMenu) => {
|
||||
|
||||
const highlight = (text: string) => `<span class="highlight">${text}</span>`
|
||||
|
||||
const PLATFORM_LABEL_KEY: Record<PlatformTransformType, string> = {
|
||||
pc: 'PC',
|
||||
google_play: 'Google Play',
|
||||
app_store: 'App Store',
|
||||
}
|
||||
|
||||
const tmWithGameName = (key: string): string => {
|
||||
const raw = tm(key)
|
||||
if (typeof raw !== 'string') return ''
|
||||
@@ -215,7 +204,10 @@ const handleStartClick = () => {
|
||||
window.open(url, '_blank')
|
||||
}
|
||||
|
||||
const stopClickOutside = onClickOutside(navAreaRef, () => handleMenuClose())
|
||||
watchEffect(() => {
|
||||
if (!startWidth.value) return // 0, null, undefined면 스킵
|
||||
calculateOverflow()
|
||||
})
|
||||
|
||||
// 화면 크기 변경 시 오버플로우 재계산
|
||||
watch(width, () => {
|
||||
@@ -224,51 +216,47 @@ watch(width, () => {
|
||||
|
||||
onMounted(() => {
|
||||
overflowNam.value = 0
|
||||
isMounted.value = true
|
||||
|
||||
// 초기 계산 시도
|
||||
nextTick(() => {
|
||||
if (navAreaRef.value && startRef.value) {
|
||||
navWidth.value = calculateNavWidth()
|
||||
startWidth.value = calculateStartWidth()
|
||||
calculateOfficialItemWidths()
|
||||
}
|
||||
calculateNavWidth()
|
||||
calculateOfficialItemWidths()
|
||||
calculateOverflow()
|
||||
})
|
||||
})
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
if (stopClickOutside) {
|
||||
stopClickOutside()
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<header class="header">
|
||||
<BlocksStoveGnbNew class="h-[48px]" />
|
||||
<div :class="['game-wrap', { 'is-fixed': isPassedStoveGnb }]">
|
||||
<NuxtLinkLocale to="/brand" class="mx-auto md:hidden router-link-active router-link-exact-active">
|
||||
<AtomsLocaleLink to="/" class="mx-auto md:hidden">
|
||||
<img
|
||||
:src="getImageHost(gnbData?.bi_path)"
|
||||
:alt="gameData?.game_name"
|
||||
class="h-[30px]"
|
||||
/>
|
||||
</NuxtLinkLocale>
|
||||
</atomslocalelink>
|
||||
<button class="btn-open" @click="handleMenuOpen">
|
||||
<AtomsIconsMenuBoldLine class="mx-auto" />
|
||||
<span class="sr-only">menu open</span>
|
||||
</button>
|
||||
<div :class="['nav-wrap', { 'is-open': isMenuOpen }]">
|
||||
<div ref="navAreaRef" class="nav-area">
|
||||
<div
|
||||
:class="['nav-wrap', { 'is-open': isMenuOpen }]"
|
||||
@click="handleMenuClose"
|
||||
>
|
||||
<div ref="navAreaRef" class="nav-area" @click.stop>
|
||||
<div class="nav-logo">
|
||||
<NuxtLinkLocale to="/brand" class="router-link-active router-link-exact-active" @click="handleMenuClose">
|
||||
<AtomsLocaleLink to="/" @click="handleMenuClose">
|
||||
<img
|
||||
:src="getImageHost(gnbData?.bi_path)"
|
||||
:alt="gameData?.game_name"
|
||||
class="h-[30px]"
|
||||
/>
|
||||
</NuxtLinkLocale>
|
||||
</div>
|
||||
<nav class="nav-list">
|
||||
<div v-if="gnbData?.menus" class="official">
|
||||
</AtomsLocaleLink>
|
||||
<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"
|
||||
@@ -376,45 +364,48 @@ onBeforeUnmount(() => {
|
||||
class="nav-1depth text-gradient-pink"
|
||||
>
|
||||
<AtomsIconsStarFill />
|
||||
<span>이벤트</span>
|
||||
<span>{{ tm('Gnb_Event') }}</span>
|
||||
<AtomsIconsStarFill />
|
||||
</AtomsLocaleLink>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
<div ref="startRef" class="btn-start">
|
||||
<ClientOnly>
|
||||
<component
|
||||
:is="
|
||||
breakpoints.isDesktop ? 'BlocksButtonLauncher' : 'AtomsButton'
|
||||
"
|
||||
type="custom"
|
||||
platform="pc"
|
||||
:background-color="
|
||||
getColorCodeFromData(gnb1depthButtonData?.btn_info, 'btn')
|
||||
"
|
||||
:text-color="
|
||||
getColorCodeFromData(gnb1depthButtonData?.btn_info, 'txt')
|
||||
"
|
||||
@click="handleStartClick"
|
||||
>
|
||||
{{ gnb1depthButtonData?.btn_info?.txt_btn_name }}
|
||||
</component>
|
||||
|
||||
<div
|
||||
v-if="breakpoints.isDesktop && gnb2depthButtonData"
|
||||
class="nav-2depth"
|
||||
>
|
||||
<ul>
|
||||
<li v-for="(item, key) in gnb2depthButtonData" :key="key">
|
||||
<BlocksButtonLauncher type="custom" :platform="key">
|
||||
{{ item.btn_info?.txt_btn_name }}
|
||||
</BlocksButtonLauncher>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</ClientOnly>
|
||||
</div>
|
||||
<ClientOnly>
|
||||
<div ref="startRef" class="btn-start">
|
||||
<template v-if="gnb1depthButtonData">
|
||||
<component
|
||||
:is="
|
||||
breakpoints.isDesktop
|
||||
? 'BlocksButtonLauncher'
|
||||
: 'AtomsButton'
|
||||
"
|
||||
type="custom"
|
||||
platform="pc"
|
||||
:background-color="
|
||||
getColorCodeFromData(gnb1depthButtonData?.btn_info, 'btn')
|
||||
"
|
||||
:text-color="
|
||||
getColorCodeFromData(gnb1depthButtonData?.btn_info, 'txt')
|
||||
"
|
||||
@click="handleStartClick"
|
||||
>
|
||||
{{ gnb1depthButtonData?.btn_info?.txt_btn_name }}
|
||||
</component>
|
||||
<div
|
||||
v-if="breakpoints.isDesktop && gnb2depthButtonData"
|
||||
class="nav-2depth"
|
||||
>
|
||||
<ul>
|
||||
<li v-for="(item, key) in gnb2depthButtonData" :key="key">
|
||||
<BlocksButtonLauncher type="custom" :platform="key">
|
||||
{{ item.btn_info?.txt_btn_name }}
|
||||
</BlocksButtonLauncher>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</ClientOnly>
|
||||
<button class="btn-close" @click="handleMenuClose">
|
||||
<AtomsIconsCloseLine
|
||||
size="24"
|
||||
@@ -426,12 +417,12 @@ onBeforeUnmount(() => {
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
</div></header>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.header {
|
||||
@apply bg-theme-foreground text-theme-foreground-reversal relative z-[200];
|
||||
@apply bg-theme-foreground text-theme-foreground-reversal relative font-[500] tracking-[-0.48px] z-[200];
|
||||
}
|
||||
.game-wrap {
|
||||
@apply absolute flex w-full h-[48px] items-center whitespace-nowrap px-[52px] bg-theme-foreground sm:px-[72px] md:h-16 md:pl-0 md:pr-[40px]
|
||||
@@ -471,7 +462,7 @@ onBeforeUnmount(() => {
|
||||
|
||||
.nav-area {
|
||||
@apply flex flex-col w-[100vw] max-w-[360px] min-w-[320px] bg-theme-foreground-10 translate-x-[-100%]
|
||||
md:inline-flex md:flex-row md:w-auto md:max-w-none md:h-full md:pl-[40px] md:items-center md:bg-transparent md:transform-none;
|
||||
md:inline-flex md:flex-row md:w-auto md:max-w-[100%] md:h-full md:pl-[40px] md:items-center md:bg-transparent md:transform-none;
|
||||
}
|
||||
|
||||
.nav-logo {
|
||||
@@ -480,7 +471,10 @@ onBeforeUnmount(() => {
|
||||
|
||||
.nav-list {
|
||||
@apply overflow-hidden flex flex-col order-1 h-full mt-2 mb-4 px-2
|
||||
md:flex-row md:order-none md:h-full md:my-0 md:ml-10 md:mr-6 md:px-0 md:overflow-visible;
|
||||
md:flex-row md:order-none md:h-full md:my-0 md:ml-10 md:mr-6 md:px-0;
|
||||
}
|
||||
.nav-list.is-mounted {
|
||||
@apply md:overflow-visible;
|
||||
}
|
||||
|
||||
.nav-item {
|
||||
@@ -528,6 +522,12 @@ onBeforeUnmount(() => {
|
||||
.official {
|
||||
@apply overflow-x-hidden overflow-y-auto pb-2 md:flex md:items-center md:space-x-8 md:pb-0 md:overflow-visible;
|
||||
}
|
||||
.custom-theme-scrollbar::-webkit-scrollbar {
|
||||
@apply w-1;
|
||||
}
|
||||
.custom-theme-scrollbar::-webkit-scrollbar-thumb {
|
||||
@apply border-0;
|
||||
}
|
||||
|
||||
.more {
|
||||
@apply relative hidden ml-[32px] pt-[11px] md:block;
|
||||
|
||||
Reference in New Issue
Block a user