feat(gyms): show gym logos in navbar buttons and brand; accept JPEG XL uploads
This commit is contained in:
1 parent
a85bec6851
commit
d445ba64b9
7 files changed
+51
-18
No files matched your search
@@ -116,6 +116,14 @@ function gym_brand_vars(array $gym): string {
|
||||
. ';--fitme-accent-ink:' . $shade($lum > .5 ? .5 : .85) . ';--fitme-on-accent:' . ($lum > .5 ? '#0B0B0D' : '#FFFFFF');
|
||||
}
|
||||
|
||||
// The gym's logo (relative path). The main gym falls back to the site's own
|
||||
// FitMe 3070 logo, so its navbar button has one before anything is uploaded.
|
||||
function gym_logo(array $gym): string {
|
||||
$logo = (string) ($gym['logo'] ?? '');
|
||||
if ($logo === '' && !empty($gym['is_default'])) $logo = 'site/assets/img/logos/logo_black.svg';
|
||||
return $logo;
|
||||
}
|
||||
|
||||
function gym_brand_css(array $gym): string {
|
||||
$v = gym_brand_vars($gym);
|
||||
return $v === '' ? '' : ':root{' . $v . '}';
|
||||
@@ -205,14 +213,14 @@ function gyms_from_post(PDO $pdo, array $post, array &$errors, ?int $id = null):
|
||||
$other = db_gyms_by_slug($pdo, $slug);
|
||||
if ($other && (int) $other['id'] !== (int) $id) $errors[] = 'Já existe um ginásio com essa pasta da URL.';
|
||||
}
|
||||
if ($data['logo'] !== '' && !preg_match('~^(site/assets/img|uploads)/[A-Za-z0-9_./ -]+\.(svg|png|webp|jpe?g)$~i', $data['logo'])) {
|
||||
if ($data['logo'] !== '' && !preg_match('~^(site/assets/img|uploads)/[A-Za-z0-9_./ -]+\.(svg|png|webp|jpe?g|jxl)$~i', $data['logo'])) {
|
||||
$errors[] = 'Logótipo: imagem inválida.';
|
||||
}
|
||||
if ($data['brand_color'] !== '' && !preg_match('/^#[0-9A-F]{6}$/', $data['brand_color'])) {
|
||||
$errors[] = 'Cor da marca: formato #RRGGBB (ex.: #C2D500).';
|
||||
}
|
||||
if ($data['is_default'] && !$data['is_published']) $errors[] = 'O ginásio principal tem de estar publicado.';
|
||||
if ($data['hero_image'] !== '' && !preg_match('~^(site/assets/img|uploads)/[A-Za-z0-9_./ -]+\.(jpe?g|png|webp)$~i', $data['hero_image'])) {
|
||||
if ($data['hero_image'] !== '' && !preg_match('~^(site/assets/img|uploads)/[A-Za-z0-9_./ -]+\.(jpe?g|png|webp|jxl)$~i', $data['hero_image'])) {
|
||||
$errors[] = 'Imagem do header: imagem inválida.';
|
||||
}
|
||||
return $data;
|
||||
@@ -283,10 +291,10 @@ function gyms_save_image(array $file, string $kind, ?string &$error = null): ?st
|
||||
return null;
|
||||
}
|
||||
if (($file['size'] ?? 0) > 6 * 1024 * 1024) { $error = 'máximo 6 MB.'; return null; }
|
||||
$allowed = $kind === 'hero' ? ['jpg', 'jpeg', 'png', 'webp'] : ['svg', 'png', 'webp', 'jpg', 'jpeg'];
|
||||
$allowed = $kind === 'hero' ? ['jpg', 'jpeg', 'png', 'webp', 'jxl'] : ['svg', 'png', 'webp', 'jpg', 'jpeg', 'jxl'];
|
||||
$ext = upload_image_ext($file, $allowed);
|
||||
if ($ext === null) {
|
||||
$error = $kind === 'hero' ? 'usa JPG, PNG ou WebP.' : 'usa SVG, PNG, WebP ou JPG (SVG sem scripts).';
|
||||
$error = $kind === 'hero' ? 'usa JPG, PNG, WebP ou JPEG XL.' : 'usa SVG, PNG, WebP, JPG ou JPEG XL (SVG sem scripts).';
|
||||
return null;
|
||||
}
|
||||
$dir = gyms_upload_dir();
|
||||
|
||||
@@ -39,6 +39,15 @@ function upload_image_ext(array $file, array $allowed): ?string {
|
||||
}
|
||||
$raster = ['image/jpeg' => 'jpg', 'image/png' => 'png', 'image/gif' => 'gif', 'image/webp' => 'webp'];
|
||||
|
||||
// JPEG XL: o getimagesize()/GD não o conhecem e o finfo só nas versões
|
||||
// recentes, por isso vê-se pela assinatura (codestream FF 0A ou contentor
|
||||
// ISOBMFF "JXL "). Só entra onde quem chama pôs 'jxl' em $allowed; o
|
||||
// img_optimize() salta-o (não há GD para JXL).
|
||||
if (in_array('jxl', $allowed, true)) {
|
||||
$head = (string) @file_get_contents($tmp, false, null, 0, 12);
|
||||
if (str_starts_with($head, "\xFF\x0A") || $head === "\x00\x00\x00\x0CJXL \x0D\x0A\x87\x0A") return 'jxl';
|
||||
}
|
||||
|
||||
if (isset($raster[$mime]) || $mime === '') {
|
||||
$info = @getimagesize($tmp);
|
||||
$ext = $info ? ($raster[$info['mime']] ?? null) : null;
|
||||
|
||||
Reference in new issue
Block a user