formatEnumLabel was leaving inputs uppercase ("TECHNOLOGY_INNOVATION"
became "TECHNOLOGY INNOVATION"); lowercasing first yields proper
title case ("Technology Innovation") and improves labels app-wide.
Apply it on the project mentor page for Ocean Issue + Category.
95 lines
2.6 KiB
TypeScript
95 lines
2.6 KiB
TypeScript
import { type ClassValue, clsx } from 'clsx'
|
|
import { twMerge } from 'tailwind-merge'
|
|
|
|
export function cn(...inputs: ClassValue[]) {
|
|
return twMerge(clsx(inputs))
|
|
}
|
|
|
|
export function formatDate(date: Date | string): string {
|
|
return new Intl.DateTimeFormat('en-US', {
|
|
dateStyle: 'medium',
|
|
timeStyle: 'short',
|
|
}).format(new Date(date))
|
|
}
|
|
|
|
export function formatDateOnly(date: Date | string): string {
|
|
return new Intl.DateTimeFormat('en-US', {
|
|
dateStyle: 'long',
|
|
}).format(new Date(date))
|
|
}
|
|
|
|
export function truncate(str: string, length: number): string {
|
|
if (str.length <= length) return str
|
|
return str.slice(0, length) + '...'
|
|
}
|
|
|
|
export function getInitials(name: string): string {
|
|
return name
|
|
.split(' ')
|
|
.map((n) => n[0])
|
|
.join('')
|
|
.toUpperCase()
|
|
.slice(0, 2)
|
|
}
|
|
|
|
export function slugify(str: string): string {
|
|
return str
|
|
.toLowerCase()
|
|
.replace(/[^\w\s-]/g, '')
|
|
.replace(/[\s_-]+/g, '-')
|
|
.replace(/^-+|-+$/g, '')
|
|
}
|
|
|
|
export function formatFileSize(bytes: number): string {
|
|
if (bytes === 0) return '0 Bytes'
|
|
const k = 1024
|
|
const sizes = ['Bytes', 'KB', 'MB', 'GB']
|
|
const i = Math.floor(Math.log(bytes) / Math.log(k))
|
|
return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i]
|
|
}
|
|
|
|
export function formatEnumLabel(value: string): string {
|
|
return value
|
|
.toLowerCase()
|
|
.replace(/_/g, ' ')
|
|
.replace(/\b\w/g, (c) => c.toUpperCase())
|
|
}
|
|
|
|
export function daysUntil(date: Date | string): number {
|
|
const target = new Date(date)
|
|
const now = new Date()
|
|
return Math.ceil((target.getTime() - now.getTime()) / (1000 * 60 * 60 * 24))
|
|
}
|
|
|
|
const CATEGORY_LABELS: Record<string, string> = {
|
|
STARTUP: 'Start-up',
|
|
BUSINESS_CONCEPT: 'Business Concept',
|
|
}
|
|
|
|
export function formatCategory(category: string | null | undefined): string {
|
|
if (!category) return ''
|
|
return CATEGORY_LABELS[category] ?? category.replace(/_/g, ' ')
|
|
}
|
|
|
|
export function formatRelativeTime(date: Date | string): string {
|
|
const now = new Date()
|
|
const target = new Date(date)
|
|
const diffMs = now.getTime() - target.getTime()
|
|
const diffSec = Math.floor(diffMs / 1000)
|
|
const diffMin = Math.floor(diffSec / 60)
|
|
const diffHour = Math.floor(diffMin / 60)
|
|
const diffDay = Math.floor(diffHour / 24)
|
|
const diffWeek = Math.floor(diffDay / 7)
|
|
|
|
if (diffSec < 60) return 'just now'
|
|
if (diffMin < 60) return `${diffMin}m ago`
|
|
if (diffHour < 24) return `${diffHour}h ago`
|
|
if (diffDay < 7) return `${diffDay}d ago`
|
|
if (diffWeek < 4) return `${diffWeek}w ago`
|
|
|
|
return new Intl.DateTimeFormat('en-US', {
|
|
month: 'short',
|
|
day: 'numeric',
|
|
}).format(target)
|
|
}
|