183 lines
5.0 KiB
Vue
183 lines
5.0 KiB
Vue
<script setup lang="ts">
|
|
import { SplideSlide } from '@splidejs/vue-splide'
|
|
import { globalDateFormat } from '@seed-next/date'
|
|
import { getComponentGroup } from '#layers/utils/dataUtil'
|
|
import type { PageDataTemplateComponents } from '#layers/types/api/pageData'
|
|
import type { CwmsArticleItem } from '#layers/types/api/cwmsArticle'
|
|
|
|
interface Props {
|
|
components: PageDataTemplateComponents
|
|
pageVerTmplSeq: number
|
|
pageVerTmplNameEn: string
|
|
}
|
|
|
|
const props = defineProps<Props>()
|
|
|
|
const gameDataStore = useGameDataStore()
|
|
const pageDataStore = usePageDataStore()
|
|
const { getCwmsArticle } = useCwmsArticle()
|
|
const { locale } = useI18n()
|
|
|
|
const { gameData } = storeToRefs(gameDataStore)
|
|
const { pageData } = storeToRefs(pageDataStore)
|
|
|
|
const boardId = computed(
|
|
() => getComponentGroup(props.components, 'boardId')?.display?.text
|
|
)
|
|
const backgroundData = computed(() =>
|
|
getComponentGroup(props.components, 'background')
|
|
)
|
|
const mainTitleData = computed(() =>
|
|
getComponentGroup(props.components, 'mainTitle')
|
|
)
|
|
const descriptionData = computed(() =>
|
|
getComponentGroup(props.components, 'description')
|
|
)
|
|
const arrowsData = computed(() =>
|
|
getComponentGroupAry(props.components, 'arrow')
|
|
)
|
|
const paginationData = computed(() => {
|
|
return getComponentGroupAry(props.components, 'pagination')
|
|
})
|
|
|
|
const buttonListData = ref(getComponentGroupAry(props.components, 'buttonList'))
|
|
|
|
const { data: slideData } = await useAsyncData(
|
|
`gr-board-01-resources-${pageData.value?.page_seq}-${pageData.value?.page_ver}-${props.pageVerTmplSeq}`,
|
|
async () => {
|
|
if (!boardId.value) {
|
|
return []
|
|
}
|
|
|
|
const cwmsArticleData = await getCwmsArticle('BOARD', boardId.value, {
|
|
sortTypeCode: 'LATEST',
|
|
translationYn: true,
|
|
page: 1,
|
|
size: 20,
|
|
})
|
|
|
|
return cwmsArticleData?.list as CwmsArticleItem[]
|
|
},
|
|
{
|
|
default: () => [],
|
|
server: false,
|
|
}
|
|
)
|
|
const slideLength = computed(() => slideData.value.length ?? 0)
|
|
const splideOptions = computed(() => {
|
|
return {
|
|
gap: 20,
|
|
perPage: 4,
|
|
drag: false,
|
|
arrows: slideLength.value > 4,
|
|
pagination: slideLength.value > 4,
|
|
destroy: slideLength.value <= 4,
|
|
breakpoints: {
|
|
[BREAKPOINTS.lg - 1]: {
|
|
perPage: 2,
|
|
arrows: slideLength.value > 2,
|
|
pagination: slideLength.value > 2,
|
|
destroy: slideLength.value < 3,
|
|
},
|
|
[BREAKPOINTS.md - 1]: {
|
|
drag: true,
|
|
perPage: 1,
|
|
arrows: false,
|
|
pagination: false,
|
|
destroy: slideLength.value < 2,
|
|
padding: {
|
|
left: 40,
|
|
right: 40,
|
|
},
|
|
},
|
|
[BREAKPOINTS.sm - 1]: {
|
|
padding: {
|
|
left: 20,
|
|
right: 20,
|
|
},
|
|
},
|
|
},
|
|
}
|
|
})
|
|
|
|
const getArticleUrl = (articleId: string) => {
|
|
const communityUrl = gameData.value?.url_json?.community
|
|
if (!communityUrl || !articleId || !boardId.value) {
|
|
return ''
|
|
}
|
|
return `${communityUrl}/view/${articleId}`
|
|
}
|
|
</script>
|
|
|
|
<template>
|
|
<section
|
|
class="relative min-h-[483px] py-[80px] md:min-h-[684px] md:py-[120px]"
|
|
:style="getPaginationClass(paginationData)"
|
|
>
|
|
<WidgetsBackground v-if="backgroundData" :resources-data="backgroundData" />
|
|
<div class="content-standard px-0">
|
|
<WidgetsMainTitle
|
|
v-if="mainTitleData"
|
|
:resources-data="mainTitleData"
|
|
class="title-md max-w-[944px] mx-[20px] sm:mx-[40px]"
|
|
/>
|
|
<ClientOnly>
|
|
<WidgetsSlideDefault
|
|
v-if="slideLength > 0"
|
|
v-bind="splideOptions"
|
|
:slide-item-length="slideLength"
|
|
:arrows-data="arrowsData"
|
|
class="w-full"
|
|
>
|
|
<SplideSlide
|
|
v-for="(item, index) in slideData"
|
|
:key="item.article_id || `real-${index}`"
|
|
>
|
|
<div class="slide-inner">
|
|
<BlocksCardNews
|
|
:title="item.title"
|
|
:description="globalDateFormat(item.create_datetime, locale)"
|
|
:img-path="item.media_thumbnail_url"
|
|
:url="getArticleUrl(item.article_id)"
|
|
:analytics-sarea="pageVerTmplNameEn"
|
|
link-target="_blank"
|
|
rel="noopener noreferrer"
|
|
/>
|
|
</div>
|
|
</SplideSlide>
|
|
</WidgetsSlideDefault>
|
|
</ClientOnly>
|
|
<WidgetsButtonList
|
|
v-if="buttonListData"
|
|
:resources-data="buttonListData"
|
|
class="mt-[48px] md:mt-[64px]"
|
|
/>
|
|
<WidgetsDescription
|
|
v-if="descriptionData"
|
|
:resources-data="descriptionData"
|
|
class="max-w-[944px] mt-[32px] mx-[20px] sm:mx-[40px] md:mt-[48px]"
|
|
/>
|
|
</div>
|
|
</section>
|
|
</template>
|
|
|
|
<style scoped>
|
|
.splide {
|
|
@apply mt-[24px] md:max-w-[776px] md:mt-[48px] md:mx-auto md:px-[72px] lg:max-w-[1428px];
|
|
}
|
|
.splide:deep(.arsplide__arrow--prev) {
|
|
@apply top-[calc(50%-28px)] left-[0];
|
|
}
|
|
.splide:deep(.splide__arrow--next) {
|
|
@apply top-[calc(50%-28px)] right-[0];
|
|
}
|
|
.slide-inner {
|
|
@apply w-[275px] aspect-[1/1] md:w-[306px];
|
|
}
|
|
|
|
/* destroy되었을 때 (슬라이드 비활성화) 중앙 정렬 */
|
|
.splide:not(.is-active):deep(.splide__list) {
|
|
@apply flex justify-center gap-5;
|
|
}
|
|
</style>
|