/** Small presentation helpers shared by the chat attachment chips/thumbnails. */ /** Human-readable byte size, e.g. 2048 -> "2 KB", 1536000 -> "1.5 MB". */ export function formatBytes(bytes: number): string { if (!Number.isFinite(bytes) || bytes < 0) return '' if (bytes < 1024) return `${bytes} B` const units = ['KB', 'MB', 'GB', 'TB'] let value = bytes / 1024 let i = 0 while (value >= 1024 && i < units.length - 1) { value /= 1024 i++ } const rounded = value >= 10 || Number.isInteger(value) ? Math.round(value) : Math.round(value * 10) / 10 return `${rounded} ${units[i]}` } const IMAGE_EXT = /\.(png|jpe?g|gif|webp|avif|bmp|svg|heic|heif)$/i /** Whether a filename or content-type looks like a previewable image. */ export function isImageName(nameOrType: string | undefined | null): boolean { if (!nameOrType) return false return nameOrType.startsWith('image/') || IMAGE_EXT.test(nameOrType) }