Files
lunarfront-app/packages/admin/src/components/storage/file-icons.tsx
Ryan Moon 0f6cc104d2 Add shared file storage with folder tree, permissions, and file manager UI
New document hub for centralized file storage — replaces scattered
drives and USB sticks for non-technical SMBs. Three new tables:
storage_folder (nested hierarchy), storage_folder_permission (role
and user-level access control), storage_file.

Backend: folder CRUD with nested paths, file upload/download via
signed URLs, permission checks (view/edit/admin with inheritance
from parent folders), public/private toggle, breadcrumb navigation,
file search.

Frontend: two-panel file manager — collapsible folder tree on left,
icon grid view on right. Folder icons by type, file size display,
upload button, context menu for download/delete. Breadcrumb nav.
Files sidebar link added.
2026-03-29 15:31:20 -05:00

30 lines
1.6 KiB
TypeScript

import { FileText, Image, FileSpreadsheet, File, FileType, Film } from 'lucide-react'
const ICON_MAP: Record<string, { icon: typeof FileText; color: string }> = {
'application/pdf': { icon: FileText, color: 'text-red-500' },
'image/jpeg': { icon: Image, color: 'text-blue-500' },
'image/png': { icon: Image, color: 'text-blue-500' },
'image/webp': { icon: Image, color: 'text-blue-500' },
'image/gif': { icon: Image, color: 'text-blue-500' },
'application/vnd.openxmlformats-officedocument.wordprocessingml.document': { icon: FileType, color: 'text-blue-600' },
'application/msword': { icon: FileType, color: 'text-blue-600' },
'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet': { icon: FileSpreadsheet, color: 'text-green-600' },
'application/vnd.ms-excel': { icon: FileSpreadsheet, color: 'text-green-600' },
'text/csv': { icon: FileSpreadsheet, color: 'text-green-600' },
'text/plain': { icon: FileText, color: 'text-muted-foreground' },
'video/mp4': { icon: Film, color: 'text-purple-500' },
}
export function FileIcon({ contentType, className = 'h-8 w-8' }: { contentType: string; className?: string }) {
const match = ICON_MAP[contentType] ?? { icon: File, color: 'text-muted-foreground' }
const Icon = match.icon
return <Icon className={`${className} ${match.color}`} />
}
export function formatFileSize(bytes: number): string {
if (bytes < 1024) return `${bytes} B`
if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`
if (bytes < 1024 * 1024 * 1024) return `${(bytes / (1024 * 1024)).toFixed(1)} MB`
return `${(bytes / (1024 * 1024 * 1024)).toFixed(1)} GB`
}