feat. GR_GALLERY_03 템플릿 제작
This commit is contained in:
@@ -5,7 +5,13 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.section-content {
|
.section-content {
|
||||||
@apply relative h-full flex flex-col items-center justify-center gap-4 text-center px-[20px] sm:px-[40px] md:gap-5;
|
@apply relative h-full flex flex-col items-center justify-center text-center px-[20px] sm:px-[40px];
|
||||||
|
}
|
||||||
|
|
||||||
|
.border-line {
|
||||||
|
@apply overflow-hidden relative rounded-[4px] md:rounded-lg
|
||||||
|
after:content-[''] after:absolute after:top-0 after:left-0 after:w-full after:h-full
|
||||||
|
after:border after:border-white/10 after:rounded-[4px] after:md:rounded-lg;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Title Utility Classes */
|
/* Title Utility Classes */
|
||||||
|
|||||||
@@ -3,14 +3,18 @@ import type { PageDataResourceGroup } from '#layers/types/api/pageData'
|
|||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
resourcesData?: PageDataResourceGroup
|
resourcesData?: PageDataResourceGroup
|
||||||
|
objectFit?: 'contain' | 'cover'
|
||||||
|
alt?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
const props = defineProps<Props>()
|
const props = withDefaults(defineProps<Props>(), {
|
||||||
|
objectFit: 'contain',
|
||||||
|
})
|
||||||
|
|
||||||
|
const breakpoints = useResponsiveBreakpointsReliable()
|
||||||
|
|
||||||
// 텍스트 데이터 추출
|
|
||||||
// [TODO] txt 대신 text 사용
|
|
||||||
const displayText = computed(() => {
|
const displayText = computed(() => {
|
||||||
return props.resourcesData?.display?.txt || ''
|
return props.resourcesData?.display?.text || 'image'
|
||||||
})
|
})
|
||||||
const imageSrc = computed(() => {
|
const imageSrc = computed(() => {
|
||||||
return getResponsiveSrc(props.resourcesData?.res_path)
|
return getResponsiveSrc(props.resourcesData?.res_path)
|
||||||
@@ -21,12 +25,17 @@ const colorName = computed(() => {
|
|||||||
const colorCode = computed(() => {
|
const colorCode = computed(() => {
|
||||||
return props.resourcesData?.display?.color_code
|
return props.resourcesData?.display?.color_code
|
||||||
})
|
})
|
||||||
|
const currentImageSrc = computed(() => {
|
||||||
|
if (!imageSrc.value) return ''
|
||||||
|
return breakpoints.value.isMobile
|
||||||
|
? imageSrc.value.mobileSrc || ''
|
||||||
|
: imageSrc.value.pcSrc || ''
|
||||||
|
})
|
||||||
|
|
||||||
// HTML 콘텐츠 정리 (줄바꿈 처리)
|
// HTML 콘텐츠 정리 (줄바꿈 처리)
|
||||||
const sanitizedContent = computed(() => {
|
const sanitizedContent = computed(() => {
|
||||||
return displayText.value?.replace(/\n/g, '<br/>') || ''
|
return displayText.value?.replace(/\n/g, '<br/>') || ''
|
||||||
})
|
})
|
||||||
|
|
||||||
// 이미지가 있는지 확인
|
// 이미지가 있는지 확인
|
||||||
const hasImage = computed(() => {
|
const hasImage = computed(() => {
|
||||||
return imageSrc.value && (imageSrc.value.mobileSrc || imageSrc.value.pcSrc)
|
return imageSrc.value && (imageSrc.value.mobileSrc || imageSrc.value.pcSrc)
|
||||||
@@ -34,25 +43,16 @@ const hasImage = computed(() => {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<!-- 이미지가 있는 경우 -->
|
<!-- 이미지 -->
|
||||||
<template v-if="hasImage">
|
|
||||||
<!-- 모바일 이미지 (md 미만) -->
|
|
||||||
<img
|
<img
|
||||||
v-if="imageSrc.mobileSrc"
|
v-if="hasImage && currentImageSrc"
|
||||||
:src="imageSrc.mobileSrc"
|
:src="currentImageSrc"
|
||||||
:alt="displayText"
|
:alt="alt || displayText"
|
||||||
class="md:hidden w-full h-full object-contain"
|
:class="`w-full h-full object-${objectFit}`"
|
||||||
|
loading="lazy"
|
||||||
/>
|
/>
|
||||||
<!-- PC 이미지 (md 이상) -->
|
|
||||||
<img
|
|
||||||
v-if="imageSrc.pcSrc"
|
|
||||||
:src="imageSrc.pcSrc"
|
|
||||||
:alt="displayText"
|
|
||||||
class="hidden md:block w-full h-full object-contain"
|
|
||||||
/>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<!-- 텍스트가 있는 경우 -->
|
<!-- 텍스트 -->
|
||||||
<span
|
<span
|
||||||
v-else-if="displayText"
|
v-else-if="displayText"
|
||||||
v-dompurify-html="sanitizedContent"
|
v-dompurify-html="sanitizedContent"
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import type { SlideItemSize } from '#layers/types/components/slide'
|
|||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
slideItemSize: SlideItemSize
|
slideItemSize: SlideItemSize
|
||||||
type?: 'loop' | 'slide'
|
slideItemLength?: number
|
||||||
autoplay?: boolean | string
|
autoplay?: boolean | string
|
||||||
arrows?: boolean
|
arrows?: boolean
|
||||||
pagination?: boolean
|
pagination?: boolean
|
||||||
@@ -13,22 +13,27 @@ interface Props {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const props = withDefaults(defineProps<Props>(), {
|
const props = withDefaults(defineProps<Props>(), {
|
||||||
type: 'loop',
|
|
||||||
autoplay: false,
|
autoplay: false,
|
||||||
arrows: true,
|
arrows: true,
|
||||||
pagination: true,
|
pagination: true,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const emit = defineEmits(['mounted', 'move', 'moved'])
|
||||||
|
|
||||||
|
const isMultipleItems = computed(() => {
|
||||||
|
return props.slideItemLength > 1
|
||||||
|
})
|
||||||
|
|
||||||
const options = computed((): ResponsiveOptions => {
|
const options = computed((): ResponsiveOptions => {
|
||||||
return {
|
return {
|
||||||
type: props.type,
|
type: isMultipleItems.value ? 'loop' : 'slide',
|
||||||
focus: 'center',
|
focus: 'center',
|
||||||
autoWidth: true,
|
autoWidth: true,
|
||||||
autoHeight: true,
|
autoHeight: true,
|
||||||
speed: 400,
|
speed: 400,
|
||||||
updateOnMove: true,
|
updateOnMove: true,
|
||||||
arrows: props.arrows,
|
arrows: props.arrows && isMultipleItems.value,
|
||||||
pagination: props.pagination,
|
pagination: props.pagination && isMultipleItems.value,
|
||||||
autoplay: props.autoplay,
|
autoplay: props.autoplay,
|
||||||
classes: {
|
classes: {
|
||||||
arrows: 'splide-arrows',
|
arrows: 'splide-arrows',
|
||||||
@@ -71,13 +76,37 @@ const style = computed(() => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
const handleSplideMounted = (splide: SplideType) => {
|
const handleSplideMounted = (splide: SplideType) => {
|
||||||
|
emit('mounted', splide)
|
||||||
splide.refresh()
|
splide.refresh()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const handleMove = (
|
||||||
|
splide: SplideType,
|
||||||
|
newIndex: number,
|
||||||
|
oldIndex: number,
|
||||||
|
destIndex: number
|
||||||
|
) => {
|
||||||
|
emit('move', splide, newIndex, oldIndex, destIndex)
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleMoved = (
|
||||||
|
splide: SplideType,
|
||||||
|
newIndex: number,
|
||||||
|
oldIndex: number,
|
||||||
|
destIndex: number
|
||||||
|
) => {
|
||||||
|
emit('moved', splide, newIndex, oldIndex, destIndex)
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div :class="`center-highlight ${props.class || ''}`" :style="style">
|
<div :class="`center-highlight ${props.class || ''}`" :style="style">
|
||||||
<Splide :options="options" @splide:mounted="handleSplideMounted">
|
<Splide
|
||||||
|
:options="options"
|
||||||
|
@splide:mounted="handleSplideMounted"
|
||||||
|
@splide:move="handleMove"
|
||||||
|
@splide:moved="handleMoved"
|
||||||
|
>
|
||||||
<slot />
|
<slot />
|
||||||
</Splide>
|
</Splide>
|
||||||
</div>
|
</div>
|
||||||
@@ -93,9 +122,18 @@ const handleSplideMounted = (splide: SplideType) => {
|
|||||||
height: var(--banner-height-mo-active);
|
height: var(--banner-height-mo-active);
|
||||||
margin-right: var(--banner-gap-mo);
|
margin-right: var(--banner-gap-mo);
|
||||||
}
|
}
|
||||||
|
.center-highlight:deep(.splide__slide) .slide-inner {
|
||||||
|
width: var(--banner-width-mo);
|
||||||
|
height: var(--banner-height-mo);
|
||||||
|
transition: all 0.4s cubic-bezier(0.4, 0, 0.2, 1);
|
||||||
|
}
|
||||||
.center-highlight:deep(.splide__slide.is-active) {
|
.center-highlight:deep(.splide__slide.is-active) {
|
||||||
width: var(--banner-width-mo-container);
|
width: var(--banner-width-mo-container);
|
||||||
}
|
}
|
||||||
|
.center-highlight:deep(.splide__slide.is-active) .slide-inner {
|
||||||
|
width: var(--banner-width-mo-active);
|
||||||
|
height: var(--banner-height-mo-active);
|
||||||
|
}
|
||||||
|
|
||||||
/* PC 스타일 */
|
/* PC 스타일 */
|
||||||
@media (min-width: 1024px) {
|
@media (min-width: 1024px) {
|
||||||
@@ -104,9 +142,17 @@ const handleSplideMounted = (splide: SplideType) => {
|
|||||||
height: var(--banner-height-pc-active);
|
height: var(--banner-height-pc-active);
|
||||||
margin-right: var(--banner-gap-pc);
|
margin-right: var(--banner-gap-pc);
|
||||||
}
|
}
|
||||||
|
.center-highlight:deep(.splide__slide) .slide-inner {
|
||||||
|
width: var(--banner-width-pc);
|
||||||
|
height: var(--banner-height-pc);
|
||||||
|
}
|
||||||
.center-highlight:deep(.splide__slide.is-active) {
|
.center-highlight:deep(.splide__slide.is-active) {
|
||||||
width: var(--banner-width-pc-container);
|
width: var(--banner-width-pc-container);
|
||||||
}
|
}
|
||||||
|
.center-highlight:deep(.splide__slide.is-active) .slide-inner {
|
||||||
|
width: var(--banner-width-pc-active);
|
||||||
|
height: var(--banner-height-pc-active);
|
||||||
|
}
|
||||||
.center-highlight:deep(.splide-arrow) {
|
.center-highlight:deep(.splide-arrow) {
|
||||||
left: 50%;
|
left: 50%;
|
||||||
transform: translate(-50%, -50%);
|
transform: translate(-50%, -50%);
|
||||||
|
|||||||
@@ -15,63 +15,33 @@ const props = withDefaults(defineProps<BannerListProps>(), {
|
|||||||
arrows: true,
|
arrows: true,
|
||||||
pagination: true,
|
pagination: true,
|
||||||
})
|
})
|
||||||
|
|
||||||
const isMultipleItems = computed(() => {
|
|
||||||
return props.resourcesData.length > 1
|
|
||||||
})
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<BlocksSlideCenterHighlight
|
<BlocksSlideCenterHighlight
|
||||||
:slide-item-size="props.slideItemSize"
|
:slide-item-size="props.slideItemSize"
|
||||||
:type="isMultipleItems ? 'loop' : 'slide'"
|
:slide-item-length="props.resourcesData.length"
|
||||||
:arrows="isMultipleItems ? true : false"
|
|
||||||
:pagination="false"
|
:pagination="false"
|
||||||
class="mt-[36px] md:mt-[60px]"
|
class="mt-[36px] md:mt-[60px]"
|
||||||
>
|
>
|
||||||
<SplideSlide
|
<SplideSlide v-for="(item, index) in props.resourcesData" :key="index">
|
||||||
v-for="(item, index) in props.resourcesData"
|
|
||||||
:key="index"
|
|
||||||
class="splide-slide"
|
|
||||||
>
|
|
||||||
<BlocksCardNews
|
<BlocksCardNews
|
||||||
:title="item.title"
|
:title="item.title"
|
||||||
:description="item.option01"
|
:description="item.option01"
|
||||||
:img-path="getResolvedHost(item.img_path)"
|
:img-path="getResolvedHost(item.img_path)"
|
||||||
:url="item.url"
|
:url="item.url"
|
||||||
:link-target="item.link_target"
|
:link-target="item.link_target"
|
||||||
class="news-center-highlight"
|
class="slide-inner"
|
||||||
/>
|
/>
|
||||||
</SplideSlide>
|
</SplideSlide>
|
||||||
</BlocksSlideCenterHighlight>
|
</BlocksSlideCenterHighlight>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
.center-highlight:deep(.splide__slide.is-active .news-center-highlight) {
|
|
||||||
width: var(--banner-width-mo-active);
|
|
||||||
height: var(--banner-height-mo-active);
|
|
||||||
}
|
|
||||||
.center-highlight:deep(.splide__slide.is-active .card-link) {
|
.center-highlight:deep(.splide__slide.is-active .card-link) {
|
||||||
pointer-events: auto;
|
pointer-events: auto;
|
||||||
}
|
}
|
||||||
.news-center-highlight {
|
|
||||||
width: var(--banner-width-mo);
|
|
||||||
height: var(--banner-height-mo);
|
|
||||||
transition: all 0.4s cubic-bezier(0.4, 0, 0.2, 1);
|
|
||||||
}
|
|
||||||
.center-highlight:deep(.splide__slide .card-link) {
|
.center-highlight:deep(.splide__slide .card-link) {
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* PC 스타일 */
|
|
||||||
@media (min-width: 1024px) {
|
|
||||||
.center-highlight:deep(.splide__slide.is-active .news-center-highlight) {
|
|
||||||
width: var(--banner-width-pc-active);
|
|
||||||
height: var(--banner-height-pc-active);
|
|
||||||
}
|
|
||||||
.news-center-highlight {
|
|
||||||
width: var(--banner-width-pc);
|
|
||||||
height: var(--banner-height-pc);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -1,11 +1,23 @@
|
|||||||
|
const BREAKPOINTS = {
|
||||||
|
xs: 360,
|
||||||
|
sm: 768,
|
||||||
|
md: 1024,
|
||||||
|
lg: 1440,
|
||||||
|
} as const
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 반응형 브레이크포인트 계산 헬퍼
|
* 확실한 반응형 브레이크포인트 헬퍼 (useWindowSize 기반)
|
||||||
*/
|
*/
|
||||||
export const useResponsiveBreakpoints = () => {
|
export const useResponsiveBreakpointsReliable = () => {
|
||||||
return useBreakpoints({
|
const { width } = useWindowSize()
|
||||||
xs: 360, // Mobile: 360px ~ 767px
|
|
||||||
sm: 768, // Tablet: 768px ~ 1023px
|
return computed(() => ({
|
||||||
md: 1024, // PC: 1024px ~ 1439px
|
xs: width.value >= BREAKPOINTS.xs,
|
||||||
lg: 1440, // Large PC: 1440px+
|
sm: width.value >= BREAKPOINTS.sm,
|
||||||
})
|
md: width.value >= BREAKPOINTS.md,
|
||||||
|
lg: width.value >= BREAKPOINTS.lg,
|
||||||
|
isMobile: width.value < BREAKPOINTS.md,
|
||||||
|
isTablet: width.value >= BREAKPOINTS.sm && width.value < BREAKPOINTS.md,
|
||||||
|
isDesktop: width.value >= BREAKPOINTS.md,
|
||||||
|
}))
|
||||||
}
|
}
|
||||||
|
|||||||
274
layers/public/data/GrGallery03.txt
Normal file
274
layers/public/data/GrGallery03.txt
Normal file
@@ -0,0 +1,274 @@
|
|||||||
|
const test = {
|
||||||
|
arrow: {
|
||||||
|
groups: [
|
||||||
|
{
|
||||||
|
res_path: {
|
||||||
|
path_mo: '/local/template/l9/common/btn_system_chevron_prev.svg',
|
||||||
|
},
|
||||||
|
tracking: {
|
||||||
|
click_item: '3. 네비게이션(좌)',
|
||||||
|
action_type: 'click',
|
||||||
|
click_sarea: 'aboutLord_tmpl_01__arrow',
|
||||||
|
},
|
||||||
|
group_code: 'arrow_left',
|
||||||
|
group_type: 'image',
|
||||||
|
resource_type: 'IMG_COMM_GLOBAL',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
res_path: {
|
||||||
|
path_mo: '/local/template/l9/common/btn_system_chevron_next.svg',
|
||||||
|
},
|
||||||
|
tracking: {
|
||||||
|
click_item: '3. 네비게이션(우)',
|
||||||
|
action_type: 'click',
|
||||||
|
click_sarea: 'aboutLord_tmpl_01__arrow',
|
||||||
|
},
|
||||||
|
group_code: 'arrow_right',
|
||||||
|
group_type: 'image',
|
||||||
|
resource_type: 'IMG_COMM_GLOBAL',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
mainTitle: {
|
||||||
|
groups: [
|
||||||
|
{
|
||||||
|
display: {
|
||||||
|
text: '캐릭터 소개',
|
||||||
|
color_code: '',
|
||||||
|
color_name: 'text-secondary',
|
||||||
|
},
|
||||||
|
res_scope: 'lang',
|
||||||
|
group_code: 'mainTitle_text',
|
||||||
|
group_type: 'text',
|
||||||
|
resource_type: 'TXT',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
background: {
|
||||||
|
groups: [
|
||||||
|
{
|
||||||
|
res_path: {
|
||||||
|
path_mo: '/local/template/l9/5/1/1/GR_GALLERY_02/common/bg_m.jpg',
|
||||||
|
path_pc: '/local/template/l9/5/1/1/GR_GALLERY_02/common/bg.jpg',
|
||||||
|
},
|
||||||
|
res_scope: 'comm',
|
||||||
|
group_code: 'background_img',
|
||||||
|
group_type: 'image',
|
||||||
|
resource_type: 'IMG_COMM',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
group_sets: [
|
||||||
|
{
|
||||||
|
imgList: {
|
||||||
|
groups: [
|
||||||
|
{
|
||||||
|
res_path: {
|
||||||
|
path_mo: 'https://picsum.photos/800/600',
|
||||||
|
path_pc:
|
||||||
|
'https://dummyimage.com/800x600/cccccc/969696&text=Test+Image',
|
||||||
|
},
|
||||||
|
group_code: 'imgList_img',
|
||||||
|
group_type: 'image',
|
||||||
|
resource_type: 'IMG_LANG',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
set_order: 1,
|
||||||
|
buttonList: {
|
||||||
|
groups: [
|
||||||
|
{
|
||||||
|
btn_info: {
|
||||||
|
detail: {
|
||||||
|
action: {
|
||||||
|
url: '/ko/about/lord/lael',
|
||||||
|
link_target: '_self',
|
||||||
|
click_action_type: 1,
|
||||||
|
},
|
||||||
|
btn_type: 'URL',
|
||||||
|
},
|
||||||
|
txt_btn_name: '자세히 보기',
|
||||||
|
color_code_btn: '#CECECE',
|
||||||
|
color_code_txt: '#CECECE',
|
||||||
|
color_name_btn: '',
|
||||||
|
color_name_txt: '',
|
||||||
|
},
|
||||||
|
tracking: {
|
||||||
|
click_item: '라엘',
|
||||||
|
action_type: 'click',
|
||||||
|
click_sarea: 'aboutLord_tmpl_01__buttonList_btn',
|
||||||
|
},
|
||||||
|
group_code: 'buttonList_btn',
|
||||||
|
group_type: 'button',
|
||||||
|
resource_type: 'BTN',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
subTitle: {
|
||||||
|
groups: [
|
||||||
|
{
|
||||||
|
display: {
|
||||||
|
text: '강력한 마스터리의 힘',
|
||||||
|
color_code: '#ff0000',
|
||||||
|
color_name: '',
|
||||||
|
},
|
||||||
|
group_code: 'mainTitle_text',
|
||||||
|
group_type: 'text',
|
||||||
|
resource_type: 'TXT',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
description: {
|
||||||
|
groups: [
|
||||||
|
{
|
||||||
|
display: {
|
||||||
|
text: '강력한 마스터리의 00000000',
|
||||||
|
color_code: '#f0f0f0',
|
||||||
|
color_name: '',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
imgList: {
|
||||||
|
groups: [
|
||||||
|
{
|
||||||
|
res_path: {
|
||||||
|
path_mo: 'https://picsum.photos/800/600',
|
||||||
|
path_pc: 'https://picsum.photos/800/600',
|
||||||
|
},
|
||||||
|
group_code: 'imgList_img',
|
||||||
|
group_type: 'image',
|
||||||
|
resource_type: 'IMG_LANG',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
set_order: 2,
|
||||||
|
buttonList: {
|
||||||
|
groups: [
|
||||||
|
{
|
||||||
|
btn_info: {
|
||||||
|
detail: {
|
||||||
|
action: {
|
||||||
|
url: '/ko/about/lord/rpwain',
|
||||||
|
link_target: '_self',
|
||||||
|
click_action_type: 1,
|
||||||
|
},
|
||||||
|
btn_type: 'URL',
|
||||||
|
},
|
||||||
|
txt_btn_name: '자세히 보기',
|
||||||
|
color_code_btn: '#CECECE',
|
||||||
|
color_code_txt: '#CECECE',
|
||||||
|
color_name_btn: '',
|
||||||
|
color_name_txt: '',
|
||||||
|
},
|
||||||
|
tracking: {
|
||||||
|
click_item: '로웨인',
|
||||||
|
action_type: 'click',
|
||||||
|
click_sarea: 'aboutLord_tmpl_01__buttonList_btn',
|
||||||
|
},
|
||||||
|
group_code: 'buttonList_btn',
|
||||||
|
group_type: 'button',
|
||||||
|
resource_type: 'BTN',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
subTitle: {
|
||||||
|
groups: [
|
||||||
|
{
|
||||||
|
display: {
|
||||||
|
text: '강력한 마스터리의 힘',
|
||||||
|
color_code: '#ffffff',
|
||||||
|
color_name: '',
|
||||||
|
},
|
||||||
|
group_code: 'mainTitle_text',
|
||||||
|
group_type: 'text',
|
||||||
|
resource_type: 'TXT',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
description: {
|
||||||
|
groups: [
|
||||||
|
{
|
||||||
|
display: {
|
||||||
|
text: '강력한 마스터리의 힘111111',
|
||||||
|
color_code: '#ffffff',
|
||||||
|
color_name: '',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
imgList: {
|
||||||
|
groups: [
|
||||||
|
{
|
||||||
|
res_path: {
|
||||||
|
path_mo: 'https://picsum.photos/800/600',
|
||||||
|
path_pc: 'https://picsum.photos/800/600',
|
||||||
|
},
|
||||||
|
group_code: 'imgList_img',
|
||||||
|
group_type: 'image',
|
||||||
|
resource_type: 'IMG_LANG',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
set_order: 3,
|
||||||
|
buttonList: {
|
||||||
|
groups: [
|
||||||
|
{
|
||||||
|
btn_info: {
|
||||||
|
detail: {
|
||||||
|
action: {
|
||||||
|
url: '/ko/about/lord/morian',
|
||||||
|
link_target: '_self',
|
||||||
|
click_action_type: 1,
|
||||||
|
},
|
||||||
|
btn_type: 'URL',
|
||||||
|
},
|
||||||
|
txt_btn_name: '자세히 보기',
|
||||||
|
color_code_btn: '#CECECE',
|
||||||
|
color_code_txt: '#CECECE',
|
||||||
|
color_name_btn: '',
|
||||||
|
color_name_txt: '',
|
||||||
|
},
|
||||||
|
tracking: {
|
||||||
|
click_item: '모리안',
|
||||||
|
action_type: 'click',
|
||||||
|
click_sarea: 'aboutLord_tmpl_01__buttonList_btn',
|
||||||
|
},
|
||||||
|
group_code: 'buttonList_btn',
|
||||||
|
group_type: 'button',
|
||||||
|
resource_type: 'BTN',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
subTitle: {
|
||||||
|
groups: [
|
||||||
|
{
|
||||||
|
display: {
|
||||||
|
text: '강력한 마스터리의 힘',
|
||||||
|
color_code: '#ffffff',
|
||||||
|
color_name: '',
|
||||||
|
},
|
||||||
|
group_code: 'mainTitle_text',
|
||||||
|
group_type: 'text',
|
||||||
|
resource_type: 'TXT',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
description: {
|
||||||
|
groups: [
|
||||||
|
{
|
||||||
|
display: {
|
||||||
|
text: '강력한 마스터리의 힘22222',
|
||||||
|
color_code: '#ffffff',
|
||||||
|
color_name: '',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}
|
||||||
@@ -2,8 +2,8 @@ import GrVisual01 from '#layers/templates/GrVisual01/index.vue'
|
|||||||
import GrVisual02 from '#layers/templates/GrVisual02/index.vue'
|
import GrVisual02 from '#layers/templates/GrVisual02/index.vue'
|
||||||
import GrVisual03 from '#layers/templates/GrVisual03/index.vue'
|
import GrVisual03 from '#layers/templates/GrVisual03/index.vue'
|
||||||
import GrGallery01 from '#layers/templates/GrGallery01/index.vue'
|
import GrGallery01 from '#layers/templates/GrGallery01/index.vue'
|
||||||
// import GrGallery02 from "#layers/templates/GrGallery02/index.vue";
|
import GrGallery02 from '#layers/templates/GrGallery02/index.vue'
|
||||||
// import GrGallery03 from "#layers/templates/GrGallery03/index.vue";
|
import GrGallery03 from '#layers/templates/GrGallery03/index.vue'
|
||||||
// import GrBoard01 from "#layers/templates/GrBoard01/index.vue";
|
// import GrBoard01 from "#layers/templates/GrBoard01/index.vue";
|
||||||
// import GrDetail01 from "#layers/templates/GrDetail01/index.vue";
|
// import GrDetail01 from "#layers/templates/GrDetail01/index.vue";
|
||||||
// import GrDetail02 from "#layers/templates/GrDetail02/index.vue";
|
// import GrDetail02 from "#layers/templates/GrDetail02/index.vue";
|
||||||
@@ -15,8 +15,8 @@ export const templateRegistry = {
|
|||||||
GR_VISUAL_02: { component: GrVisual02 },
|
GR_VISUAL_02: { component: GrVisual02 },
|
||||||
GR_VISUAL_03: { component: GrVisual03 },
|
GR_VISUAL_03: { component: GrVisual03 },
|
||||||
GR_GALLERY_01: { component: GrGallery01 },
|
GR_GALLERY_01: { component: GrGallery01 },
|
||||||
// GR_GALLERY_02: { component: GrGallery02 },
|
GR_GALLERY_02: { component: GrGallery02 },
|
||||||
// GR_GALLERY_03: { component: GrGallery03 },
|
GR_GALLERY_03: { component: GrGallery03 },
|
||||||
// GR_BOARD_01: { component: GrBoard01 },
|
// GR_BOARD_01: { component: GrBoard01 },
|
||||||
// GR_DETAIL_01: { component: GrDetail01 },
|
// GR_DETAIL_01: { component: GrDetail01 },
|
||||||
// GR_DETAIL_02: { component: GrDetail02 },
|
// GR_DETAIL_02: { component: GrDetail02 },
|
||||||
|
|||||||
104
layers/templates/GrGallery03/index.vue
Normal file
104
layers/templates/GrGallery03/index.vue
Normal file
@@ -0,0 +1,104 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import { SplideSlide } from '@splidejs/vue-splide'
|
||||||
|
import { getComponentGroup } from '#layers/utils/dataUtil'
|
||||||
|
import type { Splide as SplideType } from '@splidejs/splide'
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
components: Record<string, any>
|
||||||
|
pageVerTmplSeq: string
|
||||||
|
}
|
||||||
|
|
||||||
|
const props = defineProps<Props>()
|
||||||
|
|
||||||
|
const backgroundData = computed(() =>
|
||||||
|
getComponentGroup(props.components, 'background')
|
||||||
|
)
|
||||||
|
const mainTitleData = computed(() =>
|
||||||
|
getComponentGroup(props.components, 'mainTitle')
|
||||||
|
)
|
||||||
|
const slideData = computed(() => props.components.group_sets)
|
||||||
|
|
||||||
|
const subTitleData = ref(getComponentGroup(slideData?.value[0], 'subTitle'))
|
||||||
|
const descriptionData = ref(
|
||||||
|
getComponentGroup(slideData?.value[0], 'description')
|
||||||
|
)
|
||||||
|
const buttonListData = ref(
|
||||||
|
getComponentGroupAry(slideData?.value[0], 'buttonList')
|
||||||
|
)
|
||||||
|
|
||||||
|
const slideItemSize = {
|
||||||
|
mo: {
|
||||||
|
width: 275,
|
||||||
|
height: 154,
|
||||||
|
gap: 12,
|
||||||
|
},
|
||||||
|
pc: {
|
||||||
|
width: 602,
|
||||||
|
height: 338,
|
||||||
|
gap: 32,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleChange = (
|
||||||
|
_splide: SplideType,
|
||||||
|
newIndex: number,
|
||||||
|
_oldIndex: number,
|
||||||
|
_destIndex: number
|
||||||
|
) => {
|
||||||
|
subTitleData.value = getComponentGroup(slideData.value[newIndex], 'subTitle')
|
||||||
|
descriptionData.value = getComponentGroup(
|
||||||
|
slideData.value[newIndex],
|
||||||
|
'description'
|
||||||
|
)
|
||||||
|
buttonListData.value = getComponentGroupAry(
|
||||||
|
slideData.value[newIndex],
|
||||||
|
'buttonList'
|
||||||
|
)
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<section class="pt-[80px] pb-[100px] md:pt-[120px] md:pb-[140px]">
|
||||||
|
<WidgetsBackground v-if="backgroundData" :resources-data="backgroundData" />
|
||||||
|
<div class="section-content px-0 max-w-[2043px] mx-auto">
|
||||||
|
<WidgetsMainTitle
|
||||||
|
v-if="mainTitleData"
|
||||||
|
:resources-data="mainTitleData"
|
||||||
|
class="title-sm"
|
||||||
|
/>
|
||||||
|
<BlocksSlideCenterHighlight
|
||||||
|
v-if="slideData"
|
||||||
|
:slide-item-size="slideItemSize"
|
||||||
|
:slide-item-length="slideData?.length"
|
||||||
|
:pagination="false"
|
||||||
|
class="mt-[24px] md:mt-[48px]"
|
||||||
|
@move="handleChange"
|
||||||
|
>
|
||||||
|
<SplideSlide v-for="(item, index) in slideData" :key="index">
|
||||||
|
<div class="slide-inner border-line">
|
||||||
|
<BlocksVisualContent
|
||||||
|
:resources-data="getComponentGroup(item, 'imgList')"
|
||||||
|
object-fit="cover"
|
||||||
|
:alt="getComponentGroup(item, 'subTitle')?.display?.text"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</SplideSlide>
|
||||||
|
</BlocksSlideCenterHighlight>
|
||||||
|
<WidgetsSubTitle
|
||||||
|
v-if="subTitleData"
|
||||||
|
:resources-data="subTitleData"
|
||||||
|
class="title-md mt-[32px]"
|
||||||
|
/>
|
||||||
|
<WidgetsDescription
|
||||||
|
v-if="descriptionData"
|
||||||
|
:resources-data="descriptionData"
|
||||||
|
class="mt-[8px] md:mt-[16px]"
|
||||||
|
/>
|
||||||
|
<WidgetsButtonList
|
||||||
|
v-if="buttonListData"
|
||||||
|
:resources-data="buttonListData"
|
||||||
|
class="mt-[32px]"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</template>
|
||||||
Reference in New Issue
Block a user