Commit Graph
18 Commits
Author SHA1 Message Date
andre 725f5b9c26 feat(site): per-gym SEO texts, event gym selector, hero/navbar polish
- Generated SEO titles/descriptions per gym; gym seo fields override each on its own
- Keywords, author, og:site_name, favicon and JSON-LD logo follow the gym
- CrossFit page 404s before output for gyms without a box
- Events: «Mostrar em» gym selector; event page uses its gym's brand
- Hero event button text colour from the event colour (--ev-on)
- Navbar bottom line stops at the other-gym head (--switch-w)
- Diagonal hero blur mask; remove the trial link
2026-10-26 12:15:37 +00:00
andre 2e8b6d20f6 style(navbar): smaller centred logo, hero clears the bar, liquid-glass backdrop 2026-10-26 11:34:11 +00:00
andre 4f44bc1609 feat(images): JPEG XL optimizer with webp/jpg fallback and <picture> serving
img_optimize() decodes .jxl with djxl or Imagick, resizes with GD, re-encodes
with cjxl and writes foto.jxl.webp beside it; skips cleanly without a decoder.
Gallery, hero, navbar logos and JSON-LD serve the JXL with the fallback, and
trash/removal move the fallback with its .jxl.
2026-10-26 11:18:13 +00:00
andreandClaude Sonnet 5.5 a2219ebd63 style(site): apply tuned grain from the lab (freq 1.98, 1 octave, overlay on buttons, 155px tile)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-13 19:01:18 +01:00
andre 18676ad6d0 feat(icons): load Bootstrap Icons and Font Awesome from the shared platform-tools packs
Register the icons packs in platform_connect, add fit_icon_assets() with local
fallback, and add a sysadmin 'Pacotes de icones' link to platform?tool=icons.
2026-10-13 18:55:12 +01:00
andreandClaude Sonnet 5.5 781a3a324e style(site): subtler noise (buttons slightly, headings 50%)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-13 18:52:15 +01:00
andreandClaude Sonnet 5.5 18556ca8b9 style(site): noise texture on buttons and h1/h2 lettering
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-13 18:51:17 +01:00
andreandClaude Sonnet 5.5 4b2823d1e5 feat(gyms): per-gym brand colour; CrossFit pill follows it
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-13 17:08:30 +01:00
andreandClaude Sonnet 5.5 b73c23bf55 feat(dev): environment ribbon and one-click dev login on the public site and auth pages
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-13 16:56:40 +01:00
andreandClaude Fable 5 c5c4a818f2 fix(contraste+fontes): verde de texto legível em fundo claro e Roboto auto-hospedado
Contraste (auditoria 4.8, WCAG AA):
- Novo token --fitme-accent-ink #667000 (≈5.1:1 sobre #F7F8FA), aplicado aos 7
  usos de texto que estavam em --fitme-accent-dark (#A6B600 ≈2.1:1 em fundo claro).
  O --fitme-accent-dark mantém-se para fundos de botões em hover/active (onde tem
  texto escuro por cima — escurecê-lo quebraria esses estados).
- .section-eyebrow passa a usar o ink green nas secções claras (oferta, galeria,
  modalidades, horário, workhours); as secções escuras mantêm o verde vivo.

Fontes (CSS "Google Fonts ainda carregado do CDN"):
- Roboto (variável, latin, 43 KB woff2) em site/assets/fonts/roboto/.
- @font-face 100-900 em style.css; removidos os <link> para fonts.googleapis.com
  em include.php e gym_chooser.php. Ficam apenas os pedidos à API do Places
  (legítimos, server-side).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-09-25 23:22:06 +01:00
andreandClaude Sonnet 5 1e2068bea2 feat(css): site público passa de Bootstrap 4.3.1 (EOL) para 5.3.3
Auditoria: "Site público em Bootstrap 4.3.1 (EOL); backoffice em
5.3.3" — o backoffice já usa a 5.3.3 vendorizada (assets/vendor/bootstrap5/),
o site público passa a usar a mesma cópia em vez da 4.3.1.

Levantamento antes de mexer: a folha de estilo própria (style.css)
quase não usa classes utilitárias cruas do Bootstrap (grep confirma
zero ml-/mr-/pl-/pr-/float-left/float-right/custom-select/
custom-control/badge-/sr-only/font-weight-/text-left/text-right —
tudo classes próprias como .site-btn). O que precisava de mudar:

- CSS/JS: assets/vendor/bootstrap/ -> assets/vendor/bootstrap5/
  (bundle, inclui Popper).
- Os 7 atributos data-toggle/data-target/data-dismiss (BS4) ->
  data-bs-toggle/data-bs-target/data-bs-dismiss (BS5): toggle da nav
  mobile, os dois modais (aula experimental, inscrição), o botão de
  fechar do alerta. O seletor em main.js que lê data-target também
  mudou para não parar de encontrar os botões.
- .close -> .btn-close (BS5 renomeou o componente; markup sem o
  &times; interno, que o BS5 desenha via CSS).
- .form-row -> .row (BS4 tinha form-row com gutters menores; BS5 não
  tem, style.css não tinha overrides para form-row, confirmado).
- O apanhado maior: dois <script> inline chamavam
  jQuery('#trialModal').modal('show') ao estilo de plugin jQuery do
  BS4 (para reabrir o modal depois de um erro de submissão) — o BS5
  não regista plugins jQuery nenhuns, isto ficava morto em silêncio.
  Trocado por new bootstrap.Modal(...).show(), a API JS nativa do
  BS5. grep confirma zero outras chamadas .modal()/.collapse()/etc.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-25 21:47:15 +01:00
andreandClaude Sonnet 5 5cf0f14ad2 fix: correções Baixo da auditoria (escaping, dvh, transições, assets)
Fecha os itens 3.2.2, 3.3.1, 4.6, 5.2, 5.6, 5.7 e 7.4 do relatório de
auditoria de 2026-09-24: escapa saídas de site_img_url()/canonical,
valida identificadores de coluna em db_info_save(), troca 100vh por
100dvh, remove a última cor solta, encurta a transição para ~150ms,
acrescenta decoding=async/fetchpriority=high nas imagens da home, e
documenta as versões vendorizadas em ASSETS.md.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-25 12:16:33 +01:00
andreandClaude Opus 5.5 b202262da0 feat(rgpd): política de privacidade e termos, mapa a pedido, fotos locais, retenção, tema claro/escuro
- Política de privacidade reescrita: tabela de dados/finalidades/fundamento
  (inclui os pedidos de aula, inscrição e eventos com IP), prazos concretos,
  subcontratantes, Google Maps e reviews, cookies. Termos e condições novos
  (/home/termos), no rodapé e no sitemap. Campos [ENTRE PARÊNTESES RETOS]
  e revisão por jurista pendentes antes de publicar no domínio real.
- Google Maps só carrega ao carregar em «Mostrar mapa» (map_click_to_load);
  as fotos dos autores das reviews são guardadas pelo servidor em
  uploads/reviews/ e servidas localmente (review_avatar_url).
- Retenção que a política declara, aplicada pelo cron (04:00): leads com
  mais de 12 meses → lixeira; blocked_submissions e outbox de segurança
  apagados aos 90 dias (trash_retention_sweep, auditado).
- Backoffice e login com tema claro/escuro/automático: data-bs-theme
  aplicado no <head> antes do CSS (sem flash), escolha em localStorage,
  segue o sistema em tempo real, color-scheme e theme-color para os dois.
  Cores próprias passaram a variáveis do Bootstrap. lang="pt-PT".

Testado numa cópia da BD de produção: 72/72 verificações.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-25 11:39:05 +01:00
andreandClaude Opus 5.5 5e300fc341 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>
2026-09-25 07:26:40 +01:00
andreandClaude Opus 5.5 d70f13aea0 feat(galeria): masonry em JS com lightbox, em vez do slider
- «Conhece as nossas instalações» (e a galeria do CrossFit) passa de slider
  Splide a masonry: layout próprio em JS (sem biblioteca), fotos com a
  proporção original, coluna mais baixa primeiro e algumas a ocupar duas
  colunas (só quando não deixam buraco). Reorganiza ao mudar de largura
  (ResizeObserver + resize) e as fotos entram em cascata ao aparecer.
  Sem JS fica uma grelha CSS.
- Clicar abre a foto num <dialog>: anterior/seguinte, setas, Esc, deslizar.
- O Splide deixa de ser carregado (CSS e JS).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-25 07:05:25 +01:00
andreandClaude Opus 5.5 8ebf20f52f feat: horário em 3 dias, horário de funcionamento compacto, textura na equipa, estrutura/SEO
- Horário de aulas: cartões mais pequenos e estreitos; a partir de 992px mostra
  o dia anterior, hoje ao centro e o seguinte (a dar a volta à semana), com as
  horas alinhadas e os dias laterais esbatidos. O JPG continua a semana toda.
- Horário de funcionamento: cartões compactos numa <dl>, ordenados por hora.
- Equipa: fundo no cinzento da parede do ginásio com juntas de blocos e grão
  muito discretos (SVG inline).
- Tira o «FitMe 3070» do header e esconde a newsletter.
- Estrutura: um <main> em todas as páginas públicas (skip link aponta-lhe),
  h2 por secção com aria-labelledby, h3 nos itens em vez de h4, sem secções
  aninhadas, alts distintos na galeria e no h1 do CrossFit.
- robots.txt e sitemap.xml gerados com o domínio da instalação; SEO_NOINDEX
  no .env tira uma cópia de staging dos motores de pesquisa.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-24 21:46:21 +01:00
andre 3e3382df57 idk 2026-06-12 21:20:23 +01:00
andreandClaude Opus 4.8 e68d357177 Initial import of fitme3070.pt platform
Plain-PHP fleet platform with id.andmore.pt SSO. Wires shared/platform-tools
as a submodule (platform_update, backups, git/migration tools) like the other
platforms.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-12 10:44:58 +01:00