Merge branch 'feature/20250917-cl-design' into feature/20250910-all
This commit is contained in:
84
app/app.vue
84
app/app.vue
@@ -2,18 +2,14 @@
|
||||
import { useNuxtApp } from 'nuxt/app'
|
||||
import LoadingFull from '#layers/components/blocks/loading/Full.vue'
|
||||
import LoadingLocal from '#layers/components/blocks/loading/Local.vue'
|
||||
import type {
|
||||
GameDataMetaTag,
|
||||
GameDataValue,
|
||||
GameDataFaviconPath,
|
||||
} from '#layers/types/api/gameData'
|
||||
import type { GameDataMetaTag, GameDataValue } from '#layers/types/api/gameData'
|
||||
|
||||
const nuxtApp = useNuxtApp()
|
||||
|
||||
const { setGameData } = useGameDataStore()
|
||||
const { applyGameKeyCodeColors } = useGameKeyCodeColors()
|
||||
const gameDataStore = useGameDataStore()
|
||||
const { setGameData } = gameDataStore
|
||||
const { gameData } = storeToRefs(gameDataStore)
|
||||
|
||||
const gameData = ref<GameDataValue | null>(null)
|
||||
const metaData = ref<GameDataMetaTag | null>(null)
|
||||
|
||||
// SSR에서 게임 데이터 가져오기
|
||||
@@ -23,34 +19,13 @@ const getGameDataFromServer = (): GameDataValue | null => {
|
||||
: null
|
||||
}
|
||||
|
||||
// 클라이언트에서 색상 코드 적용
|
||||
const applyColorsOnClient = () => {
|
||||
if (import.meta.client) {
|
||||
const gameDataStore = useGameDataStore()
|
||||
const keyCodeCodes = gameDataStore.gameData?.key_code_codes
|
||||
// 통합 메타데이터 설정
|
||||
const setupAllMetaData = (data: GameDataValue) => {
|
||||
const meta = data.meta_tag
|
||||
const faviconPath = data.favicon_path
|
||||
const theme = data.design_theme === 1 ? 'dark' : 'light'
|
||||
|
||||
if (keyCodeCodes) {
|
||||
applyGameKeyCodeColors(keyCodeCodes)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// SEO 메타 태그 설정
|
||||
const setupSeoMeta = (meta: GameDataMetaTag) => {
|
||||
useSeoMeta({
|
||||
title: meta.page_title,
|
||||
description: meta.page_desc,
|
||||
ogTitle: meta.og_title,
|
||||
ogImage: meta.og_image,
|
||||
ogDescription: meta.og_desc,
|
||||
twitterImage: meta.x_image,
|
||||
twitterTitle: meta.x_title,
|
||||
twitterDescription: meta.x_desc,
|
||||
})
|
||||
}
|
||||
|
||||
// 파비콘 설정
|
||||
const setupFavicon = (faviconPath: GameDataFaviconPath) => {
|
||||
// 파비콘 링크 생성
|
||||
const faviconLinks = [
|
||||
{
|
||||
rel: 'icon',
|
||||
@@ -83,40 +58,55 @@ const setupFavicon = (faviconPath: GameDataFaviconPath) => {
|
||||
},
|
||||
]
|
||||
|
||||
useHead({
|
||||
link: faviconLinks,
|
||||
})
|
||||
}
|
||||
// 색상 CSS 변수 생성
|
||||
const cssVariables = Object.entries(data.key_code_codes)
|
||||
.map(([key, value]) => `--${key}: ${value};`)
|
||||
.join('\n ')
|
||||
|
||||
// HTML 속성 설정
|
||||
const setupHtmlAttributes = (data: GameDataValue) => {
|
||||
const theme = data.design_theme === 1 ? 'dark' : 'light'
|
||||
const cssContent = `
|
||||
:root {
|
||||
${cssVariables}
|
||||
}
|
||||
`
|
||||
|
||||
useHead({
|
||||
title: meta.page_title,
|
||||
meta: [
|
||||
{ name: 'description', content: meta.page_desc },
|
||||
{ property: 'og:title', content: meta.og_title },
|
||||
{ property: 'og:description', content: meta.og_desc },
|
||||
{ property: 'og:image', content: meta.og_image },
|
||||
{ name: 'twitter:title', content: meta.x_title },
|
||||
{ name: 'twitter:description', content: meta.x_desc },
|
||||
{ name: 'twitter:image', content: meta.x_image },
|
||||
],
|
||||
htmlAttrs: {
|
||||
'data-game': data.game_name || '',
|
||||
'data-theme': theme,
|
||||
lang: data.default_lang_code || 'ko',
|
||||
},
|
||||
link: faviconLinks,
|
||||
style: [
|
||||
{
|
||||
innerHTML: cssContent,
|
||||
id: 'game-color-variables',
|
||||
},
|
||||
],
|
||||
})
|
||||
}
|
||||
|
||||
// 메타 데이터 설정
|
||||
const setupMetaData = (data: GameDataValue) => {
|
||||
metaData.value = data.meta_tag
|
||||
setupSeoMeta(metaData.value)
|
||||
setupHtmlAttributes(data)
|
||||
setupFavicon(data.favicon_path)
|
||||
setupAllMetaData(data)
|
||||
}
|
||||
|
||||
// 초기화 로직 실행
|
||||
const serverGameData = getGameDataFromServer()
|
||||
|
||||
if (serverGameData) {
|
||||
gameData.value = serverGameData
|
||||
setGameData(serverGameData)
|
||||
setupMetaData(serverGameData)
|
||||
applyColorsOnClient()
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
@@ -1,16 +1,10 @@
|
||||
<script setup lang="ts">
|
||||
import { usePageDataStore } from '#layers/stores/usePageDataStore'
|
||||
import type { PageDataValue } from '#layers/types/api/pageData'
|
||||
import { getLayoutType } from '#layers/utils/dataUtil'
|
||||
|
||||
const pageDataStore = usePageDataStore()
|
||||
const { pageData } = storeToRefs(pageDataStore)
|
||||
|
||||
const getLayoutType = (
|
||||
pageData: PageDataValue | null
|
||||
): 'default' | 'promotion' => {
|
||||
return pageData?.page_type === 1 ? 'default' : 'promotion'
|
||||
}
|
||||
|
||||
const currentLayout = computed(() => getLayoutType(pageData.value))
|
||||
|
||||
definePageMeta({
|
||||
|
||||
@@ -1,16 +1,10 @@
|
||||
<script setup lang="ts">
|
||||
import { usePageDataStore } from '#layers/stores/usePageDataStore'
|
||||
import type { PageDataValue } from '#layers/types/api/pageData'
|
||||
import { getLayoutType } from '#layers/utils/dataUtil'
|
||||
|
||||
const pageDataStore = usePageDataStore()
|
||||
const { pageData } = storeToRefs(pageDataStore)
|
||||
|
||||
const getLayoutType = (
|
||||
pageData: PageDataValue | null
|
||||
): 'default' | 'promotion' => {
|
||||
return pageData?.page_type === 1 ? 'default' : 'promotion'
|
||||
}
|
||||
|
||||
const currentLayout = computed(() => getLayoutType(pageData.value))
|
||||
|
||||
definePageMeta({
|
||||
|
||||
@@ -1,16 +1,10 @@
|
||||
<script setup lang="ts">
|
||||
import { usePageDataStore } from '#layers/stores/usePageDataStore'
|
||||
import type { PageDataValue } from '#layers/types/api/pageData'
|
||||
import { getLayoutType } from '#layers/utils/dataUtil'
|
||||
|
||||
const pageDataStore = usePageDataStore()
|
||||
const { pageData } = storeToRefs(pageDataStore)
|
||||
|
||||
const getLayoutType = (
|
||||
pageData: PageDataValue | null
|
||||
): 'default' | 'promotion' => {
|
||||
return pageData?.page_type === 1 ? 'default' : 'promotion'
|
||||
}
|
||||
|
||||
const currentLayout = computed(() => getLayoutType(pageData.value))
|
||||
|
||||
definePageMeta({
|
||||
|
||||
@@ -1,16 +1,10 @@
|
||||
<script setup lang="ts">
|
||||
import { usePageDataStore } from '#layers/stores/usePageDataStore'
|
||||
import type { PageDataValue } from '#layers/types/api/pageData'
|
||||
import { getLayoutType } from '#layers/utils/dataUtil'
|
||||
|
||||
const pageDataStore = usePageDataStore()
|
||||
const { pageData } = storeToRefs(pageDataStore)
|
||||
|
||||
const getLayoutType = (
|
||||
pageData: PageDataValue | null
|
||||
): 'default' | 'promotion' => {
|
||||
return pageData?.page_type === 1 ? 'default' : 'promotion'
|
||||
}
|
||||
|
||||
const currentLayout = computed(() => getLayoutType(pageData.value))
|
||||
|
||||
definePageMeta({
|
||||
|
||||
@@ -3,7 +3,7 @@ import { templateRegistry } from '#layers/registry'
|
||||
import type {
|
||||
PageDataValue,
|
||||
PageDataTemplate,
|
||||
PageDataTemplateComponent,
|
||||
PageDataComponent,
|
||||
PageDataMetaTag,
|
||||
} from '#layers/types/api/pageData'
|
||||
|
||||
@@ -16,7 +16,7 @@ const props = defineProps<Props>()
|
||||
// 템플릿 레지스트리 타입 캐스팅
|
||||
const registry = templateRegistry as unknown as Record<
|
||||
string,
|
||||
{ component: PageDataTemplateComponent }
|
||||
{ component: PageDataComponent }
|
||||
>
|
||||
|
||||
// 개별 메타 태그 표시 여부 확인
|
||||
@@ -25,7 +25,7 @@ const shouldShowMetaTag = computed(() => props.pageData.meta_tag_type === 2)
|
||||
// 템플릿 표시 여부 확인
|
||||
const isTemplateVisible = (template: PageDataTemplate): boolean => {
|
||||
return Boolean(
|
||||
template?.components_ && Object.keys(template.components_).length > 0
|
||||
template?.components && Object.keys(template.components).length > 0
|
||||
)
|
||||
}
|
||||
|
||||
@@ -64,7 +64,7 @@ watchEffect(() => {
|
||||
>
|
||||
<component
|
||||
:is="registry[template.template_code]?.component"
|
||||
:components="template.components_"
|
||||
:components="template.components"
|
||||
/>
|
||||
</template>
|
||||
</main>
|
||||
|
||||
@@ -1,35 +1,27 @@
|
||||
<script setup lang="ts">
|
||||
import {
|
||||
getResourcesData,
|
||||
getResponsiveClass,
|
||||
getResponsiveSrc,
|
||||
} from '#layers/utils/dataUtil'
|
||||
import type { PageDataComponent } from '#layers/types/api/pageData'
|
||||
import { getResponsiveClass, getResponsiveSrc } from '#layers/utils/dataUtil'
|
||||
import type { PageDataResourceGroup } from '#layers/types/api/pageData'
|
||||
|
||||
const props = defineProps<{
|
||||
componentData: PageDataComponent
|
||||
resourcesData: PageDataResourceGroup
|
||||
gradientClass?: string
|
||||
groupSets?: boolean
|
||||
}>()
|
||||
|
||||
const resourcesData = computed(() => {
|
||||
return getResourcesData({
|
||||
resources: props.componentData?.resources,
|
||||
groupSets: props.groupSets,
|
||||
})
|
||||
const resPath = computed(() => {
|
||||
return props.resourcesData?.res_path
|
||||
})
|
||||
const bgStyles = computed(() => {
|
||||
return getResponsiveSrc(resourcesData.value?.res_path, {
|
||||
return getResponsiveSrc(resPath.value, {
|
||||
resourcesType: 'bg',
|
||||
})
|
||||
})
|
||||
const videoSrc = computed(() => {
|
||||
return getResponsiveSrc(resourcesData.value?.res_path, {
|
||||
return getResponsiveSrc(resPath.value, {
|
||||
resourcesType: 'video',
|
||||
})
|
||||
})
|
||||
const posterSrc = computed(() => {
|
||||
return getResponsiveSrc(resourcesData.value?.res_path)
|
||||
return getResponsiveSrc(resPath.value)
|
||||
})
|
||||
</script>
|
||||
|
||||
|
||||
@@ -1,31 +0,0 @@
|
||||
<script setup lang="ts">
|
||||
import { getResourcesData } from '#layers/utils/dataUtil'
|
||||
import type { PageDataComponent } from '#layers/types/api/pageData'
|
||||
|
||||
const props = defineProps<{
|
||||
componentData: PageDataComponent
|
||||
groupSets?: boolean
|
||||
}>()
|
||||
|
||||
const resourcesData = computed(() => {
|
||||
return getResourcesData({
|
||||
resources: props.componentData?.resources,
|
||||
isMultiple: true,
|
||||
groupSets: props.groupSets,
|
||||
})
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<template v-if="resourcesData">
|
||||
<AtomsButton
|
||||
v-for="button in resourcesData"
|
||||
:key="button.group_label"
|
||||
:background-color="button.btn_info?.color_code_btn"
|
||||
:text-color="button.btn_info?.color_code_txt"
|
||||
:disabled="button.btn_info?.disabled"
|
||||
>
|
||||
{{ button.btn_info?.txt_btn_name }}
|
||||
</AtomsButton>
|
||||
</template>
|
||||
</template>
|
||||
21
layers/components/widgets/ButtonList.vue
Normal file
21
layers/components/widgets/ButtonList.vue
Normal file
@@ -0,0 +1,21 @@
|
||||
<script setup lang="ts">
|
||||
import type { PageDataResourceGroup } from '#layers/types/api/pageData'
|
||||
|
||||
const props = defineProps<{
|
||||
groupsData: PageDataResourceGroup[]
|
||||
}>()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<template v-if="props.groupsData">
|
||||
<AtomsButton
|
||||
v-for="button in props.groupsData"
|
||||
:key="button.group_code"
|
||||
:background-color="button.btn_info?.color_code_btn"
|
||||
:text-color="button.btn_info?.color_code_txt"
|
||||
:disabled="button.btn_info?.disabled"
|
||||
>
|
||||
{{ button.btn_info?.txt_btn_name }}
|
||||
</AtomsButton>
|
||||
</template>
|
||||
</template>
|
||||
@@ -1,21 +1,13 @@
|
||||
<script setup lang="ts">
|
||||
import { getResourcesData, getResponsiveSrc } from '#layers/utils/dataUtil'
|
||||
import type { PageDataComponent } from '#layers/types/api/pageData'
|
||||
import { getResponsiveSrc } from '#layers/utils/dataUtil'
|
||||
import type { PageDataResourceGroup } from '#layers/types/api/pageData'
|
||||
|
||||
const props = defineProps<{
|
||||
componentData: PageDataComponent
|
||||
groupSets?: boolean
|
||||
resourcesData: PageDataResourceGroup
|
||||
}>()
|
||||
|
||||
const resourcesData = computed(() => {
|
||||
return getResourcesData({
|
||||
resources: props.componentData?.resources,
|
||||
groupSets: props.groupSets,
|
||||
})
|
||||
})
|
||||
|
||||
const displayText = resourcesData.value?.display?.txt
|
||||
const imageSrc = getResponsiveSrc(resourcesData.value?.res_path)
|
||||
const displayText = props.resourcesData?.display?.text
|
||||
const imageSrc = getResponsiveSrc(props.resourcesData?.res_path)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
||||
@@ -1,21 +1,13 @@
|
||||
<script setup lang="ts">
|
||||
import { getResourcesData, getResponsiveSrc } from '#layers/utils/dataUtil'
|
||||
import type { PageDataComponent } from '#layers/types/api/pageData'
|
||||
import { getResponsiveSrc } from '#layers/utils/dataUtil'
|
||||
import type { PageDataResourceGroup } from '#layers/types/api/pageData'
|
||||
|
||||
const props = defineProps<{
|
||||
componentData: PageDataComponent
|
||||
groupSets?: boolean
|
||||
resourcesData: PageDataResourceGroup
|
||||
}>()
|
||||
|
||||
const resourcesData = computed(() => {
|
||||
return getResourcesData({
|
||||
resources: props.componentData?.resources,
|
||||
groupSets: props.groupSets,
|
||||
})
|
||||
})
|
||||
|
||||
const displayText = resourcesData.value?.display?.txt
|
||||
const imageSrc = getResponsiveSrc(resourcesData.value?.res_path)
|
||||
const displayText = props.resourcesData?.display?.text
|
||||
const imageSrc = getResponsiveSrc(props.resourcesData?.res_path)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
||||
@@ -1,21 +1,13 @@
|
||||
<script setup lang="ts">
|
||||
import { getResourcesData, getResponsiveSrc } from '#layers/utils/dataUtil'
|
||||
import type { PageDataComponent } from '#layers/types/api/pageData'
|
||||
import { getResponsiveSrc } from '#layers/utils/dataUtil'
|
||||
import type { PageDataResourceGroup } from '#layers/types/api/pageData'
|
||||
|
||||
const props = defineProps<{
|
||||
componentData: PageDataComponent
|
||||
groupSets?: boolean
|
||||
resourcesData: PageDataResourceGroup
|
||||
}>()
|
||||
|
||||
const resourcesData = computed(() => {
|
||||
return getResourcesData({
|
||||
resources: props.componentData?.resources,
|
||||
groupSets: props.groupSets,
|
||||
})
|
||||
})
|
||||
|
||||
const displayText = resourcesData.value?.display?.txt
|
||||
const imageSrc = getResponsiveSrc(resourcesData.value?.res_path)
|
||||
const displayText = props.resourcesData?.display?.text
|
||||
const imageSrc = getResponsiveSrc(props.resourcesData?.res_path)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
||||
@@ -1,30 +1,48 @@
|
||||
<script setup lang="ts">
|
||||
import {
|
||||
getResourcesData,
|
||||
getResponsiveSrc,
|
||||
getResponsiveClass,
|
||||
} from '#layers/utils/dataUtil'
|
||||
import type { PageDataComponent } from '#layers/types/api/pageData'
|
||||
import { getResponsiveSrc, getResponsiveClass } from '#layers/utils/dataUtil'
|
||||
import type { PageDataResourceGroup } from '#layers/types/api/pageData'
|
||||
|
||||
const props = defineProps<{ componentData: PageDataComponent }>()
|
||||
const props = defineProps<{ resourcesData: PageDataResourceGroup }>()
|
||||
|
||||
const resourcesData = computed(() => {
|
||||
return getResourcesData({
|
||||
resources: props.componentData?.resources,
|
||||
})
|
||||
})
|
||||
const bgStyles = getResponsiveSrc(resourcesData.value?.res_path, {
|
||||
const bgStyles = getResponsiveSrc(props.resourcesData?.res_path, {
|
||||
resourcesType: 'bg',
|
||||
})
|
||||
|
||||
// YouTube 모달 상태 관리
|
||||
const isYouTubeModalOpen = ref(false)
|
||||
const youtubeVideoId = ref('')
|
||||
|
||||
// 비디오 플레이 버튼 클릭 핸들러
|
||||
const handleVideoPlayClick = () => {
|
||||
// TODO: 실제 YouTube 비디오 ID를 설정해야 합니다
|
||||
// 예시: 'dQw4w9WgXcQ' (Rick Astley - Never Gonna Give You Up)
|
||||
youtubeVideoId.value = 'UKVsZYHxYTc' // 임시로 설정
|
||||
isYouTubeModalOpen.value = true
|
||||
}
|
||||
|
||||
// 모달 닫기 핸들러
|
||||
const handleCloseModal = () => {
|
||||
isYouTubeModalOpen.value = false
|
||||
youtubeVideoId.value = ''
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<button
|
||||
v-if="resourcesData"
|
||||
class="bg-cover bg-center bg-no-repeat w-[66px] h-[66px] lg:w-[100px] lg:h-[100px]"
|
||||
:class="getResponsiveClass()"
|
||||
:class="getResponsiveClass"
|
||||
:style="bgStyles"
|
||||
@click="handleVideoPlayClick"
|
||||
>
|
||||
<span class="sr-only">videoPlay</span>
|
||||
</button>
|
||||
|
||||
<!-- YouTube 모달 -->
|
||||
<BlocksModalYouTube
|
||||
:is-open="isYouTubeModalOpen"
|
||||
:youtube-id="youtubeVideoId"
|
||||
@close="handleCloseModal"
|
||||
@update:is-open="(value: boolean) => (isYouTubeModalOpen = value)"
|
||||
/>
|
||||
</template>
|
||||
|
||||
@@ -1,28 +0,0 @@
|
||||
import type { GameDataKeyCodeCodes } from '#layers/types/api/gameData'
|
||||
|
||||
/**
|
||||
* 게임 데이터의 key_code_codes를 CSS 커스텀 프로퍼티로 적용하는 기능을 제공합니다.
|
||||
*/
|
||||
export const useGameKeyCodeColors = () => {
|
||||
/**
|
||||
* @param keyColorCodes
|
||||
*/
|
||||
const applyGameKeyCodeColors = (
|
||||
keyColorCodes: GameDataKeyCodeCodes | null
|
||||
) => {
|
||||
if (!keyColorCodes || import.meta.server) {
|
||||
return
|
||||
}
|
||||
|
||||
const root = document.documentElement
|
||||
|
||||
Object.entries(keyColorCodes).forEach(([key, value]) => {
|
||||
const cssVarName = `--${key}`
|
||||
root.style.setProperty(cssVarName, String(value))
|
||||
})
|
||||
}
|
||||
|
||||
return {
|
||||
applyGameKeyCodeColors,
|
||||
}
|
||||
}
|
||||
@@ -11,7 +11,7 @@ export default defineNuxtRouteMiddleware(async (to, _from) => {
|
||||
const { getPathAfterLanguage } = usePathResolver()
|
||||
|
||||
const stoveApiBaseUrl = config.public.stoveApiUrl
|
||||
const apiUrl = `${stoveApiBaseUrl}/pub-comm/v1.0/template/page`
|
||||
const apiUrl = `${stoveApiBaseUrl}/pub-comm/v2.0/template/page`
|
||||
|
||||
try {
|
||||
const pageUrl = getPathAfterLanguage(to.path)
|
||||
|
||||
@@ -10,7 +10,7 @@ const props = defineProps<Props>()
|
||||
<section class="relative h-[640px] lg:h-[1000px]">
|
||||
<WidgetsBackground
|
||||
v-if="props.components?.background"
|
||||
:component-data="props.components?.background"
|
||||
:resources-data="props.components?.background.groups[0]"
|
||||
gradient-class="bg-gradient-to-b from-[#100d0f]/0 to-[#100d0f]"
|
||||
/>
|
||||
<div
|
||||
@@ -18,16 +18,16 @@ const props = defineProps<Props>()
|
||||
>
|
||||
<WidgetsMainTitle
|
||||
v-if="props.components.mainTitle"
|
||||
:component-data="props.components.mainTitle"
|
||||
:resources-data="props.components.mainTitle.groups[0]"
|
||||
class="w-[355px] lg:w-[944px]"
|
||||
/>
|
||||
<WidgetsDescription
|
||||
v-if="props.components.description"
|
||||
:component-data="props.components.description"
|
||||
:resources-data="props.components.description.groups[0]"
|
||||
/>
|
||||
<WidgetsVideoPlay
|
||||
v-if="props.components.videoPlay"
|
||||
:component-data="props.components.videoPlay"
|
||||
:resources-data="props.components.videoPlay.groups[0]"
|
||||
/>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
@@ -4,42 +4,35 @@ interface Props {
|
||||
}
|
||||
|
||||
const props = defineProps<Props>()
|
||||
|
||||
console.log('components:', props.components)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<section class="relative h-[640px] lg:h-[1000px]">
|
||||
<WidgetsBackground
|
||||
v-if="props.components?.cardBackground"
|
||||
:component-data="props.components?.cardBackground"
|
||||
:group-sets="true"
|
||||
v-if="props.components?.background"
|
||||
:resources-data="props.components?.background.groups[0]"
|
||||
/>
|
||||
<div
|
||||
class="relative h-full flex flex-col items-center justify-center gap-4"
|
||||
>
|
||||
<WidgetsSubTitle
|
||||
v-if="props.components.cardSubTitle"
|
||||
:component-data="props.components.cardSubTitle"
|
||||
:group-sets="true"
|
||||
v-if="props.components.subTitle"
|
||||
:resources-data="props.components.subTitle.groups[0]"
|
||||
class="text-[24px] font-[500] text-[#ffffff] leading-[34px]"
|
||||
/>
|
||||
<WidgetsMainTitle
|
||||
v-if="props.components.cardMainTitle"
|
||||
:component-data="props.components.cardMainTitle"
|
||||
:group-sets="true"
|
||||
v-if="props.components.mainTitle"
|
||||
:resources-data="props.components.cardMainTitle.groups[0]"
|
||||
class="text-[50px] font-[700] text-[#c7a28b] leading-[70px]"
|
||||
/>
|
||||
<WidgetsDescription
|
||||
v-if="props.components.cardDescription"
|
||||
:component-data="props.components.cardDescription"
|
||||
:group-sets="true"
|
||||
v-if="props.components.description"
|
||||
:resources-data="props.components.description.groups[0]"
|
||||
class="text-[20px] font-[500] text-white/70 leading-[30px]"
|
||||
/>
|
||||
<WidgetsButton
|
||||
v-if="props.components.cardButtonList"
|
||||
:component-data="props.components.cardButtonList"
|
||||
:group-sets="true"
|
||||
<WidgetsButtonList
|
||||
v-if="props.components.buttonList"
|
||||
:groups-data="props.components.buttonList"
|
||||
/>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
@@ -54,20 +54,39 @@ export interface PageDataMetaTag {
|
||||
page_title: string
|
||||
}
|
||||
|
||||
// 리소스 타입
|
||||
export interface PageDataResource {
|
||||
resource_sort_order: number
|
||||
resource_name: string
|
||||
resource_type: string
|
||||
groups: Record<string, any>
|
||||
group_sets: Record<string, any>
|
||||
// 리소스 그룹 타입
|
||||
export interface PageDataResourceGroupResPath {
|
||||
path_mo: string
|
||||
path_pc?: string
|
||||
}
|
||||
|
||||
// 리소스 그룹 타입
|
||||
export interface PageDataResourceGroup {
|
||||
group_type?: string
|
||||
group_code?: string
|
||||
res_path?: PageDataResourceGroupResPath
|
||||
btn_info?: {
|
||||
color_code_btn: string
|
||||
color_code_txt: string
|
||||
disabled: boolean
|
||||
txt_btn_name: string
|
||||
detail: Record<string, any>
|
||||
}
|
||||
display?: {
|
||||
text: string
|
||||
}
|
||||
}
|
||||
|
||||
// 컴포넌트 타입
|
||||
export interface PageDataComponent {
|
||||
resources: PageDataResource[]
|
||||
groups: PageDataResourceGroup[]
|
||||
}
|
||||
|
||||
// 템플릿 컴포넌트 타입 - 두 가지 패턴 지원
|
||||
export type PageDataTemplateComponents =
|
||||
| Record<string, PageDataComponent> // 직접 PageDataComponent가 들어있는 패턴
|
||||
| { group_sets: Record<string, any> } // group_sets 안에 PageDataComponent가 들어있는 패턴
|
||||
|
||||
// LNB 메뉴 타입
|
||||
export interface PageDataLnbMenu {
|
||||
path_code: string
|
||||
@@ -86,13 +105,7 @@ export interface PageDataTemplate {
|
||||
page_ver_tmpl_name: string
|
||||
page_ver_tmpl_name_en: string
|
||||
template_code: string
|
||||
components_: PageDataTemplateComponent
|
||||
// components: string // JSON string
|
||||
}
|
||||
|
||||
// 템플릿 컴포넌트 타입
|
||||
export interface PageDataTemplateComponent {
|
||||
components: Record<string, PageDataComponent>
|
||||
components: PageDataTemplateComponents
|
||||
}
|
||||
|
||||
// ===== API 관련 타입들 =====
|
||||
|
||||
@@ -1,3 +1,15 @@
|
||||
import type {
|
||||
PageDataValue,
|
||||
PageDataResourceGroupResPath,
|
||||
} from '#layers/types/api/pageData'
|
||||
|
||||
// 레이아웃 타입 리턴하는 함수
|
||||
export const getLayoutType = (
|
||||
pageData: PageDataValue | null
|
||||
): 'default' | 'promotion' => {
|
||||
return pageData?.page_type === 1 ? 'default' : 'promotion'
|
||||
}
|
||||
|
||||
// 이미지 호스트 리턴하는 함수
|
||||
// [TODO] 환경변수 처리 수정
|
||||
export const getResolvedHost = (path: string): string => {
|
||||
@@ -10,27 +22,6 @@ export const getResolvedHost = (path: string): string => {
|
||||
return `${rootPath}${path}`
|
||||
}
|
||||
|
||||
// 리소스 데이터 리턴하는 함수
|
||||
// [TODO] data 타입 정의
|
||||
export const getResourcesData = ({
|
||||
resources,
|
||||
isMultiple = false,
|
||||
groupSets = false,
|
||||
}: {
|
||||
resources: any
|
||||
isMultiple?: boolean
|
||||
groupSets?: boolean
|
||||
}) => {
|
||||
const groups = groupSets
|
||||
? resources[0]?.group_sets[0]?.groups
|
||||
: resources[0]?.groups
|
||||
|
||||
if (isMultiple) {
|
||||
return groups
|
||||
}
|
||||
return groups?.[0] ?? null
|
||||
}
|
||||
|
||||
// 반응형 클래스 리턴하는 함수
|
||||
export const getResponsiveClass = () => {
|
||||
return ['bg-[image:var(--mobile-bg)]', 'sm:bg-[image:var(--pc-bg)]']
|
||||
@@ -38,7 +29,7 @@ export const getResponsiveClass = () => {
|
||||
|
||||
// 통합된 반응형 리소스 함수
|
||||
export const getResponsiveSrc = (
|
||||
pathArray: any,
|
||||
pathArray: PageDataResourceGroupResPath,
|
||||
options: {
|
||||
resourcesType?: 'image' | 'bg' | 'video'
|
||||
} = {}
|
||||
|
||||
Reference in New Issue
Block a user