fix. main 컴포넌트 변경, 수정된 api 구조에 맞춰 코드 수정
This commit is contained in:
137
app/app.vue
137
app/app.vue
@@ -1,73 +1,134 @@
|
|||||||
<template>
|
|
||||||
<NuxtLayout>
|
|
||||||
<h1 class="sr-only">dddd</h1>
|
|
||||||
<NuxtPage />
|
|
||||||
|
|
||||||
<LoadingFull />
|
|
||||||
<LoadingLocal />
|
|
||||||
</NuxtLayout>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { useNuxtApp } from 'nuxt/app'
|
import { useNuxtApp } from 'nuxt/app'
|
||||||
import LoadingFull from '#layers/components/blocks/loading/Full.vue'
|
import LoadingFull from '#layers/components/blocks/loading/Full.vue'
|
||||||
import LoadingLocal from '#layers/components/blocks/loading/Local.vue'
|
import LoadingLocal from '#layers/components/blocks/loading/Local.vue'
|
||||||
import { useGameDataStore } from '#layers/stores/useGameDataStore'
|
import type {
|
||||||
import { useGameColors } from '#layers/composables/useGameColors'
|
GameDataMetaTag,
|
||||||
import type { GameDataMetaTag, GameDataValue } from '#layers/types/api/gameData'
|
GameDataValue,
|
||||||
|
GameDataFaviconPath,
|
||||||
|
} from '#layers/types/api/gameData'
|
||||||
|
|
||||||
const nuxtApp = useNuxtApp()
|
const nuxtApp = useNuxtApp()
|
||||||
const getGameData = ref<GameDataValue | null>(null)
|
|
||||||
const metaData = ref<GameDataMetaTag | null>(null)
|
|
||||||
const { setGameData } = useGameDataStore()
|
const { setGameData } = useGameDataStore()
|
||||||
const { applyGameColors } = useGameColors()
|
const { applyGameKeyCodeColors } = useGameKeyCodeColors()
|
||||||
|
|
||||||
// SSR에서만 접근 가능
|
const gameData = ref<GameDataValue | null>(null)
|
||||||
const gameDataFromServer = import.meta.server
|
const metaData = ref<GameDataMetaTag | null>(null)
|
||||||
? nuxtApp.ssrContext?.event.context.gameData
|
|
||||||
|
// SSR에서 게임 데이터 가져오기
|
||||||
|
const getGameDataFromServer = (): GameDataValue | null => {
|
||||||
|
return import.meta.server
|
||||||
|
? (nuxtApp.ssrContext?.event.context.gameData ?? null)
|
||||||
: null
|
: null
|
||||||
|
|
||||||
if (gameDataFromServer) {
|
|
||||||
getGameData.value = gameDataFromServer
|
|
||||||
setGameData(gameDataFromServer)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 클라이언트에서 색상 코드 적용
|
||||||
|
const applyColorsOnClient = () => {
|
||||||
if (import.meta.client) {
|
if (import.meta.client) {
|
||||||
const gameDataStore = useGameDataStore()
|
const gameDataStore = useGameDataStore()
|
||||||
|
const keyCodeCodes = gameDataStore.gameData?.key_code_codes
|
||||||
|
|
||||||
if (gameDataStore.gameData?.key_color_codes) {
|
if (keyCodeCodes) {
|
||||||
applyGameColors(gameDataStore.gameData.key_color_codes)
|
applyGameKeyCodeColors(keyCodeCodes)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const meta = gameDataFromServer?.meta_tag ?? null
|
// SEO 메타 태그 설정
|
||||||
const theme = gameDataFromServer?.design_theme === 1 ? 'dark' : 'light'
|
const setupSeoMeta = (meta: GameDataMetaTag) => {
|
||||||
|
|
||||||
if (gameDataFromServer && meta) {
|
|
||||||
metaData.value = meta
|
|
||||||
useSeoMeta({
|
useSeoMeta({
|
||||||
title: meta.page_title,
|
title: meta.page_title,
|
||||||
description: meta.page_desc,
|
description: meta.page_desc,
|
||||||
ogTitle: meta.og_title,
|
ogTitle: meta.og_title,
|
||||||
ogImage: meta.og_image,
|
ogImage: meta.og_image,
|
||||||
ogDescription: meta.og_desc,
|
ogDescription: meta.og_desc,
|
||||||
ogUrl: meta.og_url,
|
|
||||||
twitterImage: meta.x_image,
|
twitterImage: meta.x_image,
|
||||||
twitterTitle: meta.x_title,
|
twitterTitle: meta.x_title,
|
||||||
twitterDescription: meta.x_desc,
|
twitterDescription: meta.x_desc,
|
||||||
})
|
})
|
||||||
useHead({
|
}
|
||||||
htmlAttrs: {
|
|
||||||
'data-game': gameDataFromServer.game_name || '',
|
// 파비콘 설정
|
||||||
'data-theme': theme || '',
|
const setupFavicon = (faviconPath: GameDataFaviconPath) => {
|
||||||
lang: gameDataFromServer.default_lang_code,
|
const faviconLinks = [
|
||||||
|
{
|
||||||
|
rel: 'icon',
|
||||||
|
type: 'image/x-icon',
|
||||||
|
sizes: '16x16',
|
||||||
|
href: faviconPath['16_16'],
|
||||||
},
|
},
|
||||||
//meta: [...(updatedMetaTags.value || [])],
|
{
|
||||||
//link: [...(links.value || [])]
|
rel: 'icon',
|
||||||
|
type: 'image/x-icon',
|
||||||
|
sizes: '32x32',
|
||||||
|
href: faviconPath['32_32'],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
rel: 'icon',
|
||||||
|
type: 'image/png',
|
||||||
|
sizes: '72x72',
|
||||||
|
href: faviconPath['72_72'],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
rel: 'apple-touch-icon',
|
||||||
|
sizes: '180x180',
|
||||||
|
href: faviconPath['180_180'],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
rel: 'icon',
|
||||||
|
type: 'image/png',
|
||||||
|
sizes: '192x192',
|
||||||
|
href: faviconPath['192_192'],
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
useHead({
|
||||||
|
link: faviconLinks,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// HTML 속성 설정
|
||||||
|
const setupHtmlAttributes = (data: GameDataValue) => {
|
||||||
|
const theme = data.design_theme === 1 ? 'dark' : 'light'
|
||||||
|
|
||||||
|
useHead({
|
||||||
|
htmlAttrs: {
|
||||||
|
'data-game': data.game_name || '',
|
||||||
|
'data-theme': theme,
|
||||||
|
lang: data.default_lang_code || 'ko',
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 메타 데이터 설정
|
||||||
|
const setupMetaData = (data: GameDataValue) => {
|
||||||
|
metaData.value = data.meta_tag
|
||||||
|
setupSeoMeta(metaData.value)
|
||||||
|
setupHtmlAttributes(data)
|
||||||
|
setupFavicon(data.favicon_path)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 초기화 로직 실행
|
||||||
|
const serverGameData = getGameDataFromServer()
|
||||||
|
|
||||||
|
if (serverGameData) {
|
||||||
|
gameData.value = serverGameData
|
||||||
|
setGameData(serverGameData)
|
||||||
|
setupMetaData(serverGameData)
|
||||||
|
applyColorsOnClient()
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<h1 class="sr-only">{{ gameData?.game_name }}</h1>
|
||||||
|
<NuxtPage />
|
||||||
|
|
||||||
|
<!-- 로딩 컴포넌트들 -->
|
||||||
|
<LoadingFull />
|
||||||
|
<LoadingLocal />
|
||||||
|
</template>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
@import '#layers/assets/css/app.css';
|
@import '#layers/assets/css/app.css';
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -1,37 +1,25 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { storeToRefs } from 'pinia'
|
|
||||||
import { usePageDataStore } from '#layers/stores/usePageDataStore'
|
import { usePageDataStore } from '#layers/stores/usePageDataStore'
|
||||||
|
import type { PageDataValue } from '#layers/types/api/pageData'
|
||||||
|
|
||||||
const pageDataStore = usePageDataStore()
|
const pageDataStore = usePageDataStore()
|
||||||
const { pageData } = storeToRefs(pageDataStore)
|
const { pageData } = storeToRefs(pageDataStore)
|
||||||
|
|
||||||
// const layout = pageData.value?.meta?.layout ?? "default";
|
const getLayoutType = (
|
||||||
const layout = 'default' // 기본 레이아웃 사용
|
pageData: PageDataValue | null
|
||||||
|
): 'default' | 'promotion' => {
|
||||||
// definePageMeta를 사용하여 레이아웃을 미리 설정
|
return pageData?.page_type === 1 ? 'default' : 'promotion'
|
||||||
definePageMeta({
|
|
||||||
layout: false, // 기본 레이아웃 비활성화
|
|
||||||
})
|
|
||||||
|
|
||||||
// definePageMeta를 사용하여 레이아웃을 미리 설정
|
|
||||||
watchEffect(() => {
|
|
||||||
if (pageData.value?.meta_tag) {
|
|
||||||
useSeoMeta({
|
|
||||||
title: pageData.value.meta_tag.page_title ?? '',
|
|
||||||
description: pageData.value.meta_tag.page_desc ?? '',
|
|
||||||
ogTitle: pageData.value.meta_tag.og_title ?? '',
|
|
||||||
ogDescription: pageData.value.meta_tag.og_desc ?? '',
|
|
||||||
ogImage: pageData.value.meta_tag.og_image ?? '',
|
|
||||||
twitterTitle: pageData.value.meta_tag.x_title ?? '',
|
|
||||||
twitterImage: pageData.value.meta_tag.x_image ?? '',
|
|
||||||
twitterDescription: pageData.value.meta_tag.x_desc ?? '',
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const currentLayout = computed(() => getLayoutType(pageData.value))
|
||||||
|
|
||||||
|
definePageMeta({
|
||||||
|
layout: false, // 동적 레이아웃을 위해 기본 레이아웃 비활성화
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<NuxtLayout :name="layout">
|
<NuxtLayout :name="currentLayout">
|
||||||
<LayoutsMain :templates="pageData?.templates ?? []" />
|
<LayoutsMain v-if="pageData" :page-data="pageData" />
|
||||||
</NuxtLayout>
|
</NuxtLayout>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -1,37 +1,25 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { storeToRefs } from 'pinia'
|
|
||||||
import { usePageDataStore } from '#layers/stores/usePageDataStore'
|
import { usePageDataStore } from '#layers/stores/usePageDataStore'
|
||||||
|
import type { PageDataValue } from '#layers/types/api/pageData'
|
||||||
|
|
||||||
const pageDataStore = usePageDataStore()
|
const pageDataStore = usePageDataStore()
|
||||||
const { pageData } = storeToRefs(pageDataStore)
|
const { pageData } = storeToRefs(pageDataStore)
|
||||||
|
|
||||||
// const layout = pageData.value?.meta?.layout ?? "default";
|
const getLayoutType = (
|
||||||
const layout = 'default' // 기본 레이아웃 사용
|
pageData: PageDataValue | null
|
||||||
|
): 'default' | 'promotion' => {
|
||||||
// definePageMeta를 사용하여 레이아웃을 미리 설정
|
return pageData?.page_type === 1 ? 'default' : 'promotion'
|
||||||
definePageMeta({
|
|
||||||
layout: false, // 기본 레이아웃 비활성화
|
|
||||||
})
|
|
||||||
|
|
||||||
// definePageMeta를 사용하여 레이아웃을 미리 설정
|
|
||||||
watchEffect(() => {
|
|
||||||
if (pageData.value?.meta_tag) {
|
|
||||||
useSeoMeta({
|
|
||||||
title: pageData.value.meta_tag.page_title ?? '',
|
|
||||||
description: pageData.value.meta_tag.page_desc ?? '',
|
|
||||||
ogTitle: pageData.value.meta_tag.og_title ?? '',
|
|
||||||
ogDescription: pageData.value.meta_tag.og_desc ?? '',
|
|
||||||
ogImage: pageData.value.meta_tag.og_image ?? '',
|
|
||||||
twitterTitle: pageData.value.meta_tag.x_title ?? '',
|
|
||||||
twitterImage: pageData.value.meta_tag.x_image ?? '',
|
|
||||||
twitterDescription: pageData.value.meta_tag.x_desc ?? '',
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const currentLayout = computed(() => getLayoutType(pageData.value))
|
||||||
|
|
||||||
|
definePageMeta({
|
||||||
|
layout: false, // 동적 레이아웃을 위해 기본 레이아웃 비활성화
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<NuxtLayout :name="layout">
|
<NuxtLayout :name="currentLayout">
|
||||||
<LayoutsMain :templates="pageData?.templates ?? []" />
|
<LayoutsMain v-if="pageData" :page-data="pageData" />
|
||||||
</NuxtLayout>
|
</NuxtLayout>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -1,37 +1,25 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { storeToRefs } from 'pinia'
|
|
||||||
import { usePageDataStore } from '#layers/stores/usePageDataStore'
|
import { usePageDataStore } from '#layers/stores/usePageDataStore'
|
||||||
|
import type { PageDataValue } from '#layers/types/api/pageData'
|
||||||
|
|
||||||
const pageDataStore = usePageDataStore()
|
const pageDataStore = usePageDataStore()
|
||||||
const { pageData } = storeToRefs(pageDataStore)
|
const { pageData } = storeToRefs(pageDataStore)
|
||||||
|
|
||||||
// const layout = pageData.value?.meta?.layout ?? "default";
|
const getLayoutType = (
|
||||||
const layout = 'default' // 기본 레이아웃 사용
|
pageData: PageDataValue | null
|
||||||
|
): 'default' | 'promotion' => {
|
||||||
// definePageMeta를 사용하여 레이아웃을 미리 설정
|
return pageData?.page_type === 1 ? 'default' : 'promotion'
|
||||||
definePageMeta({
|
|
||||||
layout: false, // 기본 레이아웃 비활성화
|
|
||||||
})
|
|
||||||
|
|
||||||
// definePageMeta를 사용하여 레이아웃을 미리 설정
|
|
||||||
watchEffect(() => {
|
|
||||||
if (pageData.value?.meta_tag) {
|
|
||||||
useSeoMeta({
|
|
||||||
title: pageData.value.meta_tag.page_title ?? '',
|
|
||||||
description: pageData.value.meta_tag.page_desc ?? '',
|
|
||||||
ogTitle: pageData.value.meta_tag.og_title ?? '',
|
|
||||||
ogDescription: pageData.value.meta_tag.og_desc ?? '',
|
|
||||||
ogImage: pageData.value.meta_tag.og_image ?? '',
|
|
||||||
twitterTitle: pageData.value.meta_tag.x_title ?? '',
|
|
||||||
twitterImage: pageData.value.meta_tag.x_image ?? '',
|
|
||||||
twitterDescription: pageData.value.meta_tag.x_desc ?? '',
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const currentLayout = computed(() => getLayoutType(pageData.value))
|
||||||
|
|
||||||
|
definePageMeta({
|
||||||
|
layout: false, // 동적 레이아웃을 위해 기본 레이아웃 비활성화
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<NuxtLayout :name="layout">
|
<NuxtLayout :name="currentLayout">
|
||||||
<LayoutsMain :templates="pageData?.templates ?? []" />
|
<LayoutsMain v-if="pageData" :page-data="pageData" />
|
||||||
</NuxtLayout>
|
</NuxtLayout>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -1,46 +1,25 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { storeToRefs } from 'pinia'
|
|
||||||
import { usePageDataStore } from '#layers/stores/usePageDataStore'
|
import { usePageDataStore } from '#layers/stores/usePageDataStore'
|
||||||
|
import type { PageDataValue } from '#layers/types/api/pageData'
|
||||||
|
|
||||||
const pageDataStore = usePageDataStore()
|
const pageDataStore = usePageDataStore()
|
||||||
const { pageData } = storeToRefs(pageDataStore)
|
const { pageData } = storeToRefs(pageDataStore)
|
||||||
|
|
||||||
// 동적 i18n 라우트 설정
|
const getLayoutType = (
|
||||||
// const { getI18nRouteConfig } = useDynamicI18nRoutes();
|
pageData: PageDataValue | null
|
||||||
|
): 'default' | 'promotion' => {
|
||||||
// const layout = pageData.value?.meta?.layout ?? "default";
|
return pageData?.page_type === 1 ? 'default' : 'promotion'
|
||||||
const layout = 'default' // 기본 레이아웃 사용
|
|
||||||
|
|
||||||
// definePageMeta를 사용하여 레이아웃을 미리 설정
|
|
||||||
definePageMeta({
|
|
||||||
layout: false, // 기본 레이아웃 비활성화
|
|
||||||
})
|
|
||||||
|
|
||||||
// // gameData.lang_codes를 기반으로 동적 언어 제외 설정
|
|
||||||
// const i18nRouteConfig = getI18nRouteConfig();
|
|
||||||
// if (i18nRouteConfig) {
|
|
||||||
// defineI18nRoute(i18nRouteConfig);
|
|
||||||
// }
|
|
||||||
|
|
||||||
// SEO 메타 태그 설정 - pageData가 로드된 후에만 실행
|
|
||||||
watchEffect(() => {
|
|
||||||
if (pageData.value?.meta_tag) {
|
|
||||||
useSeoMeta({
|
|
||||||
title: pageData.value.meta_tag.page_title ?? '',
|
|
||||||
description: pageData.value.meta_tag.page_desc ?? '',
|
|
||||||
ogTitle: pageData.value.meta_tag.og_title ?? '',
|
|
||||||
ogDescription: pageData.value.meta_tag.og_desc ?? '',
|
|
||||||
ogImage: pageData.value.meta_tag.og_image ?? '',
|
|
||||||
twitterTitle: pageData.value.meta_tag.x_title ?? '',
|
|
||||||
twitterImage: pageData.value.meta_tag.x_image ?? '',
|
|
||||||
twitterDescription: pageData.value.meta_tag.x_desc ?? '',
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const currentLayout = computed(() => getLayoutType(pageData.value))
|
||||||
|
|
||||||
|
definePageMeta({
|
||||||
|
layout: false, // 동적 레이아웃을 위해 기본 레이아웃 비활성화
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<NuxtLayout :name="layout">
|
<NuxtLayout :name="currentLayout">
|
||||||
<LayoutsMain :templates="pageData?.templates ?? []" />
|
<LayoutsMain v-if="pageData" :page-data="pageData" />
|
||||||
</NuxtLayout>
|
</NuxtLayout>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -1,160 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div class="p-8">
|
|
||||||
<h1 class="text-2xl font-bold mb-4">{{ t('messages.title_test_lang') }}</h1>
|
|
||||||
|
|
||||||
<div class="mb-6">
|
|
||||||
<h2 class="text-lg font-semibold mb-2">{{ t('messages.welcome') }}</h2>
|
|
||||||
<p>
|
|
||||||
<strong>{{ t('messages.GameData_load_status') }}:</strong>
|
|
||||||
<span :class="isGameDataLoaded ? 'text-green-600' : 'text-red-600'">
|
|
||||||
{{ isGameDataLoaded ? '로드됨' : '로드되지 않음' }}
|
|
||||||
</span>
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
<strong>{{ t('messages.current_language') }}:</strong>
|
|
||||||
{{ $i18n.locale }}
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
<strong>{{ t('messages.default_language') }}:</strong>
|
|
||||||
{{ gameDataStore.gameData?.default_lang_code || 'N/A' }}
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
<strong>{{ t('messages.available_languages') }}:</strong>
|
|
||||||
{{
|
|
||||||
Array.isArray(availableLanguages)
|
|
||||||
? availableLanguages.join(', ')
|
|
||||||
: availableLanguages
|
|
||||||
}}
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
<strong>{{ t('messages.current_url') }}:</strong>
|
|
||||||
{{ $route.path }}
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="mb-6">
|
|
||||||
<h2 class="text-lg font-semibold mb-2">언어 전환:</h2>
|
|
||||||
<LanguageSwitcher />
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="mb-6">
|
|
||||||
<h2 class="text-lg font-semibold mb-2">직접 링크 테스트:</h2>
|
|
||||||
<div class="space-x-4">
|
|
||||||
<NuxtLink
|
|
||||||
v-for="lang in availableLanguages"
|
|
||||||
:key="lang"
|
|
||||||
:to="`/${lang}/test-lang`"
|
|
||||||
class="px-4 py-2 bg-blue-500 text-white rounded hover:bg-blue-600"
|
|
||||||
>
|
|
||||||
{{ lang.toUpperCase() }} 페이지로 이동
|
|
||||||
</NuxtLink>
|
|
||||||
<NuxtLink
|
|
||||||
:to="`/ja/test-lang`"
|
|
||||||
class="px-4 py-2 bg-blue-500 text-white rounded hover:bg-blue-600"
|
|
||||||
>
|
|
||||||
ja 페이지로 이동
|
|
||||||
</NuxtLink>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="mb-6">
|
|
||||||
<h2 class="text-lg font-semibold mb-2">GameData 정보:</h2>
|
|
||||||
<div v-if="isGameDataLoaded" class="space-y-2">
|
|
||||||
<p>
|
|
||||||
<strong>게임 ID:</strong>
|
|
||||||
{{ gameDataStore.gameData?.game_id }}
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
<strong>게임 코드:</strong>
|
|
||||||
{{ gameDataStore.gameData?.game_code }}
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
<strong>S3 폴더명:</strong>
|
|
||||||
{{ gameDataStore.gameData?.s3_folder_name }}
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
<strong>디자인 테마:</strong>
|
|
||||||
{{ gameDataStore.gameData?.design_theme }}
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
<strong>전체:</strong>
|
|
||||||
{{
|
|
||||||
Array.isArray(gameDataStore.gameData?.key_color_codes)
|
|
||||||
? gameDataStore.gameData?.key_color_codes.join(', ')
|
|
||||||
: gameDataStore.gameData?.key_color_codes
|
|
||||||
}}
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
<pre class="bg-gray-100 p-4 rounded text-sm overflow-auto max-h-80">{{
|
|
||||||
gameDataInfo
|
|
||||||
}}</pre>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="mb-6">
|
|
||||||
<h2 class="text-lg font-semibold mb-2">동적 언어 설정 테스트:</h2>
|
|
||||||
<div class="space-y-2">
|
|
||||||
<p><strong>현재 i18n 설정:</strong></p>
|
|
||||||
<ul class="list-disc list-inside ml-4">
|
|
||||||
<li>
|
|
||||||
사용 가능한 언어:
|
|
||||||
{{ $i18n.availableLocales.map((l: any) => l.code || l).join(', ') }}
|
|
||||||
</li>
|
|
||||||
<li>기본 언어: {{ $i18n.defaultLocale }}</li>
|
|
||||||
<li>현재 언어: {{ $i18n.locale }}</li>
|
|
||||||
</ul>
|
|
||||||
<p class="text-sm text-gray-600 mt-2">
|
|
||||||
GameData에서 가져온 lang_codes가 동적으로 i18n 설정에 반영되었는지
|
|
||||||
확인하세요.
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup lang="ts">
|
|
||||||
import { useI18n } from 'vue-i18n'
|
|
||||||
import { useGameDataStore } from '#layers/stores/useGameDataStore'
|
|
||||||
import LanguageSwitcher from '#layers/components/blocks/LanguageSwitcher.vue'
|
|
||||||
|
|
||||||
const { t, locale } = useI18n()
|
|
||||||
const gameDataStore = useGameDataStore()
|
|
||||||
|
|
||||||
// 사용 가능한 언어 목록
|
|
||||||
const availableLanguages = computed(() => {
|
|
||||||
return gameDataStore.gameData?.lang_codes || ['ko']
|
|
||||||
})
|
|
||||||
|
|
||||||
// GameData가 로드되었는지 확인
|
|
||||||
const isGameDataLoaded = computed(() => {
|
|
||||||
return !!gameDataStore.gameData
|
|
||||||
})
|
|
||||||
|
|
||||||
// GameData 정보를 JSON으로 표시
|
|
||||||
const gameDataInfo = computed(() => {
|
|
||||||
if (!gameDataStore.gameData) {
|
|
||||||
return 'GameData가 로드되지 않았습니다.'
|
|
||||||
}
|
|
||||||
|
|
||||||
return JSON.stringify(
|
|
||||||
{
|
|
||||||
game_id: gameDataStore.gameData.game_id,
|
|
||||||
game_code: gameDataStore.gameData.game_code,
|
|
||||||
s3_folder_name: gameDataStore.gameData.s3_folder_name,
|
|
||||||
default_lang_code: gameDataStore.gameData.default_lang_code || 'ko',
|
|
||||||
lang_codes: gameDataStore.gameData.lang_codes,
|
|
||||||
design_theme: gameDataStore.gameData.design_theme,
|
|
||||||
key_color_codes: gameDataStore.gameData.key_color_codes,
|
|
||||||
use_game_font: gameDataStore.gameData.use_game_font,
|
|
||||||
ga_code: gameDataStore.gameData.ga_code,
|
|
||||||
favicon_path: gameDataStore.gameData.favicon_path,
|
|
||||||
},
|
|
||||||
null,
|
|
||||||
2
|
|
||||||
)
|
|
||||||
})
|
|
||||||
|
|
||||||
// 페이지 메타 설정
|
|
||||||
useHead({
|
|
||||||
title: `언어 테스트 - ${locale.value.toUpperCase()}`,
|
|
||||||
})
|
|
||||||
</script>
|
|
||||||
@@ -4,8 +4,8 @@ import type {
|
|||||||
ButtonConfig,
|
ButtonConfig,
|
||||||
ButtonProps,
|
ButtonProps,
|
||||||
} from '#layers/types/components/button'
|
} from '#layers/types/components/button'
|
||||||
|
import type { GameDataKeyCodeCodes } from '#layers/types/api/gameData'
|
||||||
|
|
||||||
// Props 정의
|
|
||||||
const props = withDefaults(defineProps<ButtonProps>(), {
|
const props = withDefaults(defineProps<ButtonProps>(), {
|
||||||
size: 'medium',
|
size: 'medium',
|
||||||
backgroundColor: 'var(--primary)',
|
backgroundColor: 'var(--primary)',
|
||||||
@@ -14,6 +14,15 @@ const props = withDefaults(defineProps<ButtonProps>(), {
|
|||||||
disabled: false,
|
disabled: false,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// 색상 코드 키 목록 key_code_codes
|
||||||
|
const PARSED_KEY_CODE_CODES_KEYS: (keyof GameDataKeyCodeCodes)[] = [
|
||||||
|
'primary',
|
||||||
|
'text-primary',
|
||||||
|
'text-secondary',
|
||||||
|
'alternative-01',
|
||||||
|
'alternative-02',
|
||||||
|
]
|
||||||
|
|
||||||
// 버튼 크기별 설정 상수
|
// 버튼 크기별 설정 상수
|
||||||
const BUTTON_CONFIGS: Record<ButtonSize, ButtonConfig> = {
|
const BUTTON_CONFIGS: Record<ButtonSize, ButtonConfig> = {
|
||||||
large: {
|
large: {
|
||||||
@@ -42,6 +51,12 @@ const BUTTON_CONFIGS: Record<ButtonSize, ButtonConfig> = {
|
|||||||
},
|
},
|
||||||
} as const
|
} as const
|
||||||
|
|
||||||
|
// 색상 값을 CSS 변수로 변환하는 헬퍼 함수
|
||||||
|
const getColorValue = (color: string) =>
|
||||||
|
PARSED_KEY_CODE_CODES_KEYS.includes(color as keyof GameDataKeyCodeCodes)
|
||||||
|
? `var(--${color})`
|
||||||
|
: color
|
||||||
|
|
||||||
const currentConfig = computed(() => BUTTON_CONFIGS[props.size])
|
const currentConfig = computed(() => BUTTON_CONFIGS[props.size])
|
||||||
const buttonClasses = computed(() => [
|
const buttonClasses = computed(() => [
|
||||||
'group relative inline-flex items-center justify-center font-medium border border-gray-600/30 overflow-hidden',
|
'group relative inline-flex items-center justify-center font-medium border border-gray-600/30 overflow-hidden',
|
||||||
@@ -49,8 +64,8 @@ const buttonClasses = computed(() => [
|
|||||||
props.disabled ? 'cursor-default' : 'cursor-pointer',
|
props.disabled ? 'cursor-default' : 'cursor-pointer',
|
||||||
])
|
])
|
||||||
const buttonStyles = computed(() => ({
|
const buttonStyles = computed(() => ({
|
||||||
backgroundColor: props.backgroundColor,
|
backgroundColor: getColorValue(props.backgroundColor),
|
||||||
color: props.textColor,
|
color: getColorValue(props.textColor),
|
||||||
}))
|
}))
|
||||||
const overlayClasses = computed(() => [
|
const overlayClasses = computed(() => [
|
||||||
'absolute inset-0 -m-px transition-opacity duration-200',
|
'absolute inset-0 -m-px transition-opacity duration-200',
|
||||||
|
|||||||
@@ -1,34 +1,70 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { templateRegistry } from '#layers/registry'
|
import { templateRegistry } from '#layers/registry'
|
||||||
import type {
|
import type {
|
||||||
|
PageDataValue,
|
||||||
PageDataTemplate,
|
PageDataTemplate,
|
||||||
TemplateComponent,
|
PageDataTemplateComponent,
|
||||||
|
PageDataMetaTag,
|
||||||
} from '#layers/types/api/pageData'
|
} from '#layers/types/api/pageData'
|
||||||
|
|
||||||
const props = defineProps<{ templates: PageDataTemplate[] }>()
|
interface Props {
|
||||||
|
pageData: PageDataValue
|
||||||
|
}
|
||||||
|
|
||||||
|
const props = defineProps<Props>()
|
||||||
|
|
||||||
|
// 템플릿 레지스트리 타입 캐스팅
|
||||||
const registry = templateRegistry as unknown as Record<
|
const registry = templateRegistry as unknown as Record<
|
||||||
string,
|
string,
|
||||||
{ component: TemplateComponent }
|
{ component: PageDataTemplateComponent }
|
||||||
>
|
>
|
||||||
|
|
||||||
const isShowTemplate = (template: PageDataTemplate) => {
|
// 개별 메타 태그 표시 여부 확인
|
||||||
|
const shouldShowMetaTag = computed(() => props.pageData.meta_tag_type === 2)
|
||||||
|
|
||||||
|
// 템플릿 표시 여부 확인
|
||||||
|
const isTemplateVisible = (template: PageDataTemplate): boolean => {
|
||||||
return Boolean(
|
return Boolean(
|
||||||
template?.components && Object.keys(template.components ?? {}).length > 0
|
template?.components_ && Object.keys(template.components_).length > 0
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 템플릿 목록 계산
|
||||||
|
const visibleTemplates = computed(() =>
|
||||||
|
Object.values(props.pageData.templates).filter(isTemplateVisible)
|
||||||
|
)
|
||||||
|
|
||||||
|
// SEO 메타 태그 설정
|
||||||
|
const setupSeoMeta = (metaTag: PageDataMetaTag) => {
|
||||||
|
useSeoMeta({
|
||||||
|
title: metaTag.page_title ?? '',
|
||||||
|
description: metaTag.page_desc ?? '',
|
||||||
|
ogTitle: metaTag.og_title ?? '',
|
||||||
|
ogDescription: metaTag.og_desc ?? '',
|
||||||
|
ogImage: metaTag.og_image ?? '',
|
||||||
|
twitterTitle: metaTag.x_title ?? '',
|
||||||
|
twitterImage: metaTag.x_image ?? '',
|
||||||
|
twitterDescription: metaTag.x_desc ?? '',
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 메타 태그 설정 감시
|
||||||
|
watchEffect(() => {
|
||||||
|
if (shouldShowMetaTag.value && props.pageData.meta_tag) {
|
||||||
|
setupSeoMeta(props.pageData.meta_tag)
|
||||||
|
}
|
||||||
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<main>
|
<main>
|
||||||
<template
|
<template
|
||||||
v-for="(template, index) in props.templates"
|
v-for="(template, index) in visibleTemplates"
|
||||||
:key="template.template_code ?? index"
|
:key="template.template_code ?? index"
|
||||||
>
|
>
|
||||||
<component
|
<component
|
||||||
:is="registry[template.template_code]?.component"
|
:is="registry[template.template_code]?.component"
|
||||||
v-if="isShowTemplate(template)"
|
:components="template.components_"
|
||||||
:components="template.components"
|
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
</main>
|
</main>
|
||||||
|
|||||||
@@ -1,26 +0,0 @@
|
|||||||
import type { ParsedKeyColorCodes } from '#layers/types/api/gameData'
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 게임 데이터의 key_color_codes를 CSS 커스텀 프로퍼티로 적용하는 기능을 제공합니다.
|
|
||||||
*/
|
|
||||||
export const useGameColors = () => {
|
|
||||||
/**
|
|
||||||
* @param keyColorCodes
|
|
||||||
*/
|
|
||||||
const applyGameColors = (keyColorCodes: ParsedKeyColorCodes | 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 {
|
|
||||||
applyGameColors,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
28
layers/composables/useGameKeyCodeColors.ts
Normal file
28
layers/composables/useGameKeyCodeColors.ts
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
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,
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,9 +1,7 @@
|
|||||||
<script setup lang="ts"></script>
|
<script setup lang="ts"></script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div>
|
|
||||||
<LayoutsHeader />
|
<LayoutsHeader />
|
||||||
<slot />
|
<slot />
|
||||||
<LayoutsFooter />
|
<LayoutsFooter />
|
||||||
</div>
|
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -1,29 +1,9 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import YouTubeModal from '#layers/components/blocks/modal/YouTube.vue'
|
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
components: Record<string, any>
|
components: Record<string, any>
|
||||||
}
|
}
|
||||||
|
|
||||||
const props = defineProps<Props>()
|
const props = defineProps<Props>()
|
||||||
|
|
||||||
// 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>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
@@ -48,16 +28,7 @@ const handleCloseModal = () => {
|
|||||||
<WidgetsVideoPlay
|
<WidgetsVideoPlay
|
||||||
v-if="props.components.videoPlay"
|
v-if="props.components.videoPlay"
|
||||||
:component-data="props.components.videoPlay"
|
:component-data="props.components.videoPlay"
|
||||||
@click="handleVideoPlayClick"
|
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<!-- YouTube 모달 -->
|
|
||||||
<YouTubeModal
|
|
||||||
:is-open="isYouTubeModalOpen"
|
|
||||||
:youtube-id="youtubeVideoId"
|
|
||||||
@close="handleCloseModal"
|
|
||||||
@update:is-open="(value: boolean) => (isYouTubeModalOpen = value)"
|
|
||||||
/>
|
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -21,54 +21,93 @@ export interface GameDataValue {
|
|||||||
game_name: string
|
game_name: string
|
||||||
ga_code: string
|
ga_code: string
|
||||||
design_theme: number
|
design_theme: number
|
||||||
lang_codes: string // JSON 문자열로 변경
|
lang_codes: string[]
|
||||||
key_color_codes: ParsedKeyColorCodes
|
key_code_codes: GameDataKeyCodeCodes
|
||||||
use_game_font: boolean
|
use_game_font: boolean
|
||||||
comm_sns_bg_color_code: string
|
comm_sns_bg_color_code: string
|
||||||
comm_multilang_filename: string
|
comm_multilang_filename: string
|
||||||
footer_dev_ci_img_yn: boolean
|
footer_dev_ci_img_yn: boolean
|
||||||
footer_dev_ci_img_path: string
|
footer_dev_ci_img_path: string
|
||||||
default_lang_code?: string // 기본 언어 코드 추가
|
default_lang_code?: string
|
||||||
game_font: string // JSON 문자열로 변경
|
game_font: GameDataGameFont
|
||||||
globals: GameDataGlobal[] // 배열로 변경
|
globals: GameDataGlobal[]
|
||||||
gnb: GameDataGnb
|
gnb: GameDataGnb
|
||||||
intro: GameDataIntro
|
intro: GameDataIntro
|
||||||
inspection: Record<string, any> // 동적 객체
|
inspection: Record<string, any>
|
||||||
stove_gnb: GameDataStoveGnb // JSON 문자열로 변경
|
stove_gnb: GameDataStoveGnb
|
||||||
favicon_path: string // JSON 문자열로 변경
|
favicon_path: GameDataFaviconPath
|
||||||
meta_tag: string // JSON 문자열로 변경
|
meta_tag: GameDataMetaTag
|
||||||
sns: string // JSON 문자열로 변경
|
sns: GameDataSns
|
||||||
footer: string // JSON 문자열로 변경
|
footer: string // JSON 문자열로 변경
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ===== 세부 데이터 타입들 =====
|
||||||
|
|
||||||
|
// 키 코드 코드 타입
|
||||||
|
export interface GameDataKeyCodeCodes {
|
||||||
|
primary: string
|
||||||
|
'text-primary': string
|
||||||
|
'text-secondary': string
|
||||||
|
'alternative-01': string
|
||||||
|
'alternative-02': string
|
||||||
|
}
|
||||||
|
|
||||||
|
// 게임 폰트 타입
|
||||||
|
export interface GameDataGameFont {
|
||||||
|
font_family: string
|
||||||
|
font_weight: string
|
||||||
|
font_style: string
|
||||||
|
}
|
||||||
|
|
||||||
|
// 파비콘 경로 타입
|
||||||
|
export interface GameDataFaviconPath {
|
||||||
|
'16_16': string
|
||||||
|
'32_32': string
|
||||||
|
'72_72': string
|
||||||
|
'180_180': string
|
||||||
|
'192_192': string
|
||||||
|
}
|
||||||
|
|
||||||
|
// 메타 태그 타입
|
||||||
|
export interface GameDataMetaTag {
|
||||||
|
x_desc: string
|
||||||
|
og_desc: string
|
||||||
|
x_image: string
|
||||||
|
x_title: string
|
||||||
|
og_image: string
|
||||||
|
og_title: string
|
||||||
|
page_desc: string
|
||||||
|
page_title: string
|
||||||
|
}
|
||||||
|
|
||||||
|
// SNS 아이템 타입
|
||||||
|
export interface GameDataSnsItem {
|
||||||
|
use_yn: number
|
||||||
|
url: string | null
|
||||||
|
}
|
||||||
|
|
||||||
|
// SNS 설정 타입
|
||||||
|
export interface GameDataSns {
|
||||||
|
kakao: GameDataSnsItem
|
||||||
|
twitter: GameDataSnsItem
|
||||||
|
discord: GameDataSnsItem
|
||||||
|
youtube: GameDataSnsItem
|
||||||
|
instagram: GameDataSnsItem
|
||||||
|
facebook: GameDataSnsItem
|
||||||
|
tiktok: GameDataSnsItem
|
||||||
|
}
|
||||||
|
|
||||||
// Global 설정 타입
|
// Global 설정 타입
|
||||||
export interface GameDataGlobal {
|
export interface GameDataGlobal {
|
||||||
system_font: string // JSON 문자열로 변경
|
system_font: string // JSON 문자열로 변경
|
||||||
lang: string // JSON 문자열로 변경
|
lang: string // JSON 문자열로 변경
|
||||||
}
|
}
|
||||||
|
|
||||||
// 폰트 타입
|
// 트래킹 타입
|
||||||
export interface GameDataFont {
|
export interface GameDataTracking {
|
||||||
'font-family': string
|
viewType: string
|
||||||
}
|
actionType: string
|
||||||
|
clickSarea: string
|
||||||
// 언어 설정 타입
|
|
||||||
export interface GameDataLang {
|
|
||||||
dir: string
|
|
||||||
iso: string
|
|
||||||
code: string
|
|
||||||
name: string
|
|
||||||
}
|
|
||||||
|
|
||||||
// GNB 설정 타입
|
|
||||||
export interface GameDataGnb {
|
|
||||||
game_gnb_ver: string
|
|
||||||
display_start_dt: string // ISO 문자열로 변경
|
|
||||||
theme_type: string
|
|
||||||
bi_path: string
|
|
||||||
lang_codes: string // JSON 문자열로 변경
|
|
||||||
buttons: GameDataButton[]
|
|
||||||
menus: Record<string, GameDataMenu> // 동적 객체로 변경
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 버튼 타입
|
// 버튼 타입
|
||||||
@@ -90,35 +129,22 @@ export interface GameDataMenu {
|
|||||||
tracking: string | GameDataTracking // JSON 문자열 또는 객체로 변경
|
tracking: string | GameDataTracking // JSON 문자열 또는 객체로 변경
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GNB 설정 타입
|
||||||
|
export interface GameDataGnb {
|
||||||
|
game_gnb_ver: string
|
||||||
|
theme_type: string
|
||||||
|
bi_path: string
|
||||||
|
lang_codes: string // JSON 문자열로 변경
|
||||||
|
buttons: GameDataButton[]
|
||||||
|
menus: Record<string, GameDataMenu> // 동적 객체로 변경
|
||||||
|
}
|
||||||
|
|
||||||
// 인트로 타입
|
// 인트로 타입
|
||||||
export interface GameDataIntro {
|
export interface GameDataIntro {
|
||||||
seq: number
|
seq: number
|
||||||
display_start_dt: string
|
|
||||||
display_end_dt: string
|
|
||||||
page_url: string
|
page_url: string
|
||||||
}
|
}
|
||||||
|
|
||||||
// 트래킹 타입
|
|
||||||
export interface GameDataTracking {
|
|
||||||
viewType: string
|
|
||||||
actionType: string
|
|
||||||
clickSarea: string
|
|
||||||
}
|
|
||||||
|
|
||||||
// 퀵 메뉴 타입
|
|
||||||
export interface GameDataQuickMenu {
|
|
||||||
banner_seq: number
|
|
||||||
promotion_name: string
|
|
||||||
thumbnail: string
|
|
||||||
page_url_type: number
|
|
||||||
page_url: string
|
|
||||||
link_type: number
|
|
||||||
display_start_dt: string
|
|
||||||
display_end_dt: string
|
|
||||||
sort_order: number
|
|
||||||
banner_title: string
|
|
||||||
}
|
|
||||||
|
|
||||||
// Stove GNB Skin Type
|
// Stove GNB Skin Type
|
||||||
export type StoveGnbSkinType =
|
export type StoveGnbSkinType =
|
||||||
| 'gnb-default'
|
| 'gnb-default'
|
||||||
@@ -136,103 +162,7 @@ export interface GameDataStoveGnb {
|
|||||||
stove_install_button_visible: string
|
stove_install_button_visible: string
|
||||||
}
|
}
|
||||||
|
|
||||||
// 파비콘 경로 타입
|
// ===== API 관련 타입들 =====
|
||||||
export interface GameDataFaviconPath {
|
|
||||||
'16_16': string
|
|
||||||
'32_32': string
|
|
||||||
'72_72': string
|
|
||||||
'180_180': string
|
|
||||||
'192_192': string
|
|
||||||
}
|
|
||||||
|
|
||||||
// 공통 이미지 타입
|
|
||||||
export interface GameDataCommImg {
|
|
||||||
groups: GameDataCommImgGroup[]
|
|
||||||
}
|
|
||||||
|
|
||||||
// 공통 이미지 그룹 타입
|
|
||||||
export interface GameDataCommImgGroup {
|
|
||||||
img_path: GameDataImgPath
|
|
||||||
required: boolean
|
|
||||||
img_scope: string
|
|
||||||
group_code: string
|
|
||||||
group_label: string
|
|
||||||
}
|
|
||||||
|
|
||||||
// 이미지 경로 타입
|
|
||||||
export interface GameDataImgPath {
|
|
||||||
comm: string
|
|
||||||
}
|
|
||||||
|
|
||||||
// 메타 태그 타입
|
|
||||||
export interface GameDataMetaTag {
|
|
||||||
x_desc: string
|
|
||||||
og_desc: string
|
|
||||||
x_image: string
|
|
||||||
x_title: string
|
|
||||||
og_image: string
|
|
||||||
og_title: string
|
|
||||||
page_desc: string
|
|
||||||
page_title: string
|
|
||||||
}
|
|
||||||
|
|
||||||
// YouTube 설정 타입
|
|
||||||
export interface GameDataYoutube {
|
|
||||||
use_yn: number
|
|
||||||
api_key: string
|
|
||||||
}
|
|
||||||
|
|
||||||
// SNS 설정 타입
|
|
||||||
export interface GameDataSns {
|
|
||||||
kakao: GameDataSnsItem
|
|
||||||
tiktok: GameDataSnsItem
|
|
||||||
discord: GameDataSnsItem
|
|
||||||
twitter: GameDataSnsItem
|
|
||||||
youtube: GameDataSnsItem
|
|
||||||
facebook: GameDataSnsItem
|
|
||||||
instagram: GameDataSnsItem
|
|
||||||
}
|
|
||||||
|
|
||||||
// SNS 아이템 타입
|
|
||||||
export interface GameDataSnsItem {
|
|
||||||
url: string | null
|
|
||||||
use_yn: number
|
|
||||||
}
|
|
||||||
|
|
||||||
// 마켓 설정 타입
|
|
||||||
export interface GameDataMarket {
|
|
||||||
pc: GameDataMarketItem
|
|
||||||
app_store: GameDataMarketItem
|
|
||||||
google_play: GameDataMarketItem
|
|
||||||
}
|
|
||||||
|
|
||||||
// 마켓 아이템 타입
|
|
||||||
export interface GameDataMarketItem {
|
|
||||||
url: string | null
|
|
||||||
use_yn: number
|
|
||||||
}
|
|
||||||
|
|
||||||
// 푸터 설정 타입
|
|
||||||
export interface GameDataFooter {
|
|
||||||
dev_ci_url: string
|
|
||||||
use_dev_ci_url: boolean
|
|
||||||
fund_display_yn: boolean
|
|
||||||
use_game_rating: boolean
|
|
||||||
fund_display_url: string
|
|
||||||
game_rating_info: GameDataGameRatingInfo
|
|
||||||
}
|
|
||||||
|
|
||||||
// 게임 등급 정보 타입
|
|
||||||
export interface GameDataGameRatingInfo {
|
|
||||||
title: string
|
|
||||||
reg_no: string
|
|
||||||
prod_date: string
|
|
||||||
rating_type: string
|
|
||||||
company_name: string
|
|
||||||
content_info: string
|
|
||||||
rating_grade: string
|
|
||||||
rating_class_no: string
|
|
||||||
}
|
|
||||||
|
|
||||||
// API 에러 응답 타입
|
// API 에러 응답 타입
|
||||||
export interface GameDataErrorResponse {
|
export interface GameDataErrorResponse {
|
||||||
@@ -262,70 +192,3 @@ export interface GameDataApiResult {
|
|||||||
data: GameDataResponse | null
|
data: GameDataResponse | null
|
||||||
error: string | null
|
error: string | null
|
||||||
}
|
}
|
||||||
|
|
||||||
// JSON 문자열 파싱을 위한 유틸리티 타입들
|
|
||||||
export interface ParsedKeyColorCodes {
|
|
||||||
'alternative-01': string
|
|
||||||
'alternative-02': string
|
|
||||||
primary: string
|
|
||||||
'text-primary': string
|
|
||||||
'text-secondary': string
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ParsedGameFont {
|
|
||||||
'font-family': string
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ParsedGlobal {
|
|
||||||
system_font: ParsedGameFont
|
|
||||||
lang: GameDataLang
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ParsedButton {
|
|
||||||
google_play: {
|
|
||||||
label: Record<string, string>
|
|
||||||
url: string
|
|
||||||
tracking: GameDataTracking
|
|
||||||
}
|
|
||||||
app_store: {
|
|
||||||
label: Record<string, string>
|
|
||||||
url: string
|
|
||||||
tracking: GameDataTracking
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ParsedStoveGnb {
|
|
||||||
skin_type: StoveGnbSkinType
|
|
||||||
stove_install_button_visible: string
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ParsedSns {
|
|
||||||
kakao: GameDataSnsItem
|
|
||||||
twitter: GameDataSnsItem
|
|
||||||
discord: GameDataSnsItem
|
|
||||||
youtube: GameDataSnsItem
|
|
||||||
instagram: GameDataSnsItem
|
|
||||||
facebook: GameDataSnsItem
|
|
||||||
tiktok: GameDataSnsItem
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ParsedFooter {
|
|
||||||
use_game_rating: boolean
|
|
||||||
game_rating_info: GameDataGameRatingInfo
|
|
||||||
use_dev_ci_url: boolean
|
|
||||||
dev_ci_url: string
|
|
||||||
fund_display_yn: boolean
|
|
||||||
fund_display_url: string
|
|
||||||
}
|
|
||||||
|
|
||||||
// 파비콘 경로 파싱 타입
|
|
||||||
export interface ParsedFaviconPath {
|
|
||||||
'16_16': string
|
|
||||||
'32_32': string
|
|
||||||
'72_72': string
|
|
||||||
'180_180': string
|
|
||||||
'192_192': string
|
|
||||||
}
|
|
||||||
|
|
||||||
// 기존 gameData 타입과의 호환성을 위한 별칭
|
|
||||||
export type gameData = GameDataValue
|
|
||||||
|
|||||||
@@ -28,19 +28,20 @@ export interface PageDataValue {
|
|||||||
page_name: string
|
page_name: string
|
||||||
page_name_en: string
|
page_name_en: string
|
||||||
page_ver: number
|
page_ver: number
|
||||||
display_start_dt: string
|
|
||||||
lang_codes: string // JSON string
|
|
||||||
is_login_required: boolean
|
|
||||||
meta_tag_type: number
|
meta_tag_type: number
|
||||||
fit_page_height: boolean
|
fit_page_height: boolean
|
||||||
use_top_btn: boolean
|
use_top_btn: boolean
|
||||||
use_sns_btn: boolean
|
use_sns_btn: boolean
|
||||||
use_lnb: boolean
|
use_lnb: boolean
|
||||||
|
lnb_text_color_code_active: string
|
||||||
|
lnb_text_color_code_deactive: string
|
||||||
lnb_menus: PageDataLnbMenu[]
|
lnb_menus: PageDataLnbMenu[]
|
||||||
templates: PageDataTemplate[]
|
templates: Record<string, PageDataTemplate>
|
||||||
meta_tag: PageDataMetaTag // JSON string
|
meta_tag: PageDataMetaTag
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ===== 세부 데이터 타입들 =====
|
||||||
|
|
||||||
// 메타 태그 타입
|
// 메타 태그 타입
|
||||||
export interface PageDataMetaTag {
|
export interface PageDataMetaTag {
|
||||||
x_desc: string
|
x_desc: string
|
||||||
@@ -53,10 +54,22 @@ export interface PageDataMetaTag {
|
|||||||
page_title: string
|
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 PageDataComponent {
|
||||||
|
resources: PageDataResource[]
|
||||||
|
}
|
||||||
|
|
||||||
// LNB 메뉴 타입
|
// LNB 메뉴 타입
|
||||||
export interface PageDataLnbMenu {
|
export interface PageDataLnbMenu {
|
||||||
text_color_code_active: string
|
|
||||||
text_color_code_deactive: string
|
|
||||||
path_code: string
|
path_code: string
|
||||||
depth: number
|
depth: number
|
||||||
sort_order: number
|
sort_order: number
|
||||||
@@ -68,72 +81,21 @@ export interface PageDataLnbMenu {
|
|||||||
|
|
||||||
// 템플릿 타입
|
// 템플릿 타입
|
||||||
export interface PageDataTemplate {
|
export interface PageDataTemplate {
|
||||||
|
page_ver_tmpl_seq: number
|
||||||
tmpl_sort_order: number
|
tmpl_sort_order: number
|
||||||
page_ver_tmpl_name: string
|
page_ver_tmpl_name: string
|
||||||
page_ver_tmpl_name_en: string
|
page_ver_tmpl_name_en: string
|
||||||
template_code: string
|
template_code: string
|
||||||
|
components_: PageDataTemplateComponent
|
||||||
|
// components: string // JSON string
|
||||||
|
}
|
||||||
|
|
||||||
|
// 템플릿 컴포넌트 타입
|
||||||
|
export interface PageDataTemplateComponent {
|
||||||
components: Record<string, PageDataComponent>
|
components: Record<string, PageDataComponent>
|
||||||
}
|
}
|
||||||
|
|
||||||
// 컴포넌트 타입
|
// ===== API 관련 타입들 =====
|
||||||
export interface PageDataComponent {
|
|
||||||
component_sort_order: number
|
|
||||||
set_count: number
|
|
||||||
component_name: string
|
|
||||||
has_operational_resource: boolean
|
|
||||||
resources: PageDataResource[]
|
|
||||||
list_resources: PageDataListResource[]
|
|
||||||
flag_resources: PageDataFlagResource[]
|
|
||||||
}
|
|
||||||
|
|
||||||
// 리소스 타입
|
|
||||||
export interface PageDataResource {
|
|
||||||
resource_sort_order: number
|
|
||||||
resource_name: string
|
|
||||||
resource_type: string
|
|
||||||
groups: Record<string, any>
|
|
||||||
group_sets: Record<string, any>
|
|
||||||
}
|
|
||||||
|
|
||||||
// 리스트 리소스 타입
|
|
||||||
export interface PageDataListResource {
|
|
||||||
seq: number
|
|
||||||
title: string
|
|
||||||
img_path: string
|
|
||||||
url: string
|
|
||||||
link_target: string
|
|
||||||
display_start_dt: string
|
|
||||||
display_end_dt: string
|
|
||||||
is_display_status: number
|
|
||||||
display_status: number
|
|
||||||
option01: number
|
|
||||||
option02: number
|
|
||||||
option03: string
|
|
||||||
}
|
|
||||||
|
|
||||||
// 플래그 리소스 타입
|
|
||||||
export interface PageDataFlagResource {
|
|
||||||
seq: number
|
|
||||||
flag_type: number
|
|
||||||
option01: number
|
|
||||||
option02: number
|
|
||||||
option03: string
|
|
||||||
}
|
|
||||||
|
|
||||||
// 운영 리소스 타입 (기존 호환성 유지)
|
|
||||||
export interface PageDataOperateResource {
|
|
||||||
seq: number
|
|
||||||
col: string
|
|
||||||
col2: string
|
|
||||||
col3: string
|
|
||||||
col4: string
|
|
||||||
col5: string
|
|
||||||
col6: string
|
|
||||||
col7: string
|
|
||||||
resource_control_type: number
|
|
||||||
resource_type: string
|
|
||||||
[key: string]: any // Additional Properties
|
|
||||||
}
|
|
||||||
|
|
||||||
// API 에러 응답 타입
|
// API 에러 응답 타입
|
||||||
export interface PageDataErrorResponse {
|
export interface PageDataErrorResponse {
|
||||||
@@ -165,11 +127,3 @@ export interface PageDataApiResult {
|
|||||||
data: PageDataResponse | null
|
data: PageDataResponse | null
|
||||||
error: string | null
|
error: string | null
|
||||||
}
|
}
|
||||||
|
|
||||||
// 페이지 데이터 별칭 (기존 호환성)
|
|
||||||
export type pageData = PageDataValue
|
|
||||||
|
|
||||||
// Vue 컴포넌트 타입 정의
|
|
||||||
export interface TemplateComponent {
|
|
||||||
components: Record<string, PageDataComponent>
|
|
||||||
}
|
|
||||||
|
|||||||
Reference in New Issue
Block a user