Merge branch 'feature/202501107-all' into feature/20251001-gil

This commit is contained in:
“hyeonggkim”
2025-11-03 13:07:45 +09:00
14 changed files with 270 additions and 292 deletions

View File

@@ -13,7 +13,7 @@
@apply relative pt-[32px] pb-[80px] px-[20px] sm:px-[40px] md:pt-[64px] md:pb-[200px] bg-[#F0F0F0];
}
.section-static {
@apply mx-auto max-w-[684px] md:max-w-[944px] lg:max-w-[1300px];
@apply mx-auto lg:max-w-[1300px];
}
.section-static + .section-static {
@apply mt-[80px] md:mt-[100px];

View File

@@ -3,10 +3,9 @@ import type { CSSProperties } from 'vue'
import type {
DownloadButtonType,
ButtonVariant,
Platform,
} from '#layers/types/components/button'
type Platform = 'google_play' | 'app_store' | 'pc' | 'stove'
interface Props {
platform: Platform
type?: DownloadButtonType

View File

@@ -86,7 +86,6 @@ const handleMove = (
<template>
<Splide
:options="options"
class="w-full"
:style="getPaginationClass(props?.paginationData)"
@splide:mounted="handleSplideMounted"
@splide:move="handleMove"

View File

@@ -35,11 +35,13 @@ const componentProps = computed(() => {
rel: 'noopener noreferrer',
}
}
return {}
})
</script>
<template>
<div class="flex flex-wrap items-end justify-between">
<div class="flex flex-wrap items-end justify-between mb-[16px] md:mb-[24px]">
<h3
class="text-[#1F1F1F] text-[18px] font-bold leading-[26px] tracking-[-0.54px] md:text-[24px] md:leading-[34px] md:tracking-[0.72px]"
>

View File

@@ -9,6 +9,7 @@ import GrDetail02 from '#layers/templates/GrDetail02/index.vue'
import GrDetail03 from '#layers/templates/GrDetail03/index.vue'
import GrBoard01 from '#layers/templates/GrBoard01/index.vue'
import GrContents01 from '#layers/templates/GrContents01/index.vue'
import FxVideo01 from '#layers/templates/FxVideo01/index.vue'
import FxDownload01 from '#layers/templates/FxDownload01/index.vue'
const templateRegistry = {
@@ -23,6 +24,7 @@ const templateRegistry = {
GR_DETAIL_02: { component: GrDetail02 },
GR_DETAIL_03: { component: GrDetail03 },
GR_CONTENTS_01: { component: GrContents01 },
FX_VIDEO_01: { component: FxVideo01 },
FX_DOWNLOAD_01: { component: FxDownload01 },
} as const

View File

@@ -2,9 +2,7 @@
import { SplideSlide } from '@splidejs/vue-splide'
import { getComponentGroup, getComponentGroupAry } from '#layers/utils/dataUtil'
import type { PageDataTemplateComponents } from '#layers/types/api/pageData'
// Types
type Platform = 'google_play' | 'app_store' | 'pc' | 'stove'
import type { Platform } from '#layers/types/components/button'
// Props
interface Props {
@@ -15,14 +13,12 @@ const props = defineProps<Props>()
// Configuration
const runtimeConfig = useRuntimeConfig()
const runType = runtimeConfig.public.runType
const staticUrl = runtimeConfig.public.staticUrl
const multilingualBaseApiUrl = `${staticUrl}/${runType}/test`
const dataResourcesUrl = runtimeConfig.public.dataResourcesUrl
const multilingualFileName = 'test_homepage_brand_download.json'
// Multilingual
const resultGetMultilingual = await useGetMultilingual({
baseApiUrl: multilingualBaseApiUrl,
baseApiUrl: dataResourcesUrl,
fileName: multilingualFileName,
})
const { tm, locale }: any = useI18n({
@@ -136,313 +132,283 @@ const handleMoveFocus = (target: 'pc' | 'mobile') => {
<template>
<WidgetsFixMainTitle
:title="tm('Download_Page_Title')"
:resourcesData="backgroundData"
:resources-data="backgroundData"
/>
<div
class="overflow-hidden h-auto pt-[32px] px-[20px] pb-[80px] bg-[#F0F0F0] sm:px-[40px] md:pt-[64px] md:pb-[200px]"
>
<section class="relative flex flex-col items-center justify-start w-full">
<div class="w-full max-w-full md:max-w-[1300px]">
<WidgetsFixSubTitle :title="tm('Download_Section_Platform_Title')" />
<div class="section-container static">
<section class="section-static">
<WidgetsFixSubTitle :title="tm('Download_Section_Platform_Title')" />
<BlocksSlideDefault
:per-page="platformList.length"
:gap="20"
:arrows="false"
:pagination="false"
:drag="false"
:breakpoints="{
1023: {
autoWidth: true,
perPage: 'auto',
gap: 12,
focus: 0,
drag: true,
padding: { left: 0, right: 0 },
},
}"
class="w-[calc(100%+40px)] px-[20px] ml-[-20px] mt-[16px] sm:w-[calc(100%+80px)] sm:px-[40px] sm:ml-[-40px] md:w-full md:px-0 md:mt-[24px] md:ml-0"
<BlocksSlideDefault
:per-page="platformList.length"
:gap="20"
:arrows="false"
:pagination="false"
:drag="false"
:breakpoints="{
1023: {
perPage: 'auto',
gap: 12,
focus: 0,
drag: true,
padding: { left: 0, right: 0 },
},
}"
class="overflow-hidden min-w-[320px] w-[100vw] px-[20px] ml-[-20px] sm:px-[40px] sm:ml-[-40px] md:w-full md:px-0 md:ml-0"
>
<SplideSlide
v-for="platform in platformList"
:key="platform"
class="flex flex-col items-center justify-between shrink-0 whitespace-normal w-[295px] h-[280px] bg-[#FFFFFF] p-[20px] rounded-[12px] text-left md:w-[calc((100%-40px)/3)] md:h-[314px] md:p-[24px] md:rounded-[16px] lg:w-[420px] lg:h-[340px] lg:p-[32px]"
>
<SplideSlide
v-for="platform in platformList"
:key="platform"
class="flex flex-col items-center justify-between shrink-0 whitespace-normal w-[295px] h-[280px] bg-[#FFFFFF] p-[20px] rounded-[12px] text-left md:w-[calc((100%-40px)/3)] md:h-[314px] md:p-[24px] md:rounded-[16px] lg:w-[420px] lg:h-[340px] lg:p-[32px]"
<div
class="flex flex-col items-start justify-start gap-[8px] w-full md:gap-[12px]"
>
<div
class="flex flex-col items-start justify-start gap-[8px] w-full md:gap-[12px]"
<WidgetsFixSubTitle :title="tm(`Download_Box_${platform}_Title`)" />
<p
v-if="
tm(`Download_Box_${platform}_Description_List`).length === 1
"
v-dompurify-html="tm(`Download_Box_${platform}_Description01`)"
class="text-[#999999] text-[14px] font-[400] leading-[24px] tracking-[-0.42px] md:text-[15px] md:tracking-[-0.45px]"
></p>
<ul
v-else-if="
tm(`Download_Box_${platform}_Description_List`).length > 1
"
>
<WidgetsFixSubTitle
:title="tm(`Download_Box_${platform}_Title`)"
<li
v-for="description in tm(
`Download_Box_${platform}_Description_List`
)"
:key="description"
v-dompurify-html="tm(description)"
class="relative pl-[22px] before:content-[''] before:absolute before:top-[10px] before:left-[9px] before:w-[3px] before:h-[3px] before:rounded-full before:bg-[#999999] text-[#999999] text-[14px] font-[400] leading-[24px] tracking-[-0.42px] md:text-[15px] md:tracking-[-0.45px]"
></li>
</ul>
<AtomsButton
v-if="platform !== 'STOVE'"
type="action"
button-size="size-small"
background-color="transparent"
text-color="#1F1F1F"
class="relative w-auto h-auto px-0 text-[16px] font-[500] leading-[24px] tracking-[-0.48px] before:content-[''] before:absolute before:z-[2] before:top-p before:left-0 before:w-full before:h-full before:bg-[#FFFFFF] before:transition-opacity before:duration-300 before:ease-in-out before:opacity-0 hover:before:opacity-20"
@click="
handleMoveFocus(platform.toLowerCase() as 'pc' | 'mobile')
"
>
<span>{{ tm(`Download_Box_${platform}_SpecCheck`) }}</span>
<AtomsIconsLongArrowRightLine
:size="20"
color="#1F1F1F"
class="relative rotate-90"
/>
</AtomsButton>
</div>
<p
v-if="
tm(`Download_Box_${platform}_Description_List`).length === 1
"
v-dompurify-html="tm(`Download_Box_${platform}_Description01`)"
class="text-[#999999] text-[14px] font-[400] leading-[24px] tracking-[-0.42px] md:text-[15px] md:tracking-[-0.45px]"
></p>
<ul
v-else-if="
tm(`Download_Box_${platform}_Description_List`).length > 1
"
>
<li
v-for="description in tm(
`Download_Box_${platform}_Description_List`
)"
:key="description"
v-dompurify-html="tm(description)"
class="relative pl-[22px] before:content-[''] before:absolute before:top-[10px] before:left-[9px] before:w-[3px] before:h-[3px] before:rounded-full before:bg-[#999999] text-[#999999] text-[14px] font-[400] leading-[24px] tracking-[-0.42px] md:text-[15px] md:tracking-[-0.45px]"
></li>
</ul>
<AtomsButton
v-if="platform !== 'STOVE'"
type="action"
button-size="size-small"
background-color="transparent"
text-color="#1F1F1F"
class="relative w-auto h-auto px-0 text-[16px] font-[500] leading-[24px] tracking-[-0.48px] before:content-[''] before:absolute before:z-[2] before:top-p before:left-0 before:w-full before:h-full before:bg-[#FFFFFF] before:transition-opacity before:duration-300 before:ease-in-out before:opacity-0 hover:before:opacity-20"
@click="
handleMoveFocus(platform.toLowerCase() as 'pc' | 'mobile')
"
>
<span>{{ tm(`Download_Box_${platform}_SpecCheck`) }}</span>
<AtomsIconsLongArrowRightLine
:size="20"
color="#1F1F1F"
class="relative rotate-90"
/>
</AtomsButton>
</div>
<div
class="flex flex-col items-center justify-center gap-[8px] w-full md:gap-[12px]"
>
<template v-if="platform === 'MOBILE'">
<template v-for="os in mobileOSList" :key="os.id">
<AtomsButtonLauncher
v-if="device.isMobile ? os.isValue : true"
:platform="`${os.platformCode as Platform}`"
class="!w-full"
>
<span>{{ os.platformText }}</span>
</AtomsButtonLauncher>
</template>
</template>
<template v-else>
<AtomsButton
v-if="breakpoints.isMobile"
type="action"
button-size="size-small"
background-color="#EBEBEB"
text-color="#999999"
:disabled="true"
class="w-full px-0 border border-solid border-[rgba(0,0,0,0.1)] cursor-default"
>
<span>{{ tm(`Download_Button_${platform}_Mobile`) }}</span>
</AtomsButton>
<div
class="flex flex-col items-center justify-center gap-[8px] w-full md:gap-[12px]"
>
<template v-if="platform === 'MOBILE'">
<template v-for="os in mobileOSList" :key="os.id">
<AtomsButtonLauncher
v-else-if="breakpoints.isMd || breakpoints.isDesktop"
:platform="`${platform.toLowerCase() as Platform}`"
v-if="device.isMobile ? os.isValue : true"
:platform="`${os.platformCode as Platform}`"
class="!w-full"
>
<span>{{ tm(`Download_Button_${platform}`) }}</span>
<span>{{ os.platformText }}</span>
</AtomsButtonLauncher>
</template>
</div>
</SplideSlide>
</BlocksSlideDefault>
</template>
<template v-else>
<AtomsButton
v-if="breakpoints.isMobile"
type="action"
button-size="size-small"
background-color="#EBEBEB"
text-color="#999999"
:disabled="true"
class="w-full px-0 border border-solid border-[rgba(0,0,0,0.1)] cursor-default"
>
<span>{{ tm(`Download_Button_${platform}_Mobile`) }}</span>
</AtomsButton>
<AtomsButtonLauncher
v-else-if="breakpoints.isMd || breakpoints.isDesktop"
:platform="`${platform.toLowerCase() as Platform}`"
class="!w-full"
>
<span>{{ tm(`Download_Button_${platform}`) }}</span>
</AtomsButtonLauncher>
</template>
</div>
</SplideSlide>
</BlocksSlideDefault>
</section>
<section ref="specPCRef" class="section-static">
<WidgetsFixSubTitle :title="tm('Download_Section_PC_Title')" />
<table>
<thead>
<tr>
<th class="w-[80px] md:w-[172px]">
{{ tm('Download_Table_Item') }}
</th>
<th>{{ tm('Download_Table_Min_Spec') }}</th>
<th>{{ tm('Download_Table_Rec_Spec') }}</th>
</tr>
</thead>
<tbody>
<template v-for="tr in pcSpecList" :key="tr.id">
<tr>
<th class="w-[80px] md:w-[172px]">{{ tr.itemText }}</th>
<template v-for="td in tr.itemData" :key="td.display.text">
<td>{{ td.display.text }}</td>
</template>
</tr>
</template>
</tbody>
</table>
<div
v-if="!breakpoints.isMobile"
class="relative flex items-end justify-between w-full mt-[24px] gap-[24px]"
>
<ul
v-if="tm('Download_Section_PC_Notice_List').length > 0"
class="relative flex flex-col items-center justify-start w-full"
>
<template
v-for="notice in tm('Download_Section_PC_Notice_List')"
:key="notice"
>
<li
v-dompurify-html="tm(notice)"
class="relative w-full pl-[26px] text-left text-[#666666] text-[16px] font-[400] leading-[26px] tracking-[-0.48px] before:content-[''] before:absolute before:top-[11px] before:left-[10px] before:w-[4px] before:h-[4px] before:bg-[#666666] before:rounded-full"
></li>
</template>
</ul>
<AtomsButton
type="action"
button-size="size-small"
background-color="#383838"
text-color="#FFFFFF"
class="shrink-0 w-[206px] px-0 text-[16px]"
@click="
checkPCSpec({
schemeFormat: schemeFormatData,
setupUrl: setupUrlData,
gameNo: gameData?.game_code?.toString(),
locale: locale as string,
})
"
>
<em
class="inline-flex items-center justify-center gap-[8px] not-italic"
>
<span
class="relative inline-flex items-center justify-center w-[20px] h-[20px]"
>
<img
:src="
getImageHost(
'/images/common/ic-v2-hardware-desktop-line.svg',
{ imageType: 'common' }
)
"
alt="Desktop-Icon"
loading="lazy"
draggable="false"
class="w-full object-contain"
/>
</span>
<span>{{ tm('Download_Button_SpecCheck') }}</span>
</em>
</AtomsButton>
</div>
</section>
<section
ref="specPCRef"
class="relative flex flex-col items-center justify-start w-full mt-[80px] md:mt-[100px]"
>
<div class="w-full max-w-full md:max-w-[1300px]">
<WidgetsFixSubTitle :title="tm('Download_Section_PC_Title')" />
<div class="mt-[16px] md:mt-[24px]">
<table>
<thead>
<tr>
<th class="w-[80px] md:w-[172px]">
{{ tm('Download_Table_Item') }}
</th>
<th>{{ tm('Download_Table_Min_Spec') }}</th>
<th>{{ tm('Download_Table_Rec_Spec') }}</th>
</tr>
</thead>
<tbody>
<template v-for="tr in pcSpecList" :key="tr.id">
<tr>
<th class="w-[80px] md:w-[172px]">{{ tr.itemText }}</th>
<template v-for="td in tr.itemData" :key="td.display.text">
<td>{{ td.display.text }}</td>
</template>
</tr>
</template>
</tbody>
</table>
</div>
<div
v-if="!breakpoints.isMobile"
class="relative flex items-end justify-between w-full mt-[24px] gap-[24px]"
>
<ul
v-if="tm('Download_Section_PC_Notice_List').length > 0"
class="relative flex flex-col items-center justify-start w-full"
>
<template
v-for="notice in tm('Download_Section_PC_Notice_List')"
:key="notice"
<section v-if="!breakpoints.isMobile" class="section-static">
<WidgetsFixSubTitle :title="tm('Download_Section_Driver_Title')" />
<ul class="flex items-center justify-between gap-[20px] w-full">
<template v-for="driver in driverList" :key="driver.id">
<li class="w-full h-[250px]">
<div
class="flex flex-col items-center justify-between gap-[16px] h-[250px] rounded-[16px] p-[20px] bg-[#FFFFFF]"
>
<li
v-dompurify-html="tm(notice)"
class="relative w-full pl-[26px] text-left text-[#666666] text-[16px] font-[400] leading-[26px] tracking-[-0.48px] before:content-[''] before:absolute before:top-[11px] before:left-[10px] before:w-[4px] before:h-[4px] before:bg-[#666666] before:rounded-full"
></li>
</template>
</ul>
<AtomsButton
type="action"
button-size="size-small"
background-color="#383838"
text-color="#FFFFFF"
class="shrink-0 w-[206px] px-0 text-[16px]"
@click="
checkPCSpec({
schemeFormat: schemeFormatData,
setupUrl: setupUrlData,
gameNo: gameData?.game_code?.toString(),
locale: locale as string,
})
"
>
<em
class="inline-flex items-center justify-center gap-[8px] not-italic"
>
<span
class="relative inline-flex items-center justify-center w-[20px] h-[20px]"
>
<div class="flex items-center justify-center w-full">
<img
:src="
getImageHost(
'/images/common/ic-v2-hardware-desktop-line.svg',
`/images/common/grades_driver/Type-${driver.driverCode}.svg`,
{ imageType: 'common' }
)
"
alt="Desktop-Icon"
:alt="driver.driverText"
loading="lazy"
draggable="false"
class="w-full object-contain"
/>
</span>
<span>{{ tm('Download_Button_SpecCheck') }}</span>
</em>
</AtomsButton>
</div>
</div>
</section>
</div>
<section
v-if="!breakpoints.isMobile"
class="relative flex flex-col items-center justify-start w-full mt-[80px] md:mt-[100px]"
>
<div class="w-full max-w-full md:max-w-[1300px]">
<WidgetsFixSubTitle :title="tm('Download_Section_Driver_Title')" />
<div class="mt-[16px] md:mt-[24px]">
<ul class="flex items-center justify-between gap-[20px] w-full">
<template v-for="driver in driverList" :key="driver.id">
<li class="w-full h-[250px]">
<div
class="flex flex-col items-center justify-between gap-[16px] h-[250px] rounded-[16px] p-[20px] bg-[#FFFFFF]"
<div
class="flex flex-col items-start justify-end gap-[16px] w-full"
>
<p
class="text-left text-[#666666] text-[16px] font-[400] leading-[26px] tracking-[-0.48px]"
>
<div class="flex items-center justify-center w-full">
<img
:src="
getImageHost(
`/images/common/grades_driver/Type-${driver.driverCode}.svg`,
{ imageType: 'common' }
)
"
:alt="driver.driverText"
loading="lazy"
draggable="false"
/>
</div>
{{ driver.driverText }}
</p>
<div
class="flex flex-col items-start justify-end gap-[16px] w-full"
>
<p
class="text-left text-[#666666] text-[16px] font-[400] leading-[26px] tracking-[-0.48px]"
>
{{ driver.driverText }}
</p>
<AtomsButton
type="download"
button-size="size-small"
background-color="#383838"
text-color="#FFFFFF"
class="w-full px-0"
target="_blank"
rel="noopener noreferrer"
:href="tm(`Download_Driver_${driver.driverCode}_Url`)"
>
<span>{{ tm('Download_Button_Download') }}</span>
</AtomsButton>
</div>
</div>
</li>
</template>
</ul>
</div>
</div>
<AtomsButton
type="download"
button-size="size-small"
background-color="#383838"
text-color="#FFFFFF"
class="w-full px-0"
target="_blank"
rel="noopener noreferrer"
:href="tm(`Download_Driver_${driver.driverCode}_Url`)"
>
<span>{{ tm('Download_Button_Download') }}</span>
</AtomsButton>
</div>
</div>
</li>
</template>
</ul>
</section>
<section
ref="specMobileRef"
class="relative flex flex-col items-center justify-start w-full mt-[80px] md:mt-[100px]"
>
<div class="w-full max-w-full md:max-w-[1300px]">
<WidgetsFixSubTitle :title="tm('Download_Section_MOBILE_Title')" />
<div class="mt-[16px] md:mt-[24px]">
<table>
<thead>
<tr>
<th rowspan="2" class="w-[80px] md:w-[172px]">
{{ tm('Download_Table_Item') }}
</th>
<th colspan="2">{{ tm('Download_Table_Min_Spec') }}</th>
<th colspan="2">{{ tm('Download_Table_Rec_Spec') }}</th>
</tr>
<tr>
<th>{{ tm('Download_Table_Device') }}</th>
<th>{{ tm('Download_Table_Os') }}</th>
<th>{{ tm('Download_Table_Device') }}</th>
<th>{{ tm('Download_Table_Os') }}</th>
</tr>
</thead>
<tbody>
<template v-for="tr in mobileSpecList" :key="tr.id">
<tr>
<th class="w-[80px] md:w-[172px]">{{ tr.itemText }}</th>
<template v-for="td in tr.itemData" :key="td.display.text">
<td>{{ td.display.text }}</td>
</template>
</tr>
<section ref="specMobileRef" class="section-static">
<WidgetsFixSubTitle :title="tm('Download_Section_MOBILE_Title')" />
<table>
<thead>
<tr>
<th rowspan="2" class="w-[80px] md:w-[172px]">
{{ tm('Download_Table_Item') }}
</th>
<th colspan="2">{{ tm('Download_Table_Min_Spec') }}</th>
<th colspan="2">{{ tm('Download_Table_Rec_Spec') }}</th>
</tr>
<tr>
<th>{{ tm('Download_Table_Device') }}</th>
<th>{{ tm('Download_Table_Os') }}</th>
<th>{{ tm('Download_Table_Device') }}</th>
<th>{{ tm('Download_Table_Os') }}</th>
</tr>
</thead>
<tbody>
<template v-for="tr in mobileSpecList" :key="tr.id">
<tr>
<th class="w-[80px] md:w-[172px]">{{ tr.itemText }}</th>
<template v-for="td in tr.itemData" :key="td.display.text">
<td>{{ td.display.text }}</td>
</template>
</tbody>
</table>
</div>
</div>
</tr>
</template>
</tbody>
</table>
</section>
</div>
</template>

View File

@@ -118,7 +118,7 @@ const onArrowClick = (direction, targetIndex) => {
v-if="slideLength > 0"
:slide-item-length="slideLength"
v-bind="splideOptions"
:class="slideClass"
:class="`${slideClass} w-full`"
@arrow-click="onArrowClick"
>
<SplideSlide

View File

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

View File

@@ -24,8 +24,8 @@ export const getImageHost = (
if (/^(https?:\/\/|www\.)/.test(path)) return path
const config = useRuntimeConfig()
const { staticUrl, assetsUrl } = config.public
const { imageType = 'game' } = options
const { staticUrl, runType } = config.public
const isDevelopment = process.env.NODE_ENV === 'development'
const isCommon = imageType === 'common'
@@ -39,9 +39,7 @@ export const getImageHost = (
if (isDevelopment) return path
// 공통/게임 여부에 따른 경로 결정
const basePath = isCommon
? `${staticUrl}/${runType}/templates/brand`
: staticUrl
const basePath = isCommon ? assetsUrl : staticUrl
return `${basePath}${path}`
}