feat: image upload on articles

This commit is contained in:
fsylvain committed 2026-09-28 02:28:20 +02:00
1 parent d4fcfb2bba
commit 938263cd6a
12 files changed
+1436 -65

No files matched your search

+44
View File
@@ -0,0 +1,44 @@
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 }
}
export function formatMegabytes(bytes: number) {
return (bytes / (1024 * 1024)).toFixed(1)
}
export function isSizeRejectionBody(body: string) {
return body.toLowerCase().includes('exceed')
}
export function rejectionTitle(filename: string) {
return `"${filename}" can't be used`
}
export function sizeRejectionText(filename: string, bytes: number) {
return `${filename} is ${formatMegabytes(bytes)} MB. Images can be up to 10 MB.`
}