mirror of
https://github.com/lukaszraczylo/claude-mnemonic.git
synced 2026-06-11 00:09:28 +00:00
Initial commit
This commit is contained in:
@@ -0,0 +1,87 @@
|
||||
/**
|
||||
* Format a timestamp as relative time (e.g., "5m ago", "2h ago")
|
||||
*/
|
||||
export function formatRelativeTime(dateOrEpoch: string | number): string {
|
||||
const timestamp = typeof dateOrEpoch === 'number' ? dateOrEpoch : new Date(dateOrEpoch).getTime()
|
||||
const now = Date.now()
|
||||
const diff = now - timestamp
|
||||
|
||||
const seconds = Math.floor(diff / 1000)
|
||||
const minutes = Math.floor(seconds / 60)
|
||||
const hours = Math.floor(minutes / 60)
|
||||
const days = Math.floor(hours / 24)
|
||||
|
||||
if (seconds < 60) return 'just now'
|
||||
if (minutes < 60) return `${minutes}m ago`
|
||||
if (hours < 24) return `${hours}h ago`
|
||||
if (days < 7) return `${days}d ago`
|
||||
|
||||
return new Date(timestamp).toLocaleDateString()
|
||||
}
|
||||
|
||||
/**
|
||||
* Format uptime duration string
|
||||
*/
|
||||
export function formatUptime(uptimeStr: string): string {
|
||||
// Parse Go duration string (e.g., "1h30m45.123456789s")
|
||||
const match = uptimeStr.match(/(?:(\d+)h)?(?:(\d+)m)?(?:(\d+(?:\.\d+)?)s)?/)
|
||||
if (!match) return uptimeStr
|
||||
|
||||
const hours = parseInt(match[1] || '0', 10)
|
||||
const minutes = parseInt(match[2] || '0', 10)
|
||||
const seconds = Math.floor(parseFloat(match[3] || '0'))
|
||||
|
||||
if (hours > 0) {
|
||||
return `${hours}h ${minutes}m`
|
||||
}
|
||||
if (minutes > 0) {
|
||||
return `${minutes}m ${seconds}s`
|
||||
}
|
||||
return `${seconds}s`
|
||||
}
|
||||
|
||||
/**
|
||||
* Truncate text to a maximum length with ellipsis
|
||||
*/
|
||||
export function truncate(text: string, maxLength: number): string {
|
||||
if (text.length <= maxLength) return text
|
||||
return text.slice(0, maxLength - 3) + '...'
|
||||
}
|
||||
|
||||
/**
|
||||
* Escape HTML entities
|
||||
*/
|
||||
export function escapeHtml(text: string): string {
|
||||
const map: Record<string, string> = {
|
||||
'&': '&',
|
||||
'<': '<',
|
||||
'>': '>',
|
||||
'"': '"',
|
||||
"'": '''
|
||||
}
|
||||
return text.replace(/[&<>"']/g, m => map[m])
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse JSON safely with fallback
|
||||
*/
|
||||
export function parseJsonSafe<T>(value: unknown, fallback: T): T {
|
||||
if (Array.isArray(value)) return value as T
|
||||
if (typeof value === 'string') {
|
||||
try {
|
||||
return JSON.parse(value) as T
|
||||
} catch {
|
||||
return fallback
|
||||
}
|
||||
}
|
||||
return fallback
|
||||
}
|
||||
|
||||
/**
|
||||
* Get string value safely from potentially nullable fields
|
||||
*/
|
||||
export function getString(value: unknown): string {
|
||||
if (typeof value === 'string') return value
|
||||
if (value === null || value === undefined) return ''
|
||||
return String(value)
|
||||
}
|
||||
Reference in New Issue
Block a user