fix. utils 함수 변경, 클래스명 수정

This commit is contained in:
clkim
2025-10-31 17:33:15 +09:00
parent 83124d56eb
commit 3569ca66c8
17 changed files with 89 additions and 104 deletions

View File

@@ -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];
}

View File

@@ -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 {

View File

@@ -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"

View File

@@ -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"

View File

@@ -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')"

View File

@@ -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')"

View File

@@ -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')"

View File

@@ -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"

View File

@@ -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)];
}

View File

@@ -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"

View File

@@ -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"

View File

@@ -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"

View File

@@ -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')"

View File

@@ -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

View File

@@ -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
}

View File

@@ -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 || ''
}

View File

@@ -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 || ''
}