feat. FX_PREREGIST_01 템플릿 제작
@@ -36,7 +36,7 @@
|
||||
@apply line-clamp-2 text-[16px] font-[500] leading-[24px] drop-shadow-[0_2px_2px_rgba(0,0,0,0.6)] md:line-clamp-1 md:text-[24px] md:leading-[34px];
|
||||
}
|
||||
.title-sm {
|
||||
@apply text-[15px] font-[500] leading-[24px] tracking-[-0.45px] md:text-[20px] md:leading-[30px] md:tracking-[-0.6px];
|
||||
@apply text-[15px] font-[500] leading-[24px] tracking-[-0.45px] drop-shadow-[0_2px_2px_rgba(0,0,0,0.6)] md:text-[20px] md:leading-[30px] md:tracking-[-0.6px];
|
||||
}
|
||||
.title-xs {
|
||||
@apply text-[14px] font-[500] leading-[20px] tracking-[-0.42px] md:text-[18px] md:leading-[26px] md:tracking-[-0.54px];
|
||||
|
||||
@@ -13,6 +13,7 @@ interface Props {
|
||||
arrows?: boolean
|
||||
pagination?: boolean
|
||||
paginationData?: PageDataResourceGroups
|
||||
destroy?: boolean
|
||||
breakpoints?: ResponsiveOptions['breakpoints']
|
||||
}
|
||||
|
||||
@@ -23,6 +24,7 @@ const props = withDefaults(defineProps<Props>(), {
|
||||
drag: true,
|
||||
arrows: true,
|
||||
pagination: true,
|
||||
destroy: false,
|
||||
})
|
||||
|
||||
const emit = defineEmits(['mounted', 'move', 'arrowClick'])
|
||||
@@ -50,6 +52,7 @@ const options = computed((): ResponsiveOptions => {
|
||||
trimSpace: false,
|
||||
arrows: props.arrows,
|
||||
pagination: props.pagination,
|
||||
destroy: props.destroy,
|
||||
classes: {
|
||||
arrows: 'splide-arrows',
|
||||
arrow: 'splide-arrow',
|
||||
|
||||
@@ -11,6 +11,7 @@ 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'
|
||||
import FxPreregist01 from '#layers/templates/FxPreregist01/index.vue'
|
||||
|
||||
const templateRegistry = {
|
||||
GR_VISUAL_01: { component: GrVisual01 },
|
||||
@@ -26,6 +27,7 @@ const templateRegistry = {
|
||||
GR_CONTENTS_01: { component: GrContents01 },
|
||||
FX_VIDEO_01: { component: FxVideo01 },
|
||||
FX_DOWNLOAD_01: { component: FxDownload01 },
|
||||
FX_PREREGIST_01: { component: FxPreregist01 },
|
||||
} as const
|
||||
|
||||
type TemplateKey = keyof typeof templateRegistry
|
||||
|
||||
@@ -1,15 +1,7 @@
|
||||
<script setup lang="ts">
|
||||
console.log('🚀 ~ promotion')
|
||||
</script>
|
||||
<script setup lang="ts"></script>
|
||||
|
||||
<template>
|
||||
<div class="promotion-wrap">
|
||||
<slot />
|
||||
</div>
|
||||
<LayoutsHeader />
|
||||
<slot />
|
||||
<LayoutsFooter />
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.promo-wrap {
|
||||
background-color: tan;
|
||||
}
|
||||
</style>
|
||||
|
||||
627
layers/templates/FxPreregist01/index.vue
Normal file
@@ -0,0 +1,627 @@
|
||||
<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'
|
||||
|
||||
interface Props {
|
||||
components: PageDataTemplateComponents
|
||||
pageVerTmplSeq: number
|
||||
}
|
||||
|
||||
const props = defineProps<Props>()
|
||||
|
||||
const { tm } = useI18n()
|
||||
|
||||
const test = {
|
||||
subTitle: {
|
||||
groups: [
|
||||
{
|
||||
display: {
|
||||
text: '사전 등록 기간 + 2024.06.04 ~ 정식 오픈 전까지',
|
||||
color_code: '',
|
||||
color_name: 'primary',
|
||||
},
|
||||
resource_type: 'TXT',
|
||||
},
|
||||
],
|
||||
},
|
||||
mainTitle: {
|
||||
groups: [
|
||||
{
|
||||
display: {
|
||||
text: '로드나인 사전 등록',
|
||||
color_code: '',
|
||||
color_name: 'primary',
|
||||
},
|
||||
resource_type: 'TXT',
|
||||
},
|
||||
],
|
||||
},
|
||||
background: {
|
||||
groups: [
|
||||
{
|
||||
res_path: {
|
||||
path_mo: '/local/template/l9/16/1/1/FX_PREREGIST_01/common/bg_m.jpg',
|
||||
path_pc: '/local/template/l9/16/1/1/FX_PREREGIST_01/common/bg.jpg',
|
||||
},
|
||||
resource_type: 'IMG_COMM',
|
||||
},
|
||||
],
|
||||
},
|
||||
txtSnsLink: {
|
||||
groups: [
|
||||
{
|
||||
display: {
|
||||
text: 'https://pf.kakao.com/_xmyxjpG',
|
||||
},
|
||||
resource_type: 'TXT',
|
||||
},
|
||||
{
|
||||
display: {
|
||||
text: 'https://www.youtube.com/@LORDNINE_KR',
|
||||
},
|
||||
resource_type: 'TXT',
|
||||
},
|
||||
],
|
||||
},
|
||||
description: {
|
||||
groups: [
|
||||
{
|
||||
display: {
|
||||
text: '로드나인은 PC, GooglePlay, AppStore에서 즐기실 수 있습니다',
|
||||
color_code: '',
|
||||
color_name: 'text-primary',
|
||||
},
|
||||
resource_type: 'TXT',
|
||||
},
|
||||
],
|
||||
},
|
||||
imgAccReward: {
|
||||
groups: [
|
||||
{
|
||||
display: {
|
||||
text: '골드 100,000',
|
||||
},
|
||||
res_path: {
|
||||
path_mo:
|
||||
'/local/template/l9/16/1/1/FX_PREREGIST_01/ko/img_acc_reward01_m.png',
|
||||
path_pc:
|
||||
'/local/template/l9/16/1/1/FX_PREREGIST_01/ko/img_acc_reward01.png',
|
||||
},
|
||||
resource_type: 'IMG_LANG',
|
||||
},
|
||||
{
|
||||
display: {
|
||||
text: '중급 물약 x100',
|
||||
},
|
||||
res_path: {
|
||||
path_mo:
|
||||
'/local/template/l9/16/1/1/FX_PREREGIST_01/ko/img_acc_reward02_m.png',
|
||||
path_pc:
|
||||
'/local/template/l9/16/1/1/FX_PREREGIST_01/ko/img_acc_reward02.png',
|
||||
},
|
||||
resource_type: 'IMG_LANG',
|
||||
},
|
||||
{
|
||||
display: {
|
||||
text: '방어구 강화석 x3',
|
||||
},
|
||||
res_path: {
|
||||
path_mo:
|
||||
'/local/template/l9/16/1/1/FX_PREREGIST_01/ko/img_acc_reward03_m.png',
|
||||
path_pc:
|
||||
'/local/template/l9/16/1/1/FX_PREREGIST_01/ko/img_acc_reward03.png',
|
||||
},
|
||||
resource_type: 'IMG_LANG',
|
||||
},
|
||||
{
|
||||
display: {
|
||||
text: '무기 강화석 x3',
|
||||
},
|
||||
res_path: {
|
||||
path_mo:
|
||||
'/local/template/l9/16/1/1/FX_PREREGIST_01/ko/img_acc_reward04_m.png',
|
||||
path_pc:
|
||||
'/local/template/l9/16/1/1/FX_PREREGIST_01/ko/img_acc_reward04.png',
|
||||
},
|
||||
resource_type: 'IMG_LANG',
|
||||
},
|
||||
// {
|
||||
// display: {
|
||||
// text: '순수한 무기 강화석 x1',
|
||||
// },
|
||||
// res_path: {
|
||||
// path_mo:
|
||||
// '/local/template/l9/16/1/1/FX_PREREGIST_01/ko/img_acc_reward05_m.png',
|
||||
// path_pc:
|
||||
// '/local/template/l9/16/1/1/FX_PREREGIST_01/ko/img_acc_reward05.png',
|
||||
// },
|
||||
// resource_type: 'IMG_LANG',
|
||||
// },
|
||||
],
|
||||
},
|
||||
imgSnsButton: {
|
||||
groups: [
|
||||
{
|
||||
res_path: {
|
||||
path_mo:
|
||||
'/local/template/l9/16/1/1/FX_PREREGIST_01/ko/sns_button01_m.jpg',
|
||||
path_pc:
|
||||
'/local/template/l9/16/1/1/FX_PREREGIST_01/ko/sns_button01.jpg',
|
||||
},
|
||||
tracking: {
|
||||
click_item: 'imgSnsButton_7. 사전등록-SNS버튼이미지(1)',
|
||||
action_type: 'click',
|
||||
click_sarea: 'promotionPreregist_tmpl_01__imgSnsButton',
|
||||
},
|
||||
resource_type: 'IMG_LANG',
|
||||
},
|
||||
{
|
||||
res_path: {
|
||||
path_mo:
|
||||
'/local/template/l9/16/1/1/FX_PREREGIST_01/ko/sns_button02_m.jpg',
|
||||
path_pc:
|
||||
'/local/template/l9/16/1/1/FX_PREREGIST_01/ko/sns_button02.jpg',
|
||||
},
|
||||
tracking: {
|
||||
click_item: 'imgSnsButton_7. 사전등록-SNS버튼이미지(2)',
|
||||
action_type: 'click',
|
||||
click_sarea: 'promotionPreregist_tmpl_01__imgSnsButton',
|
||||
},
|
||||
resource_type: 'IMG_LANG',
|
||||
},
|
||||
],
|
||||
},
|
||||
imgSnsReward: {
|
||||
groups: [
|
||||
{
|
||||
res_path: {
|
||||
path_mo:
|
||||
'/local/template/l9/16/1/1/FX_PREREGIST_01/ko/img_preregist_reward_sns_m.png',
|
||||
path_pc:
|
||||
'/local/template/l9/16/1/1/FX_PREREGIST_01/ko/img_preregist_reward_sns.png',
|
||||
},
|
||||
resource_type: 'IMG_LANG',
|
||||
},
|
||||
],
|
||||
},
|
||||
subTitleAccReward: {
|
||||
groups: [
|
||||
{
|
||||
display: {
|
||||
text: '이벤트 기간 + 2024.06.04 ~ 정식 오픈 전까지',
|
||||
color_code: '#c5902f',
|
||||
color_name: '',
|
||||
},
|
||||
resource_type: 'TXT',
|
||||
},
|
||||
],
|
||||
},
|
||||
imgPreregistReward: {
|
||||
groups: [
|
||||
{
|
||||
res_path: {
|
||||
path_mo:
|
||||
'/local/template/l9/16/1/1/FX_PREREGIST_01/ko/img_preregist_reward_m.png',
|
||||
path_pc:
|
||||
'/local/template/l9/16/1/1/FX_PREREGIST_01/ko/img_preregist_reward.png',
|
||||
},
|
||||
resource_type: 'IMG_LANG',
|
||||
},
|
||||
],
|
||||
},
|
||||
mainTitleAccReward: {
|
||||
groups: [
|
||||
{
|
||||
display: {
|
||||
text: '카카오톡 공식 채널 구독 이벤트',
|
||||
color_code: '#c5902f',
|
||||
color_name: '',
|
||||
},
|
||||
resource_type: 'TXT',
|
||||
},
|
||||
],
|
||||
},
|
||||
backgroundAccReward: {
|
||||
groups: [
|
||||
{
|
||||
res_path: {
|
||||
path_mo:
|
||||
'/local/template/l9/16/1/1/FX_PREREGIST_01/common/bg_acc_reward_m.jpg',
|
||||
path_pc:
|
||||
'/local/template/l9/16/1/1/FX_PREREGIST_01/common/bg_acc_reward.jpg',
|
||||
},
|
||||
resource_type: 'IMG_COMM',
|
||||
},
|
||||
],
|
||||
},
|
||||
descriptionAccReward: {
|
||||
groups: [
|
||||
{
|
||||
display: {
|
||||
text: '※ 달성 여부는 실시간으로 반영되지 않을 수 있습니다.',
|
||||
color_code: '#737474',
|
||||
color_name: '',
|
||||
},
|
||||
resource_type: 'TXT',
|
||||
},
|
||||
],
|
||||
},
|
||||
isAccRewardCompleted: {},
|
||||
preregistButtonColor: {
|
||||
groups: [
|
||||
{
|
||||
display: {
|
||||
color_code: '#cc0000',
|
||||
color_name: '',
|
||||
},
|
||||
resource_type: 'COLOR',
|
||||
},
|
||||
{
|
||||
display: {
|
||||
color_code: '#ccff00',
|
||||
color_name: '',
|
||||
},
|
||||
resource_type: 'COLOR',
|
||||
},
|
||||
],
|
||||
},
|
||||
rewardTitleAccReward: {
|
||||
groups: [
|
||||
{
|
||||
display: {
|
||||
text: '누적 목표를 달성할수록 더 많은 보상을 드립니다!',
|
||||
color_code: '#33312e',
|
||||
color_name: '',
|
||||
},
|
||||
resource_type: 'TXT',
|
||||
},
|
||||
],
|
||||
},
|
||||
imgAccRewardIncomplete: {
|
||||
groups: [
|
||||
{
|
||||
display: {
|
||||
text: '골드 100,000',
|
||||
},
|
||||
res_path: {
|
||||
path_mo:
|
||||
'/local/template/l9/16/1/1/FX_PREREGIST_01/ko/img_acc_reward_incomplete01_m.png',
|
||||
path_pc:
|
||||
'/local/template/l9/16/1/1/FX_PREREGIST_01/ko/img_acc_reward_incomplete01.png',
|
||||
},
|
||||
resource_type: 'IMG_LANG',
|
||||
},
|
||||
{
|
||||
display: {
|
||||
text: '중급 물약 x100',
|
||||
},
|
||||
res_path: {
|
||||
path_mo:
|
||||
'/local/template/l9/16/1/1/FX_PREREGIST_01/ko/img_acc_reward_incomplete02_m.png',
|
||||
path_pc:
|
||||
'/local/template/l9/16/1/1/FX_PREREGIST_01/ko/img_acc_reward_incomplete02.png',
|
||||
},
|
||||
resource_type: 'IMG_LANG',
|
||||
},
|
||||
{
|
||||
display: {
|
||||
text: '방어구 강화석 x3',
|
||||
},
|
||||
res_path: {
|
||||
path_mo:
|
||||
'/local/template/l9/16/1/1/FX_PREREGIST_01/ko/img_acc_reward_incomplete03_m.png',
|
||||
path_pc:
|
||||
'/local/template/l9/16/1/1/FX_PREREGIST_01/ko/img_acc_reward_incomplete03.png',
|
||||
},
|
||||
resource_type: 'IMG_LANG',
|
||||
},
|
||||
{
|
||||
display: {
|
||||
text: '무기 강화석 x3',
|
||||
},
|
||||
res_path: {
|
||||
path_mo:
|
||||
'/local/template/l9/16/1/1/FX_PREREGIST_01/ko/img_acc_reward_incomplete04_m.png',
|
||||
path_pc:
|
||||
'/local/template/l9/16/1/1/FX_PREREGIST_01/ko/img_acc_reward_incomplete04.png',
|
||||
},
|
||||
resource_type: 'IMG_LANG',
|
||||
},
|
||||
{
|
||||
display: {
|
||||
text: '순수한 무기 강화석 x1',
|
||||
},
|
||||
res_path: {
|
||||
path_mo:
|
||||
'/local/template/l9/16/1/1/FX_PREREGIST_01/ko/img_acc_reward_incomplete05_m.png',
|
||||
path_pc:
|
||||
'/local/template/l9/16/1/1/FX_PREREGIST_01/ko/img_acc_reward_incomplete05.png',
|
||||
},
|
||||
resource_type: 'IMG_LANG',
|
||||
},
|
||||
],
|
||||
},
|
||||
} as any
|
||||
|
||||
// Constants
|
||||
const PREREGIST_PLATFORMS = [
|
||||
{ platform: 'stove', label: '사전 등록 하기' },
|
||||
{ platform: 'google_play', label: '사전 등록 하기' },
|
||||
{ platform: 'app_store', label: '사전 등록 하기' },
|
||||
] as const
|
||||
|
||||
const COLOR_INDEX = {
|
||||
BACKGROUND: 0,
|
||||
TEXT: 1,
|
||||
} as const
|
||||
|
||||
// Preregist Section
|
||||
const backgroundData = computed(() =>
|
||||
getComponentGroup(props.components, 'background')
|
||||
)
|
||||
const mainTitleData = computed(() =>
|
||||
getComponentGroup(props.components, 'mainTitle')
|
||||
)
|
||||
const subTitleData = computed(() =>
|
||||
getComponentGroup(props.components, 'subTitle')
|
||||
)
|
||||
const imgPreregistRewardData = computed(() =>
|
||||
getComponentGroup(props.components, 'imgPreregistReward')
|
||||
)
|
||||
const imgSnsRewardData = computed(() =>
|
||||
getComponentGroup(props.components, 'imgSnsReward')
|
||||
)
|
||||
const preregistButtonColorData = computed(() =>
|
||||
getComponentGroupAry(props.components, 'preregistButtonColor')
|
||||
)
|
||||
const imgSnsButtonData = computed(() =>
|
||||
getComponentGroupAry(props.components, 'imgSnsButton')
|
||||
)
|
||||
const txtSnsLinkData = computed(() =>
|
||||
getComponentGroupAry(props.components, 'txtSnsLink')
|
||||
)
|
||||
const descriptionData = computed(() =>
|
||||
getComponentGroup(props.components, 'description')
|
||||
)
|
||||
const snsButtons = computed(() => {
|
||||
const buttons = imgSnsButtonData.value
|
||||
const links = txtSnsLinkData.value
|
||||
|
||||
if (!buttons?.length) return []
|
||||
|
||||
return buttons.map((button, index) => ({
|
||||
image: button,
|
||||
link: links?.[index]?.display?.text ?? '',
|
||||
}))
|
||||
})
|
||||
const buttonColors = computed(() => {
|
||||
const colorData = preregistButtonColorData.value
|
||||
|
||||
if (!colorData?.length) {
|
||||
return { background: undefined, text: undefined }
|
||||
}
|
||||
|
||||
return {
|
||||
background: getColorCode({
|
||||
colorName: colorData[COLOR_INDEX.BACKGROUND]?.display?.color_name,
|
||||
colorCode: colorData[COLOR_INDEX.BACKGROUND]?.display?.color_code,
|
||||
}),
|
||||
text: getColorCode({
|
||||
colorName: colorData[COLOR_INDEX.TEXT]?.display?.color_name,
|
||||
colorCode: colorData[COLOR_INDEX.TEXT]?.display?.color_code,
|
||||
}),
|
||||
}
|
||||
})
|
||||
|
||||
// Reward Section
|
||||
const backgroundAccRewardData = computed(() =>
|
||||
getComponentGroup(props.components, 'backgroundAccReward')
|
||||
)
|
||||
const mainTitleAccRewardData = computed(() =>
|
||||
getComponentGroup(props.components, 'mainTitleAccReward')
|
||||
)
|
||||
const subTitleAccRewardData = computed(() =>
|
||||
getComponentGroup(props.components, 'subTitleAccReward')
|
||||
)
|
||||
const rewardTitleAccRewardData = computed(() =>
|
||||
getComponentGroup(props.components, 'rewardTitleAccReward')
|
||||
)
|
||||
const imgAccRewardData = computed(() =>
|
||||
getComponentGroupAry(test, 'imgAccReward')
|
||||
)
|
||||
const imgAccRewardLength = computed(() => imgAccRewardData.value?.length ?? 0)
|
||||
const descriptionAccRewardData = computed(() =>
|
||||
getComponentGroup(props.components, 'descriptionAccReward')
|
||||
)
|
||||
|
||||
const splideOptions = computed(() => {
|
||||
return {
|
||||
type: 'slide',
|
||||
gap: 16,
|
||||
arrows: false,
|
||||
pagination: false,
|
||||
destroy: true,
|
||||
breakpoints: {
|
||||
[BREAKPOINTS.md - 1]: {
|
||||
destroy: imgAccRewardLength.value <= 3,
|
||||
perPage: 'auto',
|
||||
focus: 'center',
|
||||
drag: imgAccRewardLength.value > 3,
|
||||
padding: {
|
||||
left: 40,
|
||||
right: 40,
|
||||
},
|
||||
},
|
||||
[BREAKPOINTS.sm - 1]: {
|
||||
destroy: false,
|
||||
gap: 12,
|
||||
drag: true,
|
||||
padding: {
|
||||
left: 20,
|
||||
right: 20,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<section class="relative py-[80px] md:py-[120px]">
|
||||
<WidgetsBackground v-if="backgroundData" :resources-data="backgroundData" />
|
||||
<div class="content-standard">
|
||||
<WidgetsMainTitle
|
||||
v-if="mainTitleData"
|
||||
:resources-data="mainTitleData"
|
||||
class="title-xlg"
|
||||
/>
|
||||
<WidgetsSubTitle
|
||||
v-if="subTitleData"
|
||||
:resources-data="subTitleData"
|
||||
class="title-sm mt-2"
|
||||
/>
|
||||
<div class="flex flex-col gap-4 mt-8 md:flex-row">
|
||||
<div v-if="imgPreregistRewardData" class="w-full max-w-[446px]">
|
||||
<AtomsImg
|
||||
:src="getImagePaths(imgPreregistRewardData)"
|
||||
loading="lazy"
|
||||
decoding="async"
|
||||
class="w-full h-full object-contain"
|
||||
/>
|
||||
</div>
|
||||
<div v-if="imgSnsRewardData" class="relative w-full max-w-[446px]">
|
||||
<AtomsImg
|
||||
:src="getImagePaths(imgSnsRewardData)"
|
||||
loading="lazy"
|
||||
decoding="async"
|
||||
class="w-full h-full object-contain"
|
||||
/>
|
||||
<ul
|
||||
v-if="snsButtons.length"
|
||||
class="absolute bottom-[20px] left-0 w-full flex items-center justify-center gap-2 md:bottom-[24px] md:gap-3"
|
||||
>
|
||||
<li
|
||||
v-for="(snsButton, index) in snsButtons"
|
||||
:key="`sns-${snsButton.link}-${index}`"
|
||||
>
|
||||
<a
|
||||
:href="snsButton.link"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
<AtomsImg :src="getImagePaths(snsButton.image)" />
|
||||
<span class="sr-only">
|
||||
{{ snsButton.link }}
|
||||
</span>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
v-if="PREREGIST_PLATFORMS.length"
|
||||
class="flex gap-3 justify-center flex-wrap mt-8 md:gap-2.5"
|
||||
>
|
||||
<AtomsButtonLauncher
|
||||
v-for="item in PREREGIST_PLATFORMS"
|
||||
:key="`preregist-${item.platform}`"
|
||||
type="duplication"
|
||||
:platform="item.platform"
|
||||
:background-color="buttonColors.background"
|
||||
:text-color="buttonColors.text"
|
||||
>
|
||||
{{ item.label }}
|
||||
</AtomsButtonLauncher>
|
||||
</div>
|
||||
<WidgetsDescription
|
||||
v-if="descriptionData"
|
||||
:resources-data="descriptionData"
|
||||
class="mt-8"
|
||||
/>
|
||||
</div>
|
||||
</section>
|
||||
<section class="relative py-[80px] md:py-[120px]">
|
||||
<WidgetsBackground
|
||||
v-if="backgroundAccRewardData"
|
||||
:resources-data="backgroundAccRewardData"
|
||||
/>
|
||||
<div class="content-standard">
|
||||
<WidgetsMainTitle
|
||||
v-if="mainTitleAccRewardData"
|
||||
:resources-data="mainTitleAccRewardData"
|
||||
class="title-xlg"
|
||||
/>
|
||||
<WidgetsSubTitle
|
||||
v-if="subTitleAccRewardData"
|
||||
:resources-data="subTitleAccRewardData"
|
||||
class="title-sm mt-2"
|
||||
/>
|
||||
<WidgetsSubTitle
|
||||
v-if="rewardTitleAccRewardData"
|
||||
tag="h4"
|
||||
:resources-data="rewardTitleAccRewardData"
|
||||
class="mt-[48px] text-[18px] font-[700] leading-[26px] tracking-[-0.54px] drop-shadow-[0_2px_2px_rgba(0,0,0,0.6)] md:mt-[72px] md:text-[24px] md:leading-[34px] md:tracking-[0.72px]"
|
||||
/>
|
||||
<div v-if="imgAccRewardLength" class="mt-6 md:mt-8">
|
||||
<ul class="hidden md:flex justify-center md:mb-[20px]">
|
||||
<li
|
||||
v-for="index in imgAccRewardLength"
|
||||
:key="index"
|
||||
class="flex items-center"
|
||||
>
|
||||
<span class="progress-bullet"></span>
|
||||
<div v-if="index !== imgAccRewardLength" class="progress-bar">
|
||||
<span class="progress-fill"></span>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
<BlocksSlideDefault
|
||||
v-bind="splideOptions"
|
||||
class="w-[100vw] mx-[-20px] sm:mx-[-40px] md:w-auto md:mx-auto"
|
||||
>
|
||||
<SplideSlide
|
||||
v-for="(item, index) in imgAccRewardData"
|
||||
:key="`reward-${item.id ?? index}`"
|
||||
class="w-[162px] h-[228px] md:w-[176px] md:h-[249px]"
|
||||
>
|
||||
<AtomsImg
|
||||
:src="getImagePaths(item)"
|
||||
:alt="item?.display?.text ?? `Reward ${index + 1}`"
|
||||
loading="lazy"
|
||||
decoding="async"
|
||||
class="w-full h-full object-contain"
|
||||
/>
|
||||
</SplideSlide>
|
||||
</BlocksSlideDefault>
|
||||
</div>
|
||||
<WidgetsDescription
|
||||
v-if="descriptionAccRewardData"
|
||||
:resources-data="descriptionAccRewardData"
|
||||
class="mt-6 md:mt-8"
|
||||
/>
|
||||
</div>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
/* destroy되었을 때 (슬라이드 비활성화) 중앙 정렬 */
|
||||
.splide:not(.is-active):deep(.splide__list) {
|
||||
@apply flex justify-center gap-3 md:gap-4;
|
||||
}
|
||||
|
||||
.progress-bullet {
|
||||
@apply block w-3 h-3 rounded-full transition-all duration-300;
|
||||
background-color: red;
|
||||
/* background-color: var(--pagination-disabled); */
|
||||
}
|
||||
.progress-bar {
|
||||
@apply relative w-[180px] h-0.5 overflow-hidden;
|
||||
/* background-color: var(--pagination-disabled); */
|
||||
background-color: red;
|
||||
}
|
||||
.progress-fill {
|
||||
@apply absolute inset-y-0 left-0 w-[0];
|
||||
background-color: var(--pagination-active);
|
||||
}
|
||||
</style>
|
||||
@@ -58,33 +58,42 @@ const { data: slideData } = await useAsyncData(
|
||||
server: false,
|
||||
}
|
||||
)
|
||||
const slideLength = computed(() => slideData.value.length)
|
||||
const slideClass = computed(() => ({
|
||||
'is-one-item': slideLength.value === 1,
|
||||
'is-two-items': slideLength.value === 2,
|
||||
'is-three-items': slideLength.value === 3,
|
||||
'is-four-items': slideLength.value === 4,
|
||||
}))
|
||||
const splideOptions = computed(() => ({
|
||||
gap: 20,
|
||||
perPage: 4,
|
||||
drag: false,
|
||||
arrows: slideLength.value > 4,
|
||||
pagination: slideLength.value > 4,
|
||||
breakpoints: {
|
||||
[BREAKPOINTS.lg - 1]: {
|
||||
perPage: 2,
|
||||
arrows: slideLength.value > 2,
|
||||
pagination: slideLength.value > 2,
|
||||
const slideLength = computed(() => slideData.value.length ?? 0)
|
||||
const splideOptions = computed(() => {
|
||||
return {
|
||||
gap: 20,
|
||||
perPage: 4,
|
||||
drag: false,
|
||||
arrows: slideLength.value > 4,
|
||||
pagination: slideLength.value > 4,
|
||||
destroy: slideLength.value <= 4,
|
||||
breakpoints: {
|
||||
[BREAKPOINTS.lg - 1]: {
|
||||
perPage: 2,
|
||||
arrows: slideLength.value > 2,
|
||||
pagination: slideLength.value > 2,
|
||||
destroy: slideLength.value < 3,
|
||||
},
|
||||
[BREAKPOINTS.md - 1]: {
|
||||
drag: true,
|
||||
perPage: 1,
|
||||
arrows: false,
|
||||
pagination: false,
|
||||
destroy: slideLength.value < 2,
|
||||
padding: {
|
||||
left: 40,
|
||||
right: 40,
|
||||
},
|
||||
},
|
||||
[BREAKPOINTS.sm - 1]: {
|
||||
padding: {
|
||||
left: 20,
|
||||
right: 20,
|
||||
},
|
||||
},
|
||||
},
|
||||
[BREAKPOINTS.md - 1]: {
|
||||
drag: true,
|
||||
perPage: 1,
|
||||
arrows: false,
|
||||
pagination: false,
|
||||
},
|
||||
},
|
||||
}))
|
||||
}
|
||||
})
|
||||
|
||||
const getArticleUrl = (articleId: string) => {
|
||||
const communityUrl = gameData.value?.url_json?.community
|
||||
@@ -118,7 +127,7 @@ const onArrowClick = (direction, targetIndex) => {
|
||||
v-if="slideLength > 0"
|
||||
:slide-item-length="slideLength"
|
||||
v-bind="splideOptions"
|
||||
:class="`${slideClass} w-full`"
|
||||
class="w-full"
|
||||
@arrow-click="onArrowClick"
|
||||
>
|
||||
<SplideSlide
|
||||
@@ -158,9 +167,6 @@ const onArrowClick = (direction, targetIndex) => {
|
||||
.splide {
|
||||
@apply mt-[24px] md:max-w-[776px] md:mt-[48px] md:mx-auto md:px-[72px] lg:max-w-[1428px];
|
||||
}
|
||||
.splide:deep(.splide__track) {
|
||||
@apply !px-[20px] md:max-w-[632px] lg:max-w-[1284px] md:mx-auto md:!px-[0] sm:!px-[40px];
|
||||
}
|
||||
.splide:deep(.arrow-prev) {
|
||||
@apply top-[calc(50%-28px)] left-[0];
|
||||
}
|
||||
@@ -168,23 +174,11 @@ const onArrowClick = (direction, targetIndex) => {
|
||||
@apply top-[calc(50%-28px)] right-[0];
|
||||
}
|
||||
.slide-inner {
|
||||
@apply w-[275px] aspect-[1/1] md:w-[306px] md:box-border;
|
||||
@apply w-[275px] aspect-[1/1] md:w-[306px];
|
||||
}
|
||||
|
||||
.splide.is-one-item:deep(.splide__track) {
|
||||
@apply max-w-[315px] sm:max-w-[355px] mx-auto md:max-w-[306px];
|
||||
}
|
||||
.splide.is-two-items:deep(.splide__track) {
|
||||
@apply lg:max-w-[632px];
|
||||
}
|
||||
.splide.is-two-items:deep(.splide__list) {
|
||||
@apply md:!translate-x-0;
|
||||
}
|
||||
.splide.is-three-items:deep(.splide__track) {
|
||||
@apply lg:max-w-[958px];
|
||||
}
|
||||
.splide.is-three-items:deep(.splide__list),
|
||||
.splide.is-four-items:deep(.splide__list) {
|
||||
@apply lg:!translate-x-0;
|
||||
/* destroy되었을 때 (슬라이드 비활성화) 중앙 정렬 */
|
||||
.splide:not(.is-active):deep(.splide__list) {
|
||||
@apply flex justify-center gap-5;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -49,6 +49,7 @@ const buttonListData = computed(() => {
|
||||
v-if="getImagePaths(item)"
|
||||
:src="getImagePaths(item)"
|
||||
:alt="item?.group_label"
|
||||
class="w-full object-contain"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
BIN
public/images/sample/FX_PREREGIST_01/common/bg_acc_reward.jpg
Normal file
|
After Width: | Height: | Size: 1.5 MiB |
BIN
public/images/sample/FX_PREREGIST_01/common/bg_acc_reward_m.jpg
Normal file
|
After Width: | Height: | Size: 887 KiB |
BIN
public/images/sample/FX_PREREGIST_01/ko/img_acc_reward01.png
Normal file
|
After Width: | Height: | Size: 74 KiB |
BIN
public/images/sample/FX_PREREGIST_01/ko/img_acc_reward01_m.png
Normal file
|
After Width: | Height: | Size: 209 KiB |
BIN
public/images/sample/FX_PREREGIST_01/ko/img_acc_reward02.png
Normal file
|
After Width: | Height: | Size: 236 KiB |
BIN
public/images/sample/FX_PREREGIST_01/ko/img_acc_reward02_m.png
Normal file
|
After Width: | Height: | Size: 204 KiB |
BIN
public/images/sample/FX_PREREGIST_01/ko/img_acc_reward03.png
Normal file
|
After Width: | Height: | Size: 234 KiB |
BIN
public/images/sample/FX_PREREGIST_01/ko/img_acc_reward03_m.png
Normal file
|
After Width: | Height: | Size: 206 KiB |
BIN
public/images/sample/FX_PREREGIST_01/ko/img_acc_reward04.png
Normal file
|
After Width: | Height: | Size: 218 KiB |
BIN
public/images/sample/FX_PREREGIST_01/ko/img_acc_reward04_m.png
Normal file
|
After Width: | Height: | Size: 190 KiB |
BIN
public/images/sample/FX_PREREGIST_01/ko/img_acc_reward05.png
Normal file
|
After Width: | Height: | Size: 239 KiB |
BIN
public/images/sample/FX_PREREGIST_01/ko/img_acc_reward05_m.png
Normal file
|
After Width: | Height: | Size: 211 KiB |
|
After Width: | Height: | Size: 248 KiB |
|
After Width: | Height: | Size: 222 KiB |
|
After Width: | Height: | Size: 248 KiB |
|
After Width: | Height: | Size: 222 KiB |
|
After Width: | Height: | Size: 248 KiB |
|
After Width: | Height: | Size: 222 KiB |
|
After Width: | Height: | Size: 248 KiB |
|
After Width: | Height: | Size: 222 KiB |
|
After Width: | Height: | Size: 248 KiB |
|
After Width: | Height: | Size: 222 KiB |
|
Before Width: | Height: | Size: 351 KiB After Width: | Height: | Size: 351 KiB |
|
Before Width: | Height: | Size: 638 KiB After Width: | Height: | Size: 638 KiB |
|
Before Width: | Height: | Size: 315 KiB After Width: | Height: | Size: 315 KiB |
|
Before Width: | Height: | Size: 570 KiB After Width: | Height: | Size: 570 KiB |
|
Before Width: | Height: | Size: 3.6 KiB After Width: | Height: | Size: 3.6 KiB |
|
Before Width: | Height: | Size: 5.8 KiB After Width: | Height: | Size: 5.8 KiB |
|
Before Width: | Height: | Size: 3.5 KiB After Width: | Height: | Size: 3.5 KiB |
|
Before Width: | Height: | Size: 5.5 KiB After Width: | Height: | Size: 5.5 KiB |