feat(gyms): per-gym brand colour; CrossFit pill follows it
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
716eec9f6d
commit
4b2823d1e5
6 files changed
+47
-14
No files matched your search
@@ -41,7 +41,7 @@ function gym_defaults(): array {
|
||||
'slug' => '', 'name' => '', 'locality' => '', 'postal_code' => '', 'is_published' => 0,
|
||||
'is_default' => 0, 'sections' => null, 'hero_title' => '', 'hero_subtitle' => '',
|
||||
'hero_image' => '', 'seo_title' => '', 'seo_description' => '', 'gallery_id' => null,
|
||||
'google_place_id' => '', 'has_crossfit' => 0, 'item_order' => 0,
|
||||
'google_place_id' => '', 'has_crossfit' => 0, 'brand_color' => '', 'item_order' => 0,
|
||||
];
|
||||
}
|
||||
|
||||
@@ -103,6 +103,19 @@ function gym_section_on(array $gym, string $key): bool {
|
||||
return !is_array($list) || in_array($key, $list, true);
|
||||
}
|
||||
|
||||
// Brand colour of a gym as :root overrides for the public site. Derives the
|
||||
// hover shade, the text-on-light ink and the text colour that stays readable on
|
||||
// the colour (dark on light brands, white on dark ones). '' = stylesheet default.
|
||||
function gym_brand_css(array $gym): string {
|
||||
$hex = strtoupper((string) ($gym['brand_color'] ?? ''));
|
||||
if (!preg_match('/^#[0-9A-F]{6}$/', $hex)) return '';
|
||||
[$r, $g, $b] = [hexdec(substr($hex, 1, 2)), hexdec(substr($hex, 3, 2)), hexdec(substr($hex, 5, 2))];
|
||||
$shade = fn(float $k) => sprintf('#%02X%02X%02X', (int) round($r * $k), (int) round($g * $k), (int) round($b * $k));
|
||||
$lum = (0.2126 * $r + 0.7152 * $g + 0.0722 * $b) / 255;
|
||||
return ':root{--fitme-accent:' . $hex . ';--fitme-accent-rgb:' . "$r, $g, $b" . ';--fitme-accent-dark:' . $shade(.86)
|
||||
. ';--fitme-accent-ink:' . $shade($lum > .5 ? .5 : .85) . ';--fitme-on-accent:' . ($lum > .5 ? '#0B0B0D' : '#FFFFFF') . '}';
|
||||
}
|
||||
|
||||
function gym_url(array $gym, string $path = ''): string {
|
||||
return base_url(rawurlencode((string) $gym['slug']) . '/' . ltrim($path, '/'));
|
||||
}
|
||||
@@ -159,6 +172,7 @@ function gyms_from_post(PDO $pdo, array $post, array &$errors, ?int $id = null):
|
||||
'gallery_id' => (int) ($post['gallery_id'] ?? 0) ?: null,
|
||||
'google_place_id' => mb_substr(trim((string) ($post['google_place_id'] ?? '')), 0, 120),
|
||||
'has_crossfit' => !empty($post['has_crossfit']) ? 1 : 0,
|
||||
'brand_color' => strtoupper(trim((string) ($post['brand_color'] ?? ''))),
|
||||
'item_order' => (int) ($post['item_order'] ?? 0),
|
||||
];
|
||||
$on = array_values(array_intersect(array_keys(gym_sections()), (array) ($post['sections'] ?? [])));
|
||||
@@ -173,6 +187,9 @@ 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['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'])) {
|
||||
$errors[] = 'Imagem do header: caminho de uma imagem do site (ex.: site/assets/img/home.jpg).';
|
||||
@@ -183,15 +200,15 @@ function gyms_from_post(PDO $pdo, array $post, array &$errors, ?int $id = null):
|
||||
function _gyms_params(array $d): array {
|
||||
return [$d['slug'], $d['name'], $d['locality'], $d['postal_code'], $d['is_published'], $d['is_default'],
|
||||
$d['sections'], $d['hero_title'], $d['hero_subtitle'], $d['hero_image'], $d['seo_title'],
|
||||
$d['seo_description'], $d['gallery_id'], $d['google_place_id'], $d['has_crossfit'], $d['item_order']];
|
||||
$d['seo_description'], $d['gallery_id'], $d['google_place_id'], $d['has_crossfit'], $d['brand_color'], $d['item_order']];
|
||||
}
|
||||
|
||||
function db_gyms_create(PDO $pdo, array $d): int {
|
||||
$pdo->beginTransaction();
|
||||
$pdo->prepare("INSERT INTO gyms (slug, name, locality, postal_code, is_published, is_default, sections,
|
||||
hero_title, hero_subtitle, hero_image, seo_title, seo_description, gallery_id,
|
||||
google_place_id, has_crossfit, item_order, created_at, updated_at)
|
||||
VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?, NOW(), NOW())")->execute(_gyms_params($d));
|
||||
google_place_id, has_crossfit, brand_color, item_order, created_at, updated_at)
|
||||
VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?, NOW(), NOW())")->execute(_gyms_params($d));
|
||||
$id = (int) $pdo->lastInsertId();
|
||||
if ($d['is_default']) $pdo->prepare("UPDATE gyms SET is_default = 0 WHERE id <> ?")->execute([$id]);
|
||||
// Its own contacts row (id = gym id), starting from the gym's name.
|
||||
@@ -211,7 +228,7 @@ function db_gyms_update(PDO $pdo, int $id, array $d): bool {
|
||||
$st = $pdo->prepare("UPDATE gyms SET slug = ?, name = ?, locality = ?, postal_code = ?, is_published = ?,
|
||||
is_default = ?, sections = ?, hero_title = ?, hero_subtitle = ?, hero_image = ?,
|
||||
seo_title = ?, seo_description = ?, gallery_id = ?, google_place_id = ?,
|
||||
has_crossfit = ?, item_order = ?, updated_at = NOW()
|
||||
has_crossfit = ?, brand_color = ?, item_order = ?, updated_at = NOW()
|
||||
WHERE id = ?");
|
||||
$st->execute($params);
|
||||
$changed = $st->rowCount() > 0;
|
||||
|
||||
Reference in new issue
Block a user