import { fileExtension, isImageMimeType } from '@dorfteich/shared'; /** Human-readable byte size (binary units) for the file listings (#61). */ export function formatBytes(bytes: number): string { if (bytes < 1024) return `${bytes} B`; const units = ['KiB', 'MiB', 'GiB', 'TiB']; let value = bytes / 1024; let unit = 0; while (value >= 1024 && unit < units.length - 1) { value /= 1024; unit += 1; } return `${value.toFixed(value < 10 ? 1 : 0)} ${units[unit]}`; } /** * A tiny emoji glyph standing in for a file-type icon (no icon asset pipeline * yet) — enough to tell an image, a document, a spreadsheet, and an archive * apart at a glance in the attachment lists. */ export function fileGlyph(fileName: string, mimeType: string): string { if (isImageMimeType(mimeType) || mimeType === 'image/svg+xml') return '🖼️'; const ext = fileExtension(fileName); if (ext === 'pdf') return '📕'; if (['doc', 'docx', 'odt', 'rtf', 'txt', 'md'].includes(ext)) return '📄'; if (['xls', 'xlsx', 'ods', 'csv'].includes(ext)) return '📊'; if (['ppt', 'pptx', 'odp'].includes(ext)) return '📽️'; if (['zip'].includes(ext)) return '🗜️'; return '📎'; } /** The permission-checked download URL for an attachment (ADR 0011). */ export const mediaUrl = (fileId: string): string => `/api/v1/media/${fileId}`;