fix. utils 함수 변경, 클래스명 수정
This commit is contained in:
@@ -1,20 +1,31 @@
|
||||
/* Layout Utility Classes */
|
||||
@layer components {
|
||||
.section-wrap {
|
||||
/* 표준형 */
|
||||
.section-standard {
|
||||
@apply relative h-[640px] md:h-[1000px];
|
||||
}
|
||||
|
||||
.section-content {
|
||||
.content-standard {
|
||||
@apply relative h-full flex flex-col items-center justify-center text-center px-[20px] sm:px-[40px];
|
||||
}
|
||||
|
||||
/* 고정형 */
|
||||
.section-container.static {
|
||||
@apply relative pt-[32px] pb-[80px] px-[20px] sm:px-[40px] md:pt-[64px] md:pb-[200px] bg-[#F0F0F0];
|
||||
}
|
||||
.section-static {
|
||||
@apply mx-auto max-w-[684px] md:max-w-[944px] lg:max-w-[1300px];
|
||||
}
|
||||
.section-static + .section-static {
|
||||
@apply mt-[80px] md:mt-[100px];
|
||||
}
|
||||
|
||||
.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 Classes */
|
||||
.title-xlg {
|
||||
@apply line-clamp-4 text-[24px] font-[700] leading-[34px] drop-shadow-[0_2px_2px_rgba(0,0,0,0.6)] md:line-clamp-3 md:text-[50px] md:leading-[70px];
|
||||
}
|
||||
|
||||
@@ -173,7 +173,7 @@ onBeforeUnmount(() => {
|
||||
<header class="header">
|
||||
<BlocksStoveGnb class="min-h-[48px]" />
|
||||
|
||||
<div class="game-wrapper" :class="{ 'is-fixed': isPassedStoveGnb }">
|
||||
<div class="game-wrap" :class="{ 'is-fixed': isPassedStoveGnb }">
|
||||
<AtomsLocaleLink to="/brand" class="mx-auto md:hidden">
|
||||
<img
|
||||
:src="getImageHost(gnbData?.bi_path)"
|
||||
@@ -361,11 +361,11 @@ onBeforeUnmount(() => {
|
||||
.header {
|
||||
@apply bg-theme-foreground text-theme-foreground-reversal relative z-[100];
|
||||
}
|
||||
.game-wrapper {
|
||||
.game-wrap {
|
||||
@apply absolute flex w-full h-[48px] items-center whitespace-nowrap px-[52px] bg-theme-foreground sm:px-[72px] md:h-16 md:pl-0 md:pr-[40px]
|
||||
before:content-[''] before:absolute before:top-0 before:left-0 before:right-0 before:h-px before:bg-theme-foreground-reversal-6;
|
||||
}
|
||||
.game-wrapper.is-fixed {
|
||||
.game-wrap.is-fixed {
|
||||
@apply fixed top-0 left-0;
|
||||
}
|
||||
.game-logo {
|
||||
|
||||
@@ -107,7 +107,7 @@ const onArrowClick = (direction, targetIndex) => {
|
||||
:style="getPaginationClass(paginationData)"
|
||||
>
|
||||
<WidgetsBackground v-if="backgroundData" :resources-data="backgroundData" />
|
||||
<div class="section-content px-0">
|
||||
<div class="content-standard px-0">
|
||||
<WidgetsMainTitle
|
||||
v-if="mainTitleData"
|
||||
:resources-data="mainTitleData"
|
||||
|
||||
@@ -32,7 +32,7 @@ const buttonListData = computed(() => {
|
||||
<template>
|
||||
<section class="relative py-[80px] md:py-[120px]">
|
||||
<WidgetsBackground v-if="backgroundData" :resources-data="backgroundData" />
|
||||
<div class="section-content">
|
||||
<div class="content-standard">
|
||||
<WidgetsMainTitle
|
||||
v-if="mainTitleData"
|
||||
:resources-data="mainTitleData"
|
||||
|
||||
@@ -41,7 +41,7 @@ const handleSplideMove = (_splide: SplideType, newIndex: number) => {
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<section class="section-wrap">
|
||||
<section class="section-standard">
|
||||
<BlocksSlideFade
|
||||
v-if="slideData"
|
||||
ref="splideRef"
|
||||
@@ -58,7 +58,7 @@ const handleSplideMove = (_splide: SplideType, newIndex: number) => {
|
||||
v-if="hasComponentGroup(item, 'background')"
|
||||
:resources-data="getComponentGroup(item, 'background')"
|
||||
/>
|
||||
<div class="section-content">
|
||||
<div class="content-standard">
|
||||
<WidgetsMainTitle
|
||||
v-if="hasComponentGroup(item, 'mainTitle')"
|
||||
:resources-data="getComponentGroup(item, 'mainTitle')"
|
||||
|
||||
@@ -22,7 +22,7 @@ const paginationData = computed(() => {
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<section class="section-wrap">
|
||||
<section class="section-standard">
|
||||
<BlocksSlideThumbnail
|
||||
:slide-data="slideData"
|
||||
:pagination-data="paginationData"
|
||||
@@ -32,7 +32,7 @@ const paginationData = computed(() => {
|
||||
v-if="hasComponentGroup(item, 'background')"
|
||||
:resources-data="getComponentGroup(item, 'background')"
|
||||
/>
|
||||
<div class="section-content">
|
||||
<div class="content-standard">
|
||||
<WidgetsMainTitle
|
||||
v-if="hasComponentGroup(item, 'mainTitle')"
|
||||
:resources-data="getComponentGroup(item, 'mainTitle')"
|
||||
|
||||
@@ -43,7 +43,7 @@ const handleSplideMove = (_splide: SplideType, newIndex: number) => {
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<section class="section-wrap">
|
||||
<section class="section-standard">
|
||||
<BlocksSlideThumbnail
|
||||
:slide-data="slideData"
|
||||
:pagination-data="paginationData"
|
||||
@@ -60,7 +60,7 @@ const handleSplideMove = (_splide: SplideType, newIndex: number) => {
|
||||
:resources-data="getComponentGroup(item, 'foreground')"
|
||||
/>
|
||||
<div
|
||||
class="section-content max-w-[1024px] mx-auto items-start pt-[48px] md:pt-0"
|
||||
class="content-standard max-w-[1024px] mx-auto items-start pt-[48px] md:pt-0"
|
||||
>
|
||||
<WidgetsSubTitle
|
||||
v-if="hasComponentGroup(item, 'category')"
|
||||
|
||||
@@ -6,7 +6,7 @@ import {
|
||||
getComponentGroup,
|
||||
isTypeVideo,
|
||||
} from '#layers/utils/dataUtil'
|
||||
import { getMediaImgSrc, getMediaSrc } from '#layers/utils/youtubeUtil'
|
||||
import { getMediaImgSrc } from '#layers/utils/styleUtil'
|
||||
import type {
|
||||
PageDataTemplateComponents,
|
||||
PageDataTemplateComponentSet,
|
||||
@@ -50,7 +50,8 @@ const getMediaImgSrcFromItem = (item: PageDataTemplateComponentSet) => {
|
||||
const getYouTubeEmbedUrlFromMedia = (item: PageDataTemplateComponentSet) => {
|
||||
const mediaComponent = getMediaComponent(item)
|
||||
if (!mediaComponent) return ''
|
||||
const mediaSrc = getMediaSrc(mediaComponent)
|
||||
|
||||
const mediaSrc = mediaComponent.display?.text
|
||||
return mediaSrc ? getYouTubeEmbedUrl(mediaSrc, true) : ''
|
||||
}
|
||||
|
||||
@@ -102,9 +103,9 @@ const onArrowClick = (direction, targetIndex) => {
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<section class="section-wrap min-h-[700px]">
|
||||
<section class="section-standard min-h-[700px]">
|
||||
<WidgetsBackground v-if="backgroundData" :resources-data="backgroundData" />
|
||||
<div class="section-content">
|
||||
<div class="content-standard">
|
||||
<WidgetsMainTitle
|
||||
v-if="mainTitleData"
|
||||
:resources-data="mainTitleData"
|
||||
|
||||
@@ -59,9 +59,9 @@ const onArrowClick = (direction, targetIndex) => {
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<section class="section-wrap">
|
||||
<section class="section-standard">
|
||||
<WidgetsBackground v-if="backgroundData" :resources-data="backgroundData" />
|
||||
<div class="section-content px-0">
|
||||
<div class="content-standard px-0">
|
||||
<WidgetsMainTitle
|
||||
v-if="mainTitleData"
|
||||
:resources-data="mainTitleData"
|
||||
@@ -98,7 +98,7 @@ const onArrowClick = (direction, targetIndex) => {
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.section-wrap {
|
||||
.section-standard {
|
||||
@apply before:hidden md:before:block before:content-[''] before:absolute before:top-0 before:left-0 before:w-[104px] before:h-full before:bg-gradient-to-l from-transparent to-[rgba(0,0,0,0.7)] before:z-[5]
|
||||
after:hidden md:after:block after:content-[''] after:absolute after:top-0 after:right-0 after:w-[104px] after:h-full after:bg-gradient-to-r from-transparent to-[rgba(0,0,0,0.7)];
|
||||
}
|
||||
|
||||
@@ -72,7 +72,7 @@ const onArrowClick = (direction, targetIndex) => {
|
||||
<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">
|
||||
<div class="content-standard px-0 max-w-[2043px] mx-auto">
|
||||
<WidgetsMainTitle
|
||||
v-if="mainTitleData"
|
||||
:resources-data="mainTitleData"
|
||||
|
||||
@@ -27,13 +27,13 @@ const buttonListData = computed(() =>
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<section class="section-wrap">
|
||||
<section class="section-standard">
|
||||
<WidgetsBackground
|
||||
v-if="backgroundData"
|
||||
:resources-data="backgroundData"
|
||||
gradient="h-[342px] bg-[linear-gradient(180deg,rgba(16,13,15,0)_0%,#100D0F_90%)] md:h-[720px]"
|
||||
/>
|
||||
<div class="section-content gap-4 md:gap-5">
|
||||
<div class="content-standard gap-4 md:gap-5">
|
||||
<WidgetsMainTitle
|
||||
v-if="mainTitleData"
|
||||
:resources-data="mainTitleData"
|
||||
|
||||
@@ -90,7 +90,7 @@ const onArrowClick = direction => {
|
||||
:resources-data="backgroundData"
|
||||
gradient="h-[440px] bg-[linear-gradient(180deg,rgba(16,13,15,0)_0%,#100D0F_40%)] md:h-[720px] md:bg-[linear-gradient(180deg,rgba(16,13,15,0)_0%,#100D0F_50%)]"
|
||||
/>
|
||||
<div class="section-content px-0 gap-5">
|
||||
<div class="content-standard px-0 gap-5">
|
||||
<WidgetsMainTitle
|
||||
v-if="mainTitleData"
|
||||
:resources-data="mainTitleData"
|
||||
|
||||
@@ -33,7 +33,7 @@ const onArrowClick = direction => {
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<section class="section-wrap">
|
||||
<section class="section-standard">
|
||||
<BlocksSlideFade
|
||||
v-if="slideData"
|
||||
:arrows="true"
|
||||
@@ -47,7 +47,7 @@ const onArrowClick = direction => {
|
||||
v-if="hasComponentGroup(item, 'background')"
|
||||
:resources-data="getComponentGroup(item, 'background')"
|
||||
/>
|
||||
<div class="section-content gap-3 md:gap-5">
|
||||
<div class="content-standard gap-3 md:gap-5">
|
||||
<WidgetsSubTitle
|
||||
v-if="hasComponentGroup(item, 'subTitle')"
|
||||
:resources-data="getComponentGroup(item, 'subTitle')"
|
||||
|
||||
@@ -5,13 +5,12 @@
|
||||
// OperateResources
|
||||
export interface OperateGroupItem {
|
||||
seq: number
|
||||
flag_type?: number
|
||||
sort_order: number
|
||||
title: string
|
||||
img_path: string
|
||||
url: string
|
||||
link_target: string
|
||||
display_status: number
|
||||
reg_dt?: number
|
||||
reg_dt: number
|
||||
option01: number
|
||||
option02: number
|
||||
option03: string
|
||||
|
||||
@@ -116,21 +116,6 @@ export const getComponentContainer = (
|
||||
return result
|
||||
}
|
||||
|
||||
/**
|
||||
* 컴포넌트 그룹의 첫 번째 데이터를 반환합니다.
|
||||
* @param components props.components 또는 group 객체
|
||||
* @param componentName 컴포넌트 이름
|
||||
* @returns 첫 번째 그룹 데이터 또는 null
|
||||
*/
|
||||
export const getComponentGroup = (
|
||||
components: PageDataTemplateComponents | OperateComponents,
|
||||
componentName: string
|
||||
) => {
|
||||
if (!components) return null
|
||||
|
||||
return components[componentName]?.groups?.[0] || null
|
||||
}
|
||||
|
||||
/**
|
||||
* 컴포넌트 그룹의 모든 데이터를 반환합니다.
|
||||
* @param components props.components 또는 group 객체
|
||||
@@ -159,3 +144,18 @@ export const getImagePaths = (resourcesData: PageDataResourceGroup) => {
|
||||
mo: moPath,
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 컴포넌트 그룹의 첫 번째 데이터를 반환합니다.
|
||||
* @param components props.components 또는 group 객체
|
||||
* @param componentName 컴포넌트 이름
|
||||
* @returns 첫 번째 그룹 데이터 또는 null
|
||||
*/
|
||||
export const getComponentGroup = (
|
||||
components: PageDataTemplateComponents | OperateComponents,
|
||||
componentName: string
|
||||
) => {
|
||||
if (!components) return null
|
||||
|
||||
return components[componentName]?.groups?.[0] || null
|
||||
}
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
/**
|
||||
* 스타일 유틸리티 함수
|
||||
* @description 스타일 처리에 필요한 유틸리티 함수를 제공합니다.
|
||||
* @description ui 처리에 필요한 유틸리티 함수를 제공합니다.
|
||||
*/
|
||||
|
||||
import { isTypeVideo } from '#layers/utils/dataUtil'
|
||||
import type {
|
||||
PageDataResourceGroups,
|
||||
PageDataResourceGroup,
|
||||
PageDataResourceGroupResPath,
|
||||
} from '#layers/types/api/pageData'
|
||||
|
||||
@@ -128,3 +130,26 @@ export const getPaginationClass = (
|
||||
'--pagination-disabled': paginationDisabled,
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 미디어 이미지를 반환합니다. (이미지 / 유튜브 썸네일)
|
||||
* @param resourceGroups - 미디어 리소스 그룹 객체
|
||||
* @param quality - 썸네일 품질
|
||||
* @returns 미디어 이미지 소스 (이미지 / 유튜브 썸네일)
|
||||
*/
|
||||
export const getMediaImgSrc = (
|
||||
resourceGroups: PageDataResourceGroup,
|
||||
quality: 'default' | 'medium' | 'high' | 'standard' | 'maxres' = 'high'
|
||||
): string => {
|
||||
if (!resourceGroups) return ''
|
||||
|
||||
const mediaSrc = resourceGroups?.display?.text
|
||||
const mediaType = resourceGroups?.resource_type
|
||||
|
||||
if (isTypeVideo(mediaType) && mediaSrc) {
|
||||
const thumbnailUrl = getYouTubeThumbnail(mediaSrc, quality)
|
||||
return thumbnailUrl
|
||||
}
|
||||
|
||||
return mediaSrc || ''
|
||||
}
|
||||
|
||||
@@ -3,15 +3,12 @@
|
||||
* @description 유튜브 관련 유틸리티 함수를 제공합니다.
|
||||
*/
|
||||
|
||||
import { isTypeVideo } from '#layers/utils/dataUtil'
|
||||
import type { PageDataResourceGroup } from '#layers/types/api/pageData'
|
||||
|
||||
/**
|
||||
* 유튜브 URL에서 비디오 ID를 추출합니다.
|
||||
* @param url - 유튜브 URL (watch, embed, youtu.be 등 다양한 형태 지원)
|
||||
* @returns 비디오 ID 또는 빈 문자열
|
||||
*/
|
||||
export const getYouTubeVideoId = (url: string): string => {
|
||||
export const getYouTubeId = (url: string): string => {
|
||||
if (!url) return ''
|
||||
|
||||
// 다양한 유튜브 URL 패턴 지원
|
||||
@@ -45,7 +42,7 @@ export const getYouTubeEmbedUrl = (
|
||||
autoplay: boolean = false,
|
||||
rel: boolean = false
|
||||
): string => {
|
||||
const videoId = getYouTubeVideoId(url)
|
||||
const videoId = getYouTubeId(url)
|
||||
if (!videoId) return ''
|
||||
|
||||
const params = new URLSearchParams()
|
||||
@@ -57,15 +54,16 @@ export const getYouTubeEmbedUrl = (
|
||||
}
|
||||
|
||||
/**
|
||||
* 유튜브 비디오 ID로부터 썸네일 URL을 생성합니다.
|
||||
* @param videoId - 유튜브 비디오 ID
|
||||
* 유튜브 URL에서 비디오 ID를 추출하고, 비디오 ID로부터 썸네일 URL을 생성합니다.
|
||||
* @param url - 유튜브 URL
|
||||
* @param quality - 썸네일 품질 ('default', 'medium', 'high', 'standard', 'maxres')
|
||||
* @returns 썸네일 URL
|
||||
*/
|
||||
export const getYouTubeThumbnail = (
|
||||
videoId: string,
|
||||
url: string,
|
||||
quality: 'default' | 'medium' | 'high' | 'standard' | 'maxres' = 'high'
|
||||
): string => {
|
||||
const videoId = getYouTubeId(url)
|
||||
if (!videoId) return ''
|
||||
|
||||
const qualityMap = {
|
||||
@@ -78,52 +76,3 @@ export const getYouTubeThumbnail = (
|
||||
|
||||
return `https://img.youtube.com/vi/${videoId}/${qualityMap[quality]}.jpg`
|
||||
}
|
||||
|
||||
/**
|
||||
* 유튜브 URL에서 직접 썸네일 URL을 추출합니다.
|
||||
* @param url - 유튜브 URL
|
||||
* @param quality - 썸네일 품질
|
||||
* @returns 썸네일 URL
|
||||
*/
|
||||
export const getYouTubeThumbnailFromUrl = (
|
||||
url: string,
|
||||
quality: 'default' | 'medium' | 'high' | 'standard' | 'maxres' = 'high'
|
||||
): string => {
|
||||
const videoId = getYouTubeVideoId(url)
|
||||
return getYouTubeThumbnail(videoId, quality)
|
||||
}
|
||||
|
||||
/**
|
||||
* 미디어 text(src)를 추출합니다.
|
||||
* @param source - 미디어 소스 객체
|
||||
* @returns 미디어 text(src)
|
||||
*/
|
||||
export const getMediaSrc = (resourceGroup: PageDataResourceGroup): string => {
|
||||
if (!resourceGroup) return ''
|
||||
const mediaSrc = resourceGroup?.display?.text
|
||||
return mediaSrc || ''
|
||||
}
|
||||
|
||||
/**
|
||||
* 미디어 이미지를 추출합니다. (유튜브인 경우 썸네일)
|
||||
* @param source - 미디어 소스 객체
|
||||
* @param quality - 썸네일 품질
|
||||
* @returns 미디어 이미지 소스
|
||||
*/
|
||||
export const getMediaImgSrc = (
|
||||
resourceGroups: PageDataResourceGroup,
|
||||
quality: 'default' | 'medium' | 'high' | 'standard' | 'maxres' = 'high'
|
||||
): string => {
|
||||
if (!resourceGroups) return ''
|
||||
|
||||
const mediaSrc = getMediaSrc(resourceGroups)
|
||||
const mediaType = resourceGroups?.resource_type
|
||||
|
||||
if (isTypeVideo(mediaType) && mediaSrc) {
|
||||
const videoId = getYouTubeVideoId(mediaSrc)
|
||||
const thumbnailUrl = getYouTubeThumbnail(videoId, quality)
|
||||
return thumbnailUrl
|
||||
}
|
||||
|
||||
return mediaSrc || ''
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user