first commit

This commit is contained in:
2026-06-16 17:12:08 +09:00
commit e1bc5a1dfc
257 changed files with 49823 additions and 0 deletions
+77
View File
@@ -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 }
}