feat: vários ginásios (/3070/ e /<código postal>/), CRUD de ginásios, modalidades após a galeria
Estrutura multi-ginásio: as mesmas secções do site, conteúdo próprio por ginásio, e cada um numa pasta da URL com o código postal da zona. - migration_20260926_gyms: tabela gyms (pasta, nome, localidade, publicado, principal, secções visíveis, título/imagem do header, SEO, galeria, Place ID, página CrossFit) com o FitMe 3070 como ginásio 1 em /3070/; gym_id em team, modalidades (o horário segue a modalidade), work_hours, memberships, membership_leads e website_offer (tudo o existente → ginásio 1); events com gym_id NULL = todos; fitme3070_info passa a uma linha por ginásio (id = gym). - Site: /<pasta>/, /<pasta>/crossfit, /<pasta>/agendar|inscricao. Ginásio por publicar → 404 para o público, pré-visualização (com faixa) para a equipa. / e /home → 301 para o ginásio principal (a manter a query); com mais de um ginásio publicado, a raiz passa a uma página para escolher. Secções desligadas não aparecem nem no menu; menu, canonical, JSON-LD, sitemap, formulários, e-mails e reviews (Place ID e cache) são do ginásio. - Backoffice: Gestão → Ginásios (criar/editar/apagar, secções, e «começar com o conteúdo de» outro ginásio — cópias independentes) e o seletor «A editar» no topo; equipa, modalidades, horários, horário de funcionamento, mensalidades, pedidos, contactos e reviews trabalham sobre o ginásio escolhido, e um registo de outro ginásio não abre. - Modalidades passam para logo a seguir à galeria das instalações. - Galeria sem cantos arredondados (raio da marca). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
2f8f68c61a
commit
5e300fc341
33 files changed
+1146
-197
No files matched your search
@@ -0,0 +1,52 @@
|
||||
<?php
|
||||
// Root page when more than one gym is published (site/index.php includes this
|
||||
// instead of redirecting): pick a gym. Self-contained — no gym is "current"
|
||||
// here, so it doesn't go through _open.php. Expects $pdo and $published.
|
||||
$gyms = $published ?? db_gyms_published($pdo);
|
||||
$brand = 'FitMe';
|
||||
?><!doctype html>
|
||||
<html lang="pt">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title><?= htmlspecialchars($brand) ?> — Escolhe o teu ginásio</title>
|
||||
<meta name="description" content="<?= htmlspecialchars($brand) ?>: <?= htmlspecialchars(implode(', ', array_map(fn($g) => $g['name'] . ($g['locality'] !== '' ? ' (' . $g['locality'] . ')' : ''), $gyms))) ?>.">
|
||||
<link rel="canonical" href="<?= htmlspecialchars(base_url()) ?>">
|
||||
<?php if (seo_noindex()): ?><meta name="robots" content="noindex, nofollow"><?php endif; ?>
|
||||
<link href="https://fonts.googleapis.com/css?family=Roboto:400,700,900&display=swap" rel="stylesheet">
|
||||
<link rel="icon" type="image/svg+xml" href="<?= base_url('site/assets/img/logos/logo_black.svg') ?>">
|
||||
<style>
|
||||
:root { --accent:#C2D500; --dark:#0B0B0D; --dark2:#16181A; --ash:#B8B9BE; }
|
||||
* { box-sizing: border-box; }
|
||||
body { margin:0; min-height:100svh; font-family:Roboto,system-ui,sans-serif; color:#fff;
|
||||
background:#141517 url('<?= base_url('site/assets/img/home.jpg') ?>') center/cover fixed; }
|
||||
.wrap { min-height:100svh; background:rgba(11,11,13,.82); display:flex; flex-direction:column;
|
||||
align-items:center; justify-content:center; padding:48px 16px; gap:36px; }
|
||||
h1 { margin:0; font-size:clamp(1.8rem,4vw,2.6rem); font-weight:900; text-transform:uppercase; text-align:center; }
|
||||
h1 span { color:var(--accent); }
|
||||
.gyms { display:flex; flex-wrap:wrap; gap:18px; justify-content:center; width:100%; max-width:900px; }
|
||||
a.gym { flex:1 1 260px; max-width:320px; display:block; padding:28px 24px; border-radius:8px; text-decoration:none;
|
||||
color:#fff; background:var(--dark2); border:2px solid rgba(255,255,255,.08);
|
||||
transition:border-color .25s, transform .25s; }
|
||||
a.gym:hover, a.gym:focus-visible { border-color:var(--accent); transform:translateY(-4px); outline:none; }
|
||||
.gym strong { display:block; font-size:1.4rem; font-weight:900; text-transform:uppercase; }
|
||||
.gym span { color:var(--ash); }
|
||||
.gym em { display:inline-block; margin-top:14px; font-style:normal; font-weight:700; color:var(--accent); }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<main class="wrap">
|
||||
<img src="<?= base_url('site/assets/img/logos/logo_black.svg') ?>" alt="<?= htmlspecialchars($brand) ?>" style="width:170px;filter:invert(1)">
|
||||
<h1>Escolhe o teu <span>ginásio</span></h1>
|
||||
<div class="gyms">
|
||||
<?php foreach ($gyms as $g): ?>
|
||||
<a class="gym" href="<?= htmlspecialchars(gym_url($g)) ?>">
|
||||
<strong><?= htmlspecialchars($g['name']) ?></strong>
|
||||
<?php if ($g['locality'] !== ''): ?><span><?= htmlspecialchars($g['locality']) ?></span><?php endif; ?>
|
||||
<br><em>Entrar →</em>
|
||||
</a>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
</main>
|
||||
</body>
|
||||
</html>
|
||||
Reference in new issue
Block a user