diff --git a/ASSETS.md b/ASSETS.md new file mode 100644 index 0000000..d0c6ddd --- /dev/null +++ b/ASSETS.md @@ -0,0 +1,39 @@ +# Assets de front-end desta app + +Estado real a 25/09/2026 (auditoria em `CLAUDE_GITEA/audits/fitme3070-auditoria-2026-09-24.html`, +ponto 7.4). Não segue ainda a convenção da frota (`shared/platform-tools/ASSETS.md`): sem +Composer, sem versão no nome das pastas, duas bibliotecas em duplicado. + +## O que está vendorizado e onde + +| Biblioteca | Versão | Caminho | Usado em | +|------------------------|--------|----------------------------------------|----------------------| +| Bootstrap | 4.3.1 (EOL) | `assets/vendor/bootstrap/` | Site público | +| Bootstrap | 5.3.3 | `assets/vendor/bootstrap5/` | Backoffice | +| Bootstrap Icons | — | `assets/vendor/bootstrap-icons/` | Backoffice | +| jQuery | 3.7.1 | `assets/vendor/jquery/jquery-3.7.1.min.js` | Backoffice | +| jQuery | 3.7.1 | `site/assets/js/jquery-3.7.1.min.js` | Site público (cópia idêntica, pasta diferente) | +| Font Awesome Free | 5.13.1 | `site/assets/fonts/fontawesome/` | Site público (~18 MB, todo o pacote) | +| PHPMailer | 7.1.1 | `vendor/PHPMailer/` | Envio de email (`config/functions_mail.php`) | + +Nenhuma pasta tem a versão no nome; para confirmar a versão real de cada uma, ver os comentários +de cabeçalho dos `.min.css`/`.min.js` ou `VERSION`/`const VERSION` no caso do PHPMailer. + +## Porque não segue a convenção da frota + +- **Sem Composer** (ver ponto 7.1 da auditoria): o PHPMailer devia vir de `composer require + phpmailer/phpmailer` e copiar-se o ficheiro final para vendor/, não ser colado à mão. +- **Duas versões de Bootstrap no mesmo projeto** porque o site público nunca migrou para o 5; até + lá, as duas cópias mantêm-se (o backoffice não pode regredir para o 4). +- **jQuery duplicado** em `assets/vendor/` e `site/assets/js/` — mesma versão, cópia + desnecessária; devia ser um só ficheiro partilhado pelos dois lados. +- **Google Fonts ainda vem de CDN** (`site/includes/include.php`) — pendente self-hosting do + Roboto (ver [[fitme-audit-2026-09]] na memória do projeto, "Pending for André"). + +## Antes de adicionar ou atualizar uma biblioteca + +1. Preferir Composer sempre que o pacote exista (ver a convenção da frota). +2. Sem Composer: descarregar uma vez, commitar, e nomear a pasta com a versão + (`vendor/-/`), não um nome genérico. +3. Nunca duplicar a mesma versão em duas pastas — importar de um único sítio. +4. Atualizar esta tabela. diff --git a/config/functions_info.php b/config/functions_info.php index b97918b..eec7713 100644 --- a/config/functions_info.php +++ b/config/functions_info.php @@ -43,6 +43,11 @@ function info_from_post(array $post, array &$errors): array { function db_info_save(PDO $pdo, array $data): bool { $cols = array_keys(info_fields()); + foreach ($cols as $c) { + if (!preg_match('/^[A-Za-z0-9_]+$/', $c)) { + throw new InvalidArgumentException("Nome de coluna inválido: $c"); + } + } // One row per gym (id = gyms.id): the gym being edited in the backoffice. $gid = admin_gym_id(); $__before = audit_row($pdo, 'fitme3070_info', 'id', (int) $gid); diff --git a/config/functions_site.php b/config/functions_site.php index 9cd08fc..93eba77 100644 --- a/config/functions_site.php +++ b/config/functions_site.php @@ -194,5 +194,5 @@ function modalidade_icon_html(?string $icon): string { return $svg; } } - return ''; + return ''; } diff --git a/site/assets/css/style.css b/site/assets/css/style.css index 0eb608d..3aeef9b 100644 --- a/site/assets/css/style.css +++ b/site/assets/css/style.css @@ -53,7 +53,7 @@ --fitme-shadow: 0 2px 20px rgba(11, 11, 13, .07); --fitme-shadow-lg: 0 8px 40px rgba(11, 11, 13, .13); --fitme-radius: 2px; - --fitme-transition: 0.25s ease; + --fitme-transition: 0.15s ease; } /* ── Bootstrap 4 Overrides ─────────────────────────────────────────────────── */ @@ -449,7 +449,7 @@ section[id] { /* ── Hero ──────────────────────────────────────────────────────────────────── */ .hero-section { position: relative; - min-height: 100vh; + min-height: 100dvh; display: flex; align-items: center; justify-content: center; @@ -1968,7 +1968,7 @@ h3.contact-title { /* Hero */ .hero-section { min-height: max(100svh, 500px); - min-height: max(100vh, 500px); + min-height: max(100dvh, 500px); } .hero-text { @@ -2576,7 +2576,7 @@ h3.contact-title { max-width: 540px; min-height: 0; margin: 0 auto; - max-height: calc(100vh - 48px); + max-height: calc(100dvh - 48px); flex-direction: row; clip-path: none; transform: none; @@ -2600,7 +2600,7 @@ h3.contact-title { .md-card .ib-icon { width: 60px; height: 60px; margin-bottom: .8rem; } .md-card h3 { font-size: .95rem; } .md-body, - .md-flip .md-body { max-height: calc(100vh - 48px); padding: 16px 16px 16px 14px; transform: none; } + .md-flip .md-body { max-height: calc(100dvh - 48px); padding: 16px 16px 16px 14px; transform: none; } } @media (max-width: 339px) { @@ -3127,7 +3127,7 @@ h3.contact-title { text-align: center; font-size: .85rem; font-weight: 600; - color: #0B0B0D; + color: var(--fitme-text); background: #ffd84d; } @@ -3538,7 +3538,7 @@ h3.contact-title { max-width: 560px; min-height: 0; margin: 0 auto; - max-height: calc(100vh - 48px); + max-height: calc(100dvh - 48px); flex-direction: row; clip-path: none; transform: none; @@ -3561,7 +3561,7 @@ h3.contact-title { .td-photo { flex-basis: 34%; border-width: 3px; } .td-photo img { min-height: 180px; } .td-body, - .td-flip .td-body { max-height: calc(100vh - 48px); padding: 16px 16px 16px 14px; transform: none; } + .td-flip .td-body { max-height: calc(100dvh - 48px); padding: 16px 16px 16px 14px; transform: none; } } @media (max-width: 339px) { @@ -4196,7 +4196,7 @@ h3.contact-title { /* Lightbox */ .gal-lightbox { width: 100vw; - height: 100vh; + height: 100dvh; max-width: none; max-height: none; margin: 0; @@ -4219,7 +4219,7 @@ h3.contact-title { .gal-lb-figure { margin: 0; max-width: calc(100vw - 140px); - max-height: calc(100vh - 80px); + max-height: calc(100dvh - 80px); display: flex; flex-direction: column; align-items: center; @@ -4227,7 +4227,7 @@ h3.contact-title { .gal-lb-figure img { max-width: 100%; - max-height: calc(100vh - 110px); + max-height: calc(100dvh - 110px); object-fit: contain; border-radius: var(--fitme-radius); box-shadow: 0 20px 60px rgba(0, 0, 0, .5); diff --git a/site/gym_chooser.php b/site/gym_chooser.php index 480827c..9ca48e4 100644 --- a/site/gym_chooser.php +++ b/site/gym_chooser.php @@ -36,7 +36,7 @@ $brand = 'FitMe';
- <?= htmlspecialchars($brand) ?> + <?= htmlspecialchars($brand) ?>

Escolhe o teu ginásio

diff --git a/site/includes/crossfit_badge.php b/site/includes/crossfit_badge.php index f850557..1e53bc1 100644 --- a/site/includes/crossfit_badge.php +++ b/site/includes/crossfit_badge.php @@ -4,7 +4,7 @@
-

CrossFit Journal: The Performance-Based Lifestyle Resource

+

CrossFit Journal: The Performance-Based Lifestyle Resource

diff --git a/site/includes/header_video.php b/site/includes/header_video.php index d296ce1..fa5d8ee 100644 --- a/site/includes/header_video.php +++ b/site/includes/header_video.php @@ -7,7 +7,7 @@
-

CrossFit 3070 — box de CrossFit em Mira

+

CrossFit 3070 — box de CrossFit em Mira

diff --git a/site/includes/horario.php b/site/includes/horario.php index 9e9ac22..e96490c 100644 --- a/site/includes/horario.php +++ b/site/includes/horario.php @@ -69,7 +69,7 @@ foreach ($rows as $d) { $grid[$d['dia_semana']][$d['hora_inicio']][] = $d; }
- <?= htmlspecialchars((string) $d['nome']) ?> + <?= htmlspecialchars((string) $d['nome']) ?>
diff --git a/site/includes/include.php b/site/includes/include.php index 3f8cafd..4bd8c70 100644 --- a/site/includes/include.php +++ b/site/includes/include.php @@ -41,7 +41,7 @@ $canonical = $GLOBALS['_canonical_override'] ?? match ($page) { <?= htmlspecialchars($page_title) ?> - + @@ -51,7 +51,7 @@ $canonical = $GLOBALS['_canonical_override'] ?? match ($page) { - + @@ -72,7 +72,7 @@ $canonical = $GLOBALS['_canonical_override'] ?? match ($page) { - + diff --git a/site/includes/navbar.php b/site/includes/navbar.php index d4d4904..0e8712d 100644 --- a/site/includes/navbar.php +++ b/site/includes/navbar.php @@ -10,7 +10,7 @@ else