mirror of
https://github.com/fsolla/teqo.git
synced 2026-11-12 22:13:05 +00:00
feat(PUB5): slogan 'Mais saúde mais futuro' no hero e rodapé
This commit is contained in:
parent
346da3896e
commit
cc374ea7eb
8 changed files with 70 additions and 11 deletions
|
|
@ -4,6 +4,8 @@ Conteúdo movido do `AGENTS.md` em 2026-07-30 (fatiamento do paradigma de agente
|
|||
|
||||
---
|
||||
|
||||
**PUB5** — slogan da campanha "Mais saúde mais futuro" no hero e no rodapé da home (jorgesolla1313.com.br), no lugar de "Um mandato do tamanho da Bahia" (discurso do mandato vigente; o novo é da campanha 2026 — saúde é o tema-âncora do candidato). Troca de copy cirúrgica, sem redesenho nem migration: h1 do hero em duas linhas uppercase "MAIS SAÚDE / MAIS FUTURO" com `aria-label` acompanhando ("MAIS SAÚDE MAIS FUTURO"), segunda linha já em `font-black` (anatomia existente), e o rodapé em sentence case com ponto ("Mais saúde mais futuro."). Testes que pinavam a string antiga atualizados (`campaignHero.unit`, `campaignHome.unit`, `frontend.e2e`). Fora de escopo decidido no gate: cabeçalho de artigos ("O mandato do tamanho da Bahia") e docs históricos. Verificação: unit 2269 + int 791 verdes, e2e frontend 8/8 em prod mode (`E2E_PROD=1`, `.next-e2e`), lint/format/typecheck/cycles/knip/build verdes; render conferido por screenshot + DOM (hero duas linhas, rodapé com ponto). `/simplify` 3 reviewers: sem P0/P1; P2 corrigidos no impl plan (redação + line refs); débitos descartados por serem convenções pré-existentes ou decisões do gate.
|
||||
|
||||
**Recently resolved (2026-08-17):** **OPS51** — o banco de produção saiu do Neon para o Postgres do homeserver (`teqo_1313`, container `teqo-1313`), sem mudança de config: o `~/stack/teqo-1313.env` já apontava para o banco preparado (criado 16/08 com role própria + cadeia completa de 56 migrations + zero conteúdo — verificado), então restaurar = a produção "apareceu" no container. **Divergência deliberada da intenção (questão A/B validada como B):** rejeitado criar `teqo_prod` novo — o argumento "o banco do 1313 tem vida própria" não se sustenta (o site 1313 É a produção deste repo) e o OPS53 já trata `teqo_1313` como produção. Execução 100% no homeserver (PII nunca tocou a workstation): URL do Neon puxada do Vercel (`vercel env pull`, projeto `jorgesolla`, `DATABASE_URL_UNPOOLED` → `NEON_DATABASE_URL` em `~/stack/.env` chmod 600), `pg_dump -Fc` (Neon PG 17.10) → `/srv/hdd/backups/teqo-neon-pre-migracao/teqo-neon-full-20260817-204800.dump` (5,8 MB, sha256 `f12196f2…`), `pg_restore --no-owner --no-privileges` como a role `teqo_1313` (drop schema + grant, padrão do `db-pull`), verificado: contagens por tabela idênticas ao Neon (1919 contatos, 39 posts, 1487 assinaturas, 1484 subscrições, 35 campaign_users, 392 lideranças, 2 pledges, 435 municípios, 6 atividades; supporter segue 0 — blocker LGPD ainda de pé), sequences no topo (`last_value == max(id)`), objetos com dono `teqo_1313`, `payload migrate` no-op (56 = 56, serviço de maintenance `teqo-1313-migrate`), 3 credenciais WebAuthn + 34 sessions + 5 chaves Consent restauradas (RP ID não mudou — biometria segue valendo). Smoke sem deploy: `/`, artigo com conteúdo restaurado, `/campanha/login`, `/admin`, `POST /api/revalidate` (`posts` + `global_privacy-policy`), WebAuthn `login-options`, barreira 307 sem sessão — verdes; smoke de browser (login, biometria, convites) validado manualmente. **Rollback documentado:** Neon nunca foi escrito (só lido); voltar = re-apontar `DATABASE_URL` do `teqo-1313.env` para o Neon + `compose up -d`. **Débito registrado (→ OPS52):** as 40 rows de `media` têm URLs relativas (`/api/media/file/…`) sem arquivos em lugar nenhum — capas dão 500 no homeserver e **404 no próprio Vercel/produção atual** (estado pré-existente; migração manteve paridade). Repo: plano da intenção concluído, `AGENTS.md` e help de `db:pull`/`check-push-chain` sem a referência ao Neon; infra-solla `STATE.md` atualizado à parte.
|
||||
|
||||
**Recently resolved (2026-08-16):** **CAMPAIGN-HOME-RESPONSIVE**: a primeira dobra da home pública agora acompanha as referências do Penpot em 393, 768, 1024, 1280, 1366 e 1920 px. Retrato, aliados, marca, texto, CTAs e prova parlamentar interpolam entre os tamanhos com `clamp()`, `vw` e `dvh`, sem saltos por proporção de tela nem overflow horizontal; texto, ações e condecorações permanecem no fluxo e crescem com os ajustes de espaçamento da WCAG 1.4.12. No desktop, a escala e a posição horizontal das fotos dependem somente da largura: Solla, Lula e Wagner ficam ancorados ao rodapé real do hero até quando o conteúdo aumenta a seção, e um palco centralizado de 1920 px preserva a proximidade entre retrato e texto em monitores ultrawide. O E2E fixa a geometria das seis referências, larguras intermediárias, transições de proporção, desktops baixos, ultrawide e os overrides de acessibilidade; o caso de regressão também foi executado no Firefox. Sem migration, schema ou mudança de conteúdo.
|
||||
|
|
|
|||
1
docs/changelog/2026-08-17-pub5.md
Normal file
1
docs/changelog/2026-08-17-pub5.md
Normal file
|
|
@ -0,0 +1 @@
|
|||
**PUB5** — slogan da campanha "Mais saúde mais futuro" no hero e no rodapé da home (jorgesolla1313.com.br), no lugar de "Um mandato do tamanho da Bahia" (discurso do mandato vigente; o novo é da campanha 2026 — saúde é o tema-âncora do candidato). Troca de copy cirúrgica, sem redesenho nem migration: h1 do hero em duas linhas uppercase "MAIS SAÚDE / MAIS FUTURO" com `aria-label` acompanhando ("MAIS SAÚDE MAIS FUTURO"), segunda linha já em `font-black` (anatomia existente), e o rodapé em sentence case com ponto ("Mais saúde mais futuro."). Testes que pinavam a string antiga atualizados (`campaignHero.unit`, `campaignHome.unit`, `frontend.e2e`). Fora de escopo decidido no gate: cabeçalho de artigos ("O mandato do tamanho da Bahia") e docs históricos. Verificação: unit 2269 + int 791 verdes, e2e frontend 8/8 em prod mode (`E2E_PROD=1`, `.next-e2e`), lint/format/typecheck/cycles/knip/build verdes; render conferido por screenshot + DOM (hero duas linhas, rodapé com ponto). `/simplify` 3 reviewers: sem P0/P1; P2 corrigidos no impl plan (redação + line refs); débitos descartados por serem convenções pré-existentes ou decisões do gate.
|
||||
60
docs/plans/slogan-mais-saude-mais-futuro-impl.md
Normal file
60
docs/plans/slogan-mais-saude-mais-futuro-impl.md
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
# Impl: Slogan da campanha "Mais saúde mais futuro" no hero e no rodapé
|
||||
|
||||
Status: aprovado
|
||||
Atualizado em: 2026-08-17
|
||||
Issue: #15
|
||||
Intenção: docs/plans/slogan-mais-saude-mais-futuro.md
|
||||
Appetite restante: herdado (~0,25–0,5 dia; diff real é troca de 4 strings em 2 componentes + 3 testes)
|
||||
|
||||
## Leitura da intenção
|
||||
|
||||
- **Outcome:** o hero e o rodapé da home de campanha exibem o slogan novo "Mais saúde mais futuro" no lugar de "Um mandato do tamanho da Bahia", com o aria-label do h1 acompanhando e os testes que pinam a string antiga atualizados.
|
||||
- **O que NÃO negociar:** copy fixa no componente (nada de campo editável no admin); anatomia do hero/rodapé intacta (sem redesenho — a referência do Penpot vale só para o texto); cabeçalho da página de artigos NÃO muda (decidido no gate).
|
||||
- **O que reavaliar:** a hipótese de "segunda linha em peso maior" já é a anatomia atual do componente (`font-medium` → `font-black`) — não há mudança de classes, só de texto.
|
||||
|
||||
## Abordagem recomendada
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
A[CampaignHero.tsx] -->|swap de 2 spans + aria-label| H1["MAIS SAÚDE / MAIS FUTURO"]
|
||||
B[CampaignFooter.tsx] -->|swap de 1 linha| P["Mais saúde mais futuro."]
|
||||
T[tests: hero + home + e2e] -->|atualiza name pinado| N["MAIS SAÚDE MAIS FUTURO"]
|
||||
```
|
||||
|
||||
**Opções consideradas:** A | B | C
|
||||
**Recomendação:** A — troca inline das strings nos dois componentes — porque é o menor diff possível, mantém a copy no componente (convenção atual) e toca exatamente o aceite. A estrutura de duas linhas já existe; a primeira linha segue `font-medium` e a segunda `font-black` (peso maior), como hoje.
|
||||
**Rejeitadas:**
|
||||
|
||||
- B — extrair o slogan para uma constante módulo compartilhado (`src/lib/campaignSlogan.ts`): duas ocorrências não justificam abstração; criaria um módulo novo para esconder duas strings.
|
||||
- C — tornar o slogan editável via global/collection no admin: anti-goal explícito da intenção ("fora do pedido — copy fixa no componente, como hoje").
|
||||
|
||||
### Componentes / mudanças
|
||||
|
||||
- **`CampaignHero`** (`src/components/CampaignHero.tsx:88-93`): `aria-label` → `"MAIS SAÚDE MAIS FUTURO"`; primeiro span `Mais saúde`, segundo span `Mais futuro` (JSX em title case; o `uppercase` já vem do CSS do h1, como hoje).
|
||||
- **`CampaignFooter`** (`src/components/CampaignFooter.tsx:22`): linha do bloco de identificação → `Mais saúde mais futuro.` (sentence case com ponto — padrão tipográfico do rodapé, decidido no gate).
|
||||
- **Migration:** sem migration (troca de strings em componentes).
|
||||
- **Access / Consent:** N/A.
|
||||
- **UI:** Impeccable A (encaixe de copy em superfícies existentes); anatomia, pesos e layout intactos; slogan novo é mais curto, sem risco de quebra de linha.
|
||||
|
||||
## Fases verificáveis
|
||||
|
||||
1. **Swap de strings** — `CampaignHero.tsx` + `CampaignFooter.tsx`.
|
||||
2. **Testes** — atualizar os três nomes pinados: `tests/unit/campaignHero.unit.spec.tsx:21`, `tests/unit/campaignHome.unit.spec.tsx:24`, `tests/e2e/frontend.e2e.spec.ts:37` → `'MAIS SAÚDE MAIS FUTURO'` (mesmo formato do name atual: caixa alta, sem ponto).
|
||||
3. **Gates** — `pnpm test` (unit+int), e2e do frontend, `tsc --noEmit`, `pnpm lint`, `pnpm format:check`, knip, `pnpm check:cycles`, `pnpm build`.
|
||||
|
||||
## Rabbit holes / Não escopo (engenharia)
|
||||
|
||||
- Caçar a frase antiga em `docs/campanha/*`, `.opencode/` ou skills — registro histórico, não superfície pública (corte da própria intenção).
|
||||
- `src/app/(frontend)/artigos/page.tsx` ("O mandato do tamanho da Bahia") — fora de escopo decidido no gate.
|
||||
- Ajustar pesos/classes do h1 para "ficar mais parecido com o Penpot" — o hero real já tem a segunda linha em `font-black`; mudar mais é redesenho.
|
||||
|
||||
## Riscos e mitigação
|
||||
|
||||
- **Name exato nos testes:** `getByRole` com `name` é match exato do accessible name (vem do `aria-label`) — o valor novo tem que bater sem variação de caixa/ponto. Mitigação: usar exatamente `'MAIS SAÚDE MAIS FUTURO'`, espelhando o padrão atual.
|
||||
- **Rodapé sem teste pinado:** nenhum teste cobre a linha do rodapé — troca não quebra suíte, e o e2e da home segue cobrindo o hero. Sem teste novo (aceite não pede).
|
||||
|
||||
## Aceite de engenharia
|
||||
|
||||
- [x] Aceite de produto da intenção ainda coberto (hero duas linhas uppercase + peso maior na segunda; rodapé sentence case com ponto; frase antiga fora das superfícies públicas; testes atualizados)
|
||||
- [x] Invariantes AGENTS/engineering-standards (sem migration, sem novo módulo, copy no dono)
|
||||
- [x] Testes de domínio previstos onde strings pinadas mudam (3 arquivos)
|
||||
|
|
@ -19,7 +19,7 @@ export const CampaignFooter = () => (
|
|||
<p className="m-0 text-[rgb(255_248_242/75%)]">
|
||||
Deputado Federal · PT · Bahia
|
||||
<br />
|
||||
Um mandato do tamanho da Bahia.
|
||||
Mais saúde mais futuro.
|
||||
</p>
|
||||
</div>
|
||||
<div>
|
||||
|
|
|
|||
|
|
@ -85,11 +85,11 @@ export const CampaignHero = () => (
|
|||
<div className="campaign-hero-content relative z-30">
|
||||
<h1
|
||||
id="campaign-title"
|
||||
aria-label="UM MANDATO DO TAMANHO DA BAHIA"
|
||||
aria-label="MAIS SAÚDE MAIS FUTURO"
|
||||
className="campaign-hero-title m-0 border-0 p-0 font-[family-name:var(--font-exo2)] leading-[1.12] tracking-[-0.02em] text-balance uppercase"
|
||||
>
|
||||
<span className="block font-medium">Um mandato do</span>
|
||||
<span className="block font-black">tamanho da Bahia</span>
|
||||
<span className="block font-medium">Mais saúde</span>
|
||||
<span className="block font-black">Mais futuro</span>
|
||||
</h1>
|
||||
|
||||
<p className="campaign-hero-copy m-0 text-left font-sans leading-[1.2] uppercase">
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ test.describe('Frontend', () => {
|
|||
|
||||
const heading = page.getByRole('heading', {
|
||||
level: 1,
|
||||
name: 'UM MANDATO DO TAMANHO DA BAHIA',
|
||||
name: 'MAIS SAÚDE MAIS FUTURO',
|
||||
})
|
||||
|
||||
await expect(heading).toBeVisible()
|
||||
|
|
|
|||
|
|
@ -18,9 +18,7 @@ describe('CampaignHero', () => {
|
|||
it('apresenta a candidatura e mantém um único CTA primário', () => {
|
||||
render(<CampaignHero />)
|
||||
|
||||
expect(
|
||||
screen.getByRole('heading', { level: 1, name: 'UM MANDATO DO TAMANHO DA BAHIA' }),
|
||||
).toBeTruthy()
|
||||
expect(screen.getByRole('heading', { level: 1, name: 'MAIS SAÚDE MAIS FUTURO' })).toBeTruthy()
|
||||
|
||||
const supportLink = screen.getByRole('link', { name: /Quero apoiar/i })
|
||||
expect(supportLink.getAttribute('href')).toBe('https://apoiar.me/jorgesolla')
|
||||
|
|
|
|||
|
|
@ -21,9 +21,7 @@ describe('Campaign home', () => {
|
|||
it('monta as quatro seções previstas e o rodapé eleitoral', async () => {
|
||||
render(await HomePage())
|
||||
|
||||
expect(
|
||||
screen.getByRole('heading', { level: 1, name: 'UM MANDATO DO TAMANHO DA BAHIA' }),
|
||||
).toBeTruthy()
|
||||
expect(screen.getByRole('heading', { level: 1, name: 'MAIS SAÚDE MAIS FUTURO' })).toBeTruthy()
|
||||
expect(screen.getByText('3.333')).toBeTruthy()
|
||||
expect(screen.getByText('1.031')).toBeTruthy()
|
||||
expect(screen.getByText('3º')).toBeTruthy()
|
||||
|
|
|
|||
Loading…
Reference in a new issue