mirror of
https://github.com/Sendouc/sendou.ink.git
synced 2026-09-30 15:17:43 -05:00
62 lines
1.8 KiB
TypeScript
62 lines
1.8 KiB
TypeScript
import * as v from "valibot";
|
|
import { id } from "~/utils/schema";
|
|
|
|
/** The client compresses to webp, but browsers without canvas webp encoding (Safari, Brave) silently fall back to png. */
|
|
const IMAGE_FIELD_DATA_URL_PREFIX_REGEX = /^data:image\/(webp|png);base64,/;
|
|
|
|
/** Caps the JSON body size; a `thick-banner` webp base64-encodes to ~200KB, so this leaves comfortable headroom. */
|
|
const IMAGE_FIELD_MAX_DATA_URL_LENGTH = 3_000_000;
|
|
|
|
/** `null` (none / removed), an unchanged `EXISTING` image (id + preview url, never bytes), or a `NEW` base64 webp/png data URL. */
|
|
export const imageValue = v.nullable(
|
|
v.union([
|
|
v.object({
|
|
type: v.literal("EXISTING"),
|
|
imgId: id,
|
|
url: v.string(),
|
|
}),
|
|
v.object({
|
|
type: v.literal("NEW"),
|
|
dataUrl: v.pipe(
|
|
v.string(),
|
|
v.maxLength(IMAGE_FIELD_MAX_DATA_URL_LENGTH),
|
|
v.regex(IMAGE_FIELD_DATA_URL_PREFIX_REGEX),
|
|
),
|
|
}),
|
|
]),
|
|
);
|
|
|
|
export type ImageFieldValue = v.InferOutput<typeof imageValue>;
|
|
|
|
/** `EXISTING` {@link ImageFieldValue} for an edit form's defaults, or `null` when the id or preview url is missing. */
|
|
export function existingImage(
|
|
imgId: number | null | undefined,
|
|
url: string | null | undefined,
|
|
): ImageFieldValue {
|
|
return imgId && url ? { type: "EXISTING", imgId, url } : null;
|
|
}
|
|
|
|
export type ImageFieldDimensions =
|
|
| "logo"
|
|
| "thick-banner"
|
|
| { width: number; height: number };
|
|
|
|
const IMAGE_FIELD_DIMENSION_PRESETS = {
|
|
logo: { width: 400, height: 400 },
|
|
"thick-banner": { width: 1000, height: 500 },
|
|
} as const;
|
|
|
|
/** Resolves an `image` field's `dimensions` (preset name or explicit numbers) to a `{ width, height }`. */
|
|
export function resolveImageFieldDimensions(
|
|
dimensions?: ImageFieldDimensions,
|
|
): {
|
|
width: number;
|
|
height: number;
|
|
} {
|
|
if (!dimensions || typeof dimensions === "string") {
|
|
return IMAGE_FIELD_DIMENSION_PRESETS[dimensions ?? "logo"];
|
|
}
|
|
|
|
return dimensions;
|
|
}
|