feat. header 컴포넌트 반응형 제작

This commit is contained in:
clkim
2025-10-01 11:23:13 +09:00
parent 5f140aced1
commit 517d2b233b
17 changed files with 514 additions and 107 deletions

180
layers/utils/formatUtil.ts Normal file
View File

@@ -0,0 +1,180 @@
/**
* 포맷 유틸리티 함수
* @description 포맷 처리에 필요한 유틸리티 함수를 제공합니다.
*/
/**
* JWT 디코딩
* @param base64EncodeVal JWT 인코딩 값
* @returns JWT 디코딩 값
*/
export const csrFormatJWT = (base64EncodeVal: string) => {
const decodeVal = JSON.parse(
decodeURIComponent(
window
.atob(base64EncodeVal)
.split('')
.map(function (c) {
return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2)
})
.join('')
)
)
return decodeVal
}
/**
* 타임스탬프를 다양한 날짜 형식으로 변환합니다.
* @param timestamp 타임스탬프 (밀리초 또는 초)
* @param format 날짜 형식 ('YYYY-MM-DD', 'YYYY-MM-DD HH:mm:ss', 'MM/DD/YYYY', 'YYYY년 MM월 DD일' 등)
* @param locale 로케일 (기본값: 'ko-KR')
* @returns 포맷된 날짜 문자열
*/
export const formatTimestamp = (
timestamp: number | string,
format: string = 'YYYY.MM.DD',
_locale: string = 'ko-KR'
): string => {
if (!timestamp) return ''
// 타임스탬프를 숫자로 변환
let ts = typeof timestamp === 'string' ? parseInt(timestamp) : timestamp
// 초 단위인 경우 밀리초로 변환
if (ts < 10000000000) {
ts = ts * 1000
}
const date = new Date(ts)
// 유효하지 않은 날짜인 경우 빈 문자열 반환
if (isNaN(date.getTime())) {
return ''
}
// 미리 정의된 형식들
const predefinedFormats: Record<string, string> = {
'YYYY.MM.DD': date.toISOString().split('T')[0].replace(/-/g, '.'),
'YYYY-MM-DD': date.toISOString().split('T')[0],
'YYYY-MM-DD HH:mm': date.toISOString().replace('T', ' ').substring(0, 16),
'YYYY-MM-DD HH:mm:ss': date.toISOString().replace('T', ' ').split('.')[0],
'MM/DD/YYYY': date.toLocaleDateString('en-US'),
'DD/MM/YYYY': date.toLocaleDateString('en-GB'),
'YYYY년 MM월 DD일': date.toLocaleDateString('ko-KR', {
year: 'numeric',
month: 'long',
day: 'numeric',
}),
'MM월 DD일': date.toLocaleDateString('ko-KR', {
month: 'long',
day: 'numeric',
}),
}
// 미리 정의된 형식이 있으면 사용
if (predefinedFormats[format]) {
return predefinedFormats[format]
}
// 커스텀 형식 처리
const year = date.getFullYear()
const month = String(date.getMonth() + 1).padStart(2, '0')
const day = String(date.getDate()).padStart(2, '0')
const hours = String(date.getHours()).padStart(2, '0')
const minutes = String(date.getMinutes()).padStart(2, '0')
const seconds = String(date.getSeconds()).padStart(2, '0')
return format
.replace('YYYY', String(year))
.replace('MM', month)
.replace('DD', day)
.replace('HH', hours)
.replace('mm', minutes)
.replace('ss', seconds)
}
/**
* 타임스탬프를 상대적 시간으로 변환합니다 (예: "3일 전", "2시간 전")
* @param timestamp 타임스탬프 (밀리초 또는 초)
* @param locale 로케일 (기본값: 'ko-KR')
* @returns 상대적 시간 문자열
*/
export const formatRelativeTime = (
timestamp: number | string,
locale: string = 'ko-KR'
): string => {
if (!timestamp) return ''
let ts = typeof timestamp === 'string' ? parseInt(timestamp) : timestamp
if (ts < 10000000000) {
ts = ts * 1000
}
const date = new Date(ts)
const now = new Date()
const diffInSeconds = Math.floor((now.getTime() - date.getTime()) / 1000)
if (diffInSeconds < 60) {
return locale === 'ko-KR' ? '방금 전' : 'just now'
}
const diffInMinutes = Math.floor(diffInSeconds / 60)
if (diffInMinutes < 60) {
return locale === 'ko-KR'
? `${diffInMinutes}분 전`
: `${diffInMinutes} minutes ago`
}
const diffInHours = Math.floor(diffInMinutes / 60)
if (diffInHours < 24) {
return locale === 'ko-KR'
? `${diffInHours}시간 전`
: `${diffInHours} hours ago`
}
const diffInDays = Math.floor(diffInHours / 24)
if (diffInDays < 30) {
return locale === 'ko-KR' ? `${diffInDays}일 전` : `${diffInDays} days ago`
}
const diffInMonths = Math.floor(diffInDays / 30)
if (diffInMonths < 12) {
return locale === 'ko-KR'
? `${diffInMonths}개월 전`
: `${diffInMonths} months ago`
}
const diffInYears = Math.floor(diffInMonths / 12)
return locale === 'ko-KR' ? `${diffInYears}년 전` : `${diffInYears} years ago`
}
/**
* 배열 또는 객체를 배열로 변환합니다.
* @param value 변환할 값 (배열, 객체, 또는 undefined/null)
* @returns 배열
*/
export const formatToArray = <T>(
value: T[] | Record<string, T> | undefined | null
): T[] => {
if (!value) return []
return Array.isArray(value) ? value : Object.values(value)
}
/**
* URL 경로에서 로케일 접두사를 제거합니다.
* @param path 경로 문자열
* @returns 로케일 접두사가 제거된 경로
*/
export const formatPathWithoutLocale = (path: string): string => {
return path.replace(/^\/[a-z]{2}(?=\/|$)/, '') || '/'
}
/**
* URL이 내부 링크인지 확인합니다.
* @param url 확인할 URL
* @returns 내부 링크 여부
*/
export const isInternalUrl = (url?: string): boolean => {
return !!url && !url.startsWith('http')
}