Files
verstak/frontend/src/lib/fileUtils.js
T
mirv 2fa583d157 stabilization: server.go split + i18n templates + frontend localization
cmd/verstak-server/server.go (2838→127 строк): разделён на 12 файлов
- config.go, tokens.go, schema.go
- server.go (только struct + NewServer + ListenAndServe)
- routes.go, middleware.go, smtp.go
- handlers_api.go, handlers_user.go, handlers_web_user.go, handlers_admin.go
- templates.go (конвертирован в функции с i18n.T())

frontend: все русские строки заменены на t() вызовы
- App.svelte, FileTreeRow.svelte, ConfirmModal.svelte
- FilePreviewModal.svelte, fileUtils.js

core: gofmt по всему проекту

Все сборки (CLI, server, gui, frontend), go vet, go test проходят.
check-i18n.sh: frontend чист, Go-файлы с кириллицей — только тесты/легаси.
2026-06-02 11:08:29 +08:00

127 lines
5.3 KiB
JavaScript

import { t } from './i18n'
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': t('mime.jpeg'),
'image/png': t('mime.png'),
'image/gif': t('mime.gif'),
'image/webp': t('mime.webp'),
'image/svg+xml': t('mime.svg'),
'image/bmp': t('mime.bmp'),
'image/tiff': t('mime.tiff'),
'image/avif': t('mime.avif'),
'application/pdf': t('mime.pdf'),
'application/msword': t('mime.word'),
'application/vnd.openxmlformats-officedocument.wordprocessingml.document': t('mime.word'),
'application/vnd.ms-excel': t('mime.excel'),
'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet': t('mime.excel'),
'application/vnd.ms-powerpoint': t('mime.ppt'),
'application/vnd.openxmlformats-officedocument.presentationml.presentation': t('mime.ppt'),
'application/zip': t('mime.zip'),
'application/gzip': t('mime.gzip'),
'application/x-tar': t('mime.tar'),
'application/x-7z-compressed': t('mime.sevenz'),
'application/x-rar-compressed': t('mime.rar'),
'text/plain': t('mime.text'),
'text/html': t('mime.html'),
'text/css': t('mime.css'),
'text/javascript': t('mime.js'),
'application/json': t('mime.json'),
'application/xml': t('mime.xml'),
'application/x-yaml': t('mime.yaml'),
'application/octet-stream': t('mime.binary'),
'application/x-msdos-program': t('mime.executable'),
'inode/directory': t('mime.folder'),
}
export function formatMimeType(mime) {
if (!mime) return t('mime.unknown')
return mimeLabels[mime] || mime
}
export function formatFileType(item) {
if (item.type === 'folder') return t('mime.folder')
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 t('mime.file')
}
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)
}