feat. FX_PREREGIST_01 템플릿 제작
This commit is contained in:
627
layers/templates/FxPreregist01/index.vue
Normal file
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>
|
||||
Reference in New Issue
Block a user