export function formatFileSize(bytes) { if (bytes == null || bytes < 0) return '—' if (bytes === 0) return '0 B' const units = ['B', 'KB', 'MB', 'GB'] const i = Math.min(Math.floor(Math.log(bytes) / Math.log(1024)), units.length - 1) const val = bytes / Math.pow(1024, i) return (i === 0 ? val.toFixed(0) : val.toFixed(1)) + ' ' + units[i] } const mimeLabels = { 'image/jpeg': 'Изображение JPEG', 'image/png': 'Изображение PNG', 'image/gif': 'Изображение GIF', 'image/webp': 'Изображение WebP', 'image/svg+xml': 'Изображение SVG', 'image/bmp': 'Изображение BMP', 'image/tiff': 'Изображение TIFF', 'image/avif': 'Изображение AVIF', 'application/pdf': 'PDF документ', 'application/msword': 'Документ Word', 'application/vnd.openxmlformats-officedocument.wordprocessingml.document': 'Документ Word', 'application/vnd.ms-excel': 'Таблица Excel', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet': 'Таблица Excel', 'application/vnd.ms-powerpoint': 'Презентация PowerPoint', 'application/vnd.openxmlformats-officedocument.presentationml.presentation': 'Презентация PowerPoint', 'application/zip': 'ZIP архив', 'application/gzip': 'GZIP архив', 'application/x-tar': 'TAR архив', 'application/x-7z-compressed': '7z архив', 'application/x-rar-compressed': 'RAR архив', 'text/plain': 'Текстовый файл', 'text/html': 'HTML файл', 'text/css': 'CSS файл', 'text/javascript': 'JavaScript файл', 'application/json': 'JSON файл', 'application/xml': 'XML файл', 'application/x-yaml': 'YAML файл', 'application/octet-stream': 'Бинарный файл', 'application/x-msdos-program': 'Исполняемый файл', 'inode/directory': 'Папка', } export function formatMimeType(mime) { if (!mime) return 'Неизвестно' return mimeLabels[mime] || mime } export function formatFileType(item) { if (item.type === 'folder') return 'Папка' const mime = (item.mime || '').toLowerCase() if (mimeLabels[mime]) return mimeLabels[mime] const name = (item.name || '').toLowerCase() const ext = name.split('.').pop() if (ext) return ext.toUpperCase() return 'Файл' } export function getFileKind(item) { if (item.type === 'folder') return 'folder' const mime = (item.mime || '').toLowerCase() if (mime.startsWith('image/')) return 'image' if (mime.startsWith('video/')) return 'video' if (mime.startsWith('audio/')) return 'audio' if (mime.startsWith('text/')) return 'text' if (mime.includes('pdf')) return 'pdf' if (mime.includes('word') || mime.includes('document')) return 'document' if (mime.includes('spreadsheet') || mime.includes('excel')) return 'spreadsheet' if (mime.includes('presentation') || mime.includes('powerpoint')) return 'presentation' if (mime.includes('zip') || mime.includes('tar') || mime.includes('gzip') || mime.includes('rar') || mime.includes('7z') || mime.includes('compress')) return 'archive' if (mime.includes('json') || mime.includes('xml') || mime.includes('yaml') || mime.includes('javascript') || mime.includes('css') || mime.includes('html')) return 'code' const name = (item.name || '').toLowerCase() const ext = name.split('.').pop() const codeExts = ['js','ts','jsx','tsx','vue','svelte','py','rs','go','c','cpp','h','hpp','java','kt','swift','rb','php','pl','sh','bash','zsh','fish','yml','yaml','json','xml','toml','ini','cfg','conf','md','markdown','css','scss','less','sass','sql','graphql','proto','gradle','cmake','makefile','dockerfile','env','gitignore'] if (codeExts.includes(ext)) return 'code' return 'generic' } const imageMimes = ['image/jpeg','image/png','image/gif','image/webp','image/bmp','image/tiff','image/avif','image/svg+xml'] const textMimes = ['text/plain','text/html','text/css','text/javascript','application/json','application/xml','application/x-yaml','text/x-shellscript'] const codeNames = ['txt','log','conf','ini','yaml','yml','json','xml','csv','sh','py','js','ts','css','html','md','markdown','cfg'] const imageExts = ['jpg','jpeg','png','gif','webp','bmp','tiff','tif','avif','svg'] export function canPreviewFile(item) { if (item.type === 'folder') return false const mime = (item.mime || '').toLowerCase() const name = (item.name || '').toLowerCase() const ext = name.split('.').pop() if (imageMimes.includes(mime) || imageExts.includes(ext)) return true if (mime.includes('pdf')) return true if (textMimes.includes(mime) || codeNames.includes(ext)) return true return false } export function isImageFile(item) { const mime = (item.mime || '').toLowerCase() const name = (item.name || '').toLowerCase() const ext = name.split('.').pop() return imageMimes.includes(mime) || imageExts.includes(ext) } export function isTextFile(item) { const mime = (item.mime || '').toLowerCase() const name = (item.name || '').toLowerCase() const ext = name.split('.').pop() return textMimes.includes(mime) || (codeNames.includes(ext) && ext !== 'md' && ext !== 'markdown') } export function isPdfFile(item) { return (item.mime || '').toLowerCase().includes('pdf') } export function isMarkdownFile(item) { const name = (item.name || '').toLowerCase() return name.endsWith('.md') || name.endsWith('.markdown') } export function needsBase64Preview(item) { return isImageFile(item) || isPdfFile(item) } export function needsTextPreview(item) { return isTextFile(item) || isMarkdownFile(item) }