155 lines
4.0 KiB
TypeScript
155 lines
4.0 KiB
TypeScript
import { t } from '@/i18n'
|
|
import type {
|
|
ImageVariant,
|
|
NewVariantRequest,
|
|
VariantDefinition,
|
|
VariantFit,
|
|
VariantFormat,
|
|
} from '@/composables/useImageVariants'
|
|
|
|
export const NAME_MAX_LENGTH = 32
|
|
const DIMENSION_MIN = 1
|
|
const DIMENSION_MAX = 8000
|
|
export const QUALITY_MIN = 1
|
|
export const QUALITY_MAX = 100
|
|
const DEFAULT_QUALITY = 80
|
|
|
|
const NAME_PATTERN = /^[a-z0-9-]{2,32}$/
|
|
const WHOLE_NUMBER = /^\d+$/
|
|
|
|
export type FieldName = 'name' | 'width' | 'height' | 'quality'
|
|
|
|
export interface VariantFormValues {
|
|
name: string
|
|
width: string
|
|
height: string
|
|
fit: VariantFit
|
|
format: VariantFormat
|
|
quality: string
|
|
generateOnUpload: boolean
|
|
enabled: boolean
|
|
}
|
|
|
|
export type FieldErrors = Partial<Record<FieldName, string>> & { dimension?: string }
|
|
|
|
export const FIELD_ORDER: FieldName[] = ['name', 'width', 'height', 'quality']
|
|
|
|
export const VARIANT_TEMPLATES = [
|
|
{ name: 'thumb', width: 400, height: 300, quality: 80 },
|
|
{ name: 'hero', width: 1200, height: 630, quality: 82 },
|
|
] as const
|
|
|
|
export function blankValues(): VariantFormValues {
|
|
return {
|
|
name: '',
|
|
width: '',
|
|
height: '',
|
|
fit: 'cover',
|
|
format: 'original',
|
|
quality: String(DEFAULT_QUALITY),
|
|
generateOnUpload: false,
|
|
enabled: true,
|
|
}
|
|
}
|
|
|
|
export function valuesFromTemplate(
|
|
template: (typeof VARIANT_TEMPLATES)[number],
|
|
): VariantFormValues {
|
|
return {
|
|
...blankValues(),
|
|
name: template.name,
|
|
width: String(template.width),
|
|
height: String(template.height),
|
|
format: 'webp',
|
|
quality: String(template.quality),
|
|
}
|
|
}
|
|
|
|
export function valuesFromVariant(variant: ImageVariant): VariantFormValues {
|
|
return {
|
|
name: variant.name,
|
|
width: variant.width === null ? '' : String(variant.width),
|
|
height: variant.height === null ? '' : String(variant.height),
|
|
fit: variant.fit,
|
|
format: variant.format,
|
|
quality: String(variant.quality ?? DEFAULT_QUALITY),
|
|
generateOnUpload: variant.generate_on_upload,
|
|
enabled: variant.enabled,
|
|
}
|
|
}
|
|
|
|
export function hasChanged(current: VariantFormValues, initial: VariantFormValues) {
|
|
return (Object.keys(initial) as (keyof VariantFormValues)[]).some(
|
|
(key) => current[key] !== initial[key],
|
|
)
|
|
}
|
|
|
|
export function usesQuality(format: VariantFormat) {
|
|
return format !== 'png'
|
|
}
|
|
|
|
function wholeNumberInRange(text: string, min: number, max: number) {
|
|
const trimmed = text.trim()
|
|
if (!WHOLE_NUMBER.test(trimmed)) {
|
|
return null
|
|
}
|
|
const value = Number(trimmed)
|
|
return value >= min && value <= max ? value : null
|
|
}
|
|
|
|
export function parseDimension(text: string) {
|
|
return wholeNumberInRange(text, DIMENSION_MIN, DIMENSION_MAX)
|
|
}
|
|
|
|
function parseQuality(text: string) {
|
|
return wholeNumberInRange(text, QUALITY_MIN, QUALITY_MAX)
|
|
}
|
|
|
|
export function validateField(field: FieldName, values: VariantFormValues): string | undefined {
|
|
if (field === 'name') {
|
|
return NAME_PATTERN.test(values.name)
|
|
? undefined
|
|
: t('Use lowercase letters, numbers and dashes, 2 to 32 characters.')
|
|
}
|
|
if (field === 'quality') {
|
|
return !usesQuality(values.format) || parseQuality(values.quality) !== null
|
|
? undefined
|
|
: t('Enter a value from 1 to 100.')
|
|
}
|
|
const text = values[field]
|
|
return text.trim() === '' || parseDimension(text) !== null
|
|
? undefined
|
|
: t('Enter a value from 1 to 8000.')
|
|
}
|
|
|
|
export function lacksDimension(values: VariantFormValues) {
|
|
return values.width.trim() === '' && values.height.trim() === ''
|
|
}
|
|
|
|
export function sliderValue(text: string) {
|
|
const parsed = Number.parseInt(text, 10)
|
|
if (Number.isNaN(parsed)) {
|
|
return QUALITY_MIN
|
|
}
|
|
return Math.min(QUALITY_MAX, Math.max(QUALITY_MIN, parsed))
|
|
}
|
|
|
|
export function toDefinition(values: VariantFormValues): VariantDefinition {
|
|
const definition: VariantDefinition = {
|
|
width: parseDimension(values.width),
|
|
height: parseDimension(values.height),
|
|
fit: values.fit,
|
|
format: values.format,
|
|
generate_on_upload: values.generateOnUpload,
|
|
enabled: values.enabled,
|
|
}
|
|
if (usesQuality(values.format)) {
|
|
definition.quality = parseQuality(values.quality) ?? DEFAULT_QUALITY
|
|
}
|
|
return definition
|
|
}
|
|
|
|
export function toNewVariant(values: VariantFormValues): NewVariantRequest {
|
|
return { name: values.name, ...toDefinition(values) }
|
|
}
|