import { z } from "zod"; export const defaultGlowColor = "#ffe6a1"; export const profileAvatarBucket = "minegeo-avatars"; export const profileAvatarMaxBytes = 5 * 1024 * 1024; export const profileAvatarMimeTypes = [ "image/jpeg", "image/png", "image/webp", ] as const; export const glowColorSchema = z .string() .regex(/^#[a-fA-F0-9]{6}$/, "Choose a valid glow color") .transform((color) => color.toLowerCase()); export const prefixIcons = [ "star", "crown", "heart", "flame", "gem", "trophy", "sparkles", ] as const; export type PrefixIcon = (typeof prefixIcons)[number]; export const customPrefixSchema = z .string() .trim() .min(1) .max(24) .refine( (value) => !/[\u0000-\u001f\u007f-\u009f\u202a-\u202e\u2066-\u2069<>]/u.test(value), "Use a prefix of 1–24 characters without hidden controls or markup", ); export const prefixUpdateSchema = z .object({ prefix: customPrefixSchema.nullable(), icon: z.enum(prefixIcons) }) .strict(); export type ProfileAppearance = { avatar_path?: string | null; profile_effect?: string | null; name_glow?: boolean; glow_color?: string; role?: string; bug_finder?: boolean; custom_prefix?: string | null; custom_prefix_icon?: string; }; export const appearanceColumns = "avatar_path,profile_effect,name_glow,glow_color,role,bug_finder,custom_prefix,custom_prefix_icon" as const; export type BadgeUser = ProfileAppearance & { id: string; display_name: string; }; export function glowColor(value?: string) { return glowColorSchema.safeParse(value).data ?? defaultGlowColor; } export function profileAvatarUrl(path?: string | null) { const base = process.env.NEXT_PUBLIC_SUPABASE_URL?.replace(/\/$/, ""); if (!base || !path) return null; const encodedPath = path.split("/").map(encodeURIComponent).join("/"); return `${base}/storage/v1/object/public/${profileAvatarBucket}/${encodedPath}`; }