diff --git a/layers/assets/css/components/_modal.css b/layers/assets/css/components/_modal.css index 00102ec..f8d9f0a 100644 --- a/layers/assets/css/components/_modal.css +++ b/layers/assets/css/components/_modal.css @@ -19,4 +19,8 @@ .content-text { @apply text-center text-[15px] text-[#333333] leading-6 tracking-[-0.45px]; } + + .content-text .highlight { + @apply text-[#FC4420]; + } } diff --git a/layers/components/atoms/Button/Circle.vue b/layers/components/atoms/Button/Circle.vue index 7d79c0c..c6e6cd6 100644 --- a/layers/components/atoms/Button/Circle.vue +++ b/layers/components/atoms/Button/Circle.vue @@ -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; } diff --git a/layers/components/layouts/Header.vue b/layers/components/layouts/Header.vue index 1490ca0..c0f0caa 100644 --- a/layers/components/layouts/Header.vue +++ b/layers/components/layouts/Header.vue @@ -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) => `${text}` + +const PLATFORM_LABEL_KEY: Record = { + 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}

${platformLines.join('
')}` + : 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(() => {
- - {{ gnb1depthButtonData?.btn_info?.txt_btn_name }} - - + + + {{ gnb1depthButtonData?.btn_info?.txt_btn_name }} + + + +