fix: 게임 시작 버튼에 OS 및 지원 플랫폼 검사 로직 추가 (미지원 시 얼럿 표시)
This commit is contained in:
@@ -19,4 +19,8 @@
|
||||
.content-text {
|
||||
@apply text-center text-[15px] text-[#333333] leading-6 tracking-[-0.45px];
|
||||
}
|
||||
|
||||
.content-text .highlight {
|
||||
@apply text-[#FC4420];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -45,6 +45,6 @@ const componentProps = computed(() => {
|
||||
w-[40px] h-[40px] md:w-[48px] md:h-[48px]
|
||||
before:content-[''] before:absolute before:top-0 before:left-0 before:w-full before:h-full before:border before:border-[rgba(255,255,255,0.06)] before:rounded-full
|
||||
after:content-[''] after:absolute after:top-0 after:left-0 after:w-full after:h-full after:bg-white after:rounded-full after:opacity-0 after:transition-all after:duration-300 after:ease-in-out
|
||||
hover:after:opacity-10;
|
||||
hover:after:opacity-10;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -6,12 +6,17 @@ import type {
|
||||
GameDataMenuChildren,
|
||||
GameDataResourceGroup,
|
||||
GameDataResourceGroupSet,
|
||||
PlatformTransformType,
|
||||
} from '#layers/types/api/gameData'
|
||||
|
||||
const route = useRoute()
|
||||
const { tm } = useI18n()
|
||||
const { width } = useWindowSize()
|
||||
const device = useDevice()
|
||||
const gameDataStore = useGameDataStore()
|
||||
const scrollStore = useScrollStore()
|
||||
const breakpoints = useResponsiveBreakpoints()
|
||||
const modalStore = useModalStore()
|
||||
|
||||
const { gameData } = storeToRefs(gameDataStore)
|
||||
const { isPassedStoveGnb } = storeToRefs(scrollStore)
|
||||
@@ -33,6 +38,12 @@ const gnb2depthButtonData = computed(
|
||||
() => gnbData?.buttons[1]?.button_json as GameDataResourceGroupSet
|
||||
)
|
||||
const currentPath = computed(() => formatPathWithoutLocale(route.path))
|
||||
const supportedPlatforms = computed(
|
||||
() =>
|
||||
getSupportedPlatforms(gameData.value?.os_type, {
|
||||
platformType: gameData.value?.platform_type,
|
||||
}) as PlatformTransformType[]
|
||||
)
|
||||
|
||||
const pathMatches = (base: string, current: string) => {
|
||||
if (!base || base === '/') return current === '/'
|
||||
@@ -151,6 +162,57 @@ const has2depthButton = (gnbItem: GameDataMenu) => {
|
||||
return gnbItem.children && Object.keys(gnbItem.children).length > 0
|
||||
}
|
||||
|
||||
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 ''
|
||||
|
||||
const withName = raw.replace(
|
||||
/%게임명%/g,
|
||||
highlight(gameData.value?.game_name || '')
|
||||
)
|
||||
|
||||
const platformLines = supportedPlatforms.value
|
||||
.map(platform => highlight(PLATFORM_LABEL_KEY[platform] as string))
|
||||
.filter(Boolean)
|
||||
|
||||
return platformLines.length
|
||||
? `${withName}<br><br>${platformLines.join('<br>')}`
|
||||
: withName
|
||||
}
|
||||
|
||||
const showNotSupportedOSAlert = () => {
|
||||
return modalStore.handleOpenAlert({
|
||||
contentText: tmWithGameName('Alert_Not_SupportedOS'),
|
||||
})
|
||||
}
|
||||
|
||||
const handleStartClick = () => {
|
||||
if (breakpoints.value.isDesktop) return
|
||||
|
||||
const target = device.isAndroid
|
||||
? 'google_play'
|
||||
: device.isApple
|
||||
? 'app_store'
|
||||
: null
|
||||
|
||||
if (!target || !supportedPlatforms.value.includes(target)) {
|
||||
return showNotSupportedOSAlert()
|
||||
}
|
||||
|
||||
const url = gameData.value?.market_json?.[target]?.url || ''
|
||||
if (!url) return showNotSupportedOSAlert()
|
||||
|
||||
window.open(url, '_blank')
|
||||
}
|
||||
|
||||
const stopClickOutside = onClickOutside(navAreaRef, () => handleMenuClose())
|
||||
|
||||
// 화면 크기 변경 시 오버플로우 재계산
|
||||
@@ -319,33 +381,37 @@ onBeforeUnmount(() => {
|
||||
</div>
|
||||
</nav>
|
||||
<div ref="startRef" class="btn-start">
|
||||
<BlocksButtonLauncher
|
||||
type="custom"
|
||||
platform="pc"
|
||||
:background-color="
|
||||
getColorCode({
|
||||
colorName: gnb1depthButtonData?.btn_info?.color_name_btn,
|
||||
colorCode: gnb1depthButtonData?.btn_info?.color_code_btn,
|
||||
})
|
||||
"
|
||||
:text-color="
|
||||
getColorCode({
|
||||
colorName: gnb1depthButtonData?.btn_info?.color_name_txt,
|
||||
colorCode: gnb1depthButtonData?.btn_info?.color_code_txt,
|
||||
})
|
||||
"
|
||||
>
|
||||
{{ gnb1depthButtonData?.btn_info?.txt_btn_name }}
|
||||
</BlocksButtonLauncher>
|
||||
<div v-if="gnb2depthButtonData" class="nav-2depth hidden md:block">
|
||||
<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>
|
||||
<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>
|
||||
<button class="btn-close" @click="handleMenuClose">
|
||||
<AtomsIconsCloseLine
|
||||
|
||||
@@ -24,18 +24,6 @@ const getBtnType = (item?: PageDataResourceGroupBtnInfo): ButtonType => {
|
||||
return 'action'
|
||||
}
|
||||
|
||||
const getBgColor = (item?: PageDataResourceGroupBtnInfo): string =>
|
||||
getColorCode({
|
||||
colorName: item?.color_name_btn,
|
||||
colorCode: item?.color_code_btn,
|
||||
})
|
||||
|
||||
const getTextColor = (item?: PageDataResourceGroupBtnInfo): string =>
|
||||
getColorCode({
|
||||
colorName: item?.color_name_txt,
|
||||
colorCode: item?.color_code_txt,
|
||||
})
|
||||
|
||||
const handleLogClick = (button: PageDataResourceGroup) => {
|
||||
sendLog(locale.value, useAnalyticsLogDataDirect(button, props.pageVerTmplSeq))
|
||||
if (button.btn_info?.detail?.btn_type === 'POP') {
|
||||
@@ -62,8 +50,8 @@ const buttonList = computed(() => props.resourcesData || [])
|
||||
v-if="button.btn_info?.detail?.btn_type === 'RUN'"
|
||||
type="duplication"
|
||||
:platform="button.btn_info?.detail?.market_type"
|
||||
:background-color="getBgColor(button.btn_info)"
|
||||
:text-color="getTextColor(button.btn_info)"
|
||||
:background-color="getColorCodeFromData(button.btn_info, 'btn')"
|
||||
:text-color="getColorCodeFromData(button.btn_info, 'txt')"
|
||||
:disabled="button?.btn_info?.disabled"
|
||||
@click="handleLogClick(button)"
|
||||
>
|
||||
@@ -75,8 +63,8 @@ const buttonList = computed(() => props.resourcesData || [])
|
||||
:href="button.btn_info?.detail?.action?.url"
|
||||
:target="button.btn_info?.detail?.action?.link_target"
|
||||
:rel="button.btn_info?.detail?.action?.rel"
|
||||
:background-color="getBgColor(button.btn_info)"
|
||||
:text-color="getTextColor(button.btn_info)"
|
||||
:background-color="getColorCodeFromData(button.btn_info, 'btn')"
|
||||
:text-color="getColorCodeFromData(button.btn_info, 'txt')"
|
||||
:disabled="button?.btn_info?.disabled"
|
||||
@click="handleLogClick(button)"
|
||||
>
|
||||
|
||||
@@ -33,11 +33,6 @@ const { pageData } = storeToRefs(usePageDataStore())
|
||||
|
||||
// Constants
|
||||
const COLOR_INDEX = { BACKGROUND: 0, TEXT: 1 } as const
|
||||
const OS_TYPE_MAP: Record<string, Platform[]> = {
|
||||
'1': ['google_play'],
|
||||
'2': ['app_store'],
|
||||
'3': ['google_play', 'app_store'],
|
||||
}
|
||||
|
||||
const preregistModalRef = ref<{
|
||||
handleOpenPreregist: () => Promise<void>
|
||||
@@ -101,12 +96,6 @@ const buttonColors = computed(() => {
|
||||
}
|
||||
})
|
||||
|
||||
// Platform Buttons
|
||||
const platformButtons = computed<Platform[]>(() => {
|
||||
const osType = String(gameData.value?.os_type ?? '')
|
||||
return OS_TYPE_MAP[osType] ?? []
|
||||
})
|
||||
|
||||
// Reward Section
|
||||
const accBackgroundData = computed(() =>
|
||||
getComponentGroup(props.components, 'backgroundAccReward')
|
||||
@@ -280,10 +269,10 @@ const handlePreregistClick = () => {
|
||||
{{ tm('Preregist_Btn_Preegist') }}
|
||||
</BlocksButtonLauncher>
|
||||
<BlocksButtonLauncher
|
||||
v-for="platform in platformButtons"
|
||||
v-for="platform in getSupportedPlatforms(gameData?.os_type)"
|
||||
:key="`preregist-${platform}`"
|
||||
type="duplication"
|
||||
:platform="platform"
|
||||
:platform="platform as Platform"
|
||||
:background-color="buttonColors.backgroundColor"
|
||||
:text-color="buttonColors.textColor"
|
||||
>
|
||||
|
||||
@@ -52,12 +52,16 @@ export interface GameDataValue {
|
||||
comm_img_json: GameDataCommImg
|
||||
market_json: Record<string, { url: string }>
|
||||
event_banner: GameDataEventBanner
|
||||
os_type: string // 1:AOS, 2:IOS, 3:둘다
|
||||
platform_type: string // 1:PC, 2:MOBILE, 3:둘다
|
||||
os_type: OsType
|
||||
platform_type: PlatformType
|
||||
}
|
||||
|
||||
// ===== 세부 데이터 타입들 =====
|
||||
|
||||
export type OsType = '1' | '2' | '3' // 1:AOS, 2:IOS, 3:둘다
|
||||
export type PlatformType = '1' | '2' | '3' // 1:PC, 2:MOBILE, 3:둘다
|
||||
export type PlatformTransformType = 'pc' | 'google_play' | 'app_store'
|
||||
|
||||
// 키 코드 코드 타입
|
||||
export interface GameDataKeyColors {
|
||||
primary: string
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
* @description gameData, pageData 처리에 필요한 유틸리티 함수를 제공합니다.
|
||||
*/
|
||||
|
||||
import type { PlatformType } from '#layers/types/api/gameData'
|
||||
import type {
|
||||
PageDataValue,
|
||||
PageDataResourceContainer,
|
||||
@@ -12,6 +13,37 @@ import type {
|
||||
} from '#layers/types/api/pageData'
|
||||
import type { OperateComponents } from '#layers/types/api/operateResources'
|
||||
|
||||
const OS_TYPE_MAP: Record<string, string[]> = {
|
||||
'1': ['google_play'],
|
||||
'2': ['app_store'],
|
||||
'3': ['google_play', 'app_store'],
|
||||
}
|
||||
|
||||
/**
|
||||
* OS 타입에 따라 가능한 플랫폼 목록을 반환합니다.
|
||||
*/
|
||||
export const getSupportedPlatforms = (
|
||||
osType: string | number,
|
||||
options?: { platformType?: PlatformType }
|
||||
): string[] => {
|
||||
const type = String(osType)
|
||||
const platformType = String(options?.platformType ?? '0')
|
||||
const storePlatforms = OS_TYPE_MAP[type] ?? []
|
||||
|
||||
switch (platformType) {
|
||||
case '1': // PC 전용
|
||||
return ['pc']
|
||||
|
||||
case '2': // 모바일 스토어 전용
|
||||
return storePlatforms
|
||||
|
||||
case '3': // PC + 모바일 스토어 모두
|
||||
return ['pc', ...storePlatforms]
|
||||
|
||||
default: // 기본: OS_TYPE_MAP
|
||||
return storePlatforms
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 페이지 데이터를 기반으로 레이아웃 타입을 결정합니다.
|
||||
* @param pageData 페이지 데이터
|
||||
|
||||
@@ -4,10 +4,12 @@
|
||||
*/
|
||||
|
||||
import { isTypeVideo } from '#layers/utils/dataUtil'
|
||||
import type { GameDataResourceGroupBtnInfo } from '#layers/types/api/gameData'
|
||||
import type {
|
||||
PageDataResourceGroups,
|
||||
PageDataResourceGroup,
|
||||
PageDataResourceGroupResPath,
|
||||
PageDataResourceGroupBtnInfo,
|
||||
} from '#layers/types/api/pageData'
|
||||
|
||||
/**
|
||||
@@ -92,11 +94,29 @@ export const getColorCode = ({
|
||||
colorName: string
|
||||
colorCode: string
|
||||
}) => {
|
||||
if (colorName) {
|
||||
return `var(--${colorName})`
|
||||
} else if (colorCode) {
|
||||
return colorCode
|
||||
}
|
||||
if (colorName) return `var(--${colorName})`
|
||||
else if (colorCode) return colorCode
|
||||
}
|
||||
|
||||
/**
|
||||
* 색상데이터를 받아 색상값을 반환합니다.
|
||||
* @param colorData 색상 데이터
|
||||
* @param type 색상 타입 (btn: 버튼, txt: 텍스트)
|
||||
* @returns 색상 값
|
||||
*/
|
||||
export const getColorCodeFromData = (
|
||||
data: GameDataResourceGroupBtnInfo | PageDataResourceGroupBtnInfo,
|
||||
type: 'btn' | 'txt' = 'txt'
|
||||
) => {
|
||||
const suffix = type === 'btn' ? '_btn' : '_txt'
|
||||
|
||||
const colorName = data?.[`color_name${suffix}` as keyof typeof data]
|
||||
const colorCode = data?.[`color_code${suffix}` as keyof typeof data]
|
||||
|
||||
return getColorCode({
|
||||
colorName: colorName as string | undefined,
|
||||
colorCode: colorCode as string | undefined,
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user