first commit
This commit is contained in:
@@ -0,0 +1,77 @@
|
||||
// 공통 포맷터 — 부수효과 없는 순수 함수만 작성
|
||||
|
||||
/**
|
||||
* 숫자를 한국 통화 표기 (예: 12345 → "12,345원")
|
||||
*/
|
||||
export function formatCurrency(value: number): string {
|
||||
return `${value.toLocaleString('ko-KR')}원`
|
||||
}
|
||||
|
||||
/**
|
||||
* Date 또는 ISO 문자열을 'YYYY-MM-DD' 형식으로 변환
|
||||
*/
|
||||
export function formatDate(input: Date | string): string {
|
||||
const date = typeof input === 'string' ? new Date(input) : input
|
||||
if (Number.isNaN(date.getTime())) return ''
|
||||
const yyyy = date.getFullYear()
|
||||
const mm = String(date.getMonth() + 1).padStart(2, '0')
|
||||
const dd = String(date.getDate()).padStart(2, '0')
|
||||
return `${yyyy}-${mm}-${dd}`
|
||||
}
|
||||
|
||||
/* ============================================================
|
||||
* 표시용 파생 값 — 백엔드 원시 데이터를 화면 라벨/색상으로 변환
|
||||
* (서버는 타임스탬프/카운트만 내려주고 여기서 계산한다)
|
||||
* ============================================================ */
|
||||
|
||||
/** 아바타 색상 키 (relay.css 의 .av-* 클래스와 대응) */
|
||||
export type AvatarColorKey = 'av-a' | 'av-b' | 'av-c' | 'av-d' | 'av-e' | 'av-f'
|
||||
|
||||
const AVATAR_COLORS: AvatarColorKey[] = ['av-a', 'av-b', 'av-c', 'av-d', 'av-e', 'av-f']
|
||||
|
||||
/** 식별자(문자열)를 결정적으로 아바타 색상에 매핑 */
|
||||
export function avatarColor(seed: string): AvatarColorKey {
|
||||
let hash = 0
|
||||
for (let i = 0; i < seed.length; i++) {
|
||||
hash = (hash * 31 + seed.charCodeAt(i)) >>> 0
|
||||
}
|
||||
return AVATAR_COLORS[hash % AVATAR_COLORS.length] ?? 'av-a'
|
||||
}
|
||||
|
||||
/** 이름의 첫 글자(아바타 이니셜) */
|
||||
export function initialOf(name: string): string {
|
||||
return name.trim().charAt(0) || '?'
|
||||
}
|
||||
|
||||
/** ISO 문자열/Date 를 한국어 상대시간으로 (예: "2시간 전", "어제", "3일 전") */
|
||||
export function relativeTimeKo(input: Date | string): string {
|
||||
const date = typeof input === 'string' ? new Date(input) : input
|
||||
if (Number.isNaN(date.getTime())) return ''
|
||||
const diffMs = Date.now() - date.getTime()
|
||||
const min = Math.floor(diffMs / 60_000)
|
||||
if (min < 1) return '방금'
|
||||
if (min < 60) return `${min}분 전`
|
||||
const hour = Math.floor(min / 60)
|
||||
if (hour < 24) return `${hour}시간 전`
|
||||
const day = Math.floor(hour / 24)
|
||||
if (day === 1) return '어제'
|
||||
if (day < 7) return `${day}일 전`
|
||||
const week = Math.floor(day / 7)
|
||||
if (week < 5) return `${week}주 전`
|
||||
return formatDate(date)
|
||||
}
|
||||
|
||||
/** 진행률 정보 (완료/전체 → 퍼센트·단계·라벨) */
|
||||
export interface ProgressInfo {
|
||||
pct: number
|
||||
level: 'done' | 'mid' | 'low'
|
||||
label: string
|
||||
}
|
||||
|
||||
/** 완료/전체 수로 진행률 계산 */
|
||||
export function progressOf(done: number, total: number): ProgressInfo {
|
||||
const pct = total > 0 ? Math.round((done / total) * 100) : 0
|
||||
const level: ProgressInfo['level'] = pct >= 90 ? 'done' : pct >= 40 ? 'mid' : 'low'
|
||||
const label = pct === 0 ? '시작 전' : `${pct}% 완료`
|
||||
return { pct, level, label }
|
||||
}
|
||||
Reference in New Issue
Block a user