fix. gnb더보기 정상동작 하지않는 이슈 수정

This commit is contained in:
clkim
2025-11-14 15:30:55 +09:00
parent 75921a93df
commit a9d34f0a38
2 changed files with 89 additions and 88 deletions

View File

@@ -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,9 @@ import type {
PlatformTransformType,
} from '#layers/types/api/gameData'
const MORE_WIDTH = 72
const START_WIDTH_MARGIN = 40
const route = useRoute()
const { tm } = useI18n()
const { width } = useWindowSize()
@@ -21,21 +23,22 @@ 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 isMenuOpen = ref(false)
const navWidth = ref(0)
const startWidth = ref(0)
const officialItemWidths = ref<number[]>([])
const overflowNam = ref<number>(0)
// const { width: navWidth } = useElementSize(navAreaRef)
const { width: startWidth } = useElementSize(startRef)
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(
@@ -72,20 +75,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 자식들의 넓이를 구하는 함수
@@ -104,24 +97,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
@@ -211,7 +200,10 @@ const handleStartClick = () => {
window.open(url, '_blank')
}
const stopClickOutside = onClickOutside(navAreaRef, () => handleMenuClose())
watchEffect(() => {
if (!startWidth.value) return // 0, null, undefined면 스킵
calculateOverflow()
})
// 화면 크기 변경 시 오버플로우 재계산
watch(width, () => {
@@ -221,20 +213,13 @@ watch(width, () => {
onMounted(() => {
overflowNam.value = 0
// 초기 계산 시도
nextTick(() => {
if (navAreaRef.value && startRef.value) {
navWidth.value = calculateNavWidth()
startWidth.value = calculateStartWidth()
calculateOfficialItemWidths()
}
calculateNavWidth()
calculateOfficialItemWidths()
calculateOverflow()
})
})
onBeforeUnmount(() => {
if (stopClickOutside) {
stopClickOutside()
}
})
</script>
<template>
@@ -252,8 +237,11 @@ onBeforeUnmount(() => {
<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">
<AtomsLocaleLink to="/brand" @click="handleMenuClose">
<img
@@ -378,39 +366,42 @@ onBeforeUnmount(() => {
</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"

View File

@@ -67,7 +67,11 @@ const cache = new LRUCache({
* @param finalLocale - 최종 언어
* @param baseDomain - 기본 도메인
*/
function setFinalLocaleCookie(event: any, finalLocale: string, baseDomain: string) {
function setFinalLocaleCookie(
event: any,
finalLocale: string,
baseDomain: string
) {
setCookie(event, 'LOCALE', finalLocale.toLowerCase(), {
domain: baseDomain,
path: '/',
@@ -95,7 +99,6 @@ function fnLocaleMiddleware(event: any, finalLocale: string) {
// 쿼리스트링 포함 시 순수 경로만 추출
arrPath = path.split('?')[0].split('/')
queryString = path.split('?')[1]
} else {
arrPath = path.split('/')
queryString = ''
@@ -134,7 +137,7 @@ export default defineEventHandler(async event => {
if (event.node.res.headersSent || event.node.res.writableEnded) {
return
}
// const runType = `${config.public.runType}`
// console.log("🚀 ~ baseDomain:", config.public.baseDomain)
// const url = getRequestURL(event)
@@ -235,9 +238,14 @@ export default defineEventHandler(async event => {
if (event.node.res.headersSent || event.node.res.writableEnded) {
return
}
// 2. 언어 코드 추출
finalLocale = ssrGetFinalLocale(event?.node.req.url, event.node.req.headers, initLangCodes, initDefaultLocale)
// 2. 언어 코드 추출
finalLocale = ssrGetFinalLocale(
event?.node.req.url,
event.node.req.headers,
initLangCodes,
initDefaultLocale
)
const path = event?.node.req.url || ''
let queryStringF = ''
@@ -255,17 +263,17 @@ export default defineEventHandler(async event => {
console.error('쿼리스트링 파싱 에러:', e)
}
}
// 테스트용 500 에러 발생
if (test500) {
throw new Error('테스트용 500 에러 발생')
}
// 미리보기 API 호출 처리
if (fValue === 'preview') {
cleanHost = 'samplegame.onstove.com'
}
const queryParams: Record<string, string> = {
game_domain: cleanHost || '',
lang_code: finalLocale,
@@ -283,7 +291,7 @@ export default defineEventHandler(async event => {
event.context.gameData = response.value
event.context.googleAnalyticsId = response.value?.ga_code
// console.log('🚀 ~ gameData:', response.value)
console.log('🚀 ~ gameData:', response.value)
// 점검 데이터 조회
let inspectionData
@@ -305,7 +313,6 @@ export default defineEventHandler(async event => {
)
inspectionData = inspectionResponse?.value?.inspection
cache.set(cacheKey, inspectionData) // 캐시에 저장
// console.log("🚀 ~ inspectionData:", inspectionData)
}
}
@@ -346,7 +353,10 @@ export default defineEventHandler(async event => {
// 허용된 IP 목록 확인
if (!inspectionData?.ip_filter_list?.includes(clientIP)) {
// 허용되지 않은 IP인 경우 점검 페이지로 이동
if (!event.node.res.headersSent && !event.node.res.writableEnded) {
if (
!event.node.res.headersSent &&
!event.node.res.writableEnded
) {
event.node.res.statusCode = 302
event.node.res.setHeader('Location', inspectionPath)
event.node.res.end()
@@ -412,7 +422,7 @@ export default defineEventHandler(async event => {
}
} catch (error) {
console.error('gameData load error:', error)
// 500 에러 발생 시 /error 페이지로 리다이렉트
if (!event.node.res.headersSent && !event.node.res.writableEnded) {
// 언어 코드 추출 시도
@@ -429,7 +439,7 @@ export default defineEventHandler(async event => {
}
// finalLocale이 undefined인 경우 기본값으로 'ko' 설정
console.log("🚀 ~ 여기도 타? error:", error)
console.log('🚀 ~ 여기도 타? error:', error)
throw createError({
statusCode: error.statusCode,
statusMessage: error.statusMessage,