fix. 개발 도구 적용. (typescript, prettier, es-lint)
This commit is contained in:
14
.eslintignore
Normal file
14
.eslintignore
Normal file
@@ -0,0 +1,14 @@
|
||||
temp/
|
||||
**/temp/**
|
||||
node_modules/
|
||||
.nuxt/
|
||||
.output/
|
||||
dist/
|
||||
build/
|
||||
coverage/
|
||||
.nyc_output/
|
||||
*.log
|
||||
*.tsbuildinfo
|
||||
.env
|
||||
.env.*
|
||||
.DS_Store
|
||||
22
.prettierignore
Normal file
22
.prettierignore
Normal file
@@ -0,0 +1,22 @@
|
||||
# Ignore artifacts
|
||||
.nuxt
|
||||
.output
|
||||
dist
|
||||
build
|
||||
coverage
|
||||
.nyc_output
|
||||
|
||||
# Ignore dependencies
|
||||
node_modules
|
||||
|
||||
# Ignore logs
|
||||
*.log
|
||||
*.tsbuildinfo
|
||||
|
||||
# Ignore environment files
|
||||
.env
|
||||
.env.*
|
||||
|
||||
# Ignore OS files
|
||||
.DS_Store
|
||||
|
||||
14
.prettierrc
Normal file
14
.prettierrc
Normal file
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"semi": false,
|
||||
"singleQuote": true,
|
||||
"trailingComma": "es5",
|
||||
"printWidth": 80,
|
||||
"tabWidth": 2,
|
||||
"useTabs": false,
|
||||
"bracketSpacing": true,
|
||||
"bracketSameLine": false,
|
||||
"arrowParens": "avoid",
|
||||
"endOfLine": "lf",
|
||||
"vueIndentScriptAndStyle": false,
|
||||
"htmlWhitespaceSensitivity": "ignore"
|
||||
}
|
||||
48
app/app.vue
48
app/app.vue
@@ -8,39 +8,33 @@
|
||||
</NuxtLayout>
|
||||
</template>
|
||||
|
||||
<style>
|
||||
@import "#layers/assets/css/app.css";
|
||||
</style>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { useNuxtApp } from "nuxt/app";
|
||||
import { useGameDataStore } from "#layers/stores/useGameDataStore";
|
||||
import type {
|
||||
gameData,
|
||||
GameDataMetaTag,
|
||||
GameDataValue,
|
||||
} from "#layers/types/api/gameData";
|
||||
import { useNuxtApp } from 'nuxt/app'
|
||||
import MoleculesLoadingFull from '#layers/components/molecules/loading/Full.vue'
|
||||
import MoleculesLoadingLocal from '#layers/components/molecules/loading/Local.vue'
|
||||
import { useGameDataStore } from '#layers/stores/useGameDataStore'
|
||||
import type { GameDataMetaTag, GameDataValue } from '#layers/types/api/gameData'
|
||||
|
||||
const nuxtApp = useNuxtApp();
|
||||
const getGameData = ref<GameDataValue | null>(null);
|
||||
const metaData = ref<GameDataMetaTag | null>(null);
|
||||
const { setGameData } = useGameDataStore();
|
||||
const nuxtApp = useNuxtApp()
|
||||
const getGameData = ref<GameDataValue | null>(null)
|
||||
const metaData = ref<GameDataMetaTag | null>(null)
|
||||
const { setGameData } = useGameDataStore()
|
||||
|
||||
// SSR에서만 접근 가능
|
||||
const gameDataFromServer = import.meta.server
|
||||
? nuxtApp.ssrContext?.event.context.gameData
|
||||
: null;
|
||||
: null
|
||||
|
||||
if (gameDataFromServer) {
|
||||
getGameData.value = gameDataFromServer;
|
||||
setGameData(gameDataFromServer);
|
||||
getGameData.value = gameDataFromServer
|
||||
setGameData(gameDataFromServer)
|
||||
}
|
||||
|
||||
const meta = gameDataFromServer?.meta_tag ?? null;
|
||||
const theme = gameDataFromServer?.design_theme === 1 ? "dark" : "light";
|
||||
const meta = gameDataFromServer?.meta_tag ?? null
|
||||
const theme = gameDataFromServer?.design_theme === 1 ? 'dark' : 'light'
|
||||
|
||||
if (gameDataFromServer && meta) {
|
||||
metaData.value = meta;
|
||||
metaData.value = meta
|
||||
useSeoMeta({
|
||||
title: meta.page_title,
|
||||
description: meta.page_desc,
|
||||
@@ -51,15 +45,19 @@ if (gameDataFromServer && meta) {
|
||||
twitterImage: meta.x_image,
|
||||
twitterTitle: meta.x_title,
|
||||
twitterDescription: meta.x_desc,
|
||||
});
|
||||
})
|
||||
useHead({
|
||||
htmlAttrs: {
|
||||
"data-game": gameDataFromServer.game_name || "",
|
||||
"data-theme": theme || "",
|
||||
'data-game': gameDataFromServer.game_name || '',
|
||||
'data-theme': theme || '',
|
||||
lang: gameDataFromServer.default_lang_code,
|
||||
},
|
||||
//meta: [...(updatedMetaTags.value || [])],
|
||||
//link: [...(links.value || [])]
|
||||
});
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
@import '#layers/assets/css/app.css';
|
||||
</style>
|
||||
|
||||
@@ -1,34 +1,34 @@
|
||||
<script setup lang="ts">
|
||||
import { storeToRefs } from "pinia";
|
||||
import { usePageDataStore } from "#layers/stores/usePageDataStore";
|
||||
import Template from "#layers/components/molecules/Template.vue";
|
||||
import { storeToRefs } from 'pinia'
|
||||
import { usePageDataStore } from '#layers/stores/usePageDataStore'
|
||||
import Template from '#layers/components/molecules/Template.vue'
|
||||
|
||||
const pageDataStore = usePageDataStore();
|
||||
const { pageData } = storeToRefs(pageDataStore);
|
||||
const pageDataStore = usePageDataStore()
|
||||
const { pageData } = storeToRefs(pageDataStore)
|
||||
|
||||
// const layout = pageData.value?.meta?.layout ?? "default";
|
||||
const layout = "default"; // 기본 레이아웃 사용
|
||||
const layout = 'default' // 기본 레이아웃 사용
|
||||
|
||||
// definePageMeta를 사용하여 레이아웃을 미리 설정
|
||||
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 ?? "",
|
||||
});
|
||||
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 ?? '',
|
||||
})
|
||||
}
|
||||
});
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
||||
@@ -1,34 +1,34 @@
|
||||
<script setup lang="ts">
|
||||
import { storeToRefs } from "pinia";
|
||||
import { usePageDataStore } from "#layers/stores/usePageDataStore";
|
||||
import Template from "#layers/components/molecules/Template.vue";
|
||||
import { storeToRefs } from 'pinia'
|
||||
import { usePageDataStore } from '#layers/stores/usePageDataStore'
|
||||
import Template from '#layers/components/molecules/Template.vue'
|
||||
|
||||
const pageDataStore = usePageDataStore();
|
||||
const { pageData } = storeToRefs(pageDataStore);
|
||||
const pageDataStore = usePageDataStore()
|
||||
const { pageData } = storeToRefs(pageDataStore)
|
||||
|
||||
// const layout = pageData.value?.meta?.layout ?? "default";
|
||||
const layout = "default"; // 기본 레이아웃 사용
|
||||
const layout = 'default' // 기본 레이아웃 사용
|
||||
|
||||
// definePageMeta를 사용하여 레이아웃을 미리 설정
|
||||
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 ?? "",
|
||||
});
|
||||
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 ?? '',
|
||||
})
|
||||
}
|
||||
});
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
||||
@@ -1,34 +1,34 @@
|
||||
<script setup lang="ts">
|
||||
import { storeToRefs } from "pinia";
|
||||
import { usePageDataStore } from "#layers/stores/usePageDataStore";
|
||||
import Template from "#layers/components/molecules/Template.vue";
|
||||
import { storeToRefs } from 'pinia'
|
||||
import { usePageDataStore } from '#layers/stores/usePageDataStore'
|
||||
import Template from '#layers/components/molecules/Template.vue'
|
||||
|
||||
const pageDataStore = usePageDataStore();
|
||||
const { pageData } = storeToRefs(pageDataStore);
|
||||
const pageDataStore = usePageDataStore()
|
||||
const { pageData } = storeToRefs(pageDataStore)
|
||||
|
||||
// const layout = pageData.value?.meta?.layout ?? "default";
|
||||
const layout = "default"; // 기본 레이아웃 사용
|
||||
const layout = 'default' // 기본 레이아웃 사용
|
||||
|
||||
// definePageMeta를 사용하여 레이아웃을 미리 설정
|
||||
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 ?? "",
|
||||
});
|
||||
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 ?? '',
|
||||
})
|
||||
}
|
||||
});
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
||||
@@ -1,21 +1,21 @@
|
||||
<script setup lang="ts">
|
||||
import { storeToRefs } from "pinia";
|
||||
import { usePageDataStore } from "#layers/stores/usePageDataStore";
|
||||
import Template from "#layers/components/molecules/Template.vue";
|
||||
import { storeToRefs } from 'pinia'
|
||||
import { usePageDataStore } from '#layers/stores/usePageDataStore'
|
||||
import Template from '#layers/components/molecules/Template.vue'
|
||||
|
||||
const pageDataStore = usePageDataStore();
|
||||
const { pageData } = storeToRefs(pageDataStore);
|
||||
const pageDataStore = usePageDataStore()
|
||||
const { pageData } = storeToRefs(pageDataStore)
|
||||
|
||||
// 동적 i18n 라우트 설정
|
||||
// const { getI18nRouteConfig } = useDynamicI18nRoutes();
|
||||
|
||||
// const layout = pageData.value?.meta?.layout ?? "default";
|
||||
const layout = "default"; // 기본 레이아웃 사용
|
||||
const layout = 'default' // 기본 레이아웃 사용
|
||||
|
||||
// definePageMeta를 사용하여 레이아웃을 미리 설정
|
||||
definePageMeta({
|
||||
layout: false, // 기본 레이아웃 비활성화
|
||||
});
|
||||
})
|
||||
|
||||
// // gameData.lang_codes를 기반으로 동적 언어 제외 설정
|
||||
// const i18nRouteConfig = getI18nRouteConfig();
|
||||
@@ -27,17 +27,17 @@ 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 ?? "",
|
||||
});
|
||||
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 ?? '',
|
||||
})
|
||||
}
|
||||
});
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
||||
49
eslint.config.js
Normal file
49
eslint.config.js
Normal file
@@ -0,0 +1,49 @@
|
||||
import { createConfigForNuxt } from '@nuxt/eslint-config/flat'
|
||||
|
||||
export default createConfigForNuxt({
|
||||
features: {
|
||||
typescript: true,
|
||||
vue: true,
|
||||
},
|
||||
dirs: {
|
||||
src: ['layers', 'app'],
|
||||
},
|
||||
ignores: ['temp/**/*'],
|
||||
}).append({
|
||||
rules: {
|
||||
// 포맷팅 관련 규칙 비활성화 (Prettier가 담당)
|
||||
'prettier/prettier': 'off',
|
||||
'@typescript-eslint/indent': 'off',
|
||||
'@typescript-eslint/quotes': 'off',
|
||||
'@typescript-eslint/semi': 'off',
|
||||
'@typescript-eslint/comma-dangle': 'off',
|
||||
'@typescript-eslint/brace-style': 'off',
|
||||
'@typescript-eslint/space-before-function-paren': 'off',
|
||||
|
||||
// 타입 관련 규칙 완화
|
||||
'@typescript-eslint/no-explicit-any': 'off',
|
||||
'@typescript-eslint/no-unused-vars': 'warn',
|
||||
'@typescript-eslint/no-unsafe-assignment': 'off',
|
||||
'@typescript-eslint/no-unsafe-member-access': 'off',
|
||||
'@typescript-eslint/no-unsafe-call': 'off',
|
||||
'@typescript-eslint/no-unsafe-return': 'off',
|
||||
'@typescript-eslint/no-unsafe-argument': 'off',
|
||||
'@typescript-eslint/ban-ts-comment': 'off',
|
||||
|
||||
// Vue 관련 규칙 완화
|
||||
'vue/multi-word-component-names': 'off',
|
||||
'vue/no-v-html': 'off',
|
||||
'vue/require-default-prop': 'off',
|
||||
'vue/require-explicit-emits': 'off',
|
||||
'vue/no-multiple-template-root': 'off',
|
||||
'vue/no-required-prop-with-default': 'off',
|
||||
'vue/require-directive': 'off',
|
||||
|
||||
// 일반 규칙 (품질/버그 탐지)
|
||||
'no-console': 'warn',
|
||||
'no-debugger': 'error',
|
||||
'no-unused-vars': 'off', // TypeScript 버전 사용
|
||||
'prefer-const': 'warn',
|
||||
'no-var': 'error',
|
||||
},
|
||||
})
|
||||
@@ -1,63 +1,63 @@
|
||||
import type { LocaleObject, NuxtI18nOptions } from "@nuxtjs/i18n";
|
||||
import type { LocaleObject, NuxtI18nOptions } from '@nuxtjs/i18n'
|
||||
|
||||
const LANG_DIR: string = "./i18n/locales";
|
||||
// const LANG_DIR: string = './i18n/locales'
|
||||
|
||||
const DEFAULT_COVERAGES: string[] = [
|
||||
"en",
|
||||
"ja",
|
||||
"ko",
|
||||
"zh-tw",
|
||||
"fr",
|
||||
"de",
|
||||
"es",
|
||||
"pt",
|
||||
"th",
|
||||
"zh-cn",
|
||||
];
|
||||
'en',
|
||||
'ja',
|
||||
'ko',
|
||||
'zh-tw',
|
||||
'fr',
|
||||
'de',
|
||||
'es',
|
||||
'pt',
|
||||
'th',
|
||||
'zh-cn',
|
||||
]
|
||||
|
||||
const DEFAULT_LOCALES: Record<string, LocaleObject> = {
|
||||
en: { code: "en", name: "English", iso: "en", dir: "ltr" },
|
||||
"zh-tw": { code: "zh-tw", name: "繁體中文", iso: "zh-tw", dir: "ltr" },
|
||||
ja: { code: "ja", name: "日本語", iso: "ja", dir: "ltr" },
|
||||
ko: { code: "ko", name: "한국어", iso: "ko-KR", dir: "ltr" },
|
||||
fr: { code: "fr", name: "Français", iso: "fr", dir: "ltr" },
|
||||
de: { code: "de", name: "Deutsch", iso: "de", dir: "ltr" },
|
||||
es: { code: "es", name: "Español", iso: "es", dir: "ltr" },
|
||||
pt: { code: "pt", name: "Português", iso: "pt", dir: "ltr" },
|
||||
th: { code: "th", name: "ภาษาไทย", iso: "th", dir: "ltr" },
|
||||
"zh-cn": { code: "zh-cn", name: "简体中文", iso: "zh-cn", dir: "ltr" },
|
||||
};
|
||||
const DEFAULT_LOCALE_CODE = "ko";
|
||||
en: { code: 'en', name: 'English', iso: 'en', dir: 'ltr' },
|
||||
'zh-tw': { code: 'zh-tw', name: '繁體中文', iso: 'zh-tw', dir: 'ltr' },
|
||||
ja: { code: 'ja', name: '日本語', iso: 'ja', dir: 'ltr' },
|
||||
ko: { code: 'ko', name: '한국어', iso: 'ko-KR', dir: 'ltr' },
|
||||
fr: { code: 'fr', name: 'Français', iso: 'fr', dir: 'ltr' },
|
||||
de: { code: 'de', name: 'Deutsch', iso: 'de', dir: 'ltr' },
|
||||
es: { code: 'es', name: 'Español', iso: 'es', dir: 'ltr' },
|
||||
pt: { code: 'pt', name: 'Português', iso: 'pt', dir: 'ltr' },
|
||||
th: { code: 'th', name: 'ภาษาไทย', iso: 'th', dir: 'ltr' },
|
||||
'zh-cn': { code: 'zh-cn', name: '简体中文', iso: 'zh-cn', dir: 'ltr' },
|
||||
}
|
||||
const DEFAULT_LOCALE_CODE = 'ko'
|
||||
|
||||
// getI18n 함수가 NuxtI18nOptions 타입의 값을 반환하도록 명시적으로 타입을 지정합니다.
|
||||
const getI18n = (allowedLangCodes?: string[]): NuxtI18nOptions => {
|
||||
// allowedLangCodes가 제공되면 해당 언어들만 사용, 그렇지 않으면 모든 기본 언어 사용
|
||||
const targetCoverages =
|
||||
allowedLangCodes && allowedLangCodes.length > 0
|
||||
? DEFAULT_COVERAGES.filter((code) => allowedLangCodes.includes(code))
|
||||
: DEFAULT_COVERAGES;
|
||||
? DEFAULT_COVERAGES.filter(code => allowedLangCodes.includes(code))
|
||||
: DEFAULT_COVERAGES
|
||||
|
||||
const DEFAULT_LOCALE_COVERAGES_SET: LocaleObject[] = targetCoverages.map(
|
||||
(code: string): LocaleObject => ({
|
||||
code,
|
||||
code => ({
|
||||
code: code as LocaleObject['code'],
|
||||
file: `${code}.ts`,
|
||||
// 아래의 옵셔널 체이닝(?.)은 해당 코드가 undefined일 경우를 안전하게 처리합니다.
|
||||
name: DEFAULT_LOCALES[code]?.name ?? code,
|
||||
iso: DEFAULT_LOCALES[code]?.iso ?? code,
|
||||
// dir 속성은 모든 로케일 객체에 공통적으로 존재하므로, 여기서 추가할 수도 있습니다.
|
||||
dir: DEFAULT_LOCALES[code]?.dir ?? "ltr",
|
||||
dir: DEFAULT_LOCALES[code]?.dir ?? 'ltr',
|
||||
})
|
||||
);
|
||||
)
|
||||
|
||||
return {
|
||||
strategy: "prefix",
|
||||
vueI18n: "custom",
|
||||
strategy: 'prefix',
|
||||
vueI18n: 'custom',
|
||||
locales: DEFAULT_LOCALE_COVERAGES_SET,
|
||||
defaultLocale: DEFAULT_LOCALE_CODE || "ko",
|
||||
defaultLocale: DEFAULT_LOCALE_CODE || 'ko',
|
||||
detectBrowserLanguage: {
|
||||
fallbackLocale: DEFAULT_LOCALE_CODE || "ko",
|
||||
fallbackLocale: DEFAULT_LOCALE_CODE || 'ko',
|
||||
useCookie: false,
|
||||
redirectOn: "root",
|
||||
redirectOn: 'root',
|
||||
},
|
||||
compilation: {
|
||||
strictMessage: false,
|
||||
@@ -65,30 +65,30 @@ const getI18n = (allowedLangCodes?: string[]): NuxtI18nOptions => {
|
||||
},
|
||||
debug: false,
|
||||
// 동적으로 언어 제외 설정을 위한 pages 설정
|
||||
customRoutes: "config",
|
||||
customRoutes: 'config',
|
||||
pages:
|
||||
allowedLangCodes && allowedLangCodes.length > 0
|
||||
? generatePageExclusions(allowedLangCodes)
|
||||
: {},
|
||||
// 추가적인 설정이 필요하다면 여기에 포함시킬 수 있습니다.
|
||||
};
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// gameData.lang_codes를 기반으로 언어 제외 설정을 생성하는 함수
|
||||
const generatePageExclusions = (
|
||||
allowedLangCodes: string[]
|
||||
): Record<string, any> => {
|
||||
const exclusions: Record<string, any> = {};
|
||||
const exclusions: Record<string, any> = {}
|
||||
|
||||
// 모든 기본 언어에 대해 제외 설정 생성
|
||||
DEFAULT_COVERAGES.forEach((langCode) => {
|
||||
DEFAULT_COVERAGES.forEach(langCode => {
|
||||
if (!allowedLangCodes.includes(langCode)) {
|
||||
// 해당 언어가 허용되지 않으면 모든 페이지에서 제외
|
||||
exclusions[langCode] = false;
|
||||
exclusions[langCode] = false
|
||||
}
|
||||
});
|
||||
})
|
||||
|
||||
return exclusions;
|
||||
};
|
||||
return exclusions
|
||||
}
|
||||
|
||||
export { DEFAULT_LOCALE_CODE, DEFAULT_COVERAGES, getI18n };
|
||||
export { DEFAULT_LOCALE_CODE, DEFAULT_COVERAGES, getI18n }
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
@import "./base/_theme.css";
|
||||
@import "./base/_reset.css";
|
||||
@import './base/_theme.css';
|
||||
@import './base/_reset.css';
|
||||
|
||||
@tailwind base;
|
||||
@tailwind components;
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
}
|
||||
|
||||
/* 다크 테마 색상 */
|
||||
[data-theme="dark"] {
|
||||
[data-theme='dark'] {
|
||||
--foreground: #191919;
|
||||
--foreground-10: #292929;
|
||||
|
||||
|
||||
@@ -1,32 +1,32 @@
|
||||
<script setup lang="ts">
|
||||
interface Props {
|
||||
size?: "large" | "medium" | "small" | "extra-small";
|
||||
disabled?: boolean;
|
||||
icon?: string;
|
||||
size?: 'large' | 'medium' | 'small' | 'extra-small'
|
||||
disabled?: boolean
|
||||
icon?: string
|
||||
}
|
||||
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
size: "medium",
|
||||
size: 'medium',
|
||||
disabled: false,
|
||||
icon: "",
|
||||
});
|
||||
icon: '',
|
||||
})
|
||||
|
||||
// 크기별 스타일 클래스
|
||||
const sizeClasses = {
|
||||
large: "px-10 h-16 text-lg rounded-lg",
|
||||
medium: "px-10 h-14 text-base rounded-lg",
|
||||
small: "px-10 h-12 text-sm rounded-lg",
|
||||
"extra-small": "px-6 h-10 text-sm rounded",
|
||||
};
|
||||
large: 'px-10 h-16 text-lg rounded-lg',
|
||||
medium: 'px-10 h-14 text-base rounded-lg',
|
||||
small: 'px-10 h-12 text-sm rounded-lg',
|
||||
'extra-small': 'px-6 h-10 text-sm rounded',
|
||||
}
|
||||
|
||||
// 상태별 스타일 클래스
|
||||
const getStateClasses = (disabled: boolean) => {
|
||||
if (disabled) {
|
||||
return "bg-white/10 text-gray-400 cursor-not-allowed";
|
||||
return 'bg-white/10 text-gray-400 cursor-not-allowed'
|
||||
}
|
||||
|
||||
return "bg-gray-700 text-white cursor-pointer";
|
||||
};
|
||||
return 'bg-gray-700 text-white cursor-pointer'
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -41,7 +41,7 @@ const getStateClasses = (disabled: boolean) => {
|
||||
<span
|
||||
v-if="!disabled"
|
||||
class="absolute inset-0 bg-white opacity-0 group-hover:opacity-20 transition-opacity duration-200 rounded-inherit"
|
||||
></span>
|
||||
/>
|
||||
<span class="relative">
|
||||
<slot />
|
||||
<span v-if="icon" :class="['flex-shrink-0']" v-html="icon" />
|
||||
|
||||
@@ -2,14 +2,13 @@
|
||||
const props = defineProps({
|
||||
to: {
|
||||
type: String,
|
||||
default: null,
|
||||
required: true,
|
||||
},
|
||||
});
|
||||
})
|
||||
|
||||
const localePath = useLocalePath();
|
||||
const localePath = useLocalePath()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<NuxtLink :to="localePath(props.to)"><slot></slot></NuxtLink>
|
||||
<NuxtLink :to="localePath(props.to)"><slot /></NuxtLink>
|
||||
</template>
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
<script setup lang="ts">
|
||||
interface Props {
|
||||
size?: number | string;
|
||||
color?: string;
|
||||
className?: string;
|
||||
size?: number | string
|
||||
color?: string
|
||||
className?: string
|
||||
}
|
||||
|
||||
withDefaults(defineProps<Props>(), {
|
||||
size: 12,
|
||||
color: "#7F7F7F",
|
||||
className: "",
|
||||
});
|
||||
color: '#7F7F7F',
|
||||
className: '',
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
<script setup lang="ts">
|
||||
interface Props {
|
||||
size?: number | string;
|
||||
color?: string;
|
||||
className?: string;
|
||||
size?: number | string
|
||||
color?: string
|
||||
className?: string
|
||||
}
|
||||
|
||||
withDefaults(defineProps<Props>(), {
|
||||
size: 16,
|
||||
color: "#B2B2B2",
|
||||
className: "",
|
||||
});
|
||||
color: '#B2B2B2',
|
||||
className: '',
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
<script setup lang="ts">
|
||||
interface Props {
|
||||
size?: number | string;
|
||||
color?: string;
|
||||
className?: string;
|
||||
size?: number | string
|
||||
color?: string
|
||||
className?: string
|
||||
}
|
||||
|
||||
withDefaults(defineProps<Props>(), {
|
||||
size: 12,
|
||||
color: "#FD3886",
|
||||
className: "",
|
||||
});
|
||||
color: '#FD3886',
|
||||
className: '',
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
||||
@@ -1,34 +1,34 @@
|
||||
<template>
|
||||
<div id="header-stove" class="relative z-[5]"></div>
|
||||
<div id="header-stove" class="relative z-[5]" />
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
const runtimeConfig = useRuntimeConfig();
|
||||
const { locale } = useI18n();
|
||||
const { $i18n } = useNuxtApp();
|
||||
const { gameData } = useGameDataStore();
|
||||
import { useGameDataStore } from '#layers/stores/useGameDataStore'
|
||||
|
||||
const stoveInflowPath = runtimeConfig.public.stoveInflowPath;
|
||||
const stoveGameNo = runtimeConfig.public.stoveGameNo;
|
||||
const gnbData = gameData?.stove_gnb;
|
||||
const runtimeConfig = useRuntimeConfig()
|
||||
const { locale, availableLocales } = useI18n()
|
||||
const { gameData } = useGameDataStore()
|
||||
|
||||
const stoveInflowPath = runtimeConfig.public.stoveInflowPath
|
||||
const stoveGameNo = runtimeConfig.public.stoveGameNo
|
||||
const gnbData = gameData?.stove_gnb
|
||||
|
||||
const languageCodes = computed(() => {
|
||||
const availableLocales = ($i18n as any).availableLocales;
|
||||
if (Array.isArray(availableLocales)) {
|
||||
return availableLocales.map(
|
||||
(localeCode: any) => localeCode.code || localeCode
|
||||
);
|
||||
)
|
||||
}
|
||||
return [locale.value];
|
||||
});
|
||||
return [locale]
|
||||
})
|
||||
|
||||
function loadGnb(locale: string) {
|
||||
locale = locale.toLowerCase();
|
||||
locale = locale.toLowerCase()
|
||||
|
||||
const gnbOption = {
|
||||
wrapper: "#header-stove",
|
||||
wrapper: '#header-stove',
|
||||
isResponsive: true,
|
||||
skin: gnbData?.skin_type || "gnb-dark-mini",
|
||||
skin: gnbData?.skin_type || 'gnb-dark-mini',
|
||||
widget: {
|
||||
gameListAndService: false,
|
||||
languageSelect: false,
|
||||
@@ -37,25 +37,25 @@ function loadGnb(locale: string) {
|
||||
},
|
||||
global: {
|
||||
userGds: true,
|
||||
defaultSelectedLanguage: locale || "en",
|
||||
defaultSelectedLanguage: locale || 'en',
|
||||
languageCoverages: languageCodes.value,
|
||||
},
|
||||
loginMethod: {
|
||||
params: {
|
||||
inflow_path: stoveInflowPath,
|
||||
game_no: stoveGameNo,
|
||||
show_play_button: gnbData?.stove_install_button_visible || "Y",
|
||||
show_play_button: gnbData?.stove_install_button_visible || 'Y',
|
||||
},
|
||||
redirectCurrentPage: true,
|
||||
windowTitle: undefined,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
const cpHeader = new (window as any).cp.Header(gnbOption);
|
||||
cpHeader.render();
|
||||
const cpHeader = new (window as any).cp.Header(gnbOption)
|
||||
cpHeader.render()
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
loadGnb(locale.value);
|
||||
});
|
||||
loadGnb(locale.value)
|
||||
})
|
||||
</script>
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
<script setup lang="ts">
|
||||
import type { GameDataValue, GameDataGnb } from "#layers/types/api/gameData";
|
||||
import { useGameDataStore } from '#layers/stores/useGameDataStore'
|
||||
import type { GameDataValue, GameDataGnb } from '#layers/types/api/gameData'
|
||||
|
||||
const gameDataStore = useGameDataStore();
|
||||
const gameDataStore = useGameDataStore()
|
||||
|
||||
const gameData = gameDataStore.gameData as GameDataValue;
|
||||
const gnbList = gameData?.gnb?.menus as GameDataGnb["menus"];
|
||||
const gameData = gameDataStore.gameData as GameDataValue
|
||||
const gnbList = gameData?.gnb?.menus as GameDataGnb['menus']
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -45,7 +46,7 @@ const gnbList = gameData?.gnb?.menus as GameDataGnb["menus"];
|
||||
<AtomsIconsArrowDown v-if="gnbItem.children" class="ml-1" />
|
||||
<span
|
||||
class="absolute bottom-0 left-0 w-full h-2 border-b-2 border-transparent transition-border-color group-hover:border-theme-foreground-reversal group-active:border-theme-foreground-reversal-10"
|
||||
></span>
|
||||
/>
|
||||
</MoleculesHybridLink>
|
||||
<div
|
||||
v-if="gnbItem.children"
|
||||
@@ -74,7 +75,7 @@ const gnbList = gameData?.gnb?.menus as GameDataGnb["menus"];
|
||||
</template>
|
||||
|
||||
<!-- 구분선 -->
|
||||
<div class="w-px h-4 bg-theme-foreground-reversal-30"></div>
|
||||
<div class="w-px h-4 bg-theme-foreground-reversal-30" />
|
||||
|
||||
<!-- 이벤트 -->
|
||||
<a href="#" class="flex items-center space-x-[3px] text-gradient-pink">
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
<script setup lang="ts">
|
||||
interface Props {
|
||||
to: string;
|
||||
target?: string;
|
||||
class?: string;
|
||||
to: string
|
||||
target?: string
|
||||
class?: string
|
||||
}
|
||||
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
target: "",
|
||||
class: "",
|
||||
});
|
||||
target: '',
|
||||
class: '',
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
<template>
|
||||
<div class="bg-white">
|
||||
<select
|
||||
class="text-black px-2 py-1 rounded-md"
|
||||
v-model="selectedLocale"
|
||||
class="text-black px-2 py-1 rounded-md"
|
||||
@change="switchLanguage"
|
||||
>
|
||||
<option
|
||||
@@ -17,36 +17,36 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
const gameDataStore = useGameDataStore();
|
||||
const gameDataStore = useGameDataStore()
|
||||
|
||||
// 사용 가능한 언어 목록
|
||||
const availableLanguages = computed(() => {
|
||||
return gameDataStore.gameData?.lang_codes || ["ko"];
|
||||
});
|
||||
return gameDataStore.gameData?.lang_codes || ['ko']
|
||||
})
|
||||
|
||||
const { locale } = useI18n();
|
||||
const switchLocalePath = useSwitchLocalePath();
|
||||
const router = useRouter();
|
||||
const { locale } = useI18n()
|
||||
const switchLocalePath = useSwitchLocalePath()
|
||||
const router = useRouter()
|
||||
|
||||
const selectedLocale = ref(locale.value);
|
||||
const selectedLocale = ref(locale.value)
|
||||
|
||||
// 언어 변경 함수
|
||||
const switchLanguage = async () => {
|
||||
console.log(
|
||||
"🚀 ~ switchLanguage ~ selectedLocale.value:",
|
||||
'🚀 ~ switchLanguage ~ selectedLocale.value:',
|
||||
selectedLocale.value
|
||||
);
|
||||
)
|
||||
if (selectedLocale.value) {
|
||||
// URL 경로를 통해 언어 변경
|
||||
const path = switchLocalePath(selectedLocale.value);
|
||||
const path = switchLocalePath(selectedLocale.value)
|
||||
if (path) {
|
||||
await router.push(path);
|
||||
await router.push(path)
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// locale이 변경될 때 selectedLocale도 동기화
|
||||
watch(locale, (newLocale) => {
|
||||
selectedLocale.value = newLocale;
|
||||
});
|
||||
watch(locale, newLocale => {
|
||||
selectedLocale.value = newLocale
|
||||
})
|
||||
</script>
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
<script setup lang="ts">
|
||||
import { useTemplateRegistry } from "#layers/composables/useTemplateRegistry";
|
||||
import type { PageDataTemplate } from "#layers/types/api/pageData";
|
||||
import { useTemplateRegistry } from '#layers/composables/useTemplateRegistry'
|
||||
import type { PageDataTemplate } from '#layers/types/api/pageData'
|
||||
|
||||
const props = defineProps<{ templates: PageDataTemplate[] }>();
|
||||
const registry = useTemplateRegistry() as Record<string, { component: any }>;
|
||||
const props = defineProps<{ templates: PageDataTemplate[] }>()
|
||||
const registry = useTemplateRegistry() as Record<string, { component: any }>
|
||||
|
||||
const isShowTemplate = (template: PageDataTemplate) => {
|
||||
return template?.components && Object.keys(template.components).length > 0;
|
||||
};
|
||||
return template?.components && Object.keys(template.components).length > 0
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -16,8 +16,8 @@ const isShowTemplate = (template: PageDataTemplate) => {
|
||||
:key="template.template_code ?? index"
|
||||
>
|
||||
<component
|
||||
v-if="isShowTemplate(template)"
|
||||
:is="registry[template.template_code]?.component"
|
||||
v-if="isShowTemplate(template)"
|
||||
:components="template.components"
|
||||
/>
|
||||
</template>
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
<script setup lang="ts">
|
||||
interface Props {
|
||||
tag: string;
|
||||
text: string;
|
||||
imageSrc?: any;
|
||||
imageClass?: string;
|
||||
tag: string
|
||||
text: string
|
||||
imageSrc?: any
|
||||
imageClass?: string
|
||||
}
|
||||
|
||||
const props = defineProps<Props>();
|
||||
const props = defineProps<Props>()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
<script setup lang="ts">
|
||||
import { useLoadingStore } from "#layers/stores/useLoadingStore";
|
||||
import { useLoadingStore } from '#layers/stores/useLoadingStore'
|
||||
|
||||
const loadingStore = useLoadingStore();
|
||||
const { fullLoading } = storeToRefs(loadingStore);
|
||||
const loadingStore = useLoadingStore()
|
||||
const { fullLoading } = storeToRefs(loadingStore)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -23,22 +23,22 @@ const { fullLoading } = storeToRefs(loadingStore);
|
||||
<!-- 외부 링 -->
|
||||
<div
|
||||
class="absolute inset-0 border-4 border-transparent border-t-blue-500 rounded-full animate-spin"
|
||||
></div>
|
||||
/>
|
||||
<!-- 중간 링 -->
|
||||
<div
|
||||
class="absolute inset-1 border-4 border-transparent border-t-purple-500 rounded-full animate-spin"
|
||||
style="animation-delay: -0.3s"
|
||||
></div>
|
||||
/>
|
||||
<!-- 내부 링 -->
|
||||
<div
|
||||
class="absolute inset-2 border-4 border-transparent border-t-cyan-500 rounded-full animate-spin"
|
||||
style="animation-delay: -0.6s"
|
||||
></div>
|
||||
/>
|
||||
<!-- 중심 링 -->
|
||||
<div
|
||||
class="absolute inset-3 border-4 border-transparent border-t-emerald-500 rounded-full animate-spin"
|
||||
style="animation-delay: -0.9s"
|
||||
></div>
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</Transition>
|
||||
|
||||
@@ -1,8 +1,14 @@
|
||||
<script setup lang="ts">
|
||||
import { useLoadingStore } from "#layers/stores/useLoadingStore";
|
||||
import { useLoadingStore } from '#layers/stores/useLoadingStore'
|
||||
|
||||
const loadingStore = useLoadingStore();
|
||||
const { localLoadings } = storeToRefs(loadingStore);
|
||||
const loadingStore = useLoadingStore()
|
||||
const localLoadings = computed(() => Object.entries(loadingStore.localLoadings))
|
||||
const canTeleport = (localId: string) => {
|
||||
if (!import.meta.client) {
|
||||
return false
|
||||
}
|
||||
return !!document.getElementById(localId)
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -25,22 +31,22 @@ const { localLoadings } = storeToRefs(loadingStore);
|
||||
<!-- 외부 링 -->
|
||||
<div
|
||||
class="absolute inset-0 border-4 border-transparent border-t-blue-500 rounded-full animate-spin"
|
||||
></div>
|
||||
/>
|
||||
<!-- 중간 링 -->
|
||||
<div
|
||||
class="absolute inset-1 border-4 border-transparent border-t-purple-500 rounded-full animate-spin"
|
||||
style="animation-delay: -0.3s"
|
||||
></div>
|
||||
/>
|
||||
<!-- 내부 링 -->
|
||||
<div
|
||||
class="absolute inset-2 border-4 border-transparent border-t-cyan-500 rounded-full animate-spin"
|
||||
style="animation-delay: -0.6s"
|
||||
></div>
|
||||
/>
|
||||
<!-- 중심 링 -->
|
||||
<div
|
||||
class="absolute inset-3 border-4 border-transparent border-t-emerald-500 rounded-full animate-spin"
|
||||
style="animation-delay: -0.9s"
|
||||
></div>
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</Transition>
|
||||
|
||||
@@ -21,17 +21,13 @@
|
||||
leave-from-class="opacity-100 scale-100"
|
||||
leave-to-class="opacity-0 scale-95"
|
||||
>
|
||||
<div
|
||||
v-if="isOpen"
|
||||
class="relative w-full max-w-4xl mx-4"
|
||||
@click.stop
|
||||
>
|
||||
<div v-if="isOpen" class="relative w-full max-w-4xl mx-4" @click.stop>
|
||||
<!-- 헤더 -->
|
||||
<div class="flex justify-end">
|
||||
<button
|
||||
@click="closeModal"
|
||||
class="p-1 text-white rounded-full transition-colors"
|
||||
aria-label="모달 닫기"
|
||||
@click="closeModal"
|
||||
>
|
||||
<svg
|
||||
class="w-8 h-8"
|
||||
@@ -85,7 +81,7 @@ interface Emits {
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
title: '',
|
||||
description: '',
|
||||
closeOnBackdrop: true
|
||||
closeOnBackdrop: true,
|
||||
})
|
||||
|
||||
const emit = defineEmits<Emits>()
|
||||
@@ -120,13 +116,16 @@ onUnmounted(() => {
|
||||
})
|
||||
|
||||
// 모달이 열릴 때 body 스크롤 방지
|
||||
watch(() => props.isOpen, (isOpen) => {
|
||||
if (isOpen) {
|
||||
document.body.style.overflow = 'hidden'
|
||||
} else {
|
||||
document.body.style.overflow = ''
|
||||
watch(
|
||||
() => props.isOpen,
|
||||
isOpen => {
|
||||
if (isOpen) {
|
||||
document.body.style.overflow = 'hidden'
|
||||
} else {
|
||||
document.body.style.overflow = ''
|
||||
}
|
||||
}
|
||||
})
|
||||
)
|
||||
|
||||
// 컴포넌트 언마운트 시 body 스크롤 복원
|
||||
onUnmounted(() => {
|
||||
|
||||
@@ -3,34 +3,34 @@ import {
|
||||
getResourcesData,
|
||||
getResponsiveClass,
|
||||
getResponsiveSrc,
|
||||
} from "#layers/utils/dataUtil";
|
||||
import type { PageDataComponent } from "#layers/types/api/pageData";
|
||||
} from '#layers/utils/dataUtil'
|
||||
import type { PageDataComponent } from '#layers/types/api/pageData'
|
||||
|
||||
const props = defineProps<{
|
||||
componentData: PageDataComponent;
|
||||
gradientClass?: string;
|
||||
groupSets?: boolean;
|
||||
}>();
|
||||
componentData: PageDataComponent
|
||||
gradientClass?: string
|
||||
groupSets?: boolean
|
||||
}>()
|
||||
|
||||
const resourcesData = computed(() => {
|
||||
return getResourcesData({
|
||||
resources: props.componentData?.resources,
|
||||
groupSets: props.groupSets,
|
||||
});
|
||||
});
|
||||
})
|
||||
})
|
||||
const bgStyles = computed(() => {
|
||||
return getResponsiveSrc(resourcesData.value?.res_path, {
|
||||
resourcesType: "bg",
|
||||
});
|
||||
});
|
||||
resourcesType: 'bg',
|
||||
})
|
||||
})
|
||||
const videoSrc = computed(() => {
|
||||
return getResponsiveSrc(resourcesData.value?.res_path, {
|
||||
resourcesType: "video",
|
||||
});
|
||||
});
|
||||
resourcesType: 'video',
|
||||
})
|
||||
})
|
||||
const posterSrc = computed(() => {
|
||||
return getResponsiveSrc(resourcesData.value?.res_path);
|
||||
});
|
||||
return getResponsiveSrc(resourcesData.value?.res_path)
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -41,7 +41,7 @@ const posterSrc = computed(() => {
|
||||
class="w-full h-full bg-cover bg-center bg-no-repeat"
|
||||
:class="getResponsiveClass()"
|
||||
:style="bgStyles"
|
||||
></div>
|
||||
/>
|
||||
|
||||
<!-- 비디오 타입 -->
|
||||
<template v-else-if="resourcesData?.group_type === 'video'">
|
||||
@@ -73,6 +73,6 @@ const posterSrc = computed(() => {
|
||||
</video>
|
||||
</template>
|
||||
|
||||
<div class="absolute inset-0" :class="gradientClass"></div>
|
||||
<div class="absolute inset-0" :class="gradientClass" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -1,30 +1,24 @@
|
||||
<script setup lang="ts">
|
||||
import { getResourcesData } from "#layers/utils/dataUtil";
|
||||
import type { PageDataComponent } from "#layers/types/api/pageData";
|
||||
import { getResourcesData } from '#layers/utils/dataUtil'
|
||||
import type { PageDataComponent } from '#layers/types/api/pageData'
|
||||
|
||||
const props = defineProps<{
|
||||
componentData: PageDataComponent;
|
||||
groupSets?: boolean;
|
||||
}>();
|
||||
componentData: PageDataComponent
|
||||
groupSets?: boolean
|
||||
}>()
|
||||
|
||||
const resourcesData = computed(() => {
|
||||
return getResourcesData({
|
||||
resources: props.componentData?.resources,
|
||||
isMultiple: true,
|
||||
groupSets: props.groupSets,
|
||||
});
|
||||
});
|
||||
|
||||
console.log("ButtonList resourcesData:", resourcesData.value);
|
||||
})
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<template
|
||||
v-if="resourcesData"
|
||||
v-for="button in resourcesData"
|
||||
:key="button.group_label"
|
||||
>
|
||||
<AtomsButton>
|
||||
<template v-if="resourcesData">
|
||||
<AtomsButton v-for="button in resourcesData" :key="button.group_label">
|
||||
{{ button.btn_info?.txt_btn_name }}
|
||||
</AtomsButton>
|
||||
|
||||
|
||||
@@ -1,21 +1,21 @@
|
||||
<script setup lang="ts">
|
||||
import { getResourcesData, getResponsiveSrc } from "#layers/utils/dataUtil";
|
||||
import type { PageDataComponent } from "#layers/types/api/pageData";
|
||||
import { getResourcesData, getResponsiveSrc } from '#layers/utils/dataUtil'
|
||||
import type { PageDataComponent } from '#layers/types/api/pageData'
|
||||
|
||||
const props = defineProps<{
|
||||
componentData: PageDataComponent;
|
||||
groupSets?: boolean;
|
||||
}>();
|
||||
componentData: PageDataComponent
|
||||
groupSets?: boolean
|
||||
}>()
|
||||
|
||||
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 = resourcesData.value?.display?.txt
|
||||
const imageSrc = getResponsiveSrc(resourcesData.value?.res_path)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
||||
@@ -1,21 +1,21 @@
|
||||
<script setup lang="ts">
|
||||
import { getResourcesData, getResponsiveSrc } from "#layers/utils/dataUtil";
|
||||
import type { PageDataComponent } from "#layers/types/api/pageData";
|
||||
import { getResourcesData, getResponsiveSrc } from '#layers/utils/dataUtil'
|
||||
import type { PageDataComponent } from '#layers/types/api/pageData'
|
||||
|
||||
const props = defineProps<{
|
||||
componentData: PageDataComponent;
|
||||
groupSets?: boolean;
|
||||
}>();
|
||||
componentData: PageDataComponent
|
||||
groupSets?: boolean
|
||||
}>()
|
||||
|
||||
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 = resourcesData.value?.display?.txt
|
||||
const imageSrc = getResponsiveSrc(resourcesData.value?.res_path)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
||||
@@ -1,21 +1,21 @@
|
||||
<script setup lang="ts">
|
||||
import { getResourcesData, getResponsiveSrc } from "#layers/utils/dataUtil";
|
||||
import type { PageDataComponent } from "#layers/types/api/pageData";
|
||||
import { getResourcesData, getResponsiveSrc } from '#layers/utils/dataUtil'
|
||||
import type { PageDataComponent } from '#layers/types/api/pageData'
|
||||
|
||||
const props = defineProps<{
|
||||
componentData: PageDataComponent;
|
||||
groupSets?: boolean;
|
||||
}>();
|
||||
componentData: PageDataComponent
|
||||
groupSets?: boolean
|
||||
}>()
|
||||
|
||||
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 = resourcesData.value?.display?.txt
|
||||
const imageSrc = getResponsiveSrc(resourcesData.value?.res_path)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
||||
@@ -3,19 +3,19 @@ import {
|
||||
getResourcesData,
|
||||
getResponsiveSrc,
|
||||
getResponsiveClass,
|
||||
} from "#layers/utils/dataUtil";
|
||||
import type { PageDataComponent } from "#layers/types/api/pageData";
|
||||
} from '#layers/utils/dataUtil'
|
||||
import type { PageDataComponent } from '#layers/types/api/pageData'
|
||||
|
||||
const props = defineProps<{ componentData: PageDataComponent }>();
|
||||
const props = defineProps<{ componentData: PageDataComponent }>()
|
||||
|
||||
const resourcesData = computed(() => {
|
||||
return getResourcesData({
|
||||
resources: props.componentData?.resources,
|
||||
});
|
||||
});
|
||||
})
|
||||
})
|
||||
const bgStyles = getResponsiveSrc(resourcesData.value?.res_path, {
|
||||
resourcesType: "bg",
|
||||
});
|
||||
resourcesType: 'bg',
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
||||
@@ -6,15 +6,20 @@ import { DEFAULT_COVERAGES } from '@/i18n.config'
|
||||
*/
|
||||
export const useDynamicI18nRoutes = () => {
|
||||
const gameDataStore = useGameDataStore()
|
||||
|
||||
|
||||
/**
|
||||
* 현재 gameData의 lang_codes를 기반으로 허용된 언어 목록을 반환
|
||||
*/
|
||||
const getAllowedLangCodes = (): string[] => {
|
||||
const gameData = gameDataStore.gameData
|
||||
return gameData?.lang_codes || []
|
||||
// Ensure we only return string values and filter out undefined/null
|
||||
return Array.isArray(gameData?.lang_codes)
|
||||
? gameData.lang_codes.filter(
|
||||
(code): code is string => typeof code === 'string'
|
||||
)
|
||||
: []
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 특정 언어가 허용되는지 확인
|
||||
*/
|
||||
@@ -22,7 +27,7 @@ export const useDynamicI18nRoutes = () => {
|
||||
const allowedLangCodes = getAllowedLangCodes()
|
||||
return allowedLangCodes.length === 0 || allowedLangCodes.includes(langCode)
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* defineI18nRoute에서 사용할 수 있는 언어 제외 설정을 생성
|
||||
* @param pagePath - 페이지 경로 (선택사항)
|
||||
@@ -30,18 +35,18 @@ export const useDynamicI18nRoutes = () => {
|
||||
*/
|
||||
const getI18nRouteConfig = (pagePath?: string) => {
|
||||
const allowedLangCodes = getAllowedLangCodes()
|
||||
|
||||
|
||||
// 허용된 언어가 없으면 모든 언어 허용
|
||||
if (allowedLangCodes.length === 0) {
|
||||
return undefined
|
||||
}
|
||||
|
||||
|
||||
// 허용된 언어만 포함하는 설정 반환
|
||||
return {
|
||||
locales: allowedLangCodes
|
||||
locales: allowedLangCodes,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 특정 언어를 제외하는 설정을 생성
|
||||
* @param excludedLangCodes - 제외할 언어 코드 배열
|
||||
@@ -49,21 +54,33 @@ export const useDynamicI18nRoutes = () => {
|
||||
*/
|
||||
const getExcludedLangConfig = (excludedLangCodes: string[]) => {
|
||||
const allowedLangCodes = getAllowedLangCodes()
|
||||
|
||||
|
||||
// 허용된 언어에서 제외할 언어를 제거
|
||||
const finalAllowedCodes = allowedLangCodes.length > 0
|
||||
? allowedLangCodes.filter(code => !excludedLangCodes.includes(code))
|
||||
: ['en', 'ja', 'ko', 'zh-tw', 'fr', 'de', 'es', 'pt', 'th', 'zh-cn'].filter(code => !excludedLangCodes.includes(code))
|
||||
|
||||
const finalAllowedCodes =
|
||||
allowedLangCodes.length > 0
|
||||
? allowedLangCodes.filter(code => !excludedLangCodes.includes(code))
|
||||
: [
|
||||
'en',
|
||||
'ja',
|
||||
'ko',
|
||||
'zh-tw',
|
||||
'fr',
|
||||
'de',
|
||||
'es',
|
||||
'pt',
|
||||
'th',
|
||||
'zh-cn',
|
||||
].filter(code => !excludedLangCodes.includes(code))
|
||||
|
||||
return {
|
||||
locales: finalAllowedCodes
|
||||
locales: finalAllowedCodes,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return {
|
||||
getAllowedLangCodes,
|
||||
isLangAllowed,
|
||||
getI18nRouteConfig,
|
||||
getExcludedLangConfig
|
||||
getExcludedLangConfig,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,53 +1,53 @@
|
||||
import { getHeader } from "h3";
|
||||
import { useRuntimeConfig, useRequestEvent } from "nuxt/app";
|
||||
import { getHeader } from 'h3'
|
||||
import { useRuntimeConfig, useRequestEvent } from 'nuxt/app'
|
||||
|
||||
export const useGetGameAlias = () => {
|
||||
const config = useRuntimeConfig();
|
||||
const baseDomain = (config.public.baseDomain || ".onstove.com") as string;
|
||||
const config = useRuntimeConfig()
|
||||
const baseDomain = (config.public.baseDomain || '.onstove.com') as string
|
||||
|
||||
// 서버 사이드에서 실행되는 경우
|
||||
if (!import.meta.client) {
|
||||
try {
|
||||
const event = useRequestEvent();
|
||||
const event = useRequestEvent()
|
||||
|
||||
if (event) {
|
||||
// 미들웨어에서 설정한 gameAlias가 있다면 우선 사용
|
||||
if (event.context.gameAlias) {
|
||||
return event.context.gameAlias;
|
||||
return event.context.gameAlias
|
||||
}
|
||||
|
||||
const host = getHeader(event, "host") || "";
|
||||
const isGameAliasExtractable = host.includes(baseDomain);
|
||||
const host = getHeader(event, 'host') || ''
|
||||
const isGameAliasExtractable = host.includes(baseDomain)
|
||||
|
||||
if (isGameAliasExtractable) {
|
||||
const subdomain = host.split(".")[0];
|
||||
const subdomain = host.split('.')[0]
|
||||
|
||||
if (subdomain && subdomain !== "www") {
|
||||
return subdomain;
|
||||
if (subdomain && subdomain !== 'www') {
|
||||
return subdomain
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("useGetGameAlias server error: ", error);
|
||||
console.error('useGetGameAlias server error: ', error)
|
||||
}
|
||||
}
|
||||
|
||||
// 클라이언트 사이드에서 실행되는 경우
|
||||
if (import.meta.client) {
|
||||
try {
|
||||
const host = window.location.host;
|
||||
const isGameAliasExtractable = host.includes(baseDomain);
|
||||
const host = window.location.host
|
||||
const isGameAliasExtractable = host.includes(baseDomain)
|
||||
|
||||
if (isGameAliasExtractable) {
|
||||
const subdomain = host.split(".")[0];
|
||||
const subdomain = host.split('.')[0]
|
||||
|
||||
if (subdomain && subdomain !== "www") {
|
||||
return subdomain;
|
||||
if (subdomain && subdomain !== 'www') {
|
||||
return subdomain
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("useGetGameAlias client error: ", error);
|
||||
console.error('useGetGameAlias client error: ', error)
|
||||
}
|
||||
}
|
||||
return "";
|
||||
};
|
||||
return ''
|
||||
}
|
||||
|
||||
@@ -2,38 +2,38 @@ export const usePathResolver = () => {
|
||||
const getPathAfterLanguage = (url?: string): string => {
|
||||
// URL이 제공되지 않으면 현재 URL 사용
|
||||
const targetUrl =
|
||||
url || (import.meta.client ? window.location.pathname : "");
|
||||
url || (import.meta.client ? window.location.pathname : '')
|
||||
|
||||
// URL에서 언어 코드 패턴을 찾아서 그 뒤의 경로를 추출
|
||||
// 예: /ko/about/story -> /about/story
|
||||
// 예: /en/test/page -> /test/page
|
||||
// 예: /ko -> "" (빈 문자열)
|
||||
const languagePattern = /^\/[a-z]{2}\/(.+)$/;
|
||||
const match = targetUrl.match(languagePattern);
|
||||
const languagePattern = /^\/[a-z]{2}\/(.+)$/
|
||||
const match = targetUrl.match(languagePattern)
|
||||
|
||||
if (match && match[1]) {
|
||||
return `/${match[1]}`;
|
||||
return `/${match[1]}`
|
||||
}
|
||||
|
||||
// 언어 코드만 있고 뒤에 아무것도 없는 경우 (예: /ko, /en)
|
||||
const languageOnlyPattern = /^\/[a-z]{2}$/;
|
||||
const languageOnlyPattern = /^\/[a-z]{2}$/
|
||||
if (languageOnlyPattern.test(targetUrl)) {
|
||||
return "";
|
||||
return ''
|
||||
}
|
||||
|
||||
// 언어 코드가 없는 경우 원본 경로 그대로 반환 (이미 /로 시작)
|
||||
return targetUrl;
|
||||
};
|
||||
return targetUrl
|
||||
}
|
||||
|
||||
const getCurrentPath = (): string => {
|
||||
if (import.meta.client) {
|
||||
return getPathAfterLanguage();
|
||||
return getPathAfterLanguage()
|
||||
}
|
||||
return "";
|
||||
};
|
||||
return ''
|
||||
}
|
||||
|
||||
return {
|
||||
getPathAfterLanguage,
|
||||
getCurrentPath,
|
||||
};
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
import { templateRegistry } from "#layers/registry";
|
||||
export const useTemplateRegistry = () => templateRegistry;
|
||||
import { templateRegistry } from '#layers/registry'
|
||||
export const useTemplateRegistry = () => templateRegistry
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<div>
|
||||
<LayoutDefaultHeader />
|
||||
<main>
|
||||
<slot></slot>
|
||||
<slot />
|
||||
</main>
|
||||
<LayoutDefaultFooter />
|
||||
</div>
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
<template>
|
||||
<div class="promotion-wrap">
|
||||
<slot></slot>
|
||||
<slot />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
||||
@@ -1,35 +1,35 @@
|
||||
import { useGameDataStore } from "#layers/stores/useGameDataStore";
|
||||
import { useGameDataStore } from '#layers/stores/useGameDataStore'
|
||||
|
||||
export default defineNuxtRouteMiddleware(async (to, from) => {
|
||||
export default defineNuxtRouteMiddleware(async (to, _from) => {
|
||||
// 서버 사이드에서는 스킵
|
||||
if (import.meta.server) {
|
||||
return;
|
||||
return
|
||||
}
|
||||
|
||||
const gameDataStore = useGameDataStore();
|
||||
const gameDataStore = useGameDataStore()
|
||||
|
||||
// gameData가 로드되지 않았으면 스킵 (다른 미들웨어에서 로드됨)
|
||||
if (!gameDataStore.gameData) {
|
||||
return;
|
||||
return
|
||||
}
|
||||
|
||||
// 현재 경로에서 언어 코드 추출
|
||||
// 예: /ko/about/story -> ko
|
||||
// 예: /en/test/page -> en
|
||||
const languagePattern = /^\/([a-z]{2})(?:\/|$)/;
|
||||
const match = to.path.match(languagePattern);
|
||||
const currentLangCode = match ? match[1] : null;
|
||||
console.log("🚀 3333~ currentLangCode:", currentLangCode)
|
||||
|
||||
const languagePattern = /^\/([a-z]{2})(?:\/|$)/
|
||||
const match = to.path.match(languagePattern)
|
||||
const currentLangCode = match ? match[1] : null
|
||||
// console.log('🚀 3333~ currentLangCode:', currentLangCode)
|
||||
|
||||
// 허용된 언어 코드 목록
|
||||
const allowedLangCodes = gameDataStore.gameData.lang_codes || [];
|
||||
console.log("🚀 ~ allowedLangCodes:", allowedLangCodes)
|
||||
|
||||
const allowedLangCodes = gameDataStore.gameData.lang_codes || []
|
||||
// console.log('🚀 ~ allowedLangCodes:', allowedLangCodes)
|
||||
|
||||
// 현재 언어가 허용된 언어 목록에 없으면 404로 리다이렉트
|
||||
if (currentLangCode && !allowedLangCodes.includes(currentLangCode)) {
|
||||
throw createError({
|
||||
statusCode: 404,
|
||||
statusMessage: "Language not supported"
|
||||
});
|
||||
statusMessage: 'Language not supported',
|
||||
})
|
||||
}
|
||||
});
|
||||
})
|
||||
@@ -1,44 +1,44 @@
|
||||
import { commonFetch } from "#layers/utils/apiUtil";
|
||||
import { usePageDataStore } from "#layers/stores/usePageDataStore";
|
||||
import { useGetGameAlias } from "#layers/composables/useGetGameAlias";
|
||||
import { usePathResolver } from "#layers/composables/usePathResolver";
|
||||
import type { PageDataResponse } from "#layers/types/api/pageData";
|
||||
import { commonFetch } from '#layers/utils/apiUtil'
|
||||
import { usePageDataStore } from '#layers/stores/usePageDataStore'
|
||||
import { useGetGameAlias } from '#layers/composables/useGetGameAlias'
|
||||
import { usePathResolver } from '#layers/composables/usePathResolver'
|
||||
import type { PageDataResponse } from '#layers/types/api/pageData'
|
||||
|
||||
export default defineNuxtRouteMiddleware(async (to, from) => {
|
||||
export default defineNuxtRouteMiddleware(async (to, _from) => {
|
||||
if (import.meta.server) {
|
||||
return;
|
||||
return
|
||||
}
|
||||
|
||||
const config = useRuntimeConfig();
|
||||
const store = usePageDataStore();
|
||||
const gameAlias = useGetGameAlias();
|
||||
const { getPathAfterLanguage } = usePathResolver();
|
||||
const config = useRuntimeConfig()
|
||||
const store = usePageDataStore()
|
||||
const gameAlias = useGetGameAlias()
|
||||
const { getPathAfterLanguage } = usePathResolver()
|
||||
|
||||
const stoveApiBaseUrl = config.public.stoveApiUrl;
|
||||
const apiUrl = `${stoveApiBaseUrl}/pub-comm/v1.0/template/page`;
|
||||
const stoveApiBaseUrl = config.public.stoveApiUrl
|
||||
const apiUrl = `${stoveApiBaseUrl}/pub-comm/v1.0/template/page`
|
||||
|
||||
try {
|
||||
const pageUrl = getPathAfterLanguage(to.path);
|
||||
const pageUrl = getPathAfterLanguage(to.path)
|
||||
const queryParams: Record<string, string> = {
|
||||
game_alias: gameAlias,
|
||||
lang_code: "ko",
|
||||
lang_code: 'ko',
|
||||
page_url: pageUrl,
|
||||
_t: Date.now().toString(), // 캐시 무효화를 위한 타임스탬프
|
||||
};
|
||||
}
|
||||
|
||||
const response = (await commonFetch("GET", apiUrl, {
|
||||
const response = (await commonFetch('GET', apiUrl, {
|
||||
query: queryParams,
|
||||
loading: true,
|
||||
})) as PageDataResponse | null;
|
||||
})) as PageDataResponse | null
|
||||
|
||||
if (response?.code === 0 && "value" in response) {
|
||||
const cleanData = JSON.parse(JSON.stringify(response.value));
|
||||
store.setPageData(cleanData);
|
||||
if (response?.code === 0 && 'value' in response) {
|
||||
const cleanData = JSON.parse(JSON.stringify(response.value))
|
||||
store.setPageData(cleanData)
|
||||
} else {
|
||||
store.clearPageData();
|
||||
store.clearPageData()
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
store.clearPageData();
|
||||
console.error(error)
|
||||
store.clearPageData()
|
||||
}
|
||||
});
|
||||
})
|
||||
|
||||
@@ -1,8 +1,13 @@
|
||||
import { defineNuxtConfig } from "nuxt/config";
|
||||
import { defineNuxtConfig } from 'nuxt/config'
|
||||
|
||||
export default defineNuxtConfig({
|
||||
// Layer-specific configuration
|
||||
imports: {
|
||||
dirs: ["composables", "stores", "types", "middleware", "server", "utils"],
|
||||
dirs: ['composables', 'stores', 'types', 'middleware', 'server', 'utils'],
|
||||
global: true,
|
||||
},
|
||||
});
|
||||
components: {
|
||||
dirs: ['components'],
|
||||
global: true,
|
||||
},
|
||||
})
|
||||
|
||||
@@ -1,24 +1,30 @@
|
||||
export default defineNuxtPlugin(() => {
|
||||
const { $i18n } = useNuxtApp()
|
||||
const gameDataStore = useGameDataStore()
|
||||
|
||||
|
||||
// gameData가 로드되면 언어 제외 설정 적용
|
||||
watchEffect(() => {
|
||||
const gameData = gameDataStore.gameData
|
||||
if (gameData && gameData.lang_codes && gameData.lang_codes.length > 0) {
|
||||
const allowedLangCodes = gameData.lang_codes
|
||||
|
||||
|
||||
// 현재 설정된 locales에서 허용된 언어만 필터링
|
||||
const availableLocales = $i18n.locales.value.filter((locale: any) =>
|
||||
const availableLocales = $i18n.locales.value.filter((locale: any) =>
|
||||
allowedLangCodes.includes(locale.code)
|
||||
)
|
||||
|
||||
|
||||
// locales 업데이트
|
||||
$i18n.locales.value = availableLocales
|
||||
|
||||
// 에러로 인해 주석처리
|
||||
// $i18n.locales.value = availableLocales
|
||||
|
||||
// 현재 locale이 허용되지 않은 경우 기본 locale로 변경
|
||||
if (!allowedLangCodes.includes($i18n.locale.value)) {
|
||||
$i18n.locale.value = gameData.default_lang_code || 'ko'
|
||||
const defaultLang = allowedLangCodes.includes(
|
||||
gameData.default_lang_code
|
||||
)
|
||||
? gameData.default_lang_code
|
||||
: 'ko'
|
||||
$i18n.locale.value = defaultLang as any
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
@@ -1,22 +1,27 @@
|
||||
export default defineNuxtPlugin(() => {
|
||||
const { $i18n } = useNuxtApp()
|
||||
|
||||
|
||||
// SSR에서 gameData를 가져와서 언어 제외 설정 적용
|
||||
const gameDataFromServer = process.server
|
||||
const gameDataFromServer = import.meta.server
|
||||
? useNuxtApp().ssrContext?.event.context.gameData
|
||||
: null
|
||||
|
||||
if (gameDataFromServer && gameDataFromServer.lang_codes && gameDataFromServer.lang_codes.length > 0) {
|
||||
|
||||
if (
|
||||
gameDataFromServer &&
|
||||
gameDataFromServer.lang_codes &&
|
||||
gameDataFromServer.lang_codes.length > 0
|
||||
) {
|
||||
const allowedLangCodes = gameDataFromServer.lang_codes
|
||||
|
||||
|
||||
// 현재 설정된 locales에서 허용된 언어만 필터링
|
||||
const availableLocales = $i18n.locales.value.filter((locale: any) =>
|
||||
const availableLocales = $i18n.locales.value.filter((locale: any) =>
|
||||
allowedLangCodes.includes(locale.code)
|
||||
)
|
||||
|
||||
|
||||
// locales 업데이트
|
||||
$i18n.locales.value = availableLocales
|
||||
|
||||
// 에러로 인해 주석처리
|
||||
// $i18n.locales.value = availableLocales
|
||||
|
||||
// 현재 locale이 허용되지 않은 경우 기본 locale로 변경
|
||||
if (!allowedLangCodes.includes($i18n.locale.value)) {
|
||||
$i18n.locale.value = gameDataFromServer.default_lang_code || 'ko'
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
export default defineNuxtPlugin(() => {
|
||||
const runtimeConfig = useRuntimeConfig();
|
||||
const callerInfoStore = useCallerInfoStore();
|
||||
const runtimeConfig = useRuntimeConfig()
|
||||
const callerInfoStore = useCallerInfoStore()
|
||||
|
||||
const callerId = `${runtimeConfig.public.stoveGameId}`;
|
||||
const callerDetail = `${useCookie("sgs_da_uuid").value || ""}`;
|
||||
const callerId = `${runtimeConfig.public.stoveGameId}`
|
||||
const callerDetail = `${useCookie('sgs_da_uuid').value || ''}`
|
||||
|
||||
callerInfoStore.setCallerId(callerId);
|
||||
callerInfoStore.setCallerDetail(callerDetail);
|
||||
});
|
||||
callerInfoStore.setCallerId(callerId)
|
||||
callerInfoStore.setCallerDetail(callerDetail)
|
||||
})
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import GrVisual01 from "#layers/templates/GrVisual01/index.vue";
|
||||
import GrVisual02 from "#layers/templates/GrVisual02/index.vue";
|
||||
import GrVisual03 from "#layers/templates/GrVisual03/index.vue";
|
||||
import GrVisual01 from '#layers/templates/GrVisual01/index.vue'
|
||||
import GrVisual02 from '#layers/templates/GrVisual02/index.vue'
|
||||
import GrVisual03 from '#layers/templates/GrVisual03/index.vue'
|
||||
// import GrGallery01 from "#layers/templates/GrGallery01/index.vue";
|
||||
// import GrGallery02 from "#layers/templates/GrGallery02/index.vue";
|
||||
// import GrGallery03 from "#layers/templates/GrGallery03/index.vue";
|
||||
@@ -22,6 +22,6 @@ export const templateRegistry = {
|
||||
// GR_DETAIL_02: { component: GrDetail02 },
|
||||
// GR_DETAIL_03: { component: GrDetail03 },
|
||||
// GR_CONTENTS_01: { component: GrContents01 },
|
||||
} as const;
|
||||
} as const
|
||||
|
||||
export type TemplateKey = keyof typeof templateRegistry;
|
||||
export type TemplateKey = keyof typeof templateRegistry
|
||||
|
||||
@@ -3,67 +3,70 @@ import {
|
||||
getRequestHost,
|
||||
defineEventHandler,
|
||||
getRequestURL,
|
||||
} from "h3";
|
||||
} from 'h3'
|
||||
|
||||
export default defineEventHandler(async (event) => {
|
||||
const url = getRequestURL(event);
|
||||
export default defineEventHandler(async event => {
|
||||
const url = getRequestURL(event)
|
||||
|
||||
// 정적 자산, API, 파비콘 등은 제외하고 페이지 요청만 처리
|
||||
if (
|
||||
url.pathname.startsWith("/api/") ||
|
||||
url.pathname.startsWith("/_nuxt/") ||
|
||||
url.pathname.startsWith("/favicon") ||
|
||||
url.pathname.includes(".") ||
|
||||
url.pathname.startsWith("/_")
|
||||
url.pathname.startsWith('/api/') ||
|
||||
url.pathname.startsWith('/_nuxt/') ||
|
||||
url.pathname.startsWith('/favicon') ||
|
||||
url.pathname.includes('.') ||
|
||||
url.pathname.startsWith('/_')
|
||||
) {
|
||||
return;
|
||||
return
|
||||
}
|
||||
|
||||
const host =
|
||||
(getHeader(event, "host") || getRequestHost(event)).toString() || "";
|
||||
const baseDomain = process.env.BASE_DOMAIN || ".onstove.com";
|
||||
const isGameAliasExtractable = host.includes(baseDomain);
|
||||
(getHeader(event, 'host') || getRequestHost(event)).toString() || ''
|
||||
const baseDomain = process.env.BASE_DOMAIN || '.onstove.com'
|
||||
const isGameAliasExtractable = host.includes(baseDomain)
|
||||
|
||||
if (isGameAliasExtractable) {
|
||||
const gameAlias = host.split(".")[0];
|
||||
const gameAlias = host.split('.')[0]
|
||||
|
||||
if (gameAlias && gameAlias !== "www") {
|
||||
event.context.gameAlias = gameAlias;
|
||||
if (gameAlias && gameAlias !== 'www') {
|
||||
event.context.gameAlias = gameAlias
|
||||
}
|
||||
}
|
||||
|
||||
// gameData를 직접 가져와서 context에 저장 (API 호출 없이)
|
||||
try {
|
||||
const config = useRuntimeConfig();
|
||||
const stoveApiBaseUrl = config.public.stoveApiUrl;
|
||||
const apiUrl = `${stoveApiBaseUrl}/pub-comm/v1.0/template/game`;
|
||||
const config = useRuntimeConfig()
|
||||
const stoveApiBaseUrl = config.public.stoveApiUrl
|
||||
const apiUrl = `${stoveApiBaseUrl}/pub-comm/v1.0/template/game`
|
||||
|
||||
// URL의 첫 번째 path를 lang_code로 사용 (파비콘, API 경로 제외)
|
||||
const url = getRequestURL(event);
|
||||
const url = getRequestURL(event)
|
||||
const pathSegments = url.pathname
|
||||
.split("/")
|
||||
.split('/')
|
||||
.filter(
|
||||
(segment) =>
|
||||
segment =>
|
||||
segment &&
|
||||
!segment.includes("favicon") &&
|
||||
!segment.includes("api") &&
|
||||
!segment.startsWith("_")
|
||||
);
|
||||
const langCode = pathSegments[0] || "ko";
|
||||
!segment.includes('favicon') &&
|
||||
!segment.includes('api') &&
|
||||
!segment.startsWith('_')
|
||||
)
|
||||
const langCode = pathSegments[0] || 'ko'
|
||||
|
||||
const queryParams: Record<string, string> = {
|
||||
game_alias: event.context.gameAlias || "",
|
||||
game_alias: event.context.gameAlias || '',
|
||||
lang_code: langCode,
|
||||
};
|
||||
}
|
||||
|
||||
const response = await $fetch(apiUrl, {
|
||||
query: queryParams,
|
||||
});
|
||||
})
|
||||
|
||||
if (response?.code === 0 && "value" in response) {
|
||||
event.context.gameData = response.value;
|
||||
// 타입 단언을 사용하여 response의 타입 오류를 해결
|
||||
const res = response as { code?: number; value?: unknown }
|
||||
|
||||
if (res?.code === 0 && 'value' in res) {
|
||||
event.context.gameData = res.value
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("gameData load error:", error);
|
||||
console.error('gameData load error:', error)
|
||||
}
|
||||
});
|
||||
})
|
||||
|
||||
@@ -1,26 +1,26 @@
|
||||
export const useCallerInfoStore = defineStore("callerInfoStore", () => {
|
||||
const callerId = ref<string>("");
|
||||
const callerDetail = ref<string>("");
|
||||
export const useCallerInfoStore = defineStore('callerInfoStore', () => {
|
||||
const callerId = ref<string>('')
|
||||
const callerDetail = ref<string>('')
|
||||
|
||||
const setCallerId = (id: string): void => {
|
||||
callerId.value = id;
|
||||
};
|
||||
callerId.value = id
|
||||
}
|
||||
|
||||
const setCallerDetail = (detail: string): void => {
|
||||
callerDetail.value = detail;
|
||||
};
|
||||
callerDetail.value = detail
|
||||
}
|
||||
|
||||
// 초기화
|
||||
const resetCallerInfo = (): void => {
|
||||
callerId.value = "";
|
||||
callerDetail.value = "";
|
||||
};
|
||||
callerId.value = ''
|
||||
callerDetail.value = ''
|
||||
}
|
||||
|
||||
// 현재 정보 반환
|
||||
const getCallerInfo = (): { callerId: string; callerDetail: string } => ({
|
||||
callerId: callerId.value,
|
||||
callerDetail: callerDetail.value,
|
||||
});
|
||||
})
|
||||
|
||||
return {
|
||||
callerId,
|
||||
@@ -29,5 +29,5 @@ export const useCallerInfoStore = defineStore("callerInfoStore", () => {
|
||||
setCallerDetail,
|
||||
resetCallerInfo,
|
||||
getCallerInfo,
|
||||
};
|
||||
});
|
||||
}
|
||||
})
|
||||
|
||||
@@ -1,21 +1,19 @@
|
||||
import { defineStore } from "pinia";
|
||||
import { ref } from "vue";
|
||||
import type { GameDataValue } from "#layers/types/api/gameData";
|
||||
import type { GameDataValue } from '#layers/types/api/gameData'
|
||||
|
||||
export const useGameDataStore = defineStore("gameData", () => {
|
||||
const gameData = ref<GameDataValue | null>(null);
|
||||
export const useGameDataStore = defineStore('gameData', () => {
|
||||
const gameData = ref<GameDataValue | null>(null)
|
||||
|
||||
const setGameData = (data: GameDataValue) => {
|
||||
gameData.value = data;
|
||||
};
|
||||
gameData.value = data
|
||||
}
|
||||
|
||||
const clearGameData = () => {
|
||||
gameData.value = null;
|
||||
};
|
||||
gameData.value = null
|
||||
}
|
||||
|
||||
return {
|
||||
gameData,
|
||||
setGameData,
|
||||
clearGameData,
|
||||
};
|
||||
});
|
||||
}
|
||||
})
|
||||
|
||||
@@ -1,53 +1,55 @@
|
||||
import { defineStore } from "pinia";
|
||||
import { defineStore } from 'pinia'
|
||||
|
||||
export const useLoadingStore = defineStore("loadingStore", () => {
|
||||
export const useLoadingStore = defineStore('loadingStore', () => {
|
||||
// 글로벌 로딩 표기
|
||||
const fullLoading = ref(false);
|
||||
const fullLoading = ref(false)
|
||||
// 컴포넌트별 로딩 표기 - Map 대신 일반 객체 사용
|
||||
const localLoadings = ref<Record<string, { active: boolean }>>({});
|
||||
const localLoadings = ref<Record<string, { active: boolean }>>({})
|
||||
// 로딩 상태만 표기
|
||||
const isLoading = ref(false);
|
||||
const isLoading = ref(false)
|
||||
|
||||
/**
|
||||
* 모든 로딩 상태 초기화
|
||||
*/
|
||||
const initializeStore = () => {
|
||||
fullLoading.value = false;
|
||||
localLoadings.value = {};
|
||||
};
|
||||
fullLoading.value = false
|
||||
localLoadings.value = {}
|
||||
}
|
||||
|
||||
/**
|
||||
* Full 로딩
|
||||
*/
|
||||
const startFullLoading = () => {
|
||||
fullLoading.value = true;
|
||||
};
|
||||
fullLoading.value = true
|
||||
}
|
||||
|
||||
const stopFullLoading = () => {
|
||||
fullLoading.value = false;
|
||||
};
|
||||
fullLoading.value = false
|
||||
}
|
||||
|
||||
/**
|
||||
* Local 로딩
|
||||
*/
|
||||
const startLocalLoading = (localId: string) => {
|
||||
localLoadings.value[localId] = { active: true };
|
||||
};
|
||||
localLoadings.value[localId] = { active: true }
|
||||
}
|
||||
|
||||
const stopLocalLoading = (localId: string) => {
|
||||
delete localLoadings.value[localId];
|
||||
};
|
||||
if (localLoadings.value[localId]) {
|
||||
localLoadings.value[localId].active = false
|
||||
}
|
||||
}
|
||||
|
||||
const isLocalLoading = (localId: string) => {
|
||||
return localLoadings.value[localId]?.active || false;
|
||||
};
|
||||
return !!localLoadings.value[localId]?.active
|
||||
}
|
||||
|
||||
/**
|
||||
* 로딩 상태 변경
|
||||
*/
|
||||
const setLoading = (state: boolean) => {
|
||||
isLoading.value = state;
|
||||
};
|
||||
isLoading.value = state
|
||||
}
|
||||
|
||||
return {
|
||||
fullLoading,
|
||||
@@ -61,5 +63,5 @@ export const useLoadingStore = defineStore("loadingStore", () => {
|
||||
stopLocalLoading,
|
||||
isLocalLoading,
|
||||
setLoading,
|
||||
};
|
||||
});
|
||||
}
|
||||
})
|
||||
|
||||
@@ -1,21 +1,19 @@
|
||||
import { defineStore } from "pinia";
|
||||
import { ref } from "vue";
|
||||
import type { PageDataValue } from "#layers/types/api/pageData";
|
||||
import type { PageDataValue } from '#layers/types/api/pageData'
|
||||
|
||||
export const usePageDataStore = defineStore("pageData", () => {
|
||||
const pageData = ref<PageDataValue | null>(null);
|
||||
export const usePageDataStore = defineStore('pageData', () => {
|
||||
const pageData = ref<PageDataValue | null>(null)
|
||||
|
||||
const setPageData = (response: PageDataValue) => {
|
||||
pageData.value = response;
|
||||
};
|
||||
pageData.value = response
|
||||
}
|
||||
|
||||
const clearPageData = () => {
|
||||
pageData.value = null;
|
||||
};
|
||||
pageData.value = null
|
||||
}
|
||||
|
||||
return {
|
||||
pageData,
|
||||
setPageData,
|
||||
clearPageData,
|
||||
};
|
||||
});
|
||||
}
|
||||
})
|
||||
|
||||
@@ -1,29 +1,29 @@
|
||||
<script setup lang="ts">
|
||||
import YouTubeModal from "#layers/components/molecules/modal/YouTubeModal.vue";
|
||||
import YouTubeModal from '#layers/components/molecules/modal/YouTubeModal.vue'
|
||||
|
||||
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 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;
|
||||
};
|
||||
youtubeVideoId.value = 'UKVsZYHxYTc' // 임시로 설정
|
||||
isYouTubeModalOpen.value = true
|
||||
}
|
||||
|
||||
// 모달 닫기 핸들러
|
||||
const handleCloseModal = () => {
|
||||
isYouTubeModalOpen.value = false;
|
||||
youtubeVideoId.value = "";
|
||||
};
|
||||
isYouTubeModalOpen.value = false
|
||||
youtubeVideoId.value = ''
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -58,6 +58,6 @@ const handleCloseModal = () => {
|
||||
:is-open="isYouTubeModalOpen"
|
||||
:youtube-id="youtubeVideoId"
|
||||
@close="handleCloseModal"
|
||||
@update:is-open="isYouTubeModalOpen = $event"
|
||||
@update:is-open="(value: boolean) => (isYouTubeModalOpen = value)"
|
||||
/>
|
||||
</template>
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
<script setup lang="ts">
|
||||
interface Props {
|
||||
components: Record<string, any>;
|
||||
components: Record<string, any>
|
||||
}
|
||||
|
||||
const props = defineProps<Props>();
|
||||
const _props = defineProps<Props>()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<section class="template-section"></section>
|
||||
<section class="template-section" />
|
||||
</template>
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
<script setup lang="ts">
|
||||
interface Props {
|
||||
components: Record<string, any>;
|
||||
components: Record<string, any>
|
||||
}
|
||||
|
||||
const props = defineProps<Props>();
|
||||
const props = defineProps<Props>()
|
||||
|
||||
console.log("components:", props.components);
|
||||
console.log('components:', props.components)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
||||
@@ -1,317 +1,331 @@
|
||||
// API 요청 파라미터 타입
|
||||
export interface GameDataRequest {
|
||||
game_alias: string;
|
||||
lang_code: string;
|
||||
q?: string;
|
||||
qc?: string;
|
||||
game_alias: string
|
||||
lang_code: string
|
||||
q?: string
|
||||
qc?: string
|
||||
}
|
||||
|
||||
// API 응답 데이터 타입
|
||||
export interface GameDataResponse {
|
||||
code: number;
|
||||
message: string;
|
||||
value: GameDataValue;
|
||||
code: number
|
||||
message: string
|
||||
value: GameDataValue
|
||||
}
|
||||
|
||||
// API 응답의 value 객체 타입
|
||||
export interface GameDataValue {
|
||||
game_id: string;
|
||||
game_code: number;
|
||||
s3_folder_name: string;
|
||||
game_name: string;
|
||||
ga_code: string;
|
||||
favicon_path: string;
|
||||
design_theme: number;
|
||||
lang_codes: string; // JSON 문자열로 변경
|
||||
key_color_codes: string; // JSON 문자열로 변경
|
||||
use_game_font: boolean;
|
||||
footer_dev_ci_img_yn: boolean;
|
||||
footer_dev_ci_img_path: string;
|
||||
game_font: string; // JSON 문자열로 변경
|
||||
globals: GameDataGlobal[]; // 배열로 변경
|
||||
gnb: GameDataGnb;
|
||||
intro: GameDataIntro;
|
||||
inspection: Record<string, any>; // 동적 객체
|
||||
stove_gnb: string; // JSON 문자열로 변경
|
||||
meta_tag: string; // JSON 문자열로 변경
|
||||
sns: string; // JSON 문자열로 변경
|
||||
footer: string; // JSON 문자열로 변경
|
||||
game_id: string
|
||||
game_code: number
|
||||
s3_folder_name: string
|
||||
game_name: string
|
||||
ga_code: string
|
||||
design_theme: number
|
||||
lang_codes: string // JSON 문자열로 변경
|
||||
key_color_codes: string // JSON 문자열로 변경
|
||||
use_game_font: boolean
|
||||
comm_sns_bg_color_code: string
|
||||
comm_multilang_filename: string
|
||||
footer_dev_ci_img_yn: boolean
|
||||
footer_dev_ci_img_path: string
|
||||
default_lang_code?: string // 기본 언어 코드 추가
|
||||
game_font: string // JSON 문자열로 변경
|
||||
globals: GameDataGlobal[] // 배열로 변경
|
||||
gnb: GameDataGnb
|
||||
intro: GameDataIntro
|
||||
inspection: Record<string, any> // 동적 객체
|
||||
stove_gnb: GameDataStoveGnb // JSON 문자열로 변경
|
||||
favicon_path: string // JSON 문자열로 변경
|
||||
meta_tag: string // JSON 문자열로 변경
|
||||
sns: string // JSON 문자열로 변경
|
||||
footer: string // JSON 문자열로 변경
|
||||
}
|
||||
|
||||
// Global 설정 타입
|
||||
export interface GameDataGlobal {
|
||||
system_font: string; // JSON 문자열로 변경
|
||||
lang: string; // JSON 문자열로 변경
|
||||
system_font: string // JSON 문자열로 변경
|
||||
lang: string // JSON 문자열로 변경
|
||||
}
|
||||
|
||||
// 폰트 타입
|
||||
export interface GameDataFont {
|
||||
"font-family": string;
|
||||
'font-family': string
|
||||
}
|
||||
|
||||
// 언어 설정 타입
|
||||
export interface GameDataLang {
|
||||
dir: string;
|
||||
iso: string;
|
||||
code: string;
|
||||
name: string;
|
||||
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>; // 동적 객체로 변경
|
||||
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> // 동적 객체로 변경
|
||||
}
|
||||
|
||||
// 버튼 타입
|
||||
export interface GameDataButton {
|
||||
depth_type: number;
|
||||
button: string; // JSON 문자열로 변경
|
||||
depth_type: number
|
||||
button: string // JSON 문자열로 변경
|
||||
}
|
||||
|
||||
// 메뉴 타입
|
||||
export interface GameDataMenu {
|
||||
path_code: string;
|
||||
depth: number;
|
||||
sort_order: number;
|
||||
menu_name: string;
|
||||
click_action_type: number;
|
||||
url_path: string;
|
||||
link_target: string;
|
||||
children: Record<string, GameDataMenu>; // 중첩 메뉴를 위한 children 속성 추가
|
||||
tracking: string; // JSON 문자열로 변경
|
||||
path_code: string
|
||||
depth: number
|
||||
sort_order: number
|
||||
menu_name: string
|
||||
click_action_type: number
|
||||
url_path: string
|
||||
link_target: string
|
||||
children: Record<string, GameDataMenu> // 중첩 메뉴를 위한 children 속성 추가
|
||||
tracking: string | GameDataTracking // JSON 문자열 또는 객체로 변경
|
||||
}
|
||||
|
||||
// 인트로 타입
|
||||
export interface GameDataIntro {
|
||||
seq: number;
|
||||
display_start_dt: string;
|
||||
display_end_dt: string;
|
||||
page_url: string;
|
||||
seq: number
|
||||
display_start_dt: string
|
||||
display_end_dt: string
|
||||
page_url: string
|
||||
}
|
||||
|
||||
// 트래킹 타입
|
||||
export interface GameDataTracking {
|
||||
viewType: string;
|
||||
actionType: string;
|
||||
clickSarea: string;
|
||||
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;
|
||||
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
|
||||
export type StoveGnbSkinType =
|
||||
| 'gnb-default'
|
||||
| 'gnb-default-fixed'
|
||||
| 'gnb-dark-theme'
|
||||
| 'gnb-dark-mix'
|
||||
| 'gnb-dark-mini'
|
||||
| 'gnb-dark-mix-mini'
|
||||
| 'gnb-default-mini'
|
||||
| 'gnb-mobile-timeline'
|
||||
|
||||
// Stove GNB 타입
|
||||
export interface GameDataStoveGnb {
|
||||
skin_type: string;
|
||||
stove_install_button_visible: string;
|
||||
skin_type: StoveGnbSkinType
|
||||
stove_install_button_visible: string
|
||||
}
|
||||
|
||||
// 파비콘 경로 타입
|
||||
export interface GameDataFaviconPath {
|
||||
"16_16": string;
|
||||
"32_32": string;
|
||||
"72_72": string;
|
||||
"180_180": string;
|
||||
"192_192": string;
|
||||
'16_16': string
|
||||
'32_32': string
|
||||
'72_72': string
|
||||
'180_180': string
|
||||
'192_192': string
|
||||
}
|
||||
|
||||
// 공통 이미지 타입
|
||||
export interface GameDataCommImg {
|
||||
groups: GameDataCommImgGroup[];
|
||||
groups: GameDataCommImgGroup[]
|
||||
}
|
||||
|
||||
// 공통 이미지 그룹 타입
|
||||
export interface GameDataCommImgGroup {
|
||||
img_path: GameDataImgPath;
|
||||
required: boolean;
|
||||
img_scope: string;
|
||||
group_code: string;
|
||||
group_label: string;
|
||||
img_path: GameDataImgPath
|
||||
required: boolean
|
||||
img_scope: string
|
||||
group_code: string
|
||||
group_label: string
|
||||
}
|
||||
|
||||
// 이미지 경로 타입
|
||||
export interface GameDataImgPath {
|
||||
comm: string;
|
||||
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;
|
||||
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;
|
||||
use_yn: number
|
||||
api_key: string
|
||||
}
|
||||
|
||||
// SNS 설정 타입
|
||||
export interface GameDataSns {
|
||||
kakao: GameDataSnsItem;
|
||||
tiktok: GameDataSnsItem;
|
||||
discord: GameDataSnsItem;
|
||||
twitter: GameDataSnsItem;
|
||||
youtube: GameDataSnsItem;
|
||||
facebook: GameDataSnsItem;
|
||||
instagram: GameDataSnsItem;
|
||||
kakao: GameDataSnsItem
|
||||
tiktok: GameDataSnsItem
|
||||
discord: GameDataSnsItem
|
||||
twitter: GameDataSnsItem
|
||||
youtube: GameDataSnsItem
|
||||
facebook: GameDataSnsItem
|
||||
instagram: GameDataSnsItem
|
||||
}
|
||||
|
||||
// SNS 아이템 타입
|
||||
export interface GameDataSnsItem {
|
||||
url: string | null;
|
||||
use_yn: number;
|
||||
url: string | null
|
||||
use_yn: number
|
||||
}
|
||||
|
||||
// 마켓 설정 타입
|
||||
export interface GameDataMarket {
|
||||
pc: GameDataMarketItem;
|
||||
app_store: GameDataMarketItem;
|
||||
google_play: GameDataMarketItem;
|
||||
pc: GameDataMarketItem
|
||||
app_store: GameDataMarketItem
|
||||
google_play: GameDataMarketItem
|
||||
}
|
||||
|
||||
// 마켓 아이템 타입
|
||||
export interface GameDataMarketItem {
|
||||
url: string | null;
|
||||
use_yn: number;
|
||||
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;
|
||||
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;
|
||||
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 에러 응답 타입
|
||||
export interface GameDataErrorResponse {
|
||||
code: number;
|
||||
message: string;
|
||||
error?: string;
|
||||
code: number
|
||||
message: string
|
||||
error?: string
|
||||
}
|
||||
|
||||
// API 응답 래퍼 타입 (성공/실패 통합)
|
||||
export type GameDataApiResponse = GameDataResponse | GameDataErrorResponse;
|
||||
export type GameDataApiResponse = GameDataResponse | GameDataErrorResponse
|
||||
|
||||
// API 호출 옵션 타입
|
||||
export interface GameDataApiOptions {
|
||||
gameAlias: string;
|
||||
langCode: string;
|
||||
q: string;
|
||||
qc: string;
|
||||
baseUrl?: string;
|
||||
gameAlias: string
|
||||
langCode: string
|
||||
q: string
|
||||
qc: string
|
||||
baseUrl?: string
|
||||
}
|
||||
|
||||
// API 상태 타입
|
||||
export type GameDataApiStatus = "idle" | "loading" | "success" | "error";
|
||||
export type GameDataApiStatus = 'idle' | 'loading' | 'success' | 'error'
|
||||
|
||||
// API 결과 타입 (상태와 데이터를 함께 관리)
|
||||
export interface GameDataApiResult {
|
||||
status: GameDataApiStatus;
|
||||
data: GameDataResponse | null;
|
||||
error: string | null;
|
||||
status: GameDataApiStatus
|
||||
data: GameDataResponse | null
|
||||
error: string | null
|
||||
}
|
||||
|
||||
// JSON 문자열 파싱을 위한 유틸리티 타입들
|
||||
export interface ParsedKeyColorCodes {
|
||||
extra: string;
|
||||
primary: string;
|
||||
secondary: string;
|
||||
"text-primary": string;
|
||||
"text-secondary": string;
|
||||
extra: string
|
||||
primary: string
|
||||
secondary: string
|
||||
'text-primary': string
|
||||
'text-secondary': string
|
||||
}
|
||||
|
||||
export interface ParsedGameFont {
|
||||
"font-family": string;
|
||||
'font-family': string
|
||||
}
|
||||
|
||||
export interface ParsedGlobal {
|
||||
system_font: ParsedGameFont;
|
||||
lang: GameDataLang;
|
||||
system_font: ParsedGameFont
|
||||
lang: GameDataLang
|
||||
}
|
||||
|
||||
export interface ParsedButton {
|
||||
google_play: {
|
||||
label: Record<string, string>;
|
||||
url: string;
|
||||
tracking: GameDataTracking;
|
||||
};
|
||||
label: Record<string, string>
|
||||
url: string
|
||||
tracking: GameDataTracking
|
||||
}
|
||||
app_store: {
|
||||
label: Record<string, string>;
|
||||
url: string;
|
||||
tracking: GameDataTracking;
|
||||
};
|
||||
label: Record<string, string>
|
||||
url: string
|
||||
tracking: GameDataTracking
|
||||
}
|
||||
}
|
||||
|
||||
export interface ParsedStoveGnb {
|
||||
skin_type: string;
|
||||
stove_install_button_visible: string;
|
||||
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;
|
||||
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;
|
||||
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;
|
||||
'16_16': string
|
||||
'32_32': string
|
||||
'72_72': string
|
||||
'180_180': string
|
||||
'192_192': string
|
||||
}
|
||||
|
||||
// 기존 gameData 타입과의 호환성을 위한 별칭
|
||||
export type gameData = GameDataValue;
|
||||
export type gameData = GameDataValue
|
||||
|
||||
@@ -1,147 +1,170 @@
|
||||
// API 요청 파라미터 타입
|
||||
export interface PageDataRequest {
|
||||
game_alias: string;
|
||||
lang_code: string;
|
||||
page_url: string;
|
||||
q?: string;
|
||||
qc?: string;
|
||||
game_alias: string
|
||||
lang_code: string
|
||||
page_url: string
|
||||
q?: string
|
||||
qc?: string
|
||||
}
|
||||
|
||||
// API 요청 헤더 타입
|
||||
export interface PageDataRequestHeaders {
|
||||
"caller-Detail"?: string;
|
||||
"caller-ID"?: string;
|
||||
Authorization?: string;
|
||||
'caller-Detail'?: string
|
||||
'caller-ID'?: string
|
||||
Authorization?: string
|
||||
}
|
||||
|
||||
// API 응답 데이터 타입
|
||||
export interface PageDataResponse {
|
||||
code: number;
|
||||
message: string;
|
||||
value: PageDataValue;
|
||||
code: number
|
||||
message: string
|
||||
value: PageDataValue
|
||||
}
|
||||
|
||||
// API 응답의 value 객체 타입
|
||||
export interface PageDataValue {
|
||||
page_seq: number;
|
||||
page_type: number;
|
||||
page_name: string;
|
||||
page_name_en: string;
|
||||
page_ver: number;
|
||||
display_start_dt: string;
|
||||
lang_codes: string; // JSON string
|
||||
is_login_required: boolean;
|
||||
meta_tag_type: number;
|
||||
fit_page_height: boolean;
|
||||
use_top_btn: boolean;
|
||||
use_sns_btn: boolean;
|
||||
use_lnb: boolean;
|
||||
lnb_menus: PageDataLnbMenu[];
|
||||
templates: PageDataTemplate[];
|
||||
meta_tag: PageDataMetaTag;
|
||||
page_seq: number
|
||||
page_type: number
|
||||
page_name: string
|
||||
page_name_en: string
|
||||
page_ver: number
|
||||
display_start_dt: string
|
||||
lang_codes: string // JSON string
|
||||
is_login_required: boolean
|
||||
meta_tag_type: number
|
||||
fit_page_height: boolean
|
||||
use_top_btn: boolean
|
||||
use_sns_btn: boolean
|
||||
use_lnb: boolean
|
||||
lnb_menus: PageDataLnbMenu[]
|
||||
templates: PageDataTemplate[]
|
||||
meta_tag: PageDataMetaTag // JSON string
|
||||
}
|
||||
|
||||
// 메타 태그 타입
|
||||
export interface PageDataMetaTag {
|
||||
x_desc: string;
|
||||
og_desc: string;
|
||||
x_image: string;
|
||||
x_title: string;
|
||||
og_image: string;
|
||||
og_title: string;
|
||||
page_desc: string;
|
||||
page_title: string;
|
||||
x_desc: string
|
||||
og_desc: string
|
||||
x_image: string
|
||||
x_title: string
|
||||
og_image: string
|
||||
og_title: string
|
||||
page_desc: string
|
||||
page_title: string
|
||||
}
|
||||
|
||||
// LNB 메뉴 타입
|
||||
export interface PageDataLnbMenu {
|
||||
text_color_code_active: string;
|
||||
text_color_code_deactive: string;
|
||||
path_code: string;
|
||||
depth: number;
|
||||
sort_order: number;
|
||||
menu_name: string;
|
||||
target_type: number;
|
||||
page_ver_tmpl_name_en: string;
|
||||
tracking: string; // JSON string
|
||||
text_color_code_active: string
|
||||
text_color_code_deactive: string
|
||||
path_code: string
|
||||
depth: number
|
||||
sort_order: number
|
||||
menu_name: string
|
||||
target_type: number
|
||||
page_ver_tmpl_name_en: string
|
||||
tracking: string // JSON string
|
||||
}
|
||||
|
||||
// 템플릿 타입
|
||||
export interface PageDataTemplate {
|
||||
tmpl_sort_order: number;
|
||||
page_ver_tmpl_name: string;
|
||||
page_ver_tmpl_name_en: string;
|
||||
template_code: string;
|
||||
template_type_code: string;
|
||||
template_category: string;
|
||||
template_name: string;
|
||||
template_sample_img_path: string;
|
||||
template_sample_zip_path: string;
|
||||
template_type_name: string;
|
||||
is_selectable_on_create: boolean;
|
||||
components: Record<string, PageDataComponent>;
|
||||
tmpl_sort_order: number
|
||||
page_ver_tmpl_name: string
|
||||
page_ver_tmpl_name_en: string
|
||||
template_code: string
|
||||
components: Record<string, PageDataComponent>
|
||||
}
|
||||
|
||||
// 컴포넌트 타입
|
||||
export interface PageDataComponent {
|
||||
component_sort_order: number;
|
||||
component_type: string;
|
||||
set_count: number;
|
||||
component_name: string;
|
||||
is_required: boolean;
|
||||
has_operational_resource: boolean;
|
||||
min_count: number;
|
||||
max_count: number;
|
||||
component_id: string;
|
||||
operate_resources: PageDataOperateResource[];
|
||||
[key: string]: any; // Additional Properties
|
||||
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
|
||||
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 에러 응답 타입
|
||||
export interface PageDataErrorResponse {
|
||||
code: number;
|
||||
message: string;
|
||||
error?: string;
|
||||
code: number
|
||||
message: string
|
||||
error?: string
|
||||
}
|
||||
|
||||
// API 응답 래퍼 타입 (성공/실패 통합)
|
||||
export type PageDataApiResponse = PageDataResponse | PageDataErrorResponse;
|
||||
export type PageDataApiResponse = PageDataResponse | PageDataErrorResponse
|
||||
|
||||
// API 호출 옵션 타입
|
||||
export interface PageDataApiOptions {
|
||||
gameAlias: string;
|
||||
langCode: string;
|
||||
pageUrl: string;
|
||||
q?: string;
|
||||
qc?: string;
|
||||
headers?: PageDataRequestHeaders;
|
||||
baseUrl?: string;
|
||||
gameAlias: string
|
||||
langCode: string
|
||||
pageUrl: string
|
||||
q?: string
|
||||
qc?: string
|
||||
headers?: PageDataRequestHeaders
|
||||
baseUrl?: string
|
||||
}
|
||||
|
||||
// API 상태 타입
|
||||
export type PageDataApiStatus = "idle" | "loading" | "success" | "error";
|
||||
export type PageDataApiStatus = 'idle' | 'loading' | 'success' | 'error'
|
||||
|
||||
// API 결과 타입 (상태와 데이터를 함께 관리)
|
||||
export interface PageDataApiResult {
|
||||
status: PageDataApiStatus;
|
||||
data: PageDataResponse | null;
|
||||
error: string | null;
|
||||
status: PageDataApiStatus
|
||||
data: PageDataResponse | null
|
||||
error: string | null
|
||||
}
|
||||
|
||||
// 페이지 데이터 별칭 (기존 호환성)
|
||||
export type pageData = PageDataValue;
|
||||
export type pageData = PageDataValue
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { ref } from "vue";
|
||||
import { ref } from 'vue'
|
||||
|
||||
/**
|
||||
* 공통 API 호출
|
||||
@@ -13,15 +13,15 @@ import { ref } from "vue";
|
||||
*/
|
||||
export const commonFetch = async (
|
||||
method:
|
||||
| "GET"
|
||||
| "HEAD"
|
||||
| "PATCH"
|
||||
| "POST"
|
||||
| "PUT"
|
||||
| "DELETE"
|
||||
| "CONNECT"
|
||||
| "OPTIONS"
|
||||
| "TRACE" = "GET", // Required
|
||||
| 'GET'
|
||||
| 'HEAD'
|
||||
| 'PATCH'
|
||||
| 'POST'
|
||||
| 'PUT'
|
||||
| 'DELETE'
|
||||
| 'CONNECT'
|
||||
| 'OPTIONS'
|
||||
| 'TRACE' = 'GET', // Required
|
||||
url: string, // Required
|
||||
{
|
||||
query, // Optional
|
||||
@@ -30,40 +30,40 @@ export const commonFetch = async (
|
||||
key, // Optional
|
||||
loading = false, // Optional
|
||||
}: {
|
||||
query?: object | null;
|
||||
headers?: object | null;
|
||||
body?: object | null;
|
||||
key?: string | null;
|
||||
loading?: { localId?: string } | boolean;
|
||||
query?: object | null
|
||||
headers?: object | null
|
||||
body?: object | null
|
||||
key?: string | null
|
||||
loading?: { localId?: string } | boolean
|
||||
} = {}
|
||||
) => {
|
||||
let result = null;
|
||||
const currCallerId = ref("");
|
||||
const currCallerDetail = ref("");
|
||||
let result = null
|
||||
const currCallerId = ref('')
|
||||
const currCallerDetail = ref('')
|
||||
|
||||
// 로딩 스토어 가져오기 (클라이언트에서만)
|
||||
let loadingStore: ReturnType<typeof useLoadingStore> | null = null;
|
||||
let loadingStore: ReturnType<typeof useLoadingStore> | null = null
|
||||
if (import.meta.client) {
|
||||
try {
|
||||
loadingStore = useLoadingStore();
|
||||
loadingStore = useLoadingStore()
|
||||
// 로딩 시작
|
||||
loadingStore.setLoading(true);
|
||||
loadingStore.setLoading(true)
|
||||
if (loading && loadingStore) {
|
||||
if (typeof loading === "object" && loading.localId) {
|
||||
loadingStore.startLocalLoading(loading.localId);
|
||||
if (typeof loading === 'object' && loading.localId) {
|
||||
loadingStore.startLocalLoading(loading.localId)
|
||||
} else {
|
||||
loadingStore.startFullLoading();
|
||||
loadingStore.startFullLoading()
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
console.warn("[Warning] Loading store not available:", e);
|
||||
console.warn('[Warning] Loading store not available:', e)
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
const { callerId, callerDetail } = storeToRefs(useCallerInfoStore());
|
||||
currCallerId.value = `${callerId.value}`;
|
||||
currCallerDetail.value = `${callerDetail.value}`;
|
||||
const { callerId, callerDetail } = storeToRefs(useCallerInfoStore())
|
||||
currCallerId.value = `${callerId.value}`
|
||||
currCallerDetail.value = `${callerDetail.value}`
|
||||
} catch (e) {
|
||||
// SSR: pinia store 생성 전이므로 빈 값('') 세팅
|
||||
}
|
||||
@@ -71,74 +71,74 @@ export const commonFetch = async (
|
||||
try {
|
||||
const options: {
|
||||
method:
|
||||
| "GET"
|
||||
| "HEAD"
|
||||
| "PATCH"
|
||||
| "POST"
|
||||
| "PUT"
|
||||
| "DELETE"
|
||||
| "CONNECT"
|
||||
| "OPTIONS"
|
||||
| "TRACE";
|
||||
headers: Record<string, string>;
|
||||
query?: object;
|
||||
body?: object;
|
||||
key?: string;
|
||||
| 'GET'
|
||||
| 'HEAD'
|
||||
| 'PATCH'
|
||||
| 'POST'
|
||||
| 'PUT'
|
||||
| 'DELETE'
|
||||
| 'CONNECT'
|
||||
| 'OPTIONS'
|
||||
| 'TRACE'
|
||||
headers: Record<string, string>
|
||||
query?: object
|
||||
body?: object
|
||||
key?: string
|
||||
} = {
|
||||
method,
|
||||
headers: {
|
||||
"Content-Type": "application/json;charset=UTF-8",
|
||||
'Content-Type': 'application/json;charset=UTF-8',
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
if (query) {
|
||||
options.query = query;
|
||||
options.query = query
|
||||
}
|
||||
// 플랫폼 환경 API 호출 시 Caller-Id, Caller-Detail 헤더 추가
|
||||
if (url.includes(".onstove.com") || url.includes(".gate8.com")) {
|
||||
if (url.includes('.onstove.com') || url.includes('.gate8.com')) {
|
||||
const callerInfo = {
|
||||
"Caller-Id": `${currCallerId.value}`,
|
||||
"Caller-Detail": `${currCallerDetail.value}`,
|
||||
};
|
||||
options.headers = { ...options.headers, ...callerInfo };
|
||||
'Caller-Id': `${currCallerId.value}`,
|
||||
'Caller-Detail': `${currCallerDetail.value}`,
|
||||
}
|
||||
options.headers = { ...options.headers, ...callerInfo }
|
||||
}
|
||||
if (headers) {
|
||||
options.headers = { ...options.headers, ...headers };
|
||||
options.headers = { ...options.headers, ...headers }
|
||||
}
|
||||
if (body) {
|
||||
options.body = body;
|
||||
options.body = body
|
||||
}
|
||||
if (key) {
|
||||
options.key = key;
|
||||
options.key = key
|
||||
}
|
||||
|
||||
result = await $fetch(url, options);
|
||||
result = await $fetch(url, options)
|
||||
} catch (e: unknown) {
|
||||
console.error("[Exception] apiUtil.commonFetch: ", e);
|
||||
console.error('[Exception] apiUtil.commonFetch: ', e)
|
||||
const error = e as {
|
||||
data?: unknown;
|
||||
statusCode?: number;
|
||||
statusMessage?: string;
|
||||
};
|
||||
data?: unknown
|
||||
statusCode?: number
|
||||
statusMessage?: string
|
||||
}
|
||||
result = error.data || {
|
||||
code: error.statusCode,
|
||||
message: error.statusMessage,
|
||||
};
|
||||
}
|
||||
} finally {
|
||||
// 로딩 종료
|
||||
if (loadingStore) {
|
||||
loadingStore.setLoading(false);
|
||||
loadingStore.setLoading(false)
|
||||
if (loading) {
|
||||
if (typeof loading === "object" && loading.localId) {
|
||||
loadingStore.stopLocalLoading(loading.localId);
|
||||
if (typeof loading === 'object' && loading.localId) {
|
||||
loadingStore.stopLocalLoading(loading.localId)
|
||||
} else {
|
||||
loadingStore.stopFullLoading();
|
||||
loadingStore.stopFullLoading()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
};
|
||||
return result
|
||||
}
|
||||
|
||||
/**
|
||||
* 사용자 IP 조회
|
||||
@@ -146,36 +146,35 @@ export const commonFetch = async (
|
||||
* @param {object} request - 요청 객체
|
||||
*/
|
||||
export const getTrueClientIp = (request: {
|
||||
headers: Record<string, string>;
|
||||
socket: { remoteAddress?: string };
|
||||
headers: Record<string, string>
|
||||
socket: { remoteAddress?: string }
|
||||
}) => {
|
||||
const requestHeaders = request.headers;
|
||||
const requestHeaders = request.headers
|
||||
const targetHeaders = [
|
||||
"True-Client-IP",
|
||||
"X-Real-IP",
|
||||
"X-Forwarded-For",
|
||||
"Proxy-Client-IP",
|
||||
"WL-Proxy-Client-IP",
|
||||
"HTTP_CLIENT_IP",
|
||||
"HTTP_X_FORWARDED_FOR",
|
||||
];
|
||||
'True-Client-IP',
|
||||
'X-Real-IP',
|
||||
'X-Forwarded-For',
|
||||
'Proxy-Client-IP',
|
||||
'WL-Proxy-Client-IP',
|
||||
'HTTP_CLIENT_IP',
|
||||
'HTTP_X_FORWARDED_FOR',
|
||||
]
|
||||
for (const targetHeader of targetHeaders) {
|
||||
let ip =
|
||||
requestHeaders[targetHeader] ||
|
||||
requestHeaders[targetHeader.toLowerCase()];
|
||||
if (ip !== undefined && ip != null && ip !== "") {
|
||||
if (ip.includes(",")) {
|
||||
ip = ip.split(",")[0];
|
||||
requestHeaders[targetHeader] || requestHeaders[targetHeader.toLowerCase()]
|
||||
if (ip !== undefined && ip != null && ip !== '') {
|
||||
if (ip.includes(',')) {
|
||||
ip = ip.split(',')[0]
|
||||
}
|
||||
return ip;
|
||||
return ip
|
||||
}
|
||||
}
|
||||
if (
|
||||
request.socket.remoteAddress !== undefined &&
|
||||
request.socket.remoteAddress != null &&
|
||||
request.socket.remoteAddress !== ""
|
||||
request.socket.remoteAddress !== ''
|
||||
) {
|
||||
return request.socket.remoteAddress;
|
||||
return request.socket.remoteAddress
|
||||
}
|
||||
return "";
|
||||
};
|
||||
return ''
|
||||
}
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
// 이미지 호스트 리턴하는 함수
|
||||
// [TODO] 환경변수 처리 수정
|
||||
export const getResolvedHost = (path: string): string => {
|
||||
const config = useRuntimeConfig();
|
||||
const config = useRuntimeConfig()
|
||||
// const isDev = process.env.NODE_ENV === "development";
|
||||
// const rootPath = isDev ? "/images" : `${config.public.staticUrl}`;
|
||||
|
||||
const rootPath = config.public.staticUrl;
|
||||
const rootPath = config.public.staticUrl
|
||||
|
||||
return `${rootPath}${path}`;
|
||||
};
|
||||
return `${rootPath}${path}`
|
||||
}
|
||||
|
||||
// 리소스 데이터 리턴하는 함수
|
||||
// [TODO] data 타입 정의
|
||||
@@ -17,54 +17,54 @@ export const getResourcesData = ({
|
||||
isMultiple = false,
|
||||
groupSets = false,
|
||||
}: {
|
||||
resources: any;
|
||||
isMultiple?: boolean;
|
||||
groupSets?: boolean;
|
||||
resources: any
|
||||
isMultiple?: boolean
|
||||
groupSets?: boolean
|
||||
}) => {
|
||||
const groups = groupSets
|
||||
? resources[0]?.group_sets[0]?.groups
|
||||
: resources[0]?.groups;
|
||||
: resources[0]?.groups
|
||||
|
||||
if (isMultiple) {
|
||||
return groups;
|
||||
return groups
|
||||
}
|
||||
return groups?.[0] ?? null;
|
||||
};
|
||||
return groups?.[0] ?? null
|
||||
}
|
||||
|
||||
// 반응형 클래스 리턴하는 함수
|
||||
export const getResponsiveClass = () => {
|
||||
return ["bg-[image:var(--mobile-bg)]", "sm:bg-[image:var(--pc-bg)]"];
|
||||
};
|
||||
return ['bg-[image:var(--mobile-bg)]', 'sm:bg-[image:var(--pc-bg)]']
|
||||
}
|
||||
|
||||
// 통합된 반응형 리소스 함수
|
||||
export const getResponsiveSrc = (
|
||||
pathArray: any,
|
||||
options: {
|
||||
resourcesType?: "image" | "bg" | "video";
|
||||
resourcesType?: 'image' | 'bg' | 'video'
|
||||
} = {}
|
||||
) => {
|
||||
const { resourcesType = "image" } = options;
|
||||
const pcField = resourcesType === "video" ? "path_vid_pc" : "path_pc";
|
||||
const mobileField = resourcesType === "video" ? "path_vid_mo" : "path_mo";
|
||||
const { resourcesType = 'image' } = options
|
||||
const pcField = resourcesType === 'video' ? 'path_vid_pc' : 'path_pc'
|
||||
const mobileField = resourcesType === 'video' ? 'path_vid_mo' : 'path_mo'
|
||||
|
||||
if (!pathArray?.[mobileField]) {
|
||||
return null;
|
||||
return null
|
||||
}
|
||||
|
||||
const resolvedImages = {
|
||||
pc: getResolvedHost(pathArray[pcField] || pathArray[mobileField]),
|
||||
mobile: getResolvedHost(pathArray[mobileField]),
|
||||
};
|
||||
}
|
||||
|
||||
if (resourcesType === "bg") {
|
||||
if (resourcesType === 'bg') {
|
||||
return {
|
||||
"--pc-bg": `url(${resolvedImages.pc})`,
|
||||
"--mobile-bg": `url(${resolvedImages.mobile})`,
|
||||
};
|
||||
'--pc-bg': `url(${resolvedImages.pc})`,
|
||||
'--mobile-bg': `url(${resolvedImages.mobile})`,
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
mobileSrc: resolvedImages.mobile,
|
||||
pcSrc: resolvedImages.pc,
|
||||
};
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,13 +3,13 @@ export const csrDecodedJWT = (base64EncodeVal: string) => {
|
||||
decodeURIComponent(
|
||||
window
|
||||
.atob(base64EncodeVal)
|
||||
.split("")
|
||||
.split('')
|
||||
.map(function (c) {
|
||||
return "%" + ("00" + c.charCodeAt(0).toString(16)).slice(-2);
|
||||
return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2)
|
||||
})
|
||||
.join("")
|
||||
.join('')
|
||||
)
|
||||
);
|
||||
)
|
||||
|
||||
return decodeVal;
|
||||
};
|
||||
return decodeVal
|
||||
}
|
||||
|
||||
@@ -1,78 +1,78 @@
|
||||
import { csrDecodedJWT } from "#layers/utils/jwtUtil";
|
||||
import { csrDecodedJWT } from '#layers/utils/jwtUtil'
|
||||
|
||||
/**
|
||||
* Stove 로그인
|
||||
*/
|
||||
export const csrGoStoveLogin = () => {
|
||||
const runtimeConfig = useRuntimeConfig();
|
||||
const runtimeConfig = useRuntimeConfig()
|
||||
|
||||
const loginUrl = runtimeConfig.public.stoveLoginUrl;
|
||||
const stoveGameId = runtimeConfig.public.stoveGameId;
|
||||
const stoveGameNo = runtimeConfig.public.stoveGameNo;
|
||||
const redirectUrl = encodeURIComponent(location.href);
|
||||
const loginUrl = runtimeConfig.public.stoveLoginUrl
|
||||
const stoveGameId = runtimeConfig.public.stoveGameId
|
||||
const stoveGameNo = runtimeConfig.public.stoveGameNo
|
||||
const redirectUrl = encodeURIComponent(location.href)
|
||||
|
||||
const url = `${loginUrl}?redirect_url=${redirectUrl}&inflow_path=${stoveGameId}&game_no=${stoveGameNo}`;
|
||||
location.href = url;
|
||||
};
|
||||
const url = `${loginUrl}?redirect_url=${redirectUrl}&inflow_path=${stoveGameId}&game_no=${stoveGameNo}`
|
||||
location.href = url
|
||||
}
|
||||
|
||||
/**
|
||||
* Stove memberNo 조회
|
||||
*/
|
||||
export const csrGetStoveMemberNo = () => {
|
||||
let memberNo = 0;
|
||||
let memberNo = 0
|
||||
try {
|
||||
const suat = useCookie("SUAT");
|
||||
const suat = useCookie('SUAT')
|
||||
|
||||
if (suat.value !== undefined && suat.value !== "") {
|
||||
const base64Payload = suat.value?.split(".")[1] ?? "";
|
||||
const decodeVal = csrDecodedJWT(base64Payload);
|
||||
memberNo = Number(`${decodeVal.member_no}`) ?? 0;
|
||||
if (suat.value && suat.value !== '') {
|
||||
const base64Payload = suat.value?.split('.')[1] ?? ''
|
||||
const decodeVal = csrDecodedJWT(base64Payload)
|
||||
memberNo = Number(`${decodeVal.member_no}`) || 0
|
||||
} else {
|
||||
memberNo = 0;
|
||||
memberNo = 0
|
||||
}
|
||||
} catch (e) {
|
||||
console.error("[Exception] stoveUtil.csrGetStoveMemberNo: ", e);
|
||||
return 0;
|
||||
console.error('[Exception] stoveUtil.csrGetStoveMemberNo: ', e)
|
||||
return 0
|
||||
}
|
||||
return memberNo;
|
||||
};
|
||||
return memberNo
|
||||
}
|
||||
|
||||
/**
|
||||
* AccessToken 조회
|
||||
*/
|
||||
export const csrGetAccessToken = () => {
|
||||
let accessToken = "";
|
||||
let accessToken = ''
|
||||
try {
|
||||
const suat = useCookie("SUAT");
|
||||
const suat = useCookie('SUAT')
|
||||
|
||||
if (suat.value !== undefined && suat.value !== "") {
|
||||
accessToken = `${suat.value || ""}`;
|
||||
if (suat.value && suat.value !== '') {
|
||||
accessToken = `${suat.value || ''}`
|
||||
} else {
|
||||
accessToken = "";
|
||||
accessToken = ''
|
||||
}
|
||||
} catch (e) {
|
||||
console.error("[Exception] stoveUtil.csrGetAccessToken: ", e);
|
||||
return "";
|
||||
console.error('[Exception] stoveUtil.csrGetAccessToken: ', e)
|
||||
return ''
|
||||
}
|
||||
return accessToken;
|
||||
};
|
||||
return accessToken
|
||||
}
|
||||
|
||||
/**
|
||||
* 국가 코드 조회
|
||||
*/
|
||||
export const csrGetCountry = () => {
|
||||
let countryCode = "";
|
||||
let countryCode = ''
|
||||
try {
|
||||
const nnto = useCookie("NNTO");
|
||||
const nnto = useCookie('NNTO')
|
||||
|
||||
if (nnto.value !== undefined && nnto.value !== "") {
|
||||
countryCode = `${nnto.value || ""}`;
|
||||
if (nnto.value !== undefined && nnto.value !== '') {
|
||||
countryCode = `${nnto.value || ''}`
|
||||
} else {
|
||||
countryCode = "";
|
||||
countryCode = ''
|
||||
}
|
||||
} catch (e) {
|
||||
console.error("[Exception] stoveUtil.csrGetCountry: ", e);
|
||||
return "";
|
||||
console.error('[Exception] stoveUtil.csrGetCountry: ', e)
|
||||
return ''
|
||||
}
|
||||
return countryCode;
|
||||
};
|
||||
return countryCode
|
||||
}
|
||||
|
||||
@@ -1,22 +1,22 @@
|
||||
import { defineNuxtConfig } from "nuxt/config";
|
||||
import { resolve } from "node:path";
|
||||
import { getI18n } from "./i18n.config";
|
||||
import { defineNuxtConfig } from 'nuxt/config'
|
||||
import { resolve } from 'node:path'
|
||||
import { getI18n } from './i18n.config'
|
||||
|
||||
export default defineNuxtConfig({
|
||||
app: {
|
||||
head: {
|
||||
viewport: "width=device-width, initial-scale=1, maximum-scale=5",
|
||||
viewport: 'width=device-width, initial-scale=1, maximum-scale=5',
|
||||
script: [
|
||||
{
|
||||
type: "text/javascript",
|
||||
type: 'text/javascript',
|
||||
src: process.env.STOVE_GNB,
|
||||
},
|
||||
{
|
||||
type: "text/javascript",
|
||||
type: 'text/javascript',
|
||||
src: process.env.STOVE_81PLUG,
|
||||
},
|
||||
{
|
||||
type: "text/javascript",
|
||||
type: 'text/javascript',
|
||||
src: process.env.STOVE_LAUNCHER_SCRIPT,
|
||||
async: true,
|
||||
defer: true,
|
||||
@@ -25,46 +25,44 @@ export default defineNuxtConfig({
|
||||
},
|
||||
},
|
||||
modules: [
|
||||
"@vueuse/nuxt",
|
||||
"@nuxtjs/i18n",
|
||||
"@pinia/nuxt",
|
||||
"@nuxtjs/tailwindcss",
|
||||
'@vueuse/nuxt',
|
||||
'@nuxtjs/i18n',
|
||||
'@pinia/nuxt',
|
||||
'@nuxtjs/tailwindcss',
|
||||
],
|
||||
imports: {
|
||||
dirs: [
|
||||
"layers/types",
|
||||
"layers/components",
|
||||
"layers/composables",
|
||||
"layers/layouts",
|
||||
"layers/middleware",
|
||||
"layers/plugins",
|
||||
"layers/registry",
|
||||
"layers/server",
|
||||
"layers/stores",
|
||||
"layers/utils",
|
||||
'layers/types',
|
||||
'layers/components',
|
||||
'layers/composables',
|
||||
'layers/layouts',
|
||||
'layers/middleware',
|
||||
'layers/plugins',
|
||||
'layers/registry',
|
||||
'layers/server',
|
||||
'layers/stores',
|
||||
'layers/utils',
|
||||
],
|
||||
global: true,
|
||||
},
|
||||
components: {
|
||||
dirs: ["~/components", "layers/components"],
|
||||
dirs: ['~/components', 'layers/components'],
|
||||
global: true,
|
||||
},
|
||||
alias: {
|
||||
"@": resolve(__dirname, "."),
|
||||
"#layers": resolve(__dirname, "layers"),
|
||||
'@': resolve(__dirname, '.'),
|
||||
'#layers': resolve(__dirname, 'layers'),
|
||||
},
|
||||
extends: [resolve(__dirname, "layers")],
|
||||
extends: ['./layers'],
|
||||
|
||||
// i18n 설정 - 런타임에 동적으로 설정됨
|
||||
i18n: getI18n(),
|
||||
|
||||
experimental: {
|
||||
payloadExtraction: false,
|
||||
},
|
||||
typescript: {
|
||||
// [test] 타입 체크 비활성화
|
||||
typeCheck: false,
|
||||
strict: true,
|
||||
typeCheck: true,
|
||||
strict: false,
|
||||
},
|
||||
nitro: {
|
||||
prerender: { routes: [] },
|
||||
@@ -104,6 +102,6 @@ export default defineNuxtConfig({
|
||||
// 개발 환경에서는 모든 호스트 허용
|
||||
allowedHosts: true,
|
||||
},
|
||||
base: "/",
|
||||
base: '/',
|
||||
},
|
||||
});
|
||||
})
|
||||
|
||||
21
package.json
21
package.json
@@ -11,7 +11,12 @@
|
||||
"build:sandbox": "nuxt build --dotenv .env.sandbox",
|
||||
"build:live": "nuxt build --dotenv .env.live",
|
||||
"preview": "nuxt preview",
|
||||
"typecheck": "nuxt typecheck"
|
||||
"typecheck": "vue-tsc --noEmit",
|
||||
"lint": "eslint . --ext .vue,.js,.ts,.jsx,.tsx",
|
||||
"lint:fix": "eslint . --ext .vue,.js,.ts,.jsx,.tsx --fix",
|
||||
"format": "prettier --write .",
|
||||
"format:check": "prettier --check .",
|
||||
"check": "pnpm typecheck && pnpm lint && pnpm format:check"
|
||||
},
|
||||
"dependencies": {
|
||||
"@nuxtjs/i18n": "^10.0.6",
|
||||
@@ -24,12 +29,24 @@
|
||||
"vue": "^3.5.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@eslint/eslintrc": "^3.3.1",
|
||||
"@eslint/js": "^9.35.0",
|
||||
"@nuxt/eslint-config": "^1.9.0",
|
||||
"@nuxtjs/tailwindcss": "^6.14.0",
|
||||
"@types/node": "^24.3.0",
|
||||
"@typescript-eslint/eslint-plugin": "^8.43.0",
|
||||
"@typescript-eslint/parser": "^8.43.0",
|
||||
"autoprefixer": "^10.4.21",
|
||||
"eslint": "^9.35.0",
|
||||
"eslint-config-prettier": "^10.1.8",
|
||||
"eslint-plugin-nuxt": "^4.0.0",
|
||||
"eslint-plugin-prettier": "^5.5.4",
|
||||
"eslint-plugin-vue": "^10.4.0",
|
||||
"postcss": "^8.5.6",
|
||||
"prettier": "^3.6.2",
|
||||
"tailwindcss": "^3.4.17",
|
||||
"typescript": "^5.5.0"
|
||||
"typescript": "^5.5.0",
|
||||
"vue-tsc": "^3.0.7"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18.20.0"
|
||||
|
||||
7117
pnpm-lock.yaml
generated
7117
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
@@ -1,25 +1,25 @@
|
||||
import type { Config } from "tailwindcss";
|
||||
import type { Config } from 'tailwindcss'
|
||||
|
||||
export default {
|
||||
content: ["./app/**/*.{js,vue,ts}", "./layers/**/*.{js,vue,ts}"],
|
||||
content: ['./app/**/*.{js,vue,ts}', './layers/**/*.{js,vue,ts}'],
|
||||
theme: {
|
||||
extend: {
|
||||
screens: {
|
||||
xs: "360px", // Mobile: 360px ~ 767px
|
||||
sm: "768px", // Tablet: 768px ~ 1023px
|
||||
md: "1024px", // PC: 1024px ~ 1439px
|
||||
lg: "1440px", // Large PC: 1440px+
|
||||
xs: '360px', // Mobile: 360px ~ 767px
|
||||
sm: '768px', // Tablet: 768px ~ 1023px
|
||||
md: '1024px', // PC: 1024px ~ 1439px
|
||||
lg: '1440px', // Large PC: 1440px+
|
||||
},
|
||||
spacing: {},
|
||||
colors: {
|
||||
"theme-foreground": "var(--foreground)",
|
||||
"theme-foreground-10": "var(--foreground-10)",
|
||||
'theme-foreground': 'var(--foreground)',
|
||||
'theme-foreground-10': 'var(--foreground-10)',
|
||||
|
||||
"theme-foreground-reversal": "var(--foreground-reversal)",
|
||||
"theme-foreground-reversal-10": "var(--foreground-reversal-10)",
|
||||
"theme-foreground-reversal-30": "var(--foreground-reversal-30)",
|
||||
"theme-foreground-reversal-40": "var(--foreground-reversal-40)",
|
||||
"theme-foreground-reversal-70": "var(--foreground-reversal-70)",
|
||||
'theme-foreground-reversal': 'var(--foreground-reversal)',
|
||||
'theme-foreground-reversal-10': 'var(--foreground-reversal-10)',
|
||||
'theme-foreground-reversal-30': 'var(--foreground-reversal-30)',
|
||||
'theme-foreground-reversal-40': 'var(--foreground-reversal-40)',
|
||||
'theme-foreground-reversal-70': 'var(--foreground-reversal-70)',
|
||||
|
||||
// "theme-primary": "var(--light-primary)",
|
||||
// "theme-secondary": "var(--light-secondary)",
|
||||
@@ -30,4 +30,4 @@ export default {
|
||||
},
|
||||
},
|
||||
},
|
||||
} satisfies Config;
|
||||
} satisfies Config
|
||||
|
||||
@@ -1,12 +1,19 @@
|
||||
{
|
||||
"extends": "./.nuxt/tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"baseUrl": ".",
|
||||
"types": ["nuxt", "node", "@nuxtjs/i18n"],
|
||||
"moduleResolution": "bundler",
|
||||
"paths": {
|
||||
"@/*": ["."],
|
||||
"#layers/*": ["layers/*"]
|
||||
}
|
||||
}
|
||||
"strict": false,
|
||||
"noImplicitAny": false,
|
||||
"strictNullChecks": false,
|
||||
"skipLibCheck": true,
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"esModuleInterop": true
|
||||
},
|
||||
"include": [
|
||||
".nuxt/nuxt.d.ts",
|
||||
".nuxt/auto-imports.d.ts",
|
||||
"types/**/*",
|
||||
"layers/**/*",
|
||||
"app/**/*"
|
||||
],
|
||||
"exclude": [".nuxt/types/**/*", "node_modules"]
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user