Merge branch 'feature/202509XX-cl' into feature/20250910-all
This commit is contained in:
@@ -27,11 +27,10 @@ export default defineEventHandler(async (event) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log("gameAlias extraction error: ", error);
|
console.error("gameAlias extraction error: ", error);
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
||||||
const queryParams: Record<string, string> = {
|
const queryParams: Record<string, string> = {
|
||||||
game_alias: gameAlias,
|
game_alias: gameAlias,
|
||||||
};
|
};
|
||||||
@@ -44,9 +43,15 @@ export default defineEventHandler(async (event) => {
|
|||||||
event.context.gameData = response.value;
|
event.context.gameData = response.value;
|
||||||
|
|
||||||
// lang_codes를 사용해서 동적으로 i18n 설정 업데이트
|
// lang_codes를 사용해서 동적으로 i18n 설정 업데이트
|
||||||
if (response.value.lang_codes && Array.isArray(response.value.lang_codes)) {
|
if (
|
||||||
|
response.value.lang_codes &&
|
||||||
|
Array.isArray(response.value.lang_codes)
|
||||||
|
) {
|
||||||
event.context.availableLocales = response.value.lang_codes;
|
event.context.availableLocales = response.value.lang_codes;
|
||||||
event.context.defaultLocale = response.value.default_lang_code || response.value.lang_codes[0] || 'ko';
|
event.context.defaultLocale =
|
||||||
|
response.value.default_lang_code ||
|
||||||
|
response.value.lang_codes[0] ||
|
||||||
|
"ko";
|
||||||
}
|
}
|
||||||
|
|
||||||
return response.value as GameDataValue;
|
return response.value as GameDataValue;
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
@import "#layers/assets/css/theme.css";
|
@import "#layers/assets/css/app.css";
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { storeToRefs } from "pinia";
|
import { storeToRefs } from "pinia";
|
||||||
import { usePageDataStore } from "#layers/stores/usePageDataStore";
|
import { usePageDataStore } from "#layers/stores/usePageDataStore";
|
||||||
import Section from "#layers/components/molecules/Section.vue";
|
import Template from "#layers/components/molecules/Template.vue";
|
||||||
|
|
||||||
const pageDataStore = usePageDataStore();
|
const pageDataStore = usePageDataStore();
|
||||||
const { pageData } = storeToRefs(pageDataStore);
|
const { pageData } = storeToRefs(pageDataStore);
|
||||||
@@ -34,7 +34,7 @@ watchEffect(() => {
|
|||||||
<template>
|
<template>
|
||||||
<NuxtLayout :name="layout">
|
<NuxtLayout :name="layout">
|
||||||
<ClientOnly>
|
<ClientOnly>
|
||||||
<Section :templates="pageData?.templates ?? []" />
|
<Template :templates="pageData?.templates ?? []" />
|
||||||
</ClientOnly>
|
</ClientOnly>
|
||||||
</NuxtLayout>
|
</NuxtLayout>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { storeToRefs } from "pinia";
|
import { storeToRefs } from "pinia";
|
||||||
import { usePageDataStore } from "#layers/stores/usePageDataStore";
|
import { usePageDataStore } from "#layers/stores/usePageDataStore";
|
||||||
import Section from "#layers/components/molecules/Section.vue";
|
import Template from "#layers/components/molecules/Template.vue";
|
||||||
|
|
||||||
const pageDataStore = usePageDataStore();
|
const pageDataStore = usePageDataStore();
|
||||||
const { pageData } = storeToRefs(pageDataStore);
|
const { pageData } = storeToRefs(pageDataStore);
|
||||||
@@ -34,7 +34,7 @@ watchEffect(() => {
|
|||||||
<template>
|
<template>
|
||||||
<NuxtLayout :name="layout">
|
<NuxtLayout :name="layout">
|
||||||
<ClientOnly>
|
<ClientOnly>
|
||||||
<Section :templates="pageData?.templates ?? []" />
|
<Template :templates="pageData?.templates ?? []" />
|
||||||
</ClientOnly>
|
</ClientOnly>
|
||||||
</NuxtLayout>
|
</NuxtLayout>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { storeToRefs } from "pinia";
|
import { storeToRefs } from "pinia";
|
||||||
import { usePageDataStore } from "#layers/stores/usePageDataStore";
|
import { usePageDataStore } from "#layers/stores/usePageDataStore";
|
||||||
import Section from "#layers/components/molecules/Section.vue";
|
import Template from "#layers/components/molecules/Template.vue";
|
||||||
|
|
||||||
const pageDataStore = usePageDataStore();
|
const pageDataStore = usePageDataStore();
|
||||||
const { pageData } = storeToRefs(pageDataStore);
|
const { pageData } = storeToRefs(pageDataStore);
|
||||||
@@ -9,6 +9,11 @@ const { pageData } = storeToRefs(pageDataStore);
|
|||||||
// const layout = pageData.value?.meta?.layout ?? "default";
|
// const layout = pageData.value?.meta?.layout ?? "default";
|
||||||
const layout = "default"; // 기본 레이아웃 사용
|
const layout = "default"; // 기본 레이아웃 사용
|
||||||
|
|
||||||
|
// definePageMeta를 사용하여 레이아웃을 미리 설정
|
||||||
|
definePageMeta({
|
||||||
|
layout: false, // 기본 레이아웃 비활성화
|
||||||
|
});
|
||||||
|
|
||||||
// definePageMeta를 사용하여 레이아웃을 미리 설정
|
// definePageMeta를 사용하여 레이아웃을 미리 설정
|
||||||
watchEffect(() => {
|
watchEffect(() => {
|
||||||
if (pageData.value?.meta_tag) {
|
if (pageData.value?.meta_tag) {
|
||||||
@@ -29,7 +34,7 @@ watchEffect(() => {
|
|||||||
<template>
|
<template>
|
||||||
<NuxtLayout :name="layout">
|
<NuxtLayout :name="layout">
|
||||||
<ClientOnly>
|
<ClientOnly>
|
||||||
<Section :templates="pageData?.templates ?? []" />
|
<Template :templates="pageData?.templates ?? []" />
|
||||||
</ClientOnly>
|
</ClientOnly>
|
||||||
</NuxtLayout>
|
</NuxtLayout>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { storeToRefs } from "pinia";
|
import { storeToRefs } from "pinia";
|
||||||
import { usePageDataStore } from "#layers/stores/usePageDataStore";
|
import { usePageDataStore } from "#layers/stores/usePageDataStore";
|
||||||
import Section from "#layers/components/molecules/Section.vue";
|
import Template from "#layers/components/molecules/Template.vue";
|
||||||
|
|
||||||
const pageDataStore = usePageDataStore();
|
const pageDataStore = usePageDataStore();
|
||||||
const { pageData } = storeToRefs(pageDataStore);
|
const { pageData } = storeToRefs(pageDataStore);
|
||||||
@@ -43,7 +43,7 @@ watchEffect(() => {
|
|||||||
<template>
|
<template>
|
||||||
<NuxtLayout :name="layout">
|
<NuxtLayout :name="layout">
|
||||||
<ClientOnly>
|
<ClientOnly>
|
||||||
<Section :templates="pageData?.templates ?? []" />
|
<Template :templates="pageData?.templates ?? []" />
|
||||||
</ClientOnly>
|
</ClientOnly>
|
||||||
</NuxtLayout>
|
</NuxtLayout>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -1,3 +1,6 @@
|
|||||||
|
@import "./base/_theme.css";
|
||||||
|
@import "./base/_reset.css";
|
||||||
|
|
||||||
@tailwind base;
|
@tailwind base;
|
||||||
@tailwind components;
|
@tailwind components;
|
||||||
@tailwind utilities;
|
@tailwind utilities;
|
||||||
|
|||||||
6
layers/assets/css/base/_reset.css
Normal file
6
layers/assets/css/base/_reset.css
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
/* CSS 리셋 및 기본 스타일 */
|
||||||
|
@layer base {
|
||||||
|
body {
|
||||||
|
background-color: #000;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
/* 라이트 테마 기본 색상 */
|
/* CSS 변수 정의 - @layer 밖에 위치 */
|
||||||
:root {
|
:root {
|
||||||
--foreground: #ffffff;
|
--foreground: #ffffff;
|
||||||
--foreground-10: #ffffff;
|
--foreground-10: #ffffff;
|
||||||
@@ -39,7 +39,8 @@
|
|||||||
--border: #475569;
|
--border: #475569;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Gradient 텍스트 스타일 */
|
/* 커스텀 컴포넌트 스타일 */
|
||||||
|
@layer components {
|
||||||
.text-gradient-pink {
|
.text-gradient-pink {
|
||||||
background: linear-gradient(270deg, #e872ff 0%, #ff357e 100%);
|
background: linear-gradient(270deg, #e872ff 0%, #ff357e 100%);
|
||||||
-webkit-background-clip: text;
|
-webkit-background-clip: text;
|
||||||
@@ -47,3 +48,4 @@
|
|||||||
background-clip: text;
|
background-clip: text;
|
||||||
color: transparent;
|
color: transparent;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
@@ -12,14 +12,19 @@ const gnbList = gameData?.gnb?.menus as GameDataGnb["menus"];
|
|||||||
class="bg-theme-foreground text-theme-foreground-reversal relative z-50"
|
class="bg-theme-foreground text-theme-foreground-reversal relative z-50"
|
||||||
>
|
>
|
||||||
<LayoutStoveGnb />
|
<LayoutStoveGnb />
|
||||||
<div data-name="header-game" class="px-[40px] h-16 flex items-center">
|
<div
|
||||||
|
data-name="header-game"
|
||||||
|
class="px-[40px] h-16 flex items-center whitespace-nowrap"
|
||||||
|
>
|
||||||
<!-- 로고 -->
|
<!-- 로고 -->
|
||||||
<div data-name="header-logo" class="mr-[40px]">
|
<div data-name="header-logo" class="mr-[40px]">
|
||||||
|
<AtomsLocaleLink to="/brand">
|
||||||
<img
|
<img
|
||||||
:src="gameData?.gnb?.bi_path"
|
:src="gameData?.gnb?.bi_path"
|
||||||
:alt="gameData?.game_name"
|
:alt="gameData?.game_name"
|
||||||
class="h-[30px]"
|
class="h-[30px]"
|
||||||
/>
|
/>
|
||||||
|
</AtomsLocaleLink>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 메인 네비게이션 -->
|
<!-- 메인 네비게이션 -->
|
||||||
@@ -44,7 +49,7 @@ const gnbList = gameData?.gnb?.menus as GameDataGnb["menus"];
|
|||||||
</MoleculesLink>
|
</MoleculesLink>
|
||||||
<div
|
<div
|
||||||
v-if="gnbItem.children"
|
v-if="gnbItem.children"
|
||||||
class="absolute top-full left-[-28px] min-w-[190px] pt-[4px]"
|
class="absolute top-full left-[-28px] min-w-[190px] pt-[4px] pointer-events-none group-hover:pointer-events-auto"
|
||||||
>
|
>
|
||||||
<ul
|
<ul
|
||||||
class="bg-theme-foreground-10 rounded-[20px] shadow-lg opacity-0 invisible group-hover:opacity-100 group-hover:visible transition-all duration-200 z-50 p-3"
|
class="bg-theme-foreground-10 rounded-[20px] shadow-lg opacity-0 invisible group-hover:opacity-100 group-hover:visible transition-all duration-200 z-50 p-3"
|
||||||
@@ -80,56 +85,9 @@ const gnbList = gameData?.gnb?.menus as GameDataGnb["menus"];
|
|||||||
</nav>
|
</nav>
|
||||||
|
|
||||||
<!-- 오른쪽 영역 -->
|
<!-- 오른쪽 영역 -->
|
||||||
<div data-name="header-right" class="relative group ml-auto">
|
<div data-name="header-right" class="ml-auto">
|
||||||
<button
|
<div class="relative group">
|
||||||
class="bg-amber-600 hover:bg-amber-700 text-white px-6 py-3 rounded-lg font-medium transition-colors"
|
<AtomsButton size="small">게임 시작</AtomsButton>
|
||||||
>
|
|
||||||
게임 시작
|
|
||||||
</button>
|
|
||||||
|
|
||||||
<!-- 2단계 드롭다운 메뉴 -->
|
|
||||||
<div
|
|
||||||
class="absolute top-full right-0 mt-2 w-64 bg-gray-800 rounded-lg shadow-lg opacity-0 invisible group-hover:opacity-100 group-hover:visible transition-all duration-200 z-50 p-3"
|
|
||||||
>
|
|
||||||
<div class="px-4 py-2">
|
|
||||||
<a
|
|
||||||
href="#"
|
|
||||||
class="flex items-center space-x-3 hover:bg-gray-700 transition-colors"
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
class="w-8 h-8 bg-orange-500 rounded flex items-center justify-center"
|
|
||||||
>
|
|
||||||
<span class="text-white font-bold text-sm">S</span>
|
|
||||||
</div>
|
|
||||||
<span>PC 버전 다운로드</span>
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
<div class="px-4 py-2">
|
|
||||||
<a
|
|
||||||
href="#"
|
|
||||||
class="flex items-center space-x-3 hover:bg-gray-700 transition-colors"
|
|
||||||
>
|
|
||||||
<svg class="w-8 h-8" viewBox="0 0 24 24" fill="currentColor">
|
|
||||||
<path
|
|
||||||
d="M3,20.5V3.5C3,2.91 3.34,2.39 3.84,2.15L13.69,12L3.84,21.85C3.34,21.6 3,21.09 3,20.5M16.81,15.12L6.05,21.34L14.54,12.85L16.81,15.12M20.16,10.81C20.5,11.08 20.75,11.5 20.75,12C20.75,12.5 20.53,12.9 20.18,13.18L17.89,14.5L15.39,12L17.89,9.5L20.16,10.81M6.05,2.66L16.81,8.88L14.54,11.15L6.05,2.66Z"
|
|
||||||
/>
|
|
||||||
</svg>
|
|
||||||
<span>Google Store</span>
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
<div class="px-4 py-2">
|
|
||||||
<a
|
|
||||||
href="#"
|
|
||||||
class="flex items-center space-x-3 hover:bg-gray-700 transition-colors"
|
|
||||||
>
|
|
||||||
<svg class="w-8 h-8" viewBox="0 0 24 24" fill="currentColor">
|
|
||||||
<path
|
|
||||||
d="M18.71,19.5C17.88,20.74 17,21.95 15.66,21.97C14.32,22 13.89,21.18 12.37,21.18C10.84,21.18 10.37,21.95 9.1,22C7.79,22.05 6.8,20.68 5.96,19.47C4.25,17 2.94,12.45 4.7,9.39C5.57,7.87 7.13,6.91 8.82,6.88C10.1,6.86 11.32,7.75 12.11,7.75C12.89,7.75 14.37,6.68 15.92,6.84C16.57,6.87 18.39,7.1 19.56,8.82C19.47,8.88 17.39,10.1 17.41,12.63C17.44,15.65 20.06,16.66 20.09,16.67C20.06,16.74 19.67,18.11 18.71,19.5M13,3.5C13.73,2.67 14.94,2.04 15.94,2C16.07,3.17 15.6,4.35 14.9,5.19C14.21,6.04 13.07,6.7 11.95,6.61C11.8,5.46 12.36,4.26 13,3.5Z"
|
|
||||||
/>
|
|
||||||
</svg>
|
|
||||||
<span>App Store</span>
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -15,15 +15,10 @@ const isShowTemplate = (template: PageDataTemplate) => {
|
|||||||
v-for="(template, index) in props.templates"
|
v-for="(template, index) in props.templates"
|
||||||
:key="template.template_code ?? index"
|
:key="template.template_code ?? index"
|
||||||
>
|
>
|
||||||
<section v-if="isShowTemplate(template)" class="relative">
|
|
||||||
<TemplatesBackground
|
|
||||||
v-if="template.components?.background"
|
|
||||||
:component-data="template.components?.background"
|
|
||||||
/>
|
|
||||||
<component
|
<component
|
||||||
|
v-if="isShowTemplate(template)"
|
||||||
:is="registry[template.template_code]?.component"
|
:is="registry[template.template_code]?.component"
|
||||||
:components="template.components"
|
:components="template.components"
|
||||||
/>
|
/>
|
||||||
</section>
|
|
||||||
</template>
|
</template>
|
||||||
</template>
|
</template>
|
||||||
@@ -1,21 +1,31 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { getResponsiveSrc, getResponsiveClass } from "#layers/utils/dataUtil";
|
import {
|
||||||
|
getResourcesData,
|
||||||
|
getResponsiveSrc,
|
||||||
|
getResponsiveClass,
|
||||||
|
} from "#layers/utils/dataUtil";
|
||||||
import type { PageDataComponent } from "#layers/types/api/pageData";
|
import type { PageDataComponent } from "#layers/types/api/pageData";
|
||||||
|
|
||||||
const props = defineProps<{ componentData: PageDataComponent }>();
|
const props = defineProps<{ componentData: PageDataComponent }>();
|
||||||
|
|
||||||
const assetType = computed(() => {
|
const resourcesData = computed(() => {
|
||||||
return props.componentData?.component_type;
|
return getResourcesData({
|
||||||
|
resources: props.componentData?.resources,
|
||||||
});
|
});
|
||||||
const resources = computed(() => {
|
|
||||||
return props.componentData?.resources;
|
|
||||||
});
|
});
|
||||||
|
const bgStyles = computed(() => {
|
||||||
const imageSrc = getResponsiveSrc({
|
const result = getResponsiveSrc({
|
||||||
resources: resources.value,
|
pathArray: resourcesData.value?.res_path,
|
||||||
type: "bg",
|
type: "bg",
|
||||||
|
});
|
||||||
test: "test2",
|
return result && typeof result === "object" && "--pc-bg" in result
|
||||||
|
? result
|
||||||
|
: {};
|
||||||
|
});
|
||||||
|
const hasImage = computed(() => {
|
||||||
|
return (
|
||||||
|
resourcesData.value?.group_type === "image" && resourcesData.value?.res_path
|
||||||
|
);
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@@ -23,10 +33,10 @@ const imageSrc = getResponsiveSrc({
|
|||||||
<div class="absolute inset-0 w-full h-full">
|
<div class="absolute inset-0 w-full h-full">
|
||||||
<!-- 이미지 타입-->
|
<!-- 이미지 타입-->
|
||||||
<div
|
<div
|
||||||
v-if="assetType === 'IMG' && imageSrc"
|
v-if="hasImage"
|
||||||
class="w-full h-full bg-cover bg-center bg-no-repeat"
|
class="w-full h-full bg-cover bg-center bg-no-repeat"
|
||||||
:class="getResponsiveClass()"
|
:class="getResponsiveClass()"
|
||||||
:style="imageSrc"
|
:style="bgStyles"
|
||||||
></div>
|
></div>
|
||||||
|
|
||||||
<!-- 비디오 타입 -->
|
<!-- 비디오 타입 -->
|
||||||
|
|||||||
@@ -1,35 +1,42 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { getResponsiveSrc, getDisplayText } from "#layers/utils/dataUtil";
|
import { getResourcesData, getResponsiveSrc } from "#layers/utils/dataUtil";
|
||||||
import type { PageDataComponent } from "#layers/types/api/pageData";
|
import type { PageDataComponent } from "#layers/types/api/pageData";
|
||||||
|
|
||||||
const props = defineProps<{ componentData: PageDataComponent }>();
|
const props = defineProps<{ componentData: PageDataComponent }>();
|
||||||
|
|
||||||
const resources = computed(() => {
|
const resourcesData = computed(() => {
|
||||||
return props.componentData?.resources;
|
return getResourcesData({
|
||||||
|
resources: props.componentData?.resources,
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
const displayText = getDisplayText({
|
const displayText = resourcesData.value?.display?.text;
|
||||||
resources: resources.value,
|
|
||||||
});
|
|
||||||
const imageSrc = getResponsiveSrc({
|
const imageSrc = getResponsiveSrc({
|
||||||
resources: resources.value,
|
pathArray: resourcesData.value?.res_path,
|
||||||
type: "img",
|
type: "image",
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<div v-if="resourcesData">
|
||||||
<img
|
<img
|
||||||
:src="imageSrc?.mobileSrc"
|
v-if="imageSrc && 'mobileSrc' in imageSrc"
|
||||||
|
:src="imageSrc.mobileSrc"
|
||||||
:alt="displayText"
|
:alt="displayText"
|
||||||
class="w-full sm:hidden"
|
class="w-full sm:hidden"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<!-- PC 이미지 (sm 이상) -->
|
<!-- PC 이미지 (sm 이상) -->
|
||||||
<img
|
<img
|
||||||
:src="imageSrc?.pcSrc"
|
v-if="imageSrc && 'pcSrc' in imageSrc"
|
||||||
|
:src="imageSrc.pcSrc"
|
||||||
:alt="displayText"
|
:alt="displayText"
|
||||||
class="w-full hidden sm:block"
|
class="w-full hidden sm:block"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
<p
|
||||||
|
v-else
|
||||||
|
v-html="displayText?.replace(/\n/g, '<br/>') || ''"
|
||||||
|
class="text-center"
|
||||||
|
></p>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -1,35 +1,45 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { getResponsiveSrc, getDisplayText } from "#layers/utils/dataUtil";
|
import { getResourcesData, getResponsiveSrc } from "#layers/utils/dataUtil";
|
||||||
import type { PageDataComponent } from "#layers/types/api/pageData";
|
import type { PageDataComponent } from "#layers/types/api/pageData";
|
||||||
|
|
||||||
const props = defineProps<{ componentData: PageDataComponent }>();
|
const props = defineProps<{ componentData: PageDataComponent }>();
|
||||||
|
|
||||||
const resources = computed(() => {
|
const resourcesData = computed(() => {
|
||||||
return props.componentData?.resources;
|
return getResourcesData({
|
||||||
|
resources: props.componentData?.resources,
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
const displayText = getDisplayText({
|
const displayText = resourcesData.value?.display?.text;
|
||||||
resources: resources.value,
|
|
||||||
});
|
|
||||||
const imageSrc = getResponsiveSrc({
|
const imageSrc = getResponsiveSrc({
|
||||||
resources: resources.value,
|
pathArray: resourcesData.value?.res_path,
|
||||||
type: "img",
|
type: "image",
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<h2>
|
<h2>
|
||||||
|
<template v-if="resourcesData">
|
||||||
<img
|
<img
|
||||||
:src="imageSrc?.mobileSrc"
|
v-if="imageSrc && 'mobileSrc' in imageSrc"
|
||||||
|
:src="imageSrc.mobileSrc"
|
||||||
:alt="displayText"
|
:alt="displayText"
|
||||||
class="w-full sm:hidden"
|
class="w-full sm:hidden"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<!-- PC 이미지 (sm 이상) -->
|
<!-- PC 이미지 (sm 이상) -->
|
||||||
<img
|
<img
|
||||||
:src="imageSrc?.pcSrc"
|
v-if="imageSrc && 'pcSrc' in imageSrc"
|
||||||
|
:src="imageSrc.pcSrc"
|
||||||
:alt="displayText"
|
:alt="displayText"
|
||||||
class="w-full hidden sm:block"
|
class="w-full hidden sm:block"
|
||||||
/>
|
/>
|
||||||
|
</template>
|
||||||
|
<span
|
||||||
|
v-else
|
||||||
|
v-html="displayText?.replace(/\n/g, '<br/>')"
|
||||||
|
class="text-center"
|
||||||
|
>
|
||||||
|
</span>
|
||||||
</h2>
|
</h2>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
45
layers/components/templates/SubTitle.vue
Normal file
45
layers/components/templates/SubTitle.vue
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import { getResourcesData, getResponsiveSrc } from "#layers/utils/dataUtil";
|
||||||
|
import type { PageDataComponent } from "#layers/types/api/pageData";
|
||||||
|
|
||||||
|
const props = defineProps<{ componentData: PageDataComponent }>();
|
||||||
|
|
||||||
|
const resourcesData = computed(() => {
|
||||||
|
return getResourcesData({
|
||||||
|
resources: props.componentData?.resources,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
const displayText = resourcesData.value?.display?.text;
|
||||||
|
const imageSrc = getResponsiveSrc({
|
||||||
|
pathArray: resourcesData.value?.res_path,
|
||||||
|
type: "image",
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<h3>
|
||||||
|
<template v-if="resourcesData">
|
||||||
|
<img
|
||||||
|
v-if="imageSrc && 'mobileSrc' in imageSrc"
|
||||||
|
:src="imageSrc.mobileSrc"
|
||||||
|
:alt="displayText"
|
||||||
|
class="w-full sm:hidden"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<!-- PC 이미지 (sm 이상) -->
|
||||||
|
<img
|
||||||
|
v-if="imageSrc && 'pcSrc' in imageSrc"
|
||||||
|
:src="imageSrc.pcSrc"
|
||||||
|
:alt="displayText"
|
||||||
|
class="w-full hidden sm:block"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
<span
|
||||||
|
v-else
|
||||||
|
v-html="displayText?.replace(/\n/g, '<br/>')"
|
||||||
|
class="text-center"
|
||||||
|
>
|
||||||
|
</span>
|
||||||
|
</h3>
|
||||||
|
</template>
|
||||||
@@ -1,26 +1,35 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { getResponsiveSrc, getResponsiveClass } from "#layers/utils/dataUtil";
|
import {
|
||||||
|
getResourcesData,
|
||||||
|
getResponsiveSrc,
|
||||||
|
getResponsiveClass,
|
||||||
|
} from "#layers/utils/dataUtil";
|
||||||
import type { PageDataComponent } from "#layers/types/api/pageData";
|
import type { PageDataComponent } from "#layers/types/api/pageData";
|
||||||
|
|
||||||
const props = defineProps<{ componentData: PageDataComponent }>();
|
const props = defineProps<{ componentData: PageDataComponent }>();
|
||||||
|
|
||||||
const resources = computed(() => {
|
const resourcesData = computed(() => {
|
||||||
return props.componentData?.resources;
|
return getResourcesData({
|
||||||
|
resources: props.componentData?.resources,
|
||||||
});
|
});
|
||||||
|
});
|
||||||
const imageSrc = getResponsiveSrc({
|
const bgStyles = computed(() => {
|
||||||
resources: resources.value,
|
const result = getResponsiveSrc({
|
||||||
|
pathArray: resourcesData.value?.res_path,
|
||||||
type: "bg",
|
type: "bg",
|
||||||
|
});
|
||||||
test: "test",
|
return result && typeof result === "object" && "--pc-bg" in result
|
||||||
|
? result
|
||||||
|
: {};
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<button
|
<button
|
||||||
|
v-if="resourcesData"
|
||||||
class="bg-cover bg-center bg-no-repeat w-[66px] h-[66px] lg:w-[100px] lg:h-[100px]"
|
class="bg-cover bg-center bg-no-repeat w-[66px] h-[66px] lg:w-[100px] lg:h-[100px]"
|
||||||
:class="getResponsiveClass()"
|
:class="getResponsiveClass()"
|
||||||
:style="imageSrc"
|
:style="bgStyles"
|
||||||
>
|
>
|
||||||
<span class="sr-only">videoPlay</span>
|
<span class="sr-only">videoPlay</span>
|
||||||
</button>
|
</button>
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ export const useGetGameAlias = () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log("useGetGameAlias server error: ", error);
|
console.error("useGetGameAlias server error: ", error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -46,7 +46,7 @@ export const useGetGameAlias = () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log("useGetGameAlias client error: ", error);
|
console.error("useGetGameAlias client error: ", error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return "";
|
return "";
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ interface Props {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const props = defineProps<Props>();
|
const props = defineProps<Props>();
|
||||||
console.log("components:", props.components);
|
|
||||||
|
|
||||||
// YouTube 모달 상태 관리
|
// YouTube 모달 상태 관리
|
||||||
const isYouTubeModalOpen = ref(false);
|
const isYouTubeModalOpen = ref(false);
|
||||||
@@ -28,8 +27,13 @@ const handleCloseModal = () => {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
<section class="relative h-[640px] lg:h-[1000px]">
|
||||||
|
<TemplatesBackground
|
||||||
|
v-if="props.components?.background"
|
||||||
|
:component-data="props.components?.background"
|
||||||
|
/>
|
||||||
<div
|
<div
|
||||||
class="relative flex flex-col items-center justify-center h-[640px] lg:h-[1000px] gap-4"
|
class="relative h-full flex flex-col items-center justify-center gap-4"
|
||||||
>
|
>
|
||||||
<TemplatesMainTitle
|
<TemplatesMainTitle
|
||||||
v-if="props.components.mainTitle"
|
v-if="props.components.mainTitle"
|
||||||
@@ -46,6 +50,7 @@ const handleCloseModal = () => {
|
|||||||
@click="handleVideoPlayClick"
|
@click="handleVideoPlayClick"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
<!-- YouTube 모달 -->
|
<!-- YouTube 모달 -->
|
||||||
<YouTubeModal
|
<YouTubeModal
|
||||||
|
|||||||
@@ -7,7 +7,5 @@ const props = defineProps<Props>();
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div
|
<section class="template-section"></section>
|
||||||
class="relative flex flex-col items-center justify-center h-[640px] lg:h-[1000px] gap-4"
|
|
||||||
></div>
|
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -4,10 +4,34 @@ interface Props {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const props = defineProps<Props>();
|
const props = defineProps<Props>();
|
||||||
|
|
||||||
|
console.log("components:", props.components);
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
<section class="relative h-[640px] lg:h-[1000px]">
|
||||||
|
<TemplatesBackground
|
||||||
|
v-if="props.components?.background"
|
||||||
|
:component-data="props.components?.background"
|
||||||
|
/>
|
||||||
<div
|
<div
|
||||||
class="relative flex flex-col items-center justify-center h-[640px] lg:h-[1000px] gap-4"
|
class="relative h-full flex flex-col items-center justify-center gap-4"
|
||||||
></div>
|
>
|
||||||
|
<TemplatesSubTitle
|
||||||
|
v-if="props.components.subTitle"
|
||||||
|
:component-data="props.components.subTitle"
|
||||||
|
class="text-[24px] font-[500] text-[#ffffff] leading-[34px]"
|
||||||
|
/>
|
||||||
|
<TemplatesMainTitle
|
||||||
|
v-if="props.components.mainTitle"
|
||||||
|
:component-data="props.components.mainTitle"
|
||||||
|
class="text-[50px] font-[700] text-[#c7a28b] leading-[70px]"
|
||||||
|
/>
|
||||||
|
<TemplatesDescription
|
||||||
|
v-if="props.components.cardDescription"
|
||||||
|
:component-data="props.components.cardDescription"
|
||||||
|
class="text-[20px] font-[500] text-white/70 leading-[30px]"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
export type ImageType = "img" | "bg";
|
export type ImageType = "image" | "bg";
|
||||||
|
|
||||||
export interface ResponsiveImagePath {
|
export interface ResponsiveImagePath {
|
||||||
path_mo?: string;
|
path_mo?: string;
|
||||||
|
|||||||
@@ -18,48 +18,16 @@ export const getResolvedSrc = (path: string): string => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// [TODO] data 타입 정의
|
// [TODO] data 타입 정의
|
||||||
export const getDisplayText = ({
|
export const getResourcesData = ({
|
||||||
resources,
|
resources,
|
||||||
groupsDepth = 0,
|
groupsDepth = 0,
|
||||||
}: {
|
}: {
|
||||||
resources: any;
|
resources: any;
|
||||||
groupsDepth?: number;
|
groupsDepth?: number;
|
||||||
}): string => {
|
}) => {
|
||||||
const group = resources[0]?.groups?.[groupsDepth];
|
const group = resources[0]?.groups?.[groupsDepth];
|
||||||
return group?.display?.text ?? "";
|
|
||||||
};
|
|
||||||
|
|
||||||
// [TODO] data 타입 정의
|
return group ?? null;
|
||||||
export const getAssetPath = ({
|
|
||||||
resources,
|
|
||||||
groupsDepth = 0,
|
|
||||||
|
|
||||||
test,
|
|
||||||
}: {
|
|
||||||
resources: any;
|
|
||||||
groupsDepth?: number;
|
|
||||||
|
|
||||||
test?: string;
|
|
||||||
}): ResponsiveImagePath | null => {
|
|
||||||
// const group = resources[0]?.groups?.[groupsDepth].resource_data;
|
|
||||||
// const imgPath = group?.resource_data?.img_path;
|
|
||||||
|
|
||||||
const group = resources[groupsDepth];
|
|
||||||
|
|
||||||
if (test) {
|
|
||||||
if (test === "test") {
|
|
||||||
const tests = {
|
|
||||||
path_mo: group?.resource_data?.img_path.comm,
|
|
||||||
};
|
|
||||||
return tests ?? null;
|
|
||||||
}
|
|
||||||
if (test === "test2") {
|
|
||||||
return group?.resource_data?.img_path.comm ?? null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const imgPath = group?.resource_data?.img_path.ko;
|
|
||||||
return imgPath ?? null;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// 반응형 클래스 리턴하는 함수
|
// 반응형 클래스 리턴하는 함수
|
||||||
@@ -69,40 +37,30 @@ export const getResponsiveClass = () => {
|
|||||||
|
|
||||||
// 반응형 이미지 리턴하는 함수
|
// 반응형 이미지 리턴하는 함수
|
||||||
export const getResponsiveSrc = ({
|
export const getResponsiveSrc = ({
|
||||||
resources,
|
pathArray,
|
||||||
type = "img",
|
type = "image",
|
||||||
groupsDepth = 0,
|
|
||||||
|
|
||||||
test,
|
|
||||||
}: {
|
}: {
|
||||||
resources: any;
|
pathArray: any;
|
||||||
type?: ImageType;
|
type?: ImageType;
|
||||||
groupsDepth?: number;
|
|
||||||
|
|
||||||
test?: string;
|
|
||||||
}): ResponsiveImageResult | ResponsiveImagePath => {
|
}): ResponsiveImageResult | ResponsiveImagePath => {
|
||||||
const path = getAssetPath({ resources, groupsDepth, test });
|
if (!pathArray?.path_mo) {
|
||||||
|
|
||||||
if (!path?.path_mo) {
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
const resolvedImages = {
|
const resolvedImages = {
|
||||||
pc: getResolvedSrc(path.path_pc || path.path_mo),
|
pc: getResolvedSrc(pathArray.path_pc || pathArray.path_mo),
|
||||||
mobile: getResolvedSrc(path.path_mo),
|
mobile: getResolvedSrc(pathArray.path_mo),
|
||||||
};
|
};
|
||||||
|
|
||||||
// 타입별 반환 객체 생성
|
if (type === "image") {
|
||||||
const resultMap: Record<ImageType, ResponsiveImageResult> = {
|
return {
|
||||||
img: {
|
|
||||||
mobileSrc: resolvedImages.mobile,
|
mobileSrc: resolvedImages.mobile,
|
||||||
pcSrc: resolvedImages.pc,
|
pcSrc: resolvedImages.pc,
|
||||||
},
|
};
|
||||||
bg: {
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
"--pc-bg": `url(${resolvedImages.pc})`,
|
"--pc-bg": `url(${resolvedImages.pc})`,
|
||||||
"--mobile-bg": `url(${resolvedImages.mobile})`,
|
"--mobile-bg": `url(${resolvedImages.mobile})`,
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
return resultMap[type];
|
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -93,6 +93,12 @@ export default defineNuxtConfig({
|
|||||||
stove81Plug: process.env.STOVE_81PLUG,
|
stove81Plug: process.env.STOVE_81PLUG,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
postcss: {
|
||||||
|
plugins: {
|
||||||
|
tailwindcss: {},
|
||||||
|
autoprefixer: {},
|
||||||
|
},
|
||||||
|
},
|
||||||
vite: {
|
vite: {
|
||||||
server: {
|
server: {
|
||||||
// 개발 환경에서는 모든 호스트 허용
|
// 개발 환경에서는 모든 호스트 허용
|
||||||
|
|||||||
Reference in New Issue
Block a user