feat: image variants settings screens

This commit is contained in:
fsylvain committed 2026-10-08 13:57:41 +02:00
1 parent f1d56ef50e
commit f567866161
42 files changed
+7192 -11

No files matched your search

+93
View File
@@ -0,0 +1,93 @@
import { formatNumber, t } from '@/i18n'
import type { ImageVariant, VariantFit, VariantFormat } from '@/composables/useImageVariants'
const BYTES_PER_KB = 1024
const BYTES_PER_MB = BYTES_PER_KB * 1024
const KB_PER_MB = 1024
const MB_PER_GB = 1024
const NO_QUALITY = '—'
const SEPARATOR = ' · '
function oneDecimal(value: number) {
return Math.round(value * 10) / 10
}
export function formatVariantSize(bytes: number) {
const kilobytes = Math.round(bytes / BYTES_PER_KB)
if (bytes === 0) {
return t('{0} KB', [0])
}
if (kilobytes < KB_PER_MB) {
return t('{0} KB', [Math.max(1, kilobytes)])
}
const megabytes = bytes / BYTES_PER_MB
if (megabytes < MB_PER_GB) {
return t('{0} MB', [oneDecimal(megabytes)])
}
return t('{0} GB', [oneDecimal(megabytes / MB_PER_GB)])
}
export function formatDimensions(width: number | null, height: number | null) {
if (width !== null && height !== null) {
return `${width}×${height}`
}
if (width !== null) {
return `${width} × ${t('auto')}`
}
return `${t('auto')} × ${height ?? ''}`
}
export function formatLabel(format: VariantFormat) {
const labels: Record<VariantFormat, string> = {
webp: 'WebP',
jpeg: 'JPEG',
png: 'PNG',
original: t('Original'),
}
return labels[format]
}
export function fitLabel(fit: VariantFit) {
const labels: Record<VariantFit, string> = {
cover: t('cover'),
contain: t('contain'),
inside: t('inside'),
}
return labels[fit]
}
function hasQuality(variant: Pick<ImageVariant, 'format' | 'quality'>) {
return variant.format !== 'png' && variant.quality !== null
}
export function qualityCell(variant: Pick<ImageVariant, 'format' | 'quality'>) {
return hasQuality(variant) ? String(variant.quality) : NO_QUALITY
}
export function specLine(variant: ImageVariant) {
const parts = [
formatDimensions(variant.width, variant.height),
fitLabel(variant.fit),
formatLabel(variant.format),
]
if (hasQuality(variant)) {
parts.push(t('q{0}', [variant.quality ?? 0]))
}
return parts.join(SEPARATOR)
}
export function generatedLine(variant: ImageVariant) {
return t('{0} generated · {1}', [
formatNumber(variant.generated_files),
formatVariantSize(variant.cache_size),
])
}
export function variantsSummary(items: readonly ImageVariant[]) {
const files = items.reduce((total, item) => total + item.generated_files, 0)
const bytes = items.reduce((total, item) => total + item.cache_size, 0)
const variants = items.length === 1 ? t('1 variant') : t('{0} variants', [items.length])
const generated =
files === 1 ? t('1 generated file') : t('{0} generated files', [formatNumber(files)])
return [variants, generated, formatVariantSize(bytes)].join(SEPARATOR)
}