Merge commit '40dc7f0e409841a51946ac4f00aecbdc67be0a9e' into feature/20260130_cl_SWV-812

This commit is contained in:
clkim
2026-01-16 15:01:41 +09:00
37 changed files with 264 additions and 374 deletions

View File

@@ -14,8 +14,8 @@ const modalStore = useModalStore()
const scrollStore = useScrollStore()
const { setGameData } = gameDataStore
const { gameName, gaCode } = storeToRefs(gameDataStore)
const { confirm, alert } = modalStore
const { gameName, gaCode } = storeToRefs(gameDataStore)
const { scrollGnbPosition } = storeToRefs(scrollStore)
// favicon 링크 생성 헬퍼
@@ -80,7 +80,7 @@ const createMetaTags = (metaTag: Partial<GameDataMetaTag> = {}) => {
}
// CSS 변수 생성 헬퍼
const createCssVariable = (keyColorJson: GameDataKeyColors) => {
const createStyleCss = (keyColorJson: GameDataKeyColors) => {
const colorVariables = Object.entries(keyColorJson)
.filter(([key, value]) => key && value != null)
.map(([key, value]) => `--${key}: ${value};`)
@@ -94,8 +94,11 @@ const setupGameHead = (data: GameDataValue) => {
try {
const metaTag: Partial<GameDataMetaTag> = data.meta_tag_json ?? {}
const designTheme = data.design_theme === 1 ? 'light' : 'dark'
const styleLinks = createStyleLinks(data.favicon_json)
const cssVariables = createCssVariable(data.key_color_json)
const styleLinks = createStyleLinks(
data.favicon_json,
data?.game_font?.font_path
)
const styleCss = createStyleCss(data.key_color_json)
useHead({
title: metaTag.page_title ?? '',
@@ -108,7 +111,7 @@ const setupGameHead = (data: GameDataValue) => {
link: styleLinks,
style: [
{
innerHTML: cssVariables,
innerHTML: styleCss,
id: 'game-css-variables',
},
],

View File

@@ -56,80 +56,24 @@
></span>
</h3>
<div class="button-group justify-center">
<!-- <a
:href="communityUrl"
target="_blank"
rel="noopener noreferrer"
class="inspection-btn inspection-btn-outline inspection-btn-community"
:class="{ 'bg-[var(--primary)]' : !launchingStatus }"
>
<span>{{ tm('Inspection_Community_Btn') || '공식 커뮤니티' }}</span>
<AtomsIconsLongArrowRightLine :size="16" color="#1F1F1F" />
</a> -->
<AtomsButtonVariant
type="custom"
class="inspection-btn inspection-btn-community color-black text-sm px-4 md:text-base"
:class="{ 'inspection-btn-outline flex-1': launchingStatus }"
<AtomsButton
variant="outlined"
class="flex-1 size-extra-small md:size-small"
@click="handleCommunityClick"
>
<span>{{ tm('Inspection_Community_Btn') }}</span>
<span class="text">{{ tm('Inspection_Community_Btn') }}</span>
<AtomsIconsLongArrowRightLine :size="16" color="#1F1F1F" />
</AtomsButtonVariant>
<div v-if="launchingStatus" class="flex flex-1">
<BlocksButtonLauncher
v-if="
(Number(gameData?.platform_type) !== 2 &&
device.isDesktop) ||
Number(gameData?.platform_type) === 1
"
type="custom"
platform="pc"
class="inspection-btn inspection-btn-primary w-full color-black text-sm md:text-base flex-1"
>
<span>{{ tm('Txt_Game_Start') }}</span>
<svg
width="16"
height="16"
viewBox="0 0 16 16"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
fill-rule="evenodd"
clip-rule="evenodd"
d="M10.3098 1.49172C8.86574 1.28049 7.15098 1.28055 5.70176 1.49167C3.50821 1.81315 1.81986 3.50786 1.49213 5.69168L1.4918 5.69391C1.38564 6.41904 1.33331 7.19181 1.33331 7.99998C1.33331 8.80815 1.3857 9.58136 1.49187 10.3065C1.81362 12.4934 3.50335 14.1805 5.69381 14.5079L5.69577 14.5082C6.42109 14.6143 7.19417 14.6666 7.99717 14.6666C8.80032 14.6666 9.57311 14.6143 10.3035 14.5083L10.3046 14.5082C12.4928 14.1865 14.1802 12.4917 14.5078 10.3083L14.5082 10.3061C14.6143 9.58092 14.6666 8.80815 14.6666 7.99998C14.6666 7.19527 14.6203 6.42148 14.5137 5.69347C14.1921 3.50726 12.4966 1.81316 10.3098 1.49172ZM6.38756 8.95267C6.39301 9.15365 6.40004 9.35195 6.40866 9.54742L6.40968 9.57054C6.41945 9.78867 6.43118 10.0033 6.44489 10.2141C6.45959 10.4433 6.68743 10.5836 6.88293 10.4823C7.22837 10.3029 7.58116 10.1096 7.9413 9.90379C8.20002 9.7541 8.46167 9.6013 8.72479 9.43914C8.98791 9.27854 9.24516 9.11482 9.49505 8.95111C9.84196 8.72502 10.1771 8.49581 10.4961 8.26817C10.6769 8.14031 10.6769 7.85965 10.4961 7.7318C10.1771 7.50415 9.84343 7.2765 9.49505 7.04886C9.24516 6.88514 8.98791 6.72298 8.72479 6.56082C8.46167 6.39866 8.20002 6.2443 7.9413 6.09618C7.58263 5.89036 7.22837 5.69702 6.88293 5.5177C6.68743 5.41636 6.45959 5.55669 6.44489 5.78589C6.43118 5.99671 6.41945 6.21129 6.40968 6.42943L6.40866 6.45254C6.40004 6.64801 6.39301 6.84631 6.38756 7.0473C6.37874 7.3607 6.37433 7.67722 6.37433 7.99998C6.37433 8.32274 6.37874 8.64082 6.38756 8.95267Z"
fill="#332C2A"
/>
</svg>
</BlocksButtonLauncher>
<AtomsButtonVariant
v-else-if="Number(gameData?.platform_type) !== 1"
type="custom"
class="inspection-btn inspection-btn-primary w-full color-black text-sm md:text-base flex-1"
@click="handleGameStart"
>
<span>{{ tm('Txt_Game_Start') }}</span>
<svg
width="16"
height="16"
viewBox="0 0 16 16"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
fill-rule="evenodd"
clip-rule="evenodd"
d="M10.3098 1.49172C8.86574 1.28049 7.15098 1.28055 5.70176 1.49167C3.50821 1.81315 1.81986 3.50786 1.49213 5.69168L1.4918 5.69391C1.38564 6.41904 1.33331 7.19181 1.33331 7.99998C1.33331 8.80815 1.3857 9.58136 1.49187 10.3065C1.81362 12.4934 3.50335 14.1805 5.69381 14.5079L5.69577 14.5082C6.42109 14.6143 7.19417 14.6666 7.99717 14.6666C8.80032 14.6666 9.57311 14.6143 10.3035 14.5083L10.3046 14.5082C12.4928 14.1865 14.1802 12.4917 14.5078 10.3083L14.5082 10.3061C14.6143 9.58092 14.6666 8.80815 14.6666 7.99998C14.6666 7.19527 14.6203 6.42148 14.5137 5.69347C14.1921 3.50726 12.4966 1.81316 10.3098 1.49172ZM6.38756 8.95267C6.39301 9.15365 6.40004 9.35195 6.40866 9.54742L6.40968 9.57054C6.41945 9.78867 6.43118 10.0033 6.44489 10.2141C6.45959 10.4433 6.68743 10.5836 6.88293 10.4823C7.22837 10.3029 7.58116 10.1096 7.9413 9.90379C8.20002 9.7541 8.46167 9.6013 8.72479 9.43914C8.98791 9.27854 9.24516 9.11482 9.49505 8.95111C9.84196 8.72502 10.1771 8.49581 10.4961 8.26817C10.6769 8.14031 10.6769 7.85965 10.4961 7.7318C10.1771 7.50415 9.84343 7.2765 9.49505 7.04886C9.24516 6.88514 8.98791 6.72298 8.72479 6.56082C8.46167 6.39866 8.20002 6.2443 7.9413 6.09618C7.58263 5.89036 7.22837 5.69702 6.88293 5.5177C6.68743 5.41636 6.45959 5.55669 6.44489 5.78589C6.43118 5.99671 6.41945 6.21129 6.40968 6.42943L6.40866 6.45254C6.40004 6.64801 6.39301 6.84631 6.38756 7.0473C6.37874 7.3607 6.37433 7.67722 6.37433 7.99998C6.37433 8.32274 6.37874 8.64082 6.38756 8.95267Z"
fill="#332C2A"
/>
</svg>
</AtomsButtonVariant>
</div>
</AtomsButton>
<BlocksButtonLauncher
v-if="launchingStatus"
type="single"
platform="pc"
class="inspection-launcher"
:icon-component="AtomsIconsPlayRoundFill"
:icon-props="{ size: 16, color: '#332C2A' }"
>
{{ tm('Txt_Game_Start') }}
</BlocksButtonLauncher>
</div>
</div>
@@ -137,7 +81,6 @@
<div
v-if="launchingStatus"
class="inspection-card inspection-download-card"
:class="`platform-type-${gameData?.platform_type}`"
>
<h3 class="card-title text-base md:text-lg">
{{
@@ -147,18 +90,23 @@
}}
</h3>
<div class="flex flex-row gap-3 flex-wrap">
<BlocksButtonLauncher
v-for="(btn, index) in enabledMarkets"
<template
v-for="(market, index) in enabledMarkets"
:key="index"
:class="getButtonClass(btn.platform)"
class="h-[40px] md:h-[48px]"
:platform="btn.platform as any"
:url="btn.url"
:type="btn.platform === 'pc' ? 'default' : 'single'"
variant="outlined"
>
{{ getButtonText(btn.platform) }}
</BlocksButtonLauncher>
<BlocksButtonLauncher
:type="market === 'pc' ? 'default' : 'single'"
variant="outlined"
:platform="market"
:class="[
{ 'flex-1': market === 'pc' },
{ 'flex-1': market !== 'pc' && !device.isDesktop },
'size-extra-small md:size-small',
]"
>
{{ getButtonText(market) }}
</BlocksButtonLauncher>
</template>
</div>
</div>
</div>
@@ -170,6 +118,8 @@
<script setup lang="ts">
import { globalDateFormat } from '@seed-next/date'
import AtomsIconsPlayRoundFill from '#layers/components/atoms/icons/PlayRoundFill.vue'
import type { Platform } from '#layers/types/components/button'
const config = useRuntimeConfig()
const stoveApiUrl = config.public.stoveApiUrl as string
@@ -233,51 +183,21 @@ const launchingStatus = computed(() => {
return webInspectionData.value?.launching_status
})
// const market_json = {
// pc: { url: 'https://apps.apple.com/app/id1234567890', use_yn: 0 },
// app_store: { url: 'https://apps.apple.com/app/id1234567890', use_yn: 0 },
// google_play: { url: 'https://play.google.com/store/apps/details?id=example', use_yn: 1 }
// }
//gameData.value.market_json 값 중 use_yn === 1 인 항목만 배열로 변환
const enabledMarkets = computed(() => {
const platformType = Number(gameData.value.platform_type)
const markets = Object.entries(gameData.value.market_json)
// return Object.entries(market_json)
.filter(([, info]: [string, any]) => info && info.use_yn === 1)
.map(([platform, info]: [string, any]) => ({
platform,
url: info.url as string,
}))
const markets = getSupportedPlatforms(
gameData.value.platform_type,
gameData.value.os_type
) as Platform[]
// platform_type이 1이면 app_store, google_play 제외하고 pc 추가
if (platformType === 1) {
const filteredMarkets = markets.filter(
m => m.platform !== 'app_store' && m.platform !== 'google_play'
)
const hasPc = filteredMarkets.some(m => m.platform === 'pc')
if (!hasPc) {
filteredMarkets.unshift({
platform: 'pc',
url: '',
})
if (device.isMobile) {
// markets에 pc가 있다면 지우기
markets.splice(markets.indexOf('pc'), 1)
if (device.isAndroid) {
markets.splice(markets.indexOf('app_store'), 1)
}
return filteredMarkets
}
// platform_type이 2이면 pc 제외
if (platformType === 2) {
return markets.filter(m => m.platform !== 'pc')
}
// platform_type이 3이면 pc 항목 추가
if (platformType === 3) {
const hasPc = markets.some(m => m.platform === 'pc')
if (!hasPc) {
markets.unshift({
platform: 'pc',
url: '',
})
if (device.isApple) {
markets.splice(markets.indexOf('google_play'), 1)
}
}
@@ -287,7 +207,7 @@ const enabledMarkets = computed(() => {
const logoImgUrl = computed(() => {
const currentLocale = locale.value || 'ko'
const localeData = (webInspectionData.value as any)?.[currentLocale]
return formatPathHost(localeData.img_json.bi_large)
return formatPathHost(localeData?.img_json.bi_large)
})
const communityUrl = computed(() => {
@@ -299,17 +219,6 @@ const communityUrl = computed(() => {
const handleCommunityClick = () => {
window.open(communityUrl.value, '_blank')
}
// 버튼 클래스 결정 함수
const getButtonClass = (platform: string) => {
// pc가 있으면 pc만 flex-1, 나머지는 기본
// platform_type이 3일 때 조건 추가
if (Number(gameData.value.platform_type) !== 2 && platform === 'pc') {
return `flex-1 btn-platform-${platform}`
}
return `btn-platform-${platform}`
}
const getButtonText = (platform: string) => {
const platformKeyMap: Record<string, string> = {
@@ -318,24 +227,14 @@ const getButtonText = (platform: string) => {
app_store: 'platform_app_store',
}
if (platform !== 'pc' && device.isDesktop) {
return ''
}
const key = platformKeyMap[platform]
return key ? tm(key) : ''
}
const handleGameStart = () => {
const os = device.isAndroid
? 'google_play'
: device.isApple
? 'app_store'
: 'google_play'
//const os = device.isAndroid ? 'google_play' : device.isApple ? 'app_store' : 'pc'
// platform_type이 2이면서 device.isDesktop이면 window.open(gameData.value.market_json[os].url, '_blank')
window.open(gameData.value.market_json[os].url, '_blank')
}
onMounted(() => {
loadingStore.stopFullLoading()
})
@@ -415,37 +314,7 @@ definePageMeta({
}
.button-group {
@apply flex flex-row gap-3 w-full;
}
.inspection-btn {
@apply flex items-center justify-center gap-1 px-2 md:px-4 h-10 md:h-12 rounded-lg;
cursor: pointer;
transition: all 0.2s;
}
.inspection-btn span {
@apply text-[#1F1F1F];
}
.inspection-btn-outline {
@apply bg-white;
}
.inspection-btn-outline:hover {
@apply bg-gray-50;
}
.inspection-btn-primary {
@apply bg-[var(--primary)] border-[var(--primary)] text-[#000];
}
.inspection-btn-primary span {
@apply text-black;
}
.inspection-btn-primary:hover {
@apply bg-[#B89D7A];
@apply flex flex-row gap-3;
}
@media (max-width: 1024px) {
@@ -470,69 +339,18 @@ definePageMeta({
@apply w-full;
}
}
.inspection-btn-community {
@apply rounded-lg;
}
.inspection-btn-community.inspection-btn-outline {
@apply bg-white border-none;
}
.inspection-btn-community.inspection-btn-outline:hover {
@apply bg-gray-50;
}
.inspection-download-card .btn-platform-pc {
@apply w-auto flex-1;
}
.inspection-download-card.platform-type-3 .btn-platform-pc {
@apply w-full flex-none hidden md:flex md:flex-1;
.button-group:deep(.btn-base .text) {
@apply mr-[2px] md:mr-[4px] text-[#1F1F1F];
}
.inspection-download-card .btn-platform-app_store {
@apply flex-1 px-2 md:px-4;
.button-group:deep(.inspection-launcher.btn-base) {
@apply flex-1 bg-[var(--primary)] px-[20px];
}
.inspection-download-card.platform-type-3 .btn-platform-app_store,
.inspection-download-card.platform-type-3 .btn-platform-google_play {
@apply flex-1 px-2 md:px-4 md:flex-none;
}
:deep(.inspection-download-card .btn-platform-app_store .text) {
@apply block md:hidden;
}
:deep(.inspection-download-card.platform-type-2 .btn-platform-app_store .text) {
@apply block md:block;
}
:deep(.inspection-download-card .btn-platform-google_play) {
@apply flex-1 px-2 md:px-4;
}
:deep(.inspection-download-card .btn-platform-google_play .text) {
@apply block md:hidden;
}
:deep(
.inspection-download-card.platform-type-2 .btn-platform-google_play .text
) {
@apply block md:block;
}
:deep(.inspection-download-card .btn-base.single .icon-platform) {
@apply mr-2 md:mr-0;
}
.inspection-btn-primary.btn-base {
@apply bg-[var(--primary)] border-[var(--primary)] text-[#000];
}
.inspection-btn-primary.btn-base:deep(.text) {
@apply flex flex-1 items-center justify-center gap-1;
}
.inspection-btn-primary.btn-base:deep(.icon-platform) {
@apply hidden;
}
.inspection-btn-primary.btn-base {
@apply bg-[var(--primary)] border-[var(--primary)] text-[#000];
}
.inspection-btn-primary.btn-base:deep(.text) {
@apply flex flex-1 items-center justify-center gap-1;
}
.inspection-btn-primary.btn-base:deep(.icon-platform) {
.button-group:deep(.inspection-launcher.btn-base .icon-platform) {
@apply hidden;
}
</style>

View File

@@ -1,25 +1,25 @@
/* Button Size Classes */
@layer components {
/* height: 64px */
.size-large {
/* height: 64px */
@apply px-10 h-16 text-lg rounded-lg
before:rounded-lg after:rounded-lg;
}
/* height: 56px */
.size-medium {
/* height: 56px */
@apply px-10 h-14 text-base rounded-lg
before:rounded-lg after:rounded-lg;
}
/* height: 48px */
.size-small {
/* height: 48px */
@apply px-10 h-12 text-sm rounded-lg
before:rounded-lg after:rounded-lg;
}
/* height: 40px */
.size-extra-small {
/* height: 40px */
@apply px-6 h-10 text-sm rounded
before:rounded after:rounded;
}

View File

@@ -13,24 +13,28 @@ const props = withDefaults(defineProps<props>(), {
</script>
<template>
<button :class="['btn-base', props.variant]" :disabled="props.disabled">
<button
class="btn-base"
:data-variant="props.variant"
:disabled="props.disabled"
>
<slot />
</button>
</template>
<style scoped>
.btn-base {
@apply relative w-full py-[14px] px-5 text-sm font-medium rounded-lg
@apply relative inline-flex items-center justify-center w-full py-[14px] px-5 text-sm font-medium rounded-lg
before:content-[''] before:absolute before:top-0 before:left-0 before:w-full before:h-full before:border before:border-black/10 before:rounded-lg before:transition-all before:duration-300 before:ease-in-out;
}
.btn-base.filled {
.btn-base[data-variant='filled'] {
@apply bg-[var(--primary)] text-[var(--text-secondary)]
after:content-[''] after:absolute after:top-0 after:left-0 after:w-full after:h-full after:bg-white after:rounded-lg after:transition-opacity after:duration-300 after:ease-in-out after:opacity-0
hover:after:opacity-20;
}
.btn-base.outlined {
.btn-base[data-variant='outlined'] {
@apply bg-white text-[#333333]
hover:before:border-[#999];
}

View File

@@ -1,9 +1,10 @@
<script setup lang="ts">
import type { ButtonType } from '#layers/types/components/button'
import type { ButtonType, ButtonVariant } from '#layers/types/components/button'
interface props {
type?: ButtonType
buttonSize?: string
size?: string
variant?: ButtonVariant
target?: '_self' | '_blank'
href?: string
backgroundColor?: string
@@ -13,9 +14,9 @@ interface props {
const props = withDefaults(defineProps<props>(), {
type: 'action',
buttonSize: 'size-small md:size-large',
size: 'size-extra-small md:size-medium',
variant: 'filled',
target: '_self',
backgroundColor: 'var(--primary)',
textColor: 'var(--alternative-02)',
disabled: false,
})
@@ -33,6 +34,12 @@ const componentTag = computed((): string => {
return 'button'
}
})
const backgroundColor = computed(() => {
if (props.backgroundColor) {
return props.backgroundColor
}
return props.variant === 'filled' ? 'var(--primary)' : 'white'
})
const componentProps = computed(() => {
if (props.type === 'external' || props.type === 'link') {
return {
@@ -66,10 +73,11 @@ const componentProps = computed(() => {
<component
:is="componentTag"
v-bind="{ ...componentProps }"
:class="['btn-base', props.buttonSize, { disabled: props.disabled }]"
:class="['btn-base', props.size, { disabled: props.disabled }]"
:data-variant="props.variant"
:style="{
backgroundColor: props.backgroundColor,
color: props.textColor,
backgroundColor: backgroundColor,
color: props.textColor ? props.textColor : 'var(--text-secondary)',
'--text-color': props.textColor,
}"
:disabled="props.disabled"
@@ -98,17 +106,22 @@ const componentProps = computed(() => {
<style scoped>
.btn-base {
@apply overflow-hidden relative inline-flex items-center justify-center 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;
}
.btn-base:hover {
@apply after:opacity-20;
before:content-[''] before:absolute before:top-0 before:left-0 before:w-full before:h-full before:border before:border-white/10;
}
.btn-base.disabled {
@apply cursor-default pointer-events-none
after:bg-[var(--text-color)] after:opacity-20 after:z-[2];
}
.btn-base[data-variant='filled'] {
@apply 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
hover:after:opacity-20;
}
.btn-base[data-variant='outlined'] {
@apply before:border-[rgba(0,0,0,0.1)]
hover:before:border-[#999];
}
.btn-base.disabled .btn-content {
@apply opacity-50;
}

View File

@@ -44,10 +44,10 @@ const onInput = (event: Event) => {
<AtomsButton
v-if="props.useClearButton && localValue.length > 0"
type="action"
button-size="size-small"
size="size-small md:size-medium"
background-color="#00000000"
text-color="transparent"
class="!absolute top-[50%] right-[12px] translate-y-[-50%] flex items-center justify-center w-auto h-auto p-0 md:right-[16px]"
class="!absolute top-[50%] right-[12px] translate-y-[-50%] flex items-center justify-center w-auto p-0 md:right-[16px]"
@click="onClickClearButton"
>
<AtomsIconsCloseCircleFill :size="16" color="rgba(0,0,0,0.15)" />

View File

@@ -41,7 +41,7 @@ const onSelectOption = (option: { [key: string | number]: any }): void => {
<div class="relative w-full max-w-[432px]">
<button
type="button"
class="relative flex items-center justify-between gap-[12px] w-full py-[12px] px-[16px] bg-white border border-solid border-[1px] border-[#D9D9D9] rounded-[8px]"
class="relative flex items-center justify-between gap-[12px] w-full py-[12px] px-[16px] bg-white border-solid border-[1px] border-[#D9D9D9] rounded-[8px]"
@click="onToggleOpen"
>
<span

View File

@@ -5,7 +5,7 @@ interface Props {
}
withDefaults(defineProps<Props>(), {
size: 34,
size: 16,
color: 'white',
})
</script>
@@ -15,13 +15,13 @@ withDefaults(defineProps<Props>(), {
xmlns="http://www.w3.org/2000/svg"
:width="size"
:height="size"
viewBox="0 0 34 34"
viewBox="0 0 16 16"
:fill="color"
>
<path
fill-rule="evenodd"
clip-rule="evenodd"
d="M22.4412 0.396022C18.8311 -0.132052 14.5442 -0.131919 10.9211 0.39589C5.43725 1.1996 1.21636 5.43636 0.397045 10.8959L0.396229 10.9015C0.130814 12.7143 0 14.6462 0 16.6667C0 18.6871 0.130974 20.6201 0.39639 22.4329C1.20078 27.9002 5.4251 32.118 10.9013 32.9366L10.9061 32.9373C12.7195 33.2026 14.6521 33.3333 16.6596 33.3333C18.6675 33.3333 20.5995 33.2025 22.4254 32.9376L22.4283 32.9372C27.8987 32.1331 32.1171 27.8959 32.9363 22.4374L32.9371 22.4318C33.2025 20.619 33.3333 18.6871 33.3333 16.6667C33.3333 14.6549 33.2175 12.7204 32.951 10.9004C32.1469 5.43487 27.9082 1.19961 22.4412 0.396022ZM12.6356 19.0484C12.6492 19.5508 12.6668 20.0466 12.6884 20.5353L12.6909 20.5931C12.7153 21.1384 12.7447 21.6749 12.7789 22.2019C12.8157 22.7749 13.3853 23.1257 13.8741 22.8724C14.7377 22.4241 15.6196 21.9407 16.52 21.4262C17.1668 21.052 17.8209 20.67 18.4787 20.2646C19.1365 19.8631 19.7796 19.4538 20.4043 19.0445C21.2716 18.4793 22.1095 17.9063 22.9069 17.3371C23.3589 17.0175 23.3589 16.3158 22.9069 15.9962C22.1095 15.4271 21.2753 14.858 20.4043 14.2889C19.7796 13.8796 19.1365 13.4742 18.4787 13.0688C17.8209 12.6634 17.1668 12.2775 16.52 11.9072C15.6233 11.3926 14.7377 10.9093 13.8741 10.461C13.3853 10.2076 12.8157 10.5584 12.7789 11.1314C12.7447 11.6585 12.7153 12.1949 12.6909 12.7403L12.6884 12.7981C12.6668 13.2867 12.6492 13.7825 12.6356 14.285C12.6136 15.0685 12.6025 15.8598 12.6025 16.6667C12.6025 17.4736 12.6136 18.2688 12.6356 19.0484Z"
d="M10.3098 1.49172C8.86568 1.28049 7.15091 1.28055 5.7017 1.49167C3.50815 1.81315 1.8198 3.50786 1.49207 5.69168L1.49174 5.69391C1.38558 6.41904 1.33325 7.19181 1.33325 7.99998C1.33325 8.80815 1.38564 9.58136 1.49181 10.3065C1.81356 12.4934 3.50329 14.1805 5.69375 14.5079L5.69571 14.5082C6.42103 14.6143 7.19411 14.6666 7.99711 14.6666C8.80026 14.6666 9.57305 14.6143 10.3034 14.5083L10.3046 14.5082C12.4927 14.1865 14.1801 12.4917 14.5078 10.3083L14.5081 10.3061C14.6143 9.58092 14.6666 8.80815 14.6666 7.99998C14.6666 7.19527 14.6202 6.42148 14.5137 5.69347C14.192 3.50726 12.4965 1.81316 10.3098 1.49172ZM6.3875 8.95266C6.39295 9.15365 6.39998 9.35195 6.4086 9.54742L6.40962 9.57054C6.41938 9.78867 6.43112 10.0033 6.44483 10.2141C6.45952 10.4433 6.68737 10.5836 6.88287 10.4823C7.22831 10.3029 7.5811 10.1096 7.94124 9.90379C8.19995 9.7541 8.46161 9.6013 8.72473 9.43914C8.98785 9.27854 9.24509 9.11482 9.49499 8.9511C9.8419 8.72502 10.177 8.49581 10.496 8.26817C10.6768 8.14031 10.6768 7.85965 10.496 7.7318C10.177 7.50415 9.84337 7.2765 9.49499 7.04886C9.24509 6.88514 8.98785 6.72298 8.72473 6.56082C8.46161 6.39866 8.19995 6.2443 7.94124 6.09618C7.58257 5.89036 7.22831 5.69701 6.88287 5.5177C6.68737 5.41636 6.45952 5.55668 6.44483 5.78589C6.43112 5.99671 6.41938 6.21129 6.40962 6.42943L6.4086 6.45254C6.39998 6.64801 6.39295 6.84631 6.3875 7.0473C6.37868 7.3607 6.37427 7.67722 6.37427 7.99998C6.37427 8.32274 6.37868 8.64082 6.3875 8.95266Z"
/>
</svg>
</template>

View File

@@ -1,5 +1,5 @@
<script setup lang="ts">
import type { CSSProperties } from 'vue'
import type { CSSProperties, Component } from 'vue'
import type { PlatformTransformType } from '#layers/types/api/gameData'
import type {
DownloadButtonType,
@@ -13,6 +13,8 @@ interface Props {
variant?: ButtonVariant
backgroundColor?: string
textColor?: string
iconComponent?: Component
iconProps?: Record<string, any>
disabled?: boolean
}
@@ -29,7 +31,8 @@ const gameDataStore = useGameDataStore()
const modalStore = useModalStore()
const { isProcessing, validateLauncher } = useCheckGameStart()
const { gameData } = storeToRefs(gameDataStore)
const { gameName, platformType, osType, marketJson } =
storeToRefs(gameDataStore)
const PLATFORM_ICON_MAP: Record<Platform, string> = {
google_play: 'AtomsIconsLogoGoogle',
@@ -55,8 +58,8 @@ const isSingle = computed(() => props.type === 'single')
const supportedPlatforms = computed(
() =>
getSupportedPlatforms(
gameData.value?.platform_type,
gameData.value?.os_type
platformType.value,
osType.value
) as PlatformTransformType[]
)
const platformIcon = computed(() => PLATFORM_ICON_MAP[props.platform])
@@ -81,11 +84,7 @@ 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 withName = raw.replace(/%게임명%/g, highlight(gameName.value))
const platformLines = supportedPlatforms.value
.map(platform => highlight(formatSnakeToTitle(platform)))
.filter(Boolean)
@@ -105,7 +104,8 @@ const handleClick = () => {
}
if (props.platform === 'pc') {
if (device.isDesktop && gameData.value?.platform_type !== '2') {
if (device.isDesktop && platformType.value !== '2') {
// 디바이스 pc 환경이면서 모바일 스토어 전용이 아니면 런처 실행
validateLauncher()
return
} else {
@@ -122,14 +122,13 @@ const handleClick = () => {
return
}
const url = gameData.value?.market_json?.[target]?.url || ''
const url = marketJson.value?.[target]?.url ?? ''
window.open(url, '_blank')
return
}
}
const url = gameData.value?.market_json[props.platform]?.url || ''
const url = marketJson.value?.[props.platform]?.url ?? ''
if (url) window.open(url, '_blank')
}
</script>
@@ -158,6 +157,11 @@ const handleClick = () => {
<span class="text">
<slot />
</span>
<component
:is="props.iconComponent"
v-if="props.iconComponent"
v-bind="props.iconProps"
/>
<span
v-if="props.platform === 'pc' && props.type === 'default'"
class="icon-download"
@@ -170,27 +174,25 @@ const handleClick = () => {
<style scoped>
.btn-base {
@apply overflow-hidden inline-flex relative font-medium rounded-lg cursor-pointer
before:content-[''] before:absolute before:top-0 before:left-0 before:w-full before:h-full before:border before:border-white/10 before:rounded-lg
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 after:rounded-lg;
}
.btn-base:hover {
@apply after:opacity-20;
@apply overflow-hidden inline-flex relative font-medium rounded-lg cursor-pointer;
}
.btn-content {
@apply relative flex items-center w-full text-left z-[1];
@apply relative flex items-center w-full z-[1];
}
.icon-platform {
@apply w-5 h-5 flex-shrink-0;
}
.btn-base[data-variant='filled'] {
@apply bg-[#383838] text-[#ffffff];
@apply bg-[#383838] text-[#ffffff]
before:content-[''] before:absolute before:top-0 before:left-0 before:w-full before:h-full before:border before:border-white/10 before:rounded-lg
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 after:rounded-lg
hover:after:opacity-20;
}
.btn-base[data-variant='outlined'] {
@apply bg-white text-[#1F1F1F]
before:border-black/10
after:hidden;
before:content-[''] before:absolute before:top-0 before:left-0 before:w-full before:h-full before:border before:border-black/10 before:rounded-lg;
}
.btn-base[data-variant='outlined'][data-platform='app_store'] svg,
.btn-base[data-variant='outlined'][data-platform='pc'] svg,
@@ -200,25 +202,23 @@ const handleClick = () => {
/* default */
.btn-base.default {
@apply w-[296px] py-3.5 px-5
md:w-[356px] md:py-4 md:px-6;
}
.btn-base.default .text {
@apply pl-2 pr-4 line-clamp-2 text-[14px]
md:text-[16px];
}
.btn-base.default .icon-download {
@apply ml-auto pl-4;
@apply justify-center py-3.5 px-5
md:py-4 md:px-6;
}
.btn-base.default .btn-content {
@apply justify-center;
}
.btn-base.default[data-platform='pc'] .btn-content {
@apply justify-start;
.btn-base.default .text {
@apply line-clamp-2 text-[14px]
md:text-[16px];
}
.btn-base.default[data-platform='stove'] {
@apply bg-[#FC4420];
.btn-base.default .icon-platform + .text {
@apply pl-2;
}
.btn-base.default .icon-download {
@apply ml-auto pl-4;
}
.btn-base.default[data-variant='outlined'] .icon-download {
@apply border-black/10;
}
@@ -229,7 +229,7 @@ const handleClick = () => {
/* duplication */
.btn-base.duplication {
@apply bg-[16px_50%] bg-[length:auto_28px] bg-no-repeat backdrop-blur-[15px]
pt-[22px] pl-[47px] pr-[22px] pb-[7px] text-[11px]
pt-[25px] 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];
}
.btn-base.duplication[data-platform='google_play'] {
@@ -254,13 +254,17 @@ const handleClick = () => {
h-[40px] px-3.5
md:h-[48px];
}
.btn-base.single .btn-content {
@apply justify-center;
}
.btn-base.single.no-text {
@apply min-w-[40px] px-0 md:min-w-[48px];
}
.btn-base.single.no-text .icon-platform {
@apply mx-auto;
}
.btn-base.single .icon-platform {
@apply mr-1;
.btn-base[data-variant='outlined'] {
@apply hover:before:border-[#999];
}
</style>

View File

@@ -365,7 +365,7 @@ onMounted(() => {
>
<template #trigger>
<div
class="relative flex items-center justify-between w-full h-[40px] px-[16px] border border-solid border-[1px] border-[#D9D9D9] rounded-[8px] bg-white cursor-pointer"
class="relative flex items-center justify-between w-full h-[40px] px-[16px] border-solid border-[1px] border-[#D9D9D9] rounded-[8px] bg-white cursor-pointer"
>
<AtomsInput
:model-value="formatDate"

View File

@@ -99,7 +99,7 @@ const handlePagination = (page: number) => {
>
<AtomsButton
type="action"
button-size="size-small"
size="size-small"
background-color="transparent"
text-color="#333333"
:class="[

View File

@@ -3,12 +3,9 @@ let mountedInstance: any = null
onMounted(() => {
const gameDataStore = useGameDataStore()
const { stoveGnbJson, defaultLangCode, langCodes, theme } =
storeToRefs(gameDataStore)
const { gameData } = storeToRefs(gameDataStore)
const langCodes = gameData.value?.lang_codes
const defaultLangCode = gameData.value?.default_lang_code
const stoveGnbData = gameData.value?.stove_gnb_json
const designTheme = gameData.value?.design_theme
const currentDomain =
window.location.protocol + '//' + window.location.hostname
@@ -21,8 +18,8 @@ onMounted(() => {
mobile: '',
},
widget: {
notification: stoveGnbData?.notify_icon_visible ?? true,
stoveDownload: stoveGnbData?.stove_install_button_visible ?? true,
notification: stoveGnbJson.value?.notify_icon_visible ?? true,
stoveDownload: stoveGnbJson.value?.stove_install_button_visible ?? true,
languageSelect: false,
themeSelect: false,
stoveMenu: {
@@ -31,16 +28,16 @@ onMounted(() => {
},
},
global: {
languageCoverages: langCodes,
defaultSelectedLanguage: defaultLangCode ?? 'ko',
languageCoverages: langCodes.value,
defaultSelectedLanguage: defaultLangCode.value ?? 'ko',
},
loginMethod: {
redirectCurrentPage: true,
},
mode: {
theme: {
support: designTheme === 1 ? ['light'] : ['dark'],
default: designTheme === 1 ? 'light' : 'dark',
support: [theme.value],
default: theme.value,
},
mini: true,
layout: 'wide',

View File

@@ -12,16 +12,32 @@ const props = withDefaults(defineProps<Props>(), {
objectFit: 'contain',
})
const gameDataStore = useGameDataStore()
const { fontFamily } = storeToRefs(gameDataStore)
const imagePaths = computed(() => getResourceSrc(props.resourcesData))
const displayText = computed(() => props.resourcesData?.display?.text)
const displayColor = computed(() =>
getColorCodeFromData(props.resourcesData?.display, 'none')
)
// HTML 콘텐츠 정리 (줄바꿈 처리)
// HTML 콘텐츠 줄바꿈 처리
const sanitizedContent = computed(() => {
return displayText.value?.replace(/\n/g, '<br/>') || ''
})
// 텍스트 스타일
const textStyle = computed(() => {
const style: Record<string, string> = {
color: displayColor.value,
}
if (props.resourcesData?.display?.use_game_font === 1) {
style.fontFamily = fontFamily.value
}
return style
})
</script>
<template>
@@ -35,7 +51,7 @@ const sanitizedContent = computed(() => {
<span
v-else-if="isTypeText(resourcesData?.resource_type)"
v-dompurify-html="sanitizedContent"
:style="{ color: displayColor }"
:style="textStyle"
class="block"
/>
</template>

View File

@@ -42,11 +42,11 @@ const handleOutsideClick = () => {
></p>
<slot></slot>
<div class="content-btns">
<AtomsButtonVariant
<AtomsButtonModal
@click="setButtonEvent(() => emit('confirmButtonEvent'))"
>
{{ props.confirmButtonText || tm('Text_Confirm') }}
</AtomsButtonVariant>
</AtomsButtonModal>
</div>
</div>
</div>

View File

@@ -42,17 +42,17 @@ const handleOutsideClick = () => {
></p>
<slot></slot>
<div class="content-btns">
<AtomsButtonVariant
<AtomsButtonModal
variant="outlined"
@click="setButtonEvent(() => emit('cancelButtonEvent'))"
>
{{ props.cancelButtonText || tm('Text_Cancel') }}
</AtomsButtonVariant>
<AtomsButtonVariant
</AtomsButtonModal>
<AtomsButtonModal
@click="setButtonEvent(() => emit('confirmButtonEvent'))"
>
{{ props.confirmButtonText || tm('Text_Confirm') }}
</AtomsButtonVariant>
</AtomsButtonModal>
</div>
</div>
</div>

View File

@@ -374,7 +374,6 @@ onMounted(() => {
<div ref="startRef" class="btn-start">
<template v-if="start1depthData">
<BlocksButtonLauncher
type="custom"
platform="pc"
:background-color="
getColorCodeFromData(start1depthData?.btn_info, 'btn')
@@ -393,7 +392,8 @@ onMounted(() => {
<ul>
<li v-for="(item, key) in start2depthData" :key="key">
<BlocksButtonLauncher
type="custom"
type="single"
variant="custom"
:platform="key"
@click="sendLog(locale, item.tracking)"
>
@@ -573,25 +573,28 @@ onMounted(() => {
.btn-start:hover .nav-2depth {
@apply md:block;
}
.btn-start:deep(> .btn-base) {
.btn-start:deep(.btn-base[data-variant='filled']) {
@apply w-full h-[48px] px-10 font-[700] text-[16px];
}
.btn-start:deep(> .btn-base) .icon-platform {
.btn-start:deep(.btn-base[data-variant='filled']) svg {
@apply hidden;
}
.btn-start:deep(> .btn-base) .btn-content {
@apply justify-center;
}
.btn-start .nav-2depth {
@apply left-[unset] right-[-40px];
}
.btn-start .nav-2depth:deep(.btn-base) {
@apply w-full h-[48px] px-4 bg-transparent before:hidden after:hidden
@apply w-full h-[48px] px-4
hover:bg-theme-foreground-reversal-4 active:bg-theme-foreground-reversal-10;
}
.btn-start .nav-2depth:deep(.btn-base) .btn-content {
@apply justify-start;
}
.btn-start .nav-2depth:deep(.btn-base) .text {
@apply ml-1.5 text-[15px] text-theme-foreground-reversal;
@apply pl-1.5 text-[15px] text-theme-foreground-reversal;
}
.btn-start:deep(.nav-2depth .icon-download) {
@apply hidden;
}
[data-theme='light'] {

View File

@@ -7,9 +7,12 @@ import type { ButtonType } from '#layers/types/components/button'
interface Props {
resourcesData: PageDataResourceGroup[]
buttonSize?: string
}
const props = defineProps<Props>()
const props = withDefaults(defineProps<Props>(), {
buttonSize: 'size-extra-small md:size-medium',
})
const { locale, tm } = useI18n()
const device = useDevice()
@@ -119,7 +122,7 @@ const handleButtonClick = (button: PageDataResourceGroup) => {
<template>
<div
v-if="buttonList.length"
class="flex flex-wrap justify-center gap-3 md:gap-4"
class="flex flex-wrap justify-center items-center gap-3 md:gap-4"
>
<template v-for="(button, index) in buttonList" :key="index">
<template v-if="button.btn_info?.detail?.btn_type === 'RUN'">
@@ -138,6 +141,7 @@ const handleButtonClick = (button: PageDataResourceGroup) => {
<AtomsButton
v-else
:type="getButtonType(button.btn_info)"
:size="buttonSize"
:href="button.btn_info?.detail?.action?.url"
:target="button.btn_info?.detail?.action?.link_target"
:background-color="getColorCodeFromData(button.btn_info, 'btn')"

View File

@@ -22,9 +22,9 @@ const { tm } = useI18n()
class="text-info"
></p>
<AtomsButtonVariant class="max-w-[300px]" @click="downloadLauncher">
<AtomsButtonModal class="max-w-[300px]" @click="downloadLauncher">
{{ tm('Text_Download') }}
</AtomsButtonVariant>
</AtomsButtonModal>
<p
v-dompurify-html="tm('Alert_Client_Run_Normally')"
class="text-tip"

View File

@@ -333,7 +333,7 @@ defineExpose({
<div class="mt-auto px-5 pb-10 md:px-10 md:pb-12">
<AtomsButton
class="w-full"
button-size="size-small md:size-medium"
size="size-small md:size-medium"
:disabled="!canSubmit || isSubmitting"
@click="handleSubmit"
>

View File

@@ -115,7 +115,10 @@ const handleMove = (
<SplideTrack>
<slot />
</SplideTrack>
<BlocksSlideArrows v-if="props.arrows" :arrows-data="props.arrowsData" />
<BlocksButtonSlideArrows
v-if="props.arrows"
:arrows-data="props.arrowsData"
/>
</Splide>
</div>
</template>

View File

@@ -118,7 +118,10 @@ const handleMove = (
<SplideTrack>
<slot />
</SplideTrack>
<BlocksSlideArrows v-if="props.arrows" :arrows-data="props.arrowsData" />
<BlocksButtonSlideArrows
v-if="props.arrows"
:arrows-data="props.arrowsData"
/>
</Splide>
</div>
</template>

View File

@@ -98,6 +98,9 @@ const handleMove = (
<SplideTrack>
<slot />
</SplideTrack>
<BlocksSlideArrows v-if="props.arrows" :arrows-data="props.arrowsData" />
<BlocksButtonSlideArrows
v-if="props.arrows"
:arrows-data="props.arrowsData"
/>
</Splide>
</template>

View File

@@ -92,7 +92,7 @@ defineExpose({
<SplideTrack>
<slot />
</SplideTrack>
<BlocksSlideArrows
<BlocksButtonSlideArrows
v-if="props.arrows"
:arrows-data="props.arrowsData"
class="type-full"

View File

@@ -180,7 +180,10 @@ onBeforeUnmount(() => {
/>
</SplideSlide>
</SplideTrack>
<BlocksSlideArrows v-if="props.arrows" :arrows-data="props.arrowsData" />
<BlocksButtonSlideArrows
v-if="props.arrows"
:arrows-data="props.arrowsData"
/>
</Splide>
</div>
</template>

View File

@@ -6,7 +6,7 @@ export default defineNuxtRouteMiddleware(to => {
if (to.path.includes('/error')) return
// inspection 페이지는 실행X -----
if (to.path.includes('inspection')) return
if (to.path.includes('/inspection')) return
const gameDataStore = useGameDataStore()
const { langCodes, intro } = storeToRefs(gameDataStore)

View File

@@ -14,7 +14,7 @@ export default defineNuxtRouteMiddleware(async (to, _from) => {
if (to.path.includes('/error')) return
// inspection 페이지는 실행X -----
if (to.path.includes('inspection')) return
if (to.path.includes('/inspection')) return
const gameDataStore = useGameDataStore()
const pageDataStore = usePageDataStore()

View File

@@ -140,7 +140,6 @@ export default defineEventHandler(async event => {
}
const stoveApiServerBaseUrl = runtimeConfig.public.stoveApiUrlServer
const baseDomain = runtimeConfig.public.baseDomain
let gameDataResponse: GameDataResponse | null = null
let gameDataLangCodes: string[] | null = null
@@ -182,7 +181,10 @@ export default defineEventHandler(async event => {
// 1-1. 정적 파일 패스
if (isStaticFile(event.path)) return
// 1-2. 특정 경로 패스 (API, 리소스)
// 1-2. /inspection 패스
if (fullPath.includes('/inspection')) return
// 1-3. 특정 경로 패스 (API, 리소스)
if (shouldSkipPath(fullPath)) return
// 캐시 키 생성 (게임 ID 포함하여 충돌 방지)

View File

@@ -6,17 +6,22 @@ export const useGameDataStore = defineStore('gameData', () => {
gameId: null as GameDataValue['game_id'] | null,
gameCode: null as GameDataValue['game_code'] | null,
gameName: null as GameDataValue['game_name'] | null,
stoveGnbJson: null as GameDataValue['stove_gnb_json'] | null,
langCodes: null as GameDataValue['lang_codes'] | null,
defaultLangCode: null as GameDataValue['default_lang_code'] | null,
gaCode: null as GameDataValue['ga_code'] | null,
platformType: null as GameDataValue['platform_type'] | null,
osType: null as GameDataValue['os_type'] | null,
theme: null as 'light' | 'dark' | null,
intro: null as GameDataValue['intro'] | null,
imgJson: null as GameDataValue['img_json'] | null,
snsJson: null as GameDataValue['sns_json'] | null,
urlJson: null as GameDataValue['url_json'] | null,
marketJson: null as GameDataValue['market_json'] | null,
fontFamily: null as GameDataValue['game_font']['font_family'] | null,
gnb: null as GameDataValue['gnb'] | null,
eventBanner: null as GameDataValue['event_banner'] | null,
fontFamily: null as GameDataValue['game_font']['font_family'] | null,
})
const state = reactive(getInitialState())
@@ -26,17 +31,22 @@ export const useGameDataStore = defineStore('gameData', () => {
state.gameId = data?.game_id
state.gameCode = data?.game_code
state.gameName = data?.game_name
state.stoveGnbJson = data?.stove_gnb_json
state.langCodes = data?.lang_codes
state.defaultLangCode = data?.default_lang_code
state.gaCode = data?.ga_code
state.platformType = data?.platform_type
state.osType = data?.os_type
state.theme = data?.design_theme === 1 ? 'light' : 'dark'
state.intro = data?.intro
state.imgJson = data?.img_json
state.snsJson = data?.sns_json
state.urlJson = data?.url_json
state.marketJson = data?.market_json
state.fontFamily = data?.game_font?.font_family
state.gnb = data?.gnb
state.eventBanner = data?.event_banner
state.fontFamily = data?.game_font?.font_family
}
const clearGameData = () => {

View File

@@ -530,7 +530,7 @@ onMounted(async () => {
/>
<AtomsButton
type="action"
button-size="size-small"
size="size-small"
background-color="#383838"
text-color="#FFFFFF"
class="relative flex items-center justify-center w-full gap-[4px] px-0 sm:w-[143px] sm:shrink-0 md:h-[56px] md:text-[16px] md:leading-[24px] md:tracking-[-0.48px]"
@@ -575,7 +575,7 @@ onMounted(async () => {
<template v-for="month in monthSelectList" :key="month">
<AtomsButton
type="action"
button-size="size-small"
size="size-small"
background-color="#FAFAFA"
text-color="#CCCCCC"
:class="[
@@ -617,7 +617,7 @@ onMounted(async () => {
</div>
<AtomsButton
type="action"
button-size="size-small"
size="size-small"
background-color="#383838"
text-color="#FFFFFF"
class="shrink-0 w-[40px] h-[40px] p-0 md:w-auto md:px-[22px]"
@@ -720,7 +720,7 @@ onMounted(async () => {
>
<AtomsButton
type="action"
button-size="size-small"
size="size-small"
background-color="transparent"
text-color="transparent"
class="coupon-item coupon-item-use"
@@ -772,10 +772,10 @@ onMounted(async () => {
<ClientOnly>
<Teleport to="body">
<BlocksModalLayer
:is-open="isSelectCharacterModalOpen"
:is-show-dimmed="true"
:is-outside-close="true"
modal-name="modal-coupon-character-select"
:is-open="isSelectCharacterModalOpen"
area-class="max-w-[480px] p-6 bg-white rounded-[20px]"
close-class="hidden"
>
@@ -797,20 +797,20 @@ onMounted(async () => {
<div
class="relative flex items-center justify-center gap-[8px] w-full"
>
<AtomsButtonVariant
<AtomsButtonModal
variant="outlined"
class="max-w-[128px]"
@click="closeSelectCharacterModal"
>
{{ tm('Text_Cancel') }}
</AtomsButtonVariant>
<AtomsButtonVariant
</AtomsButtonModal>
<AtomsButtonModal
:disabled="isSelectCharacter ? false : true"
class="max-w-[128px]"
@click="handleCouponRegister"
>
{{ tm('Text_Confirm') }}
</AtomsButtonVariant>
</AtomsButtonModal>
</div>
</div>
</BlocksModalLayer>

View File

@@ -228,7 +228,7 @@ const handleMoveFocus = (target: 'pc' | 'mobile') => {
<BlocksButtonLauncher
v-else-if="breakpoints.isMd || breakpoints.isDesktop"
platform="pc"
class="!w-full !max-w-[300px]"
class="w-[300px]"
@click="
handleSendLog(
t('Download_Button_PC_Download', {}, { locale: 'ko' })
@@ -310,7 +310,7 @@ const handleMoveFocus = (target: 'pc' | 'mobile') => {
: true
"
:platform="`${os.platformCode as Platform}`"
class="!w-full"
class="w-full"
@click="handleSendLog(formatSnakeToTitle(os.platformCode))"
>
<span>{{ os.platformText }}</span>
@@ -384,7 +384,7 @@ const handleMoveFocus = (target: 'pc' | 'mobile') => {
</ul>
<AtomsButton
type="action"
button-size="size-small"
size="size-small"
background-color="#383838"
text-color="#FFFFFF"
class="shrink-0 w-[206px] px-0 text-[16px]"
@@ -445,7 +445,7 @@ const handleMoveFocus = (target: 'pc' | 'mobile') => {
<AtomsButton
type="link"
button-size="size-small"
size="size-small"
background-color="#383838"
text-color="#FFFFFF"
class="w-full px-0"

View File

@@ -337,7 +337,7 @@ onMounted(() => {
<AtomsButton
v-if="card.status === 'N'"
type="external"
button-size="size-small md:size-large"
size="size-small md:size-medium"
background-color="#383838"
text-color="#FFFFFF"
@click="handleClickSetup(card)"
@@ -347,7 +347,7 @@ onMounted(() => {
<AtomsButton
v-else
type="action"
button-size="size-small md:size-large"
size="size-small md:size-medium"
background-color="#EBEBEB"
text-color="#999999"
disabled

View File

@@ -195,7 +195,8 @@ const handleLoadMoreRecent = () => {
]"
/>
<AtomsIconsPlayRoundFill
class="drop-shadow-[0_0_6px_rgba(0,0,0,0.25)] absolute bottom-[14px] right-[14px] w-[20px] h-[20px] sm:bottom-[18px] sm:right-[18px] md:bottom-[23px] md:right-[23px] md:w-[33px] md:h-[33px]"
:size="breakpoints.isMobile ? 24 : 40"
class="drop-shadow-[0_0_6px_rgba(0,0,0,0.25)] absolute bottom-[12px] right-[12px] sm:bottom-[16px] sm:right-[16px] md:bottom-[16px] md:right-[16px] lg:bottom-[16px] lg:right-[16px]"
/>
</div>
<div
@@ -247,7 +248,8 @@ const handleLoadMoreRecent = () => {
class="w-full h-full object-cover group-hover:scale-110 transition-transform duration-300"
/>
<AtomsIconsPlayRoundFill
class="drop-shadow-[0_0_6px_rgba(0,0,0,0.25)] absolute bottom-[14px] right-[14px] w-[20px] h-[20px]"
size="24"
class="drop-shadow-[0_0_6px_rgba(0,0,0,0.25)] absolute bottom-[12px] right-[12px]"
/>
</div>
<div class="p-2 pt-5 md:p-3 md:pt-5">
@@ -268,7 +270,7 @@ const handleLoadMoreRecent = () => {
<div v-if="hasMore" class="mt-[40px] flex justify-center md:mt-[80px]">
<AtomsButton
type="action"
button-size="size-small md:size-medium"
size="size-small md:size-medium"
background-color="#383838"
text-color="#FFFFFF"
@click="handleLoadMoreRecent"

View File

@@ -57,6 +57,7 @@ const buttonListData = computed(() => {
<WidgetsButtonList
v-if="buttonListData"
:resources-data="buttonListData"
button-size="size-small md:size-large"
class="mt-[56px]"
/>
<WidgetsDescription

View File

@@ -72,8 +72,7 @@ export interface GameDataKeyColors {
// 게임 폰트 타입
export interface GameDataGameFont {
font_family: string
font_weight: string
font_style: string
font_path: string
}
// 파비콘 경로 타입

View File

@@ -87,6 +87,7 @@ export interface PageDataResourceGroupBtnInfo extends ColorObject {
disabled: boolean
txt_btn_name: string
detail: Record<string, any>
use_game_font: 0 | 1
}
// 리소스 그룹 타입
@@ -94,6 +95,7 @@ export interface PageDataResourceGroupDisplay extends ColorObject {
text?: string
color_code?: string
color_name?: string
use_game_font: 0 | 1
}
export interface PageDataResourceGroup {

View File

@@ -5,10 +5,10 @@ export type ButtonType =
| 'action'
| 'link'
export type DownloadButtonType = 'default' | 'single' | 'duplication' | 'custom'
export type DownloadButtonType = 'default' | 'single' | 'duplication'
export type ButtonSize = 'large' | 'medium' | 'small' | 'extra-small'
export type ButtonVariant = 'filled' | 'outlined'
export type ButtonVariant = 'filled' | 'outlined' | 'custom'
export type Platform = 'google_play' | 'app_store' | 'pc' | 'stove'