84 lines
2.6 KiB
TypeScript
84 lines
2.6 KiB
TypeScript
import { t, locale, formatNumber } from '@/i18n'
|
|
export const MAX_IMAGE_BYTES = 10 * 1024 * 1024
|
|
|
|
export const ALLOWED_IMAGE_MIME_TYPES = ['image/png', 'image/jpeg', 'image/webp', 'image/svg+xml']
|
|
|
|
export const ALLOWED_IMAGE_EXTENSIONS = ['.png', '.jpg', '.jpeg', '.webp', '.svg']
|
|
|
|
export const IMAGE_TYPE_REJECTION_TEXT = 'Use a PNG, JPEG, WEBP or SVG image, up to 10 MB.'
|
|
|
|
export type ImageRejectionKind = 'type' | 'size'
|
|
|
|
export type ImageValidationResult = { ok: true } | { ok: false; kind: ImageRejectionKind }
|
|
|
|
export function fileExtension(filename: string) {
|
|
const index = filename.lastIndexOf('.')
|
|
return index === -1 ? '' : filename.slice(index).toLowerCase()
|
|
}
|
|
|
|
export function validateImageFile(file: File): ImageValidationResult {
|
|
if (file.size > MAX_IMAGE_BYTES) {
|
|
return { ok: false, kind: 'size' }
|
|
}
|
|
const typeAllowed = ALLOWED_IMAGE_MIME_TYPES.includes(file.type)
|
|
const extensionAllowed = ALLOWED_IMAGE_EXTENSIONS.includes(fileExtension(file.name))
|
|
if (!typeAllowed || !extensionAllowed) {
|
|
return { ok: false, kind: 'type' }
|
|
}
|
|
return { ok: true }
|
|
}
|
|
|
|
const EXTENSIONS_BY_MIME_TYPE: Record<string, string[]> = {
|
|
'image/png': ['.png'],
|
|
'image/jpeg': ['.jpg', '.jpeg'],
|
|
'image/webp': ['.webp'],
|
|
'image/svg+xml': ['.svg'],
|
|
}
|
|
|
|
export function extensionMatchesType(file: File) {
|
|
return EXTENSIONS_BY_MIME_TYPE[file.type]?.includes(fileExtension(file.name)) ?? false
|
|
}
|
|
|
|
export function formatMegabytes(bytes: number) {
|
|
const value = bytes / (1024 * 1024)
|
|
return locale.value === 'fr'
|
|
? formatNumber(value, {
|
|
minimumFractionDigits: 1,
|
|
maximumFractionDigits: 1,
|
|
})
|
|
: value.toFixed(1)
|
|
}
|
|
|
|
export function isSizeRejectionBody(body: string) {
|
|
return body.toLowerCase().includes('exceed')
|
|
}
|
|
|
|
export function rejectionTitle(filename: string) {
|
|
return t("\u0022{0}\u0022 can't be used", [filename])
|
|
}
|
|
|
|
export function sizeRejectionText(filename: string, bytes: number) {
|
|
return t('{0} is {1} MB. Images can be up to 10 MB.', [filename, formatMegabytes(bytes)])
|
|
}
|
|
|
|
export function formatWholeKB(bytes: number): string {
|
|
const kb = bytes / 1024
|
|
const rounded = Math.round(kb * 10) / 10
|
|
if (locale.value === 'fr')
|
|
return formatNumber(rounded, {
|
|
minimumFractionDigits: rounded === 0 ? 1 : 0,
|
|
maximumFractionDigits: 1,
|
|
})
|
|
if (rounded === 0) {
|
|
return '0.0'
|
|
}
|
|
return Number.isInteger(rounded) ? String(rounded) : rounded.toFixed(1)
|
|
}
|
|
|
|
export function formatUploadProgress(loadedBytes: number, totalBytes: number): string {
|
|
if (totalBytes < 1024 * 1024) {
|
|
return t('Uploading {0} of {1} KB', [formatWholeKB(loadedBytes), formatWholeKB(totalBytes)])
|
|
}
|
|
return t('Uploading {0} of {1} MB', [formatMegabytes(loadedBytes), formatMegabytes(totalBytes)])
|
|
}
|