fix. 런처실행 버튼 수정
This commit is contained in:
10
app/app.vue
10
app/app.vue
@@ -146,14 +146,14 @@ onBeforeUnmount(() => {
|
||||
<NuxtPage />
|
||||
|
||||
<!-- 공통 모달 컴포넌트 -->
|
||||
<BlocksModalYouTube
|
||||
<AtomsModalYouTube
|
||||
v-model:is-open="youtube.storeIsOpen"
|
||||
:youtube-url="youtube.storeYoutubeUrl"
|
||||
:is-outside-close="youtube.storeIsOutsideClose"
|
||||
:modal-name="youtube.storeModalName"
|
||||
@close-button-event="handleResetYoutube"
|
||||
/>
|
||||
<BlocksModalConfirm
|
||||
<AtomsModalConfirm
|
||||
v-model:is-open="confirm.storeIsOpen"
|
||||
:is-show-dimmed="confirm.storeIsShowDimmed"
|
||||
:content-text="confirm.storeContentText"
|
||||
@@ -164,7 +164,7 @@ onBeforeUnmount(() => {
|
||||
@confirm-button-event="confirm.storeConfirmButtonEvent"
|
||||
@cancel-button-event="confirm.storeCancelButtonEvent"
|
||||
/>
|
||||
<BlocksModalAlert
|
||||
<AtomsModalAlert
|
||||
v-model:is-open="alert.storeIsOpen"
|
||||
:is-show-dimmed="alert.storeIsShowDimmed"
|
||||
:content-text="alert.storeContentText"
|
||||
@@ -175,8 +175,8 @@ onBeforeUnmount(() => {
|
||||
/>
|
||||
|
||||
<!-- 로딩 컴포넌트 -->
|
||||
<BlocksLoadingFull />
|
||||
<BlocksLoadingLocal />
|
||||
<AtomsLoadingFull />
|
||||
<AtomsLoadingLocal />
|
||||
</template>
|
||||
|
||||
<style>
|
||||
|
||||
@@ -22,6 +22,10 @@ const props = withDefaults(defineProps<Props>(), {
|
||||
disabled: false,
|
||||
})
|
||||
|
||||
const runtimeConfig = useRuntimeConfig()
|
||||
const { gameData } = useGameDataStore()
|
||||
const { isProcessing, validateLauncher } = useCheckGameStart()
|
||||
|
||||
const PLATFORM_ICON_MAP: Record<Platform, string> = {
|
||||
google_play: 'AtomsIconsLogoGoogle',
|
||||
app_store: 'AtomsIconsLogoApple',
|
||||
@@ -36,9 +40,15 @@ const DUP_IMAGE_MAP: Record<Platform, string> = {
|
||||
stove: '/images/common/btn_system_normal_stove_pc.svg',
|
||||
} as const
|
||||
|
||||
const componentTag = computed(() => {
|
||||
if (props.platform === 'stove') {
|
||||
return 'a'
|
||||
}
|
||||
return 'button'
|
||||
})
|
||||
const isDuplication = computed(() => props.type === 'duplication')
|
||||
const isSingle = computed(() => props.type === 'single')
|
||||
|
||||
const isCustom = computed(() => props.type === 'custom')
|
||||
const platformIcon = computed(() => PLATFORM_ICON_MAP[props.platform])
|
||||
const duplicationImage = computed(() =>
|
||||
isDuplication.value ? DUP_IMAGE_MAP[props.platform] : ''
|
||||
@@ -58,11 +68,27 @@ const inlineStyle = computed<CSSProperties>(() => {
|
||||
}
|
||||
return style
|
||||
})
|
||||
|
||||
const handleClick = () => {
|
||||
if (props.platform === 'pc') {
|
||||
validateLauncher()
|
||||
return
|
||||
}
|
||||
if (props.platform === 'stove') {
|
||||
const stoveClientDownloadUrl = runtimeConfig.public.stoveClientDownloadUrl
|
||||
location.href = stoveClientDownloadUrl
|
||||
return
|
||||
}
|
||||
|
||||
const url = gameData?.market_json[props.platform]?.url || ''
|
||||
window.open(url, '_blank')
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<button
|
||||
type="button"
|
||||
<component
|
||||
:is="componentTag"
|
||||
v-bind="$attrs"
|
||||
:class="[
|
||||
'btn-base',
|
||||
props.type,
|
||||
@@ -71,12 +97,13 @@ const inlineStyle = computed<CSSProperties>(() => {
|
||||
:data-variant="props.variant"
|
||||
:data-platform="props.platform"
|
||||
:style="inlineStyle"
|
||||
:disabled="disabled"
|
||||
:disabled="disabled || isProcessing"
|
||||
@click="handleClick"
|
||||
>
|
||||
<span class="btn-content">
|
||||
<component
|
||||
:is="platformIcon"
|
||||
v-if="!isDuplication"
|
||||
v-if="!isDuplication && !isCustom"
|
||||
class="icon-platform"
|
||||
/>
|
||||
<span class="text">
|
||||
@@ -86,12 +113,18 @@ const inlineStyle = computed<CSSProperties>(() => {
|
||||
<AtomsIconsDownloadLine />
|
||||
</span>
|
||||
</span>
|
||||
</button>
|
||||
</component>
|
||||
|
||||
<ClientOnly>
|
||||
<Teleport to="#teleports">
|
||||
<BlocksModalClient />
|
||||
</Teleport>
|
||||
</ClientOnly>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.btn-base {
|
||||
@apply overflow-hidden relative font-medium cursor-pointer
|
||||
@apply overflow-hidden inline-block relative font-medium cursor-pointer
|
||||
before:content-[''] before:absolute before:top-0 before:left-0 before:w-full before:h-full before:border before:border-white/10
|
||||
after:content-[''] after:absolute after:top-0 after:left-0 after:w-full after:h-full after:bg-white after:transition-opacity after:duration-300 after:ease-in-out after:opacity-0;
|
||||
}
|
||||
@@ -146,10 +179,8 @@ const inlineStyle = computed<CSSProperties>(() => {
|
||||
.btn-base.duplication {
|
||||
@apply items-start bg-[16px_50%] bg-[length:auto_28px] bg-no-repeat rounded-[4px]
|
||||
before:rounded-[4px] after:rounded-[4px]
|
||||
pt-[22px] pl-[44px] pr-[22px] pb-[7px] text-[11px]
|
||||
pt-[22px] pl-[47px] pr-[22px] pb-[7px] text-[11px]
|
||||
md:h-[64px] md:pt-[30px] md:pl-[64px] md:pr-[28px] md:pb-[11px] md:text-[12px] md:bg-[20px_50%] md:bg-[length:auto_40px];
|
||||
|
||||
color: red;
|
||||
}
|
||||
.btn-base.duplication[data-platform='google_play'] {
|
||||
@apply min-w-[148px] md:min-w-[194px];
|
||||
@@ -1,87 +0,0 @@
|
||||
<script setup>
|
||||
const {
|
||||
isProcessing,
|
||||
isShowCheckLauncher,
|
||||
isShowDownloadLauncher,
|
||||
validateLauncher,
|
||||
downloadLauncher,
|
||||
} = useCheckGameStart()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<AtomsButton
|
||||
button-size="size-small md:size-small"
|
||||
:class="$attrs?.class"
|
||||
:disabled="isProcessing"
|
||||
style="font-size: 16px"
|
||||
@click="validateLauncher"
|
||||
>
|
||||
<slot />
|
||||
</AtomsButton>
|
||||
|
||||
<ClientOnly>
|
||||
<Teleport to="#teleports">
|
||||
<BlocksModalLayer
|
||||
v-model:is-open="isShowCheckLauncher"
|
||||
:is-show-dimmed="true"
|
||||
:is-outside-close="false"
|
||||
:modal-name="'launcher'"
|
||||
area-class="max-w-[480px] pt-[56px] px-[24px] pb-[24px] rounded-[8px]"
|
||||
close-class="absolute top-[16px] right-[24px]"
|
||||
>
|
||||
<span class="ico-loading"></span>
|
||||
<!-- [TODO] i18n 적용 -->
|
||||
<!-- <p class="text-check">{{ tm('Common_Message_Check_Client').txt }}</p> -->
|
||||
<p class="text-check">pc 클라이언트 실행 중...</p>
|
||||
<Transition name="fade">
|
||||
<div v-if="isShowDownloadLauncher" class="client-area">
|
||||
<!-- <p
|
||||
v-dompurify-html="tm('Common_Message_Download_Client').txt"
|
||||
class="text-info"
|
||||
></p>
|
||||
<button type="button" class="btn-download" @click="downloadLauncher">
|
||||
{{ tm('Common_Message_Install').txt }}
|
||||
</button>
|
||||
<p
|
||||
v-dompurify-html="tm('Common_Message_Download_Close').txt"
|
||||
class="text-tip"
|
||||
></p> -->
|
||||
<p class="text-info">
|
||||
PC 클라이언트가 실행되지 않나요?
|
||||
<br />
|
||||
다운로드 전이라면 다운로드 후 진행해주세요
|
||||
</p>
|
||||
<AtomsButtonVariant class="max-w-[300px]" @click="downloadLauncher">
|
||||
다운로드
|
||||
</AtomsButtonVariant>
|
||||
<p
|
||||
v-dompurify-html="
|
||||
'*PC 클라이언트가 정상 실행되었다면 팝업을 닫아 주세요.'
|
||||
"
|
||||
class="text-tip"
|
||||
></p>
|
||||
</div>
|
||||
</Transition>
|
||||
</BlocksModalLayer>
|
||||
</Teleport>
|
||||
</ClientOnly>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.ico-loading {
|
||||
@apply block mx-auto mb-4 w-[80px] h-[80px] bg-[url('/images/common/stove_loading_light.png')] bg-contain bg-center bg-no-repeat;
|
||||
}
|
||||
.text-check {
|
||||
@apply mb-6 text-center text-[20px] font-bold leading-[30px] tracking-[-0.6px] text-[#333333];
|
||||
}
|
||||
|
||||
.client-area {
|
||||
@apply pt-4 border-t border-[rgba(0,0,0,0.08)] text-center;
|
||||
}
|
||||
.text-info {
|
||||
@apply mb-3 text-[14px] font-medium leading-[24px] tracking-[-0.42px] text-[#333333];
|
||||
}
|
||||
.text-tip {
|
||||
@apply mt-4 text-[14px] leading-[20px] tracking-[-0.42px] text-[#999999];
|
||||
}
|
||||
</style>
|
||||
68
layers/components/blocks/modal/Client.vue
Normal file
68
layers/components/blocks/modal/Client.vue
Normal file
@@ -0,0 +1,68 @@
|
||||
<script setup lang="ts">
|
||||
const { isShowCheckLauncher, isShowDownloadLauncher, downloadLauncher } =
|
||||
useCheckGameStart()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<AtomsModalLayer
|
||||
v-model:is-open="isShowCheckLauncher"
|
||||
:is-show-dimmed="true"
|
||||
:is-outside-close="false"
|
||||
:modal-name="'launcher'"
|
||||
area-class="max-w-[480px] pt-[56px] px-[24px] pb-[24px] rounded-[8px]"
|
||||
close-class="absolute top-[16px] right-[24px]"
|
||||
>
|
||||
<span class="ico-loading"></span>
|
||||
<!-- [TODO] i18n 적용 -->
|
||||
<!-- <p class="text-check">{{ tm('Common_Message_Check_Client').txt }}</p> -->
|
||||
<p class="text-check">pc 클라이언트 실행 중...</p>
|
||||
<Transition name="fade">
|
||||
<div v-if="isShowDownloadLauncher" class="client-area">
|
||||
<!-- <p
|
||||
v-dompurify-html="tm('Common_Message_Download_Client').txt"
|
||||
class="text-info"
|
||||
></p>
|
||||
<button type="button" class="btn-download" @click="downloadLauncher">
|
||||
{{ tm('Common_Message_Install').txt }}
|
||||
</button>
|
||||
<p
|
||||
v-dompurify-html="tm('Common_Message_Download_Close').txt"
|
||||
class="text-tip"
|
||||
></p> -->
|
||||
<p class="text-info">
|
||||
PC 클라이언트가 실행되지 않나요?
|
||||
<br />
|
||||
다운로드 전이라면 다운로드 후 진행해주세요
|
||||
</p>
|
||||
<AtomsButtonVariant class="max-w-[300px]" @click="downloadLauncher">
|
||||
다운로드
|
||||
</AtomsButtonVariant>
|
||||
<p
|
||||
v-dompurify-html="
|
||||
'*PC 클라이언트가 정상 실행되었다면 팝업을 닫아 주세요.'
|
||||
"
|
||||
class="text-tip"
|
||||
></p>
|
||||
</div>
|
||||
</Transition>
|
||||
</AtomsModalLayer>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.ico-loading {
|
||||
@apply block mx-auto mb-4 w-[80px] h-[80px] bg-[url('/images/common/stove_loading_light.png')] bg-contain bg-center bg-no-repeat;
|
||||
}
|
||||
.text-check {
|
||||
@apply mb-6 text-center text-[20px] font-bold leading-[30px] tracking-[-0.6px] text-[#333333];
|
||||
}
|
||||
|
||||
.client-area {
|
||||
@apply pt-4 border-t border-[rgba(0,0,0,0.08)] text-center;
|
||||
}
|
||||
.text-info {
|
||||
@apply mb-3 text-[14px] font-medium leading-[24px] tracking-[-0.42px] text-[#333333];
|
||||
}
|
||||
.text-tip {
|
||||
@apply mt-4 text-[14px] leading-[20px] tracking-[-0.42px] text-[#999999];
|
||||
}
|
||||
</style>
|
||||
@@ -296,9 +296,14 @@ onBeforeUnmount(() => {
|
||||
</div>
|
||||
</nav>
|
||||
<div ref="startRef" class="btn-start">
|
||||
<BlocksButtonLuncher class="w-full md:w-auto">
|
||||
<BlocksButtonDownload
|
||||
type="custom"
|
||||
platform="pc"
|
||||
class="w-full md:w-auto"
|
||||
style="font-size: 16px"
|
||||
>
|
||||
게임 시작
|
||||
</BlocksButtonLuncher>
|
||||
</BlocksButtonDownload>
|
||||
</div>
|
||||
<button class="btn-close" @click="handleMenuClose">
|
||||
<AtomsIconsMenuCloseLine class="mx-auto" />
|
||||
|
||||
@@ -12,7 +12,6 @@ interface ButtonListProps {
|
||||
|
||||
const props = defineProps<ButtonListProps>()
|
||||
|
||||
const { gameData } = useGameDataStore()
|
||||
const { locale } = useI18n()
|
||||
const { sendLog, useAnalyticsLogDataDirect } = useAnalytics()
|
||||
|
||||
@@ -40,38 +39,11 @@ const getButtonType = (btnInfo: PageDataResourceGroupBtnInfo): ButtonType => {
|
||||
return DEFAULT_BUTTON_TYPE
|
||||
}
|
||||
|
||||
const getButtonBackgroundImage = (
|
||||
btnInfo: PageDataResourceGroupBtnInfo
|
||||
): string => {
|
||||
const marketType = btnInfo?.detail?.market_type
|
||||
const marketImageMap: Record<string, string> = {
|
||||
google_play: '/images/common/btn_logo-google.svg',
|
||||
app_store: '/images/common/btn_logo-app.svg',
|
||||
pc: '/images/common/btn_logo-pc.svg',
|
||||
}
|
||||
|
||||
if (marketType && marketImageMap[marketType]) {
|
||||
return marketImageMap[marketType]
|
||||
}
|
||||
|
||||
return ''
|
||||
}
|
||||
|
||||
const handleButtonClick = (
|
||||
btnInfo: PageDataResourceGroupBtnInfo,
|
||||
index: any
|
||||
) => {
|
||||
const handleSendLog = (index: number) => {
|
||||
sendLog(
|
||||
locale.value,
|
||||
useAnalyticsLogDataDirect(props.resourcesData[index], props.pageVerTmplSeq)
|
||||
)
|
||||
|
||||
const marketType = btnInfo?.detail?.market_type
|
||||
if (marketType) {
|
||||
const url = gameData?.market_json[marketType]?.url
|
||||
window.open(url, '_blank')
|
||||
return
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -80,41 +52,29 @@ const handleButtonClick = (
|
||||
v-if="props.resourcesData?.length"
|
||||
class="flex flex-wrap justify-center gap-3 md:gap-4"
|
||||
>
|
||||
<AtomsButton
|
||||
v-for="(button, index) in props.resourcesData"
|
||||
:key="index"
|
||||
:type="getButtonType(button.btn_info)"
|
||||
:target="button.btn_info?.detail?.action?.link_target"
|
||||
:href="button.btn_info?.detail?.action?.url"
|
||||
:rel="button.btn_info?.detail?.action?.rel"
|
||||
:background-color="
|
||||
getColorCode({
|
||||
colorName: button.btn_info?.color_name_btn,
|
||||
colorCode: button.btn_info?.color_code_btn,
|
||||
})
|
||||
"
|
||||
:text-color="
|
||||
getColorCode({
|
||||
colorName: button.btn_info?.color_name_txt,
|
||||
colorCode: button.btn_info?.color_code_txt,
|
||||
})
|
||||
"
|
||||
:disabled="button.btn_info?.disabled"
|
||||
:class="button.btn_info?.detail?.market_type ? 'btn-market' : ''"
|
||||
:style="{
|
||||
backgroundImage: `url(${getButtonBackgroundImage(button.btn_info)})`,
|
||||
}"
|
||||
@click="handleButtonClick(button.btn_info, index)"
|
||||
>
|
||||
{{ button.btn_info?.txt_btn_name }}
|
||||
</AtomsButton>
|
||||
<template v-for="(button, index) in props.resourcesData" :key="index">
|
||||
<AtomsButton
|
||||
:type="getButtonType(button.btn_info)"
|
||||
:target="button.btn_info?.detail?.action?.link_target"
|
||||
:href="button.btn_info?.detail?.action?.url"
|
||||
:rel="button.btn_info?.detail?.action?.rel"
|
||||
:background-color="
|
||||
getColorCode({
|
||||
colorName: button.btn_info?.color_name_btn,
|
||||
colorCode: button.btn_info?.color_code_btn,
|
||||
})
|
||||
"
|
||||
:text-color="
|
||||
getColorCode({
|
||||
colorName: button.btn_info?.color_name_txt,
|
||||
colorCode: button.btn_info?.color_code_txt,
|
||||
})
|
||||
"
|
||||
:disabled="button.btn_info?.disabled"
|
||||
@click="handleSendLog(index)"
|
||||
>
|
||||
{{ button.btn_info?.txt_btn_name }}
|
||||
</AtomsButton>
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
:deep(.btn-market) {
|
||||
@apply flex items-start bg-[16px_50%] bg-[length:auto_28px] bg-no-repeat
|
||||
min-w-[113px] pt-[22px] pl-[44px] pr-[22px] text-[11px]
|
||||
md:min-w-[150px] md:pt-[30px] md:pl-[64px] md:pr-[28px] md:text-[12px] md:bg-[20px_50%] md:bg-[length:auto_40px];
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -9,6 +9,9 @@ interface Props {
|
||||
|
||||
const props = defineProps<Props>()
|
||||
|
||||
const { locale } = useI18n()
|
||||
const { sendLog, useAnalyticsLogDataDirect } = useAnalytics()
|
||||
|
||||
const backgroundData = computed(() =>
|
||||
getComponentGroup(props.components, 'background')
|
||||
)
|
||||
@@ -24,6 +27,13 @@ const videoPlayData = computed(() =>
|
||||
const buttonListData = computed(() =>
|
||||
getComponentGroupAry(props.components, 'buttonList')
|
||||
)
|
||||
|
||||
const handleSendLog = (index: number) => {
|
||||
sendLog(
|
||||
locale.value,
|
||||
useAnalyticsLogDataDirect(buttonListData.value[index], props.pageVerTmplSeq)
|
||||
)
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -49,13 +59,33 @@ const buttonListData = computed(() =>
|
||||
:resources-data="videoPlayData"
|
||||
:page-ver-tmpl-seq="props.pageVerTmplSeq"
|
||||
/>
|
||||
<WidgetsButtonList
|
||||
<div
|
||||
v-if="buttonListData.length > 0"
|
||||
button-type="market"
|
||||
:resources-data="buttonListData"
|
||||
:page-ver-tmpl-seq="props.pageVerTmplSeq"
|
||||
class="mt-[22px] md:mt-[52px]"
|
||||
/>
|
||||
class="flex flex-wrap justify-center gap-3 mt-[22px] md:gap-4 md:mt-[52px]"
|
||||
>
|
||||
<BlocksButtonDownload
|
||||
v-for="(button, index) in buttonListData"
|
||||
:key="index"
|
||||
type="duplication"
|
||||
:platform="button.btn_info?.detail?.market_type"
|
||||
:background-color="
|
||||
getColorCode({
|
||||
colorName: button.btn_info?.color_name_btn,
|
||||
colorCode: button.btn_info?.color_code_btn,
|
||||
})
|
||||
"
|
||||
:text-color="
|
||||
getColorCode({
|
||||
colorName: button.btn_info?.color_name_txt,
|
||||
colorCode: button.btn_info?.color_code_txt,
|
||||
})
|
||||
"
|
||||
:disabled="button.btn_info?.disabled"
|
||||
@click="handleSendLog(index)"
|
||||
>
|
||||
{{ button.btn_info?.txt_btn_name }}
|
||||
</BlocksButtonDownload>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
@@ -5,7 +5,7 @@ export type ButtonType =
|
||||
| 'action'
|
||||
| 'link'
|
||||
|
||||
export type DownloadButtonType = 'default' | 'single' | 'duplication'
|
||||
export type DownloadButtonType = 'default' | 'single' | 'duplication' | 'custom'
|
||||
|
||||
export type ButtonSize = 'large' | 'medium' | 'small' | 'extra-small'
|
||||
|
||||
|
||||
Reference in New Issue
Block a user