feat: 다운로드페이지-플랫폼 및 OS타입별 추가

This commit is contained in:
최만억 (Jo)
2025-11-24 07:29:11 +00:00
committed by 김채린
parent 2a2631d3bc
commit cc5db808b2
4 changed files with 589 additions and 84 deletions

View File

@@ -0,0 +1,422 @@
<script setup lang="ts">
interface Props {
type?: 'click' | 'hover'
position?:
| 'top'
| 'bottom'
| 'left'
| 'right'
| 'top-left'
| 'top-right'
| 'bottom-left'
| 'bottom-right'
offset?: number
backgroundColor?: string
textColor?: string
textAlign?: string
fontSize?: string
fontWeight?: string
lineHeight?: string
letterSpacing?: string
arrow?: boolean
teleport?: boolean
content?: string
}
const props = withDefaults(defineProps<Props>(), {
type: 'click',
position: 'top',
offset: 8,
arrow: true,
teleport: false,
backgroundColor: '#666666',
textColor: '#FFFFFF',
textAlign: 'center',
fontSize: '12px',
fontWeight: '400',
lineHeight: '18px',
letterSpacing: '-0.24px',
})
const isOpen = defineModel<boolean>('isOpen', { default: false })
const isLeftAligned = ref(false) // 브라우저 화면 기준으로 툴팁의 왼쪽 가장자리가 화면 밖으로 나가는 경우 좌측 정렬을 합니다.
const isRightAligned = ref(false) // 브라우저 화면 기준으로 툴팁의 오른쪽 가장자리가 화면 밖으로 나가는 경우 우측 정렬을 합니다.
const tooltipOffsetX = ref(18) // 툴팁 오프셋 X 값
const tooltipArrowOffsetX = ref(26) // 툴팁 화살표 오프셋 X 값
const tooltipPosition = ref({
// 툴팁 위치 값
top: null,
bottom: null,
left: null,
right: null,
})
const tooltipTriggerRef = ref<HTMLElement | null>(null)
const isPositions = computed(() => {
return {
isTop:
props.position === 'top' && !isLeftAligned.value && !isRightAligned.value,
isTopLeft:
props.position === 'top-left' ||
(props.position === 'top' && isRightAligned.value),
isTopRight:
props.position === 'top-right' ||
(props.position === 'top' && isLeftAligned.value),
isBottom:
props.position === 'bottom' &&
!isLeftAligned.value &&
!isRightAligned.value,
isBottomLeft:
props.position === 'bottom-left' ||
(props.position === 'bottom' && isRightAligned.value),
isBottomRight:
props.position === 'bottom-right' ||
(props.position === 'bottom' && isLeftAligned.value),
isLeft: props.position === 'left',
isRight: props.position === 'right',
}
})
/**
* 툴팁 초기화 함수입니다.
*/
const resetTooltipContent = () => {
tooltipPosition.value.top = null
tooltipPosition.value.bottom = null
tooltipPosition.value.left = null
tooltipPosition.value.right = null
isOpen.value = false
isLeftAligned.value = false
isRightAligned.value = false
tooltipTriggerRef.value = null
}
/**
* 반응형 툴팁 위치 계산 함수입니다.
* @param trigger 트리거 요소
*/
const calculateTooltipPosition = (trigger: HTMLElement) => {
const triggerRect = trigger.getBoundingClientRect()
const tooltipOffset = props.offset + 4 // 툴팁 오프셋
const triggerCenterX = triggerRect.left + triggerRect.width / 2
const triggerCenterY = triggerRect.top + triggerRect.height / 2
const isLefts =
isPositions.value.isLeft ||
isPositions.value.isTopLeft ||
isPositions.value.isBottomLeft ||
isLeftAligned.value
const isOnlyLeft =
isPositions.value.isLeft &&
Object.values(isPositions.value).filter(Boolean).length === 1
const isRights =
isPositions.value.isRight ||
isPositions.value.isTopRight ||
isPositions.value.isBottomRight ||
isRightAligned.value
const isOnlyRight =
isPositions.value.isRight &&
Object.values(isPositions.value).filter(Boolean).length === 1
let topPosition: number | null = null
let bottomPosition: number | null = null
let leftPosition: number | null = null
let rightPosition: number | null = null
if (isLefts) {
if (isOnlyLeft) {
leftPosition = triggerRect.left - tooltipOffset
} else {
leftPosition = triggerRect.left + triggerRect.width + tooltipOffsetX.value
}
} else if (isRights) {
if (isOnlyRight) {
leftPosition = triggerRect.left + triggerRect.width + tooltipOffset
} else {
leftPosition = triggerRect.left - tooltipOffsetX.value
}
} else {
leftPosition = triggerCenterX
}
if (
isPositions.value.isBottom ||
isPositions.value.isBottomLeft ||
isPositions.value.isBottomRight
) {
topPosition = triggerRect.top
} else if (
isPositions.value.isTop ||
isPositions.value.isTopLeft ||
isPositions.value.isTopRight
) {
topPosition = triggerRect.top - tooltipOffset
} else {
topPosition = triggerCenterY
}
tooltipPosition.value = {
top: topPosition,
bottom: bottomPosition,
left: leftPosition,
right: rightPosition,
}
}
/**
* 좌측 정렬이 필요한지 확인 함수입니다.
* 브라우저 화면 기준으로 툴팁의 왼쪽 가장자리가 화면 밖으로 나가는 경우 좌측 정렬을 합니다.
*/
const isValidLeftAligned = (trigger: HTMLElement): boolean => {
const tooltipWidth = 280 // 툴팁 최대 너비
const triggerRect = trigger.getBoundingClientRect()
const tooltipOffset = props.offset + 4 // 툴팁 오프셋
// trigger의 중앙 위치 계산
const triggerCenterX = triggerRect.left + triggerRect.width / 2
// 중앙 정렬 시 툴팁의 왼쪽 가장자리 위치
const tooltipLeftEdge = triggerCenterX - tooltipWidth / 2
return tooltipLeftEdge < tooltipOffset
}
/**
* 우측 정렬이 필요한지 확인 함수입니다.
* 브라우저 화면 기준으로 툴팁의 오른쪽 가장자리가 화면 밖으로 나가는 경우 우측 정렬을 합니다.
*/
const isValidRightAligned = (trigger: HTMLElement): boolean => {
const tooltipWidth = 280 // 툴팁 최대 너비
const triggerRect = trigger.getBoundingClientRect()
const windowWidth = window.innerWidth
const tooltipOffset = props.offset + 4 // 툴팁 오프셋
// trigger의 중앙 위치 계산
const triggerCenterX = triggerRect.left + triggerRect.width / 2
// 중앙 정렬 시 툴팁의 오른쪽 가장자리 위치
const tooltipRightEdge = triggerCenterX + tooltipWidth / 2
return tooltipRightEdge > windowWidth - tooltipOffset
}
/**
* 툴팁 표시 함수입니다.
* @param event 이벤트 객체
* @param text 툴팁 텍스트
*/
const handleTooltip = (event: MouseEvent, type: string) => {
if (type !== props.type) {
return
}
const trigger = (event.currentTarget || event.target) as HTMLElement
isOpen.value = !isOpen.value
if (isOpen.value) {
tooltipTriggerRef.value = trigger
isLeftAligned.value = isValidLeftAligned(trigger)
isRightAligned.value = isValidRightAligned(trigger)
calculateTooltipPosition(trigger)
} else {
resetTooltipContent()
}
}
/**
* 브라우저 리사이즈 시 툴팁 위치 재계산 함수입니다.
*/
const handleResize = () => {
if (isOpen.value && tooltipTriggerRef.value) {
isLeftAligned.value = isValidLeftAligned(tooltipTriggerRef.value)
isRightAligned.value = isValidRightAligned(tooltipTriggerRef.value)
calculateTooltipPosition(tooltipTriggerRef.value)
}
}
onMounted(() => {
window.addEventListener('resize', handleResize)
})
onUnmounted(() => {
window.removeEventListener('resize', handleResize)
})
</script>
<template>
<div
class="relative z-[100] inline-flex items-center justify-center"
v-bind="$attrs"
>
<button
type="button"
@click="handleTooltip($event, 'click')"
@mouseenter="handleTooltip($event, 'hover')"
@mouseleave="handleTooltip($event, 'hover')"
>
<slot name="trigger" />
<template v-if="!$slots.trigger">
<AtomsIconsStateInfoCircleLine :size="20" color="#7F7F7F" />
</template>
</button>
<div
v-if="!teleport && isOpen"
:class="[
'absolute z-[10] flex items-center justify-center w-[280px] py-[8px] px-[12px] rounded-[4px]',
]"
:style="[
isPositions.isTop
? `top: -${props.offset + 4}px; left: 50%; transform: translate(-50%, -100%)`
: isPositions.isBottom
? `bottom: -${props.offset + 4}px; left: 50%; transform: translate(-50%, 100%)`
: isPositions.isLeft
? `top: 50%; left: -${props.offset + 4}px; transform: translate(-100%, -50%)`
: isPositions.isRight
? `top: 50%; right: -${props.offset + 4}px; transform: translate(100%, -50%)`
: isPositions.isTopLeft
? `top: -${props.offset + 4}px; right: -${tooltipOffsetX}px; transform: translate(0, -100%)`
: isPositions.isTopRight
? `top: -${props.offset + 4}px; left: -${tooltipOffsetX}px; transform: translate(0, -100%)`
: isPositions.isBottomLeft
? `bottom: -${props.offset + 4}px; right: -${tooltipOffsetX}px; transform: translate(0, 100%)`
: isPositions.isBottomRight
? `bottom: -${props.offset + 4}px; left: -${tooltipOffsetX}px; transform: translate(0, 100%)`
: '',
`background-color: ${backgroundColor};`,
]"
>
<slot name="panel" />
<p
v-if="!$slots.panel"
v-dompurify-html="props.content"
:class="[
`relative flex items-center justify-center w-full text-${props.textAlign} text-[${props.fontSize}] font-[${props.fontWeight}] leading-[${props.lineHeight}] tracking-[${props.letterSpacing}]`,
]"
:style="[`color: ${props.textColor};`]"
></p>
<span
v-if="arrow"
class="absolute"
:style="[
isPositions.isTop
? `bottom: -4px; left: 50%; transform: translate(-50%, 0)`
: isPositions.isBottom
? `top: -4px; left: 50%; transform: translate(-50%, 0) rotate(180deg)`
: isPositions.isLeft
? `right: -4px; top: 50%; transform: translate(0, -50%) rotate(-90deg)`
: isPositions.isRight
? `left: -4px; top: 50%; transform: translate(0, -50%) rotate(90deg)`
: isPositions.isTopLeft
? `bottom: -4px; right: ${tooltipArrowOffsetX}px; transform: translate(0, 0)`
: isPositions.isTopRight
? `bottom: -4px; left: ${tooltipArrowOffsetX}px; transform: translate(0, 0)`
: isPositions.isBottomLeft
? `top: -4px; right: ${tooltipArrowOffsetX}px; transform: translate(0, 0) rotate(180deg)`
: isPositions.isBottomRight
? `top: -4px; left: ${tooltipArrowOffsetX}px; transform: translate(0, 0) rotate(180deg)`
: '',
]"
>
<svg
width="6"
height="4"
viewBox="0 0 6 4"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M2.2 2.93333L0 0H6L3.8 2.93333C3.4 3.46667 2.6 3.46667 2.2 2.93333Z"
:fill="backgroundColor"
/>
</svg>
</span>
</div>
</div>
<ClientOnly>
<Teleport to="body">
<div
v-if="teleport && isOpen"
:class="[
'absolute z-[100] flex items-center justify-center w-[280px] py-[8px] px-[12px] rounded-[4px] text-center text-[12px] font-[400] leading-[18px] tracking-[-0.24px] sm:w-auto sm:max-w-[280px]',
]"
:style="[
isPositions.isTop
? `transform: translate(-50%, -100%)`
: isPositions.isBottom
? `transform: translate(-50%, 100%)`
: isPositions.isLeft
? `transform: translate(0, -50%)`
: isPositions.isRight
? `transform: translate(0, -50%)`
: isPositions.isTopLeft
? `transform: translate(-100%, -100%)`
: isPositions.isTopRight
? `transform: translate(0, -100%)`
: isPositions.isBottomLeft
? `transform: translate(-100%, 100%)`
: isPositions.isBottomRight
? `transform: translate(0, 100%)`
: '',
`top: ${tooltipPosition.top !== null ? `${tooltipPosition.top}px` : 'auto'}; bottom: ${tooltipPosition.bottom !== null ? `${tooltipPosition.bottom}px` : 'auto'}; left: ${tooltipPosition.left !== null ? `${tooltipPosition.left}px` : 'auto'}; right: ${tooltipPosition.right !== null ? `${tooltipPosition.right}px` : 'auto'}; background-color: ${backgroundColor};`,
]"
>
<slot name="panel" />
<p
v-if="!$slots.panel"
v-dompurify-html="props.content"
:class="[
`relative flex items-center justify-center w-full text-${props.textAlign} text-[${props.fontSize}] font-[${props.fontWeight}] leading-[${props.lineHeight}] tracking-[${props.letterSpacing}]`,
]"
:style="[`color: ${props.textColor};`]"
></p>
<span
v-if="arrow"
class="absolute"
:style="[
isPositions.isTop
? `bottom: -4px; left: 50%; transform: translate(-50%, 0)`
: isPositions.isBottom
? `top: -4px; left: 50%; transform: translate(-50%, 0) rotate(180deg)`
: isPositions.isLeft
? `right: -4px; top: 50%; transform: translate(0, -50%) rotate(-90deg)`
: isPositions.isRight
? `left: -4px; top: 50%; transform: translate(0, -50%) rotate(90deg)`
: isPositions.isTopLeft
? `bottom: -4px; right: ${tooltipArrowOffsetX}px; transform: translate(0, 0)`
: isPositions.isTopRight
? `bottom: -4px; left: ${tooltipArrowOffsetX}px; transform: translate(0, 0)`
: isPositions.isBottomLeft
? `top: -4px; right: ${tooltipArrowOffsetX}px; transform: translate(0, 0) rotate(180deg)`
: isPositions.isBottomRight
? `top: -4px; left: ${tooltipArrowOffsetX}px; transform: translate(0, 0) rotate(180deg)`
: '',
]"
>
<svg
width="6"
height="4"
viewBox="0 0 6 4"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M2.2 2.93333L0 0H6L3.8 2.93333C3.4 3.46667 2.6 3.46667 2.2 2.93333Z"
:fill="backgroundColor"
/>
</svg>
</span>
</div>
</Teleport>
</ClientOnly>
</template>
<style scoped></style>

View File

@@ -0,0 +1,36 @@
<script setup lang="ts">
interface Props {
size?: number | string
color?: string
}
withDefaults(defineProps<Props>(), {
size: 12,
color: 'var(--foreground-gray-500)',
})
</script>
<template>
<svg
xmlns="http://www.w3.org/2000/svg"
:width="size"
:height="size"
viewBox="0 0 18 18"
fill="none"
>
<path
d="M8.75 13.3333C8.28976 13.3333 7.91667 12.9602 7.91667 12.5L7.91667 8.125C7.91667 7.66476 8.28976 7.29167 8.75 7.29167C9.21024 7.29167 9.58333 7.66476 9.58333 8.125V12.5C9.58333 12.9602 9.21024 13.3333 8.75 13.3333Z"
:fill="color"
/>
<path
d="M8.75 4.21875C8.14594 4.21875 7.65625 4.70844 7.65625 5.3125C7.65625 5.91656 8.14594 6.40625 8.75 6.40625C9.35406 6.40625 9.84375 5.91656 9.84375 5.3125C9.84375 4.70844 9.35406 4.21875 8.75 4.21875Z"
:fill="color"
/>
<path
fill-rule="evenodd"
clip-rule="evenodd"
d="M17.5 8.75C17.5 13.5825 13.5825 17.5 8.75 17.5C3.91751 17.5 0 13.5825 0 8.75C0 3.91751 3.91751 0 8.75 0C13.5825 0 17.5 3.91751 17.5 8.75ZM8.75 15.8333C12.662 15.8333 15.8333 12.662 15.8333 8.75C15.8333 4.83798 12.662 1.66667 8.75 1.66667C4.83798 1.66667 1.66667 4.83798 1.66667 8.75C1.66667 12.662 4.83798 15.8333 8.75 15.8333Z"
:fill="color"
/>
</svg>
</template>

View File

@@ -1,5 +1,4 @@
<script setup lang="ts">
import { SplideSlide } from '@splidejs/vue-splide'
import { getComponentGroup, getComponentGroupAry } from '#layers/utils/dataUtil'
import type { PageDataTemplateComponents } from '#layers/types/api/pageData'
import type { Platform } from '#layers/types/components/button'
@@ -16,6 +15,8 @@ const props = defineProps<Props>()
const runtimeConfig = useRuntimeConfig()
const dataResourcesUrl = runtimeConfig.public.dataResourcesUrl as string
const multilingualFileName = 'STOVE_PUBTEMPLATE_homepage_brand_download.json'
const stoveClientDownloadUrl = runtimeConfig.public
.stoveClientDownloadUrl as string
// Multilingual
const resultGetMultilingual = await useGetMultilingual({
@@ -70,13 +71,6 @@ const mobileSpecArray = ref<Array<string>>(['Android', 'Ios'])
const mobileOSArray = ref<Array<string>>(['AOS', 'iOS'])
// Computed
const platformList = computed(() => {
if (breakpoints.value.isMobile) {
return ['MOBILE', 'PC', 'STOVE']
} else {
return ['PC', 'STOVE', 'MOBILE']
}
})
const driverList = computed(() =>
driverArray.value.map(driver => ({
id: `DRIVER_${driver}`,
@@ -103,6 +97,7 @@ const mobileSpecList = computed(() =>
const mobileOSList = computed(() =>
mobileOSArray.value.map(os => ({
id: `MO_OS_${os}`,
osType: tm(`Download_${os}_Type`),
osCode: os,
osText: tm(`Download_${os}_OS`),
platformCode: tm(`Download_${os}_Platform`),
@@ -141,116 +136,164 @@ const handleMoveFocus = (target: 'pc' | 'mobile') => {
<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: {
perPage: 'auto',
gap: 12,
focus: 0,
drag: true,
padding: { left: 0, right: 0 },
},
}"
class="min-w-[320px] w-[100vw] px-[20px] ml-[-20px] sm:px-[40px] sm:ml-[-40px] md:w-full md:px-0 md:ml-0"
<div
class="relative flex flex-col-reverse sm:flex-row-reverse items-stretch justify-center gap-[20px] w-full md:flex-row"
>
<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
v-if="gameData?.platform_type !== '2'"
class="relative flex flex-1 flex-col items-start justify-start h-[270px] py-[20px] rounded-[12px] bg-white sm:h-auto md:flex-[2] md:pt-[24px] md:pb-0 lg:pt-[32px]"
>
<div
class="flex flex-col items-start justify-start gap-[8px] w-full md:gap-[12px]"
class="relative flex flex-col items-start justify-start w-full max-w-[800px] h-full px-[20px] mx-auto md:h-auto md:px-[28px] lg:px-[40px]"
>
<h4
class="relative flex justify-left items-center w-full text-left text-[#1F1F1F] text-[18px] font-bold leading-[26px] tracking-[-0.54px] md:text-[24px] md:leading-[34px] md:tracking-[0.72px]"
<span
v-if="!breakpoints.isMobile"
class="absolute top-0 right-[28px] w-[212px] h-[212px] lg:right-[40px]"
>
<span>{{ tm(`Download_Box_${platform}_Title`) }}</span>
<img
:src="
getImageHost('/images/common/img_desktop.png', {
imageType: 'common',
})
"
:alt="tm('Download_Box_PC_Title')"
loading="lazy"
draggable="false"
class="w-full h-full object-contain"
/>
</span>
<h4
class="relative flex justify-left items-center w-full gap-[4px] text-left text-[#1F1F1F] text-[18px] font-bold leading-[26px] tracking-[-0.54px] md:text-[24px] md:leading-[34px] md:tracking-[0.72px]"
>
<span>{{ tm('Download_Box_PC_Title') }}</span>
<AtomsTooltip
position="top"
:offset="8"
background-color="#666666"
text-color="#FFFFFF"
:arrow="true"
:content="tm('Download_Box_PC_Tooltip')"
/>
</h4>
<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
"
<template
v-for="(description, dIndex) in tm(
'Download_Box_PC_Description_List'
)"
:key="dIndex"
>
<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>
<p
class="relative flex items-center justify-start w-full mt-[12px] text-left text-[#999999] text-[14px] font-[400] leading-[24px] tracking-[-0.42px] md:text-[15px] md:tracking-[-0.45px]"
v-dompurify-html="tm(description as string)"
></p>
</template>
<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')
"
class="relative w-auto h-auto px-0 mt-[12px] 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('pc')"
>
<span>{{ tm(`Download_Box_${platform}_SpecCheck`) }}</span>
<span>{{ tm('Download_Box_PC_SpecCheck') }}</span>
<AtomsIconsLongArrowRightLine
:size="20"
color="#1F1F1F"
class="relative rotate-90"
/>
</AtomsButton>
<div
v-if="breakpoints.isMobile"
class="relative flex items-center justify-center w-full h-auto min-h-[48px] py-[14px] px-[40px] mt-[48px] border border-solid border-[rgba(0,0,0,0.1)] rounded-[8px] bg-[#EBEBEB] text-center text-[#999999] text-[14px] font-[500] leading-[20px] tracking-[-0.42px]"
>
<span>{{ tm('Download_Button_PC_Mobile') }}</span>
</div>
<BlocksButtonLauncher
v-else-if="breakpoints.isMd || breakpoints.isDesktop"
platform="pc"
class="!w-full !max-w-[300px] mt-[32px] lg:mt-[48px]"
>
<span>{{ tm('Download_Button_PC') }}</span>
</BlocksButtonLauncher>
</div>
<div
class="flex flex-col items-center justify-center gap-[8px] w-full md:gap-[12px]"
v-if="!breakpoints.isMobile"
class="relative flex items-center justify-center w-full p-[25px] mt-[24px] rounded-b-[12px] bg-[#FAFAFA] lg:mt-[32px]"
>
<template v-if="platform === 'MOBILE'">
<p
class="relative flex items-center justify-center w-full gap-[8px] text-[#999999] text-[16px] font-[400] leading-[26px] tracking-[-0.48px]"
>
<span>{{ tm('Download_Text_Not_STOVE_Client') }}</span>
<NuxtLink
:href="stoveClientDownloadUrl"
target="_self"
rel="noopener noreferrer"
class="inline-flex items-center justify-start gap-[4px] text-[#3C75FF] text-[16px] font-[500] reading-[24px] tracking-[-0.48px]"
>
<span>{{ tm('Download_Button_STOVE') }}</span>
<AtomsIconsDownloadLine color="#3C75FF" />
</NuxtLink>
</p>
</div>
</div>
<div
v-if="gameData?.platform_type !== '1'"
class="relative flex flex-1 flex-col items-start justify-start h-[270px] p-[20px] rounded-[12px] bg-white sm:h-auto md:py-[24px] md:px-[28px] lg:pt-[32px] lg:pb-[40px] lg:px-[40px]"
>
<div
class="relative flex flex-col items-start justify-start w-full max-w-[800px] mx-auto"
>
<h4
class="relative flex justify-left items-center w-full text-left text-[#1F1F1F] text-[18px] font-bold leading-[26px] tracking-[-0.54px] md:text-[24px] md:leading-[34px] md:tracking-[0.72px]"
>
<span>{{ tm('Download_Box_MOBILE_Title') }}</span>
</h4>
<AtomsButton
type="action"
button-size="size-small"
background-color="transparent"
text-color="#1F1F1F"
class="relative w-auto h-auto px-0 mt-[8px] mb-[48px] 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 md:mt-[12px]"
@click="handleMoveFocus('mobile')"
>
<span>{{ tm('Download_Box_MOBILE_SpecCheck') }}</span>
<AtomsIconsLongArrowRightLine
:size="20"
color="#1F1F1F"
class="relative rotate-90"
/>
</AtomsButton>
<div
class="relative flex flex-col items-start justify-start w-full gap-[8px] mt-auto md:gap-[12px]"
>
<template v-for="os in mobileOSList" :key="os.id">
<BlocksButtonLauncher
v-if="device.isMobile ? os.isValue : true"
v-if="
device.isMobile
? os.isValue
: gameData?.os_type !== '3'
? gameData?.os_type === os.osType
: true
"
:platform="`${os.platformCode as Platform}`"
class="!w-full"
>
<span>{{ os.platformText }}</span>
</BlocksButtonLauncher>
</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>
<BlocksButtonLauncher
v-else-if="breakpoints.isMd || breakpoints.isDesktop"
:platform="`${platform.toLowerCase() as Platform}`"
class="!w-full"
>
<span>{{ tm(`Download_Button_${platform}`) }}</span>
</BlocksButtonLauncher>
</template>
</div>
</div>
</SplideSlide>
</BlocksSlideDefault>
</div>
</div>
</section>
<section ref="specPCRef" class="section-static">
@@ -426,4 +469,8 @@ table td {
.splide :deep(.splide__track) {
overflow: visible !important;
}
::v-deep([data-platform='stove']) .icon-platform {
display: none !important;
}
</style>

Binary file not shown.

After

Width:  |  Height:  |  Size: 130 KiB