mirror of
https://github.com/fsolla/teqo.git
synced 2026-11-12 22:13:05 +00:00
feat(site): hero da campanha responsivo aos boards do Penpot
A primeira dobra da home pública agora acompanha as referências do Penpot em 393, 768, 1024, 1280, 1366 e 1920 px. 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 mesmo 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. E2E fixa a geometria das seis referências, transições de proporção, desktops baixos, ultrawide e os overrides da WCAG 1.4.12; o caso de regressão também roda no Firefox.
This commit is contained in:
parent
21b3c00d96
commit
665157a0c0
6 changed files with 861 additions and 64 deletions
|
|
@ -4,6 +4,8 @@ Conteúdo movido do `AGENTS.md` em 2026-07-30 (fatiamento do paradigma de agente
|
|||
|
||||
---
|
||||
|
||||
**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.
|
||||
|
||||
**Recently resolved (2026-08-15):** **IMG-RESIZE** — otimizador local de imagens para o draft do site de campanha (fotos pesadas travavam o PenPot). `pnpm images:resize` (`scripts/resize-images.mjs`) aceita múltiplos paths (arquivos ou pastas, varridas recursivamente), redimensiona para no máximo 3840px — 2× a tela desktop de 1920 — sem upscaling (`fit: 'inside'`, `withoutEnlargement`), aplica EXIF-rotation, remove metadados e converte para **AVIF** por padrão (formato leve moderno; WebP/JPEG via `--format`, qualidade por formato via `--quality`, `--out` para outra pasta — default `public/`). Saída mantém o basename (`foto.jpg` → `foto.avif`) e recusa colidir com a fonte. Derivação pura em `scripts/lib/imageResize.mjs` (parse fail-closed, alias jpg→jpeg, default de qualidade por formato), unit-testada em `tests/unit/imageResize.unit.spec.ts`. Sem migration/access/Consent/UI/schema.
|
||||
|
||||
**Recently resolved (2026-08-15):** **IMG-RESIZE** — otimizador local de imagens para o draft do site de campanha (fotos pesadas travavam o PenPot). `pnpm images:resize` (`scripts/resize-images.mjs`) aceita múltiplos paths (arquivos ou pastas, varridas recursivamente), redimensiona para no máximo 3840px — 2× a tela desktop de 1920 — sem upscaling (`fit: 'inside'`, `withoutEnlargement`), aplica EXIF-rotation, remove metadados e gera **DUAS versões por padrão**: `.avif` (formato leve moderno, para o site) e `.webp` (aceito em mais lugares, incluindo PenPot e navegadores antigos); o conjunto muda via `--format avif,webp` (lista separada por vírgula), qualidade por formato via `--quality`, pasta via `--out` (default `public/`). Saída mantém o basename (`foto.jpg` → `foto.avif` + `foto.webp`) e recusa colidir com a fonte. Derivação pura em `scripts/lib/imageResize.mjs` (parse fail-closed, alias jpg→jpeg, default de qualidade por formato), unit-testada em `tests/unit/imageResize.unit.spec.ts`. Sem migration/access/Consent/UI/schema.
|
||||
|
|
|
|||
1
docs/changelog/2026-08-16-campaign-home-responsive.md
Normal file
1
docs/changelog/2026-08-16-campaign-home-responsive.md
Normal file
|
|
@ -0,0 +1 @@
|
|||
**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.
|
||||
|
|
@ -85,15 +85,15 @@ export default async function HomePage() {
|
|||
<section
|
||||
aria-label="Experiência e atuação parlamentar"
|
||||
data-home-section="proof"
|
||||
className="flex h-[88px] justify-center bg-white lg:h-[148px]"
|
||||
className="campaign-proof flex justify-center bg-white"
|
||||
>
|
||||
<ul className="m-0 grid h-full w-[calc(100%_-_22px)] max-w-[712px] list-none grid-cols-3 items-center gap-[23px] p-0 lg:grid-cols-[147px_178px_183px] lg:items-start lg:justify-between lg:gap-0 lg:pt-[23px]">
|
||||
<ul className="campaign-proof-list m-0 grid h-full w-[calc(100%_-_22px)] max-w-[712px] list-none grid-cols-3 p-0">
|
||||
{proofItems.map((item) => (
|
||||
<li key={item.value} className="m-0 text-center">
|
||||
<strong className="block font-[family-name:var(--font-exo2)] text-[24px] leading-none font-black text-(--pt-red) lg:text-[36px] lg:leading-[1.1]">
|
||||
<strong className="campaign-proof-value block font-[family-name:var(--font-exo2)] leading-none font-black text-(--pt-red)">
|
||||
{item.value}
|
||||
</strong>
|
||||
<span className="mt-1 block text-[10px] leading-[1.08] font-medium text-[#242124] lg:text-[18px] lg:leading-[1.25]">
|
||||
<span className="campaign-proof-label mt-1 block font-medium text-[#242124]">
|
||||
{item.label}
|
||||
</span>
|
||||
</li>
|
||||
|
|
@ -104,30 +104,30 @@ export default async function HomePage() {
|
|||
<section
|
||||
aria-labelledby="problem-title"
|
||||
data-home-section="problem"
|
||||
className="relative h-[730px] bg-(--pt-red-dark) text-white lg:h-[659px]"
|
||||
className="campaign-problem relative bg-(--pt-red-dark) text-white"
|
||||
>
|
||||
<div className="relative h-full w-full">
|
||||
<p className="absolute top-[35px] left-5 m-0 font-[family-name:var(--font-exo2)] text-[10px] leading-3 font-black tracking-[0.1em] text-(--pt-yellow) uppercase lg:left-[var(--campaign-content-inset)] lg:text-[12px] lg:leading-[15px]">
|
||||
<p className="campaign-section-eyebrow campaign-problem-eyebrow absolute m-0 font-[family-name:var(--font-exo2)] font-black tracking-[0.1em] text-(--pt-yellow) uppercase">
|
||||
Por que essa eleição importa
|
||||
</p>
|
||||
<h2
|
||||
id="problem-title"
|
||||
aria-label="Eleger deputado é coisa séria. O Congresso tem nas mãos vidas reais e o SUS"
|
||||
className="absolute top-[59px] left-5 m-0 w-[331px] border-0 p-0 text-[22px] leading-[1.08] font-black tracking-[-0.02em] text-balance lg:top-[66px] lg:left-[var(--campaign-content-inset)] lg:w-[616px] lg:text-[24px] lg:leading-[1.06]"
|
||||
className="campaign-section-title campaign-problem-title absolute m-0 border-0 p-0 font-black tracking-[-0.02em] text-balance"
|
||||
>
|
||||
<span className="block">Eleger deputado é coisa séria</span>
|
||||
<span className="block text-(--pt-yellow)">
|
||||
O Congresso tem nas mãos vidas reais e o SUS
|
||||
</span>
|
||||
</h2>
|
||||
<p className="absolute top-[146px] left-5 m-0 w-[327px] font-[family-name:var(--font-exo2)] text-[14px] leading-[1.2] text-white/85 lg:top-[127px] lg:left-[var(--campaign-content-inset)] lg:w-[716px] lg:text-[16px]">
|
||||
<p className="campaign-section-copy campaign-problem-copy absolute m-0 font-[family-name:var(--font-exo2)] leading-[1.2] text-white/85">
|
||||
É no Congresso que se define o orçamento do SUS, o piso da enfermagem, a recompra de
|
||||
Mataripe e o fim da escala 6×1.{' '}
|
||||
<strong className="font-extrabold text-white">
|
||||
Reeleger Lula não basta: é preciso eleger uma bancada aliada.
|
||||
</strong>
|
||||
</p>
|
||||
<div className="absolute top-[245px] right-0 left-0 lg:top-[191px]">
|
||||
<div className="campaign-problem-carousel absolute right-0 left-0">
|
||||
<CampaignCarousel
|
||||
ariaLabel="Bandeiras que tornam esta eleição decisiva"
|
||||
items={problemItems}
|
||||
|
|
@ -141,25 +141,25 @@ export default async function HomePage() {
|
|||
id="bandeiras"
|
||||
aria-labelledby="flags-title"
|
||||
data-home-section="flags"
|
||||
className="relative h-[400px] scroll-mt-4 bg-(--campaign-band) text-black lg:h-[368px]"
|
||||
className="campaign-flags relative scroll-mt-4 bg-(--campaign-band) text-black"
|
||||
>
|
||||
<div className="relative h-full w-full">
|
||||
<p className="absolute top-[37px] left-5 m-0 font-[family-name:var(--font-exo2)] text-[10px] leading-3 font-black tracking-[0.1em] text-(--pt-red) uppercase lg:top-[33px] lg:left-[var(--campaign-content-inset)] lg:text-[12px] lg:leading-[15px]">
|
||||
<p className="campaign-section-eyebrow campaign-flags-eyebrow absolute m-0 font-[family-name:var(--font-exo2)] font-black tracking-[0.1em] text-(--pt-red) uppercase">
|
||||
Nossa caminhada
|
||||
</p>
|
||||
<h2
|
||||
id="flags-title"
|
||||
aria-label="Junto com o trabalhador e do lado de quem mais precisa, sempre."
|
||||
className="absolute top-[66px] left-5 m-0 w-[331px] border-0 p-0 text-[22px] leading-[1.08] font-black tracking-[-0.02em] text-balance lg:top-[62px] lg:left-[var(--campaign-content-inset)] lg:w-[664px] lg:text-[24px] lg:leading-[1.06]"
|
||||
className="campaign-section-title campaign-flags-title absolute m-0 border-0 p-0 font-black tracking-[-0.02em] text-balance"
|
||||
>
|
||||
<span className="block">Junto com o trabalhador e</span>
|
||||
<span className="block text-(--pt-red)">do lado de quem mais precisa, sempre.</span>
|
||||
</h2>
|
||||
<p className="absolute top-[149px] left-5 m-0 w-[327px] font-sans text-[14px] leading-[1.2] text-black/80 lg:top-[130px] lg:left-[var(--campaign-content-inset)] lg:w-[730px] lg:text-[16px]">
|
||||
<p className="campaign-section-copy campaign-flags-copy absolute m-0 font-sans leading-[1.2] text-black/80">
|
||||
Não é promessa de palanque, é a experiência de quem já fez na gestão do SUS, do
|
||||
Ministério da Saúde e da saúde da Bahia.
|
||||
</p>
|
||||
<div className="absolute top-[215px] right-0 left-0 lg:top-[184px]">
|
||||
<div className="campaign-flags-carousel absolute right-0 left-0">
|
||||
<CampaignCarousel
|
||||
ariaLabel="Bandeiras da campanha"
|
||||
items={flagItems}
|
||||
|
|
|
|||
|
|
@ -178,33 +178,561 @@ body,
|
|||
--campaign-surface: #f9faff;
|
||||
--campaign-band: #ebe9e9;
|
||||
--campaign-line: rgb(0 0 0 / 12%);
|
||||
--campaign-content-inset: 20px;
|
||||
--campaign-content-inset: clamp(20px, calc(25.36vw - 79.64px), 180px);
|
||||
}
|
||||
|
||||
/* Penpot uses two lockups from the official campaign identity: the wide mark
|
||||
on phones and the stacked mark on desktop. The PNG canvases are square and
|
||||
mostly transparent, so keep their exact board geometry instead of sizing by
|
||||
visible ink bounds. */
|
||||
/* Campaign home geometry is interpolated between the approved Penpot boards.
|
||||
Copy stays in normal flow so browser text-spacing preferences can expand the
|
||||
hero; only the photographic composition is positioned absolutely. */
|
||||
.campaign-hero {
|
||||
--campaign-hero-height: max(
|
||||
clamp(745px, calc(933.42px - 47.95vw), 780px),
|
||||
clamp(745px, calc(41.6vw + 581.51px), 901px)
|
||||
);
|
||||
min-height: var(--campaign-hero-height);
|
||||
height: auto;
|
||||
}
|
||||
|
||||
.campaign-hero-stage {
|
||||
max-width: 1920px;
|
||||
min-height: var(--campaign-hero-height);
|
||||
height: auto;
|
||||
}
|
||||
|
||||
/* Penpot uses the wide official lockup on phones/tablets. Its PNG canvas is
|
||||
square and mostly transparent, so the element follows the board geometry. */
|
||||
.campaign-home-logo {
|
||||
top: -123px;
|
||||
left: 19px;
|
||||
width: 356px;
|
||||
height: 356px;
|
||||
--campaign-logo-size: clamp(356px, calc(38.93vw + 203px), 502px);
|
||||
top: clamp(-166px, calc(-11.47vw - 77.92px), -123px);
|
||||
left: clamp(0px, calc(33.6vw - 113.05px), 145px);
|
||||
width: var(--campaign-logo-size);
|
||||
height: var(--campaign-logo-size);
|
||||
background-image: url('/Prancheta%206%403x.png');
|
||||
background-repeat: no-repeat;
|
||||
background-position: center;
|
||||
background-size: contain;
|
||||
}
|
||||
|
||||
.campaign-hero-portrait {
|
||||
top: clamp(53px, calc(9.33vw + 16.32px), 88px);
|
||||
left: calc(50% - 211px + clamp(8.5px, calc(3.07vw - 3.55px), 20px));
|
||||
width: 422px;
|
||||
height: auto;
|
||||
aspect-ratio: 422 / 469;
|
||||
}
|
||||
|
||||
.campaign-hero-portrait-image {
|
||||
top: -3.63%;
|
||||
left: 0.24%;
|
||||
width: 106.4%;
|
||||
}
|
||||
|
||||
.campaign-hero-ally {
|
||||
z-index: 0;
|
||||
width: 177px;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
.campaign-hero-ally--rui {
|
||||
top: clamp(144px, calc(9.33vw + 107.32px), 179px);
|
||||
left: calc(50% - 218.5px + clamp(0px, calc(3.07vw - 12.05px), 11.5px));
|
||||
}
|
||||
|
||||
.campaign-hero-ally--wagner {
|
||||
top: clamp(148px, calc(9.33vw + 111.32px), 183px);
|
||||
left: calc(50% - 265.5px + clamp(0px, calc(3.07vw - 12.05px), 11.5px));
|
||||
}
|
||||
|
||||
.campaign-hero-ally--jeronimo {
|
||||
top: clamp(140px, calc(9.33vw + 103.32px), 175px);
|
||||
left: calc(50% + 27.5px + clamp(0px, calc(3.07vw - 12.05px), 11.5px));
|
||||
}
|
||||
|
||||
.campaign-hero-ally--lula {
|
||||
top: clamp(179px, calc(9.33vw + 142.32px), 214px);
|
||||
left: calc(50% + 65.5px + clamp(0px, calc(3.07vw - 12.05px), 11.5px));
|
||||
z-index: 2;
|
||||
width: 216px;
|
||||
}
|
||||
|
||||
.campaign-hero-overlay {
|
||||
top: clamp(300px, calc(9.33vw + 263.32px), 335px);
|
||||
left: 50%;
|
||||
width: 100vw;
|
||||
height: 245px;
|
||||
transform: translateX(-50%);
|
||||
}
|
||||
|
||||
.campaign-hero-content {
|
||||
min-height: var(--campaign-hero-height);
|
||||
padding-top: clamp(462px, calc(9.33vw + 425.32px), 497px);
|
||||
padding-bottom: clamp(14px, calc(28.34px - 1.87vw), 21px);
|
||||
}
|
||||
|
||||
.campaign-hero-title {
|
||||
width: min(100%, clamp(392px, calc(38.67vw + 240.04px), 537px));
|
||||
margin-right: auto;
|
||||
margin-left: auto;
|
||||
text-align: center;
|
||||
font-size: clamp(32px, calc(4.27vw + 15.23px), 48px);
|
||||
}
|
||||
|
||||
.campaign-hero-copy {
|
||||
width: min(calc(100% - 40px), clamp(327px, calc(24.8vw + 229.54px), 420px));
|
||||
margin-top: clamp(13px, calc(4.59vw - 4.73px), 30.5px);
|
||||
margin-left: clamp(20px, calc(31.2vw - 98.62px), 141px);
|
||||
font-size: clamp(14px, calc(1.07vw + 9.81px), 18px);
|
||||
}
|
||||
|
||||
.campaign-hero-actions {
|
||||
width: max-content;
|
||||
margin-top: clamp(16px, calc(6.85vw - 5.92px), 31px);
|
||||
margin-right: clamp(18px, calc(52.27vw - 187.43px), 214px);
|
||||
margin-left: auto;
|
||||
gap: clamp(10px, calc(3.73vw - 4.67px), 24px);
|
||||
}
|
||||
|
||||
.campaign-hero-action {
|
||||
min-height: clamp(44px, calc(4.27vw + 27.23px), 60px);
|
||||
height: auto;
|
||||
font-size: clamp(17px, calc(0.27vw + 15.95px), 18px);
|
||||
}
|
||||
|
||||
.campaign-hero-action--secondary {
|
||||
width: clamp(145px, calc(3.47vw + 131.38px), 158px);
|
||||
}
|
||||
|
||||
.campaign-hero-action--primary {
|
||||
width: clamp(112px, calc(12.27vw + 63.79px), 158px);
|
||||
}
|
||||
|
||||
.campaign-hero-action-detail,
|
||||
.campaign-hero-action-long {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.campaign-hero-accolades {
|
||||
width: max-content;
|
||||
margin-top: clamp(16px, calc(6.13vw - 8.09px), 39px);
|
||||
margin-right: clamp(18px, calc(5.07vw - 1.91px), 37px);
|
||||
margin-left: auto;
|
||||
align-items: flex-end;
|
||||
gap: 2px;
|
||||
text-align: right;
|
||||
font-size: clamp(10px, calc(0.53vw + 7.9px), 12px);
|
||||
line-height: 1.2;
|
||||
}
|
||||
|
||||
.campaign-hero-accolade-secondary {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.campaign-proof {
|
||||
height: clamp(88px, calc(9.33vw + 51.32px), 123px);
|
||||
}
|
||||
|
||||
.campaign-proof-list {
|
||||
grid-template-columns: repeat(3, minmax(0, 1fr));
|
||||
align-items: center;
|
||||
gap: 23px;
|
||||
}
|
||||
|
||||
.campaign-proof-value {
|
||||
font-size: clamp(24px, calc(3.2vw + 11.42px), 36px);
|
||||
}
|
||||
|
||||
.campaign-proof-label {
|
||||
font-size: clamp(10px, calc(2.13vw + 1.62px), 18px);
|
||||
line-height: 1.15;
|
||||
}
|
||||
|
||||
.campaign-problem {
|
||||
height: clamp(659px, calc(774.22px - 11.25vw), 730px);
|
||||
}
|
||||
|
||||
.campaign-flags {
|
||||
height: clamp(368px, calc(419.93px - 5.08vw), 400px);
|
||||
}
|
||||
|
||||
.campaign-section-eyebrow,
|
||||
.campaign-section-title,
|
||||
.campaign-section-copy {
|
||||
left: var(--campaign-content-inset);
|
||||
}
|
||||
|
||||
.campaign-section-eyebrow {
|
||||
font-size: clamp(10px, calc(0.32vw + 8.75px), 12px);
|
||||
line-height: 1.25;
|
||||
}
|
||||
|
||||
.campaign-section-title {
|
||||
font-size: clamp(22px, calc(0.32vw + 20.75px), 24px);
|
||||
line-height: 1.07;
|
||||
}
|
||||
|
||||
.campaign-section-copy {
|
||||
font-size: clamp(14px, calc(0.32vw + 12.75px), 16px);
|
||||
}
|
||||
|
||||
.campaign-problem-eyebrow {
|
||||
top: 35px;
|
||||
}
|
||||
|
||||
.campaign-problem-title {
|
||||
top: clamp(59px, calc(1.11vw + 54.64px), 66px);
|
||||
width: min(
|
||||
calc(100% - var(--campaign-content-inset) - var(--campaign-content-inset)),
|
||||
clamp(331px, calc(45.17vw + 153.49px), 616px)
|
||||
);
|
||||
}
|
||||
|
||||
.campaign-problem-copy {
|
||||
top: clamp(127px, calc(157.83px - 3.01vw), 146px);
|
||||
width: min(
|
||||
calc(100% - var(--campaign-content-inset) - 20px),
|
||||
clamp(327px, calc(61.65vw + 84.72px), 716px)
|
||||
);
|
||||
}
|
||||
|
||||
.campaign-problem-carousel {
|
||||
top: clamp(191px, calc(278.63px - 8.56vw), 245px);
|
||||
}
|
||||
|
||||
.campaign-flags-eyebrow {
|
||||
top: clamp(33px, calc(39.49px - 0.63vw), 37px);
|
||||
}
|
||||
|
||||
.campaign-flags-title {
|
||||
top: clamp(62px, calc(68.49px - 0.63vw), 66px);
|
||||
width: min(
|
||||
calc(100% - var(--campaign-content-inset) - var(--campaign-content-inset)),
|
||||
clamp(331px, calc(52.77vw + 123.6px), 664px)
|
||||
);
|
||||
}
|
||||
|
||||
.campaign-flags-copy {
|
||||
top: clamp(130px, calc(160.83px - 3.01vw), 149px);
|
||||
width: min(
|
||||
calc(100% - var(--campaign-content-inset) - 20px),
|
||||
clamp(327px, calc(63.87vw + 76px), 730px)
|
||||
);
|
||||
}
|
||||
|
||||
.campaign-flags-carousel {
|
||||
top: clamp(215px, calc(285px - 17.81vw), 228px);
|
||||
}
|
||||
|
||||
[data-theme='campaign-site'] [data-carousel='problem'] [data-carousel-track] {
|
||||
gap: clamp(10px, calc(1.74vw + 3.16px), 21px);
|
||||
}
|
||||
|
||||
[data-theme='campaign-site'] [data-carousel='flags'] [data-carousel-track] {
|
||||
gap: clamp(10px, calc(0.63vw + 7.51px), 14px);
|
||||
}
|
||||
|
||||
[data-theme='campaign-site'] [data-carousel-chips] {
|
||||
gap: clamp(6px, calc(0.16vw + 5.37px), 7px);
|
||||
}
|
||||
|
||||
@media (min-width: 24.5625rem) {
|
||||
.campaign-flags-carousel {
|
||||
top: clamp(184px, calc(234.31px - 4.91vw), 215px);
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 40rem) {
|
||||
.campaign-hero-action-detail,
|
||||
.campaign-hero-action-long {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.campaign-hero-action-short {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 64rem) {
|
||||
[data-theme='campaign-site'] {
|
||||
--campaign-desktop-portrait-width: clamp(465px, calc(26.45vw + 194.15px), 702px);
|
||||
--campaign-desktop-portrait-height: clamp(517px, calc(29.41vw + 215.84px), 781px);
|
||||
--campaign-desktop-hero-height: max(
|
||||
var(--campaign-desktop-portrait-height),
|
||||
clamp(477px, min(clamp(543px, 52.8vw, 1014px), calc(-16.79vw + 108.01dvh + 26.8px)), 871px)
|
||||
);
|
||||
--campaign-proof-min-height: clamp(124px, calc(244px - 9.38vw), 148px);
|
||||
--campaign-proof-max-height: clamp(148px, calc(6.81vw + 78.3px), 209px);
|
||||
}
|
||||
|
||||
.campaign-hero {
|
||||
--campaign-hero-height: var(--campaign-desktop-hero-height);
|
||||
}
|
||||
|
||||
.campaign-home-logo {
|
||||
top: 55px;
|
||||
left: 47px;
|
||||
width: 197px;
|
||||
height: 150px;
|
||||
top: clamp(55px, calc(15.23vw - 101px), 94px);
|
||||
left: clamp(47px, calc(6.64vw - 21px), 64px);
|
||||
width: clamp(197px, calc(23.44vw - 43px), 257px);
|
||||
height: clamp(150px, calc(17.97vw - 34px), 196px);
|
||||
transform: none;
|
||||
background-image: url('/Prancheta%203%403x.png');
|
||||
background-position: -43px -67px;
|
||||
background-size: 283px 284px;
|
||||
background-position: clamp(-56.75px, calc(-5.37vw + 12px), -43px)
|
||||
clamp(-87.55px, calc(-8.03vw + 15.2px), -67px);
|
||||
background-size: 143.65% 189.3%;
|
||||
}
|
||||
|
||||
.campaign-hero-portrait {
|
||||
top: auto;
|
||||
bottom: 0;
|
||||
left: clamp(153px, calc(33.59vw - 191px), 239px);
|
||||
width: var(--campaign-desktop-portrait-width);
|
||||
aspect-ratio: 465 / 517;
|
||||
}
|
||||
|
||||
.campaign-hero-portrait-image {
|
||||
top: -3.67%;
|
||||
left: 0.25%;
|
||||
width: 106.45%;
|
||||
}
|
||||
|
||||
.campaign-hero-ally {
|
||||
top: auto;
|
||||
bottom: var(--campaign-ally-bottom, 0px);
|
||||
width: clamp(177px, calc(6.14vw + 93.16px), 211px);
|
||||
}
|
||||
|
||||
.campaign-hero-ally--rui {
|
||||
left: clamp(-27px, calc(37.89vw - 415px), 70px);
|
||||
--campaign-ally-bottom: clamp(67px, calc(102px - 2.73vw), 74px);
|
||||
}
|
||||
|
||||
.campaign-hero-ally--wagner {
|
||||
left: clamp(-75px, calc(37.89vw - 463px), 22px);
|
||||
--campaign-ally-bottom: 0px;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.campaign-hero-ally--jeronimo {
|
||||
left: clamp(63px, calc(31.25vw - 257px), 143px);
|
||||
--campaign-ally-bottom: clamp(49px, calc(1.56vw + 33px), 53px);
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.campaign-hero-ally--lula {
|
||||
left: clamp(-8px, calc(37.89vw - 396px), 89px);
|
||||
width: clamp(238px, calc(8.3vw + 124.6px), 284px);
|
||||
--campaign-ally-bottom: 0px;
|
||||
}
|
||||
|
||||
.campaign-hero-overlay {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.campaign-hero-content {
|
||||
--campaign-hero-content-right: clamp(47px, calc(40.23vw - 365px), 150px);
|
||||
padding-top: clamp(106px, calc(8.2vw + 22px), 127px);
|
||||
padding-bottom: 11px;
|
||||
}
|
||||
|
||||
.campaign-hero-title {
|
||||
width: 392px;
|
||||
margin-right: var(--campaign-hero-content-right);
|
||||
margin-left: auto;
|
||||
text-align: right;
|
||||
font-size: 36px;
|
||||
line-height: 1.2;
|
||||
}
|
||||
|
||||
.campaign-hero-copy {
|
||||
width: 418px;
|
||||
margin-top: 19.6px;
|
||||
margin-right: var(--campaign-hero-content-right);
|
||||
margin-left: auto;
|
||||
text-align: right;
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
.campaign-hero-actions {
|
||||
margin-top: 29px;
|
||||
margin-right: var(--campaign-hero-content-right);
|
||||
margin-left: auto;
|
||||
gap: 24px;
|
||||
}
|
||||
|
||||
.campaign-hero-action {
|
||||
width: 158px;
|
||||
min-height: 60px;
|
||||
height: auto;
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
.campaign-hero-action-detail,
|
||||
.campaign-hero-action-long,
|
||||
.campaign-hero-accolade-secondary {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.campaign-hero-action-short {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.campaign-hero-accolades {
|
||||
margin-top: clamp(64px, calc(169px - 8.2vw), 85px);
|
||||
margin-right: 0;
|
||||
margin-left: 559px;
|
||||
align-items: flex-start;
|
||||
gap: 8px;
|
||||
text-align: left;
|
||||
font-size: 12px;
|
||||
line-height: 15px;
|
||||
}
|
||||
|
||||
.campaign-proof {
|
||||
height: clamp(
|
||||
var(--campaign-proof-min-height),
|
||||
calc(100dvh - var(--campaign-desktop-hero-height)),
|
||||
var(--campaign-proof-max-height)
|
||||
);
|
||||
}
|
||||
|
||||
.campaign-proof-list {
|
||||
grid-template-columns: 147px 178px 183px;
|
||||
align-items: start;
|
||||
justify-content: space-between;
|
||||
gap: 0;
|
||||
padding-top: clamp(17px, calc(47px - 2.34vw), 23px);
|
||||
}
|
||||
|
||||
.campaign-proof-value {
|
||||
font-size: 36px;
|
||||
line-height: 1.1;
|
||||
}
|
||||
|
||||
.campaign-proof-label {
|
||||
font-size: 18px;
|
||||
line-height: 1.25;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 80rem) {
|
||||
.campaign-hero-portrait {
|
||||
left: clamp(239px, calc(100vw - 1041px), 325px);
|
||||
}
|
||||
|
||||
.campaign-home-logo {
|
||||
top: clamp(45px, calc(823.3px - 56.98vw), 94px);
|
||||
left: clamp(64px, calc(8.14vw - 40.19px), 71px);
|
||||
width: clamp(257px, calc(43.02vw - 293.7px), 294px);
|
||||
height: clamp(196px, calc(32.56vw - 220.74px), 224px);
|
||||
background-position: clamp(-64.92px, calc(64.85px - 9.5vw), -56.75px)
|
||||
clamp(-100.05px, calc(98.5px - 14.54vw), -87.55px);
|
||||
}
|
||||
|
||||
.campaign-hero-ally--rui {
|
||||
left: clamp(70px, calc(83.72vw - 1001.63px), 142px);
|
||||
--campaign-ally-bottom: clamp(64px, calc(111.65px - 3.49vw), 67px);
|
||||
}
|
||||
|
||||
.campaign-hero-ally--wagner {
|
||||
left: clamp(22px, calc(87.21vw - 1094.28px), 97px);
|
||||
--campaign-ally-bottom: 0px;
|
||||
}
|
||||
|
||||
.campaign-hero-ally--jeronimo {
|
||||
left: clamp(143px, calc(93.02vw - 1047.7px), 223px);
|
||||
--campaign-ally-bottom: clamp(49px, calc(112.53px - 4.65vw), 53px);
|
||||
}
|
||||
|
||||
.campaign-hero-ally--lula {
|
||||
left: clamp(89px, calc(87.21vw - 1027.28px), 164px);
|
||||
--campaign-ally-bottom: 0px;
|
||||
}
|
||||
|
||||
.campaign-hero-content {
|
||||
--campaign-hero-content-right: clamp(150px, calc(72.09vw - 772.8px), 212px);
|
||||
padding-top: clamp(106px, calc(439.56px - 24.42vw), 127px);
|
||||
}
|
||||
|
||||
.campaign-hero-accolades {
|
||||
margin-top: clamp(64px, calc(122.09vw - 1498.8px), 169px);
|
||||
margin-left: clamp(559px, calc(186.05vw - 1822.4px), 719px);
|
||||
}
|
||||
|
||||
.campaign-proof-list {
|
||||
padding-top: clamp(17px, calc(19.77vw - 236.02px), 34px);
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 85.375rem) {
|
||||
.campaign-hero-portrait {
|
||||
left: clamp(325px, calc(35.92vw - 165.7px), 524px);
|
||||
}
|
||||
|
||||
.campaign-home-logo {
|
||||
top: clamp(45px, calc(7.4vw - 56.1px), 86px);
|
||||
left: clamp(71px, calc(22.38vw - 234.8px), 195px);
|
||||
width: clamp(294px, calc(16.43vw + 69.6px), 385px);
|
||||
height: clamp(224px, calc(12.64vw + 51.4px), 294px);
|
||||
background-position: clamp(-85px, calc(-3.63vw - 15.35px), -64.92px)
|
||||
clamp(-131px, calc(-5.6vw - 23.6px), -100.05px);
|
||||
}
|
||||
|
||||
.campaign-hero-ally--rui {
|
||||
left: clamp(142px, calc(30.51vw - 274.7px), 311px);
|
||||
--campaign-ally-bottom: clamp(64px, calc(2.17vw + 34.4px), 76px);
|
||||
}
|
||||
|
||||
.campaign-hero-ally--wagner {
|
||||
left: clamp(97px, calc(28.88vw - 297.5px), 257px);
|
||||
--campaign-ally-bottom: 0px;
|
||||
}
|
||||
|
||||
.campaign-hero-ally--jeronimo {
|
||||
left: clamp(223px, calc(35.56vw - 262.8px), 420px);
|
||||
--campaign-ally-bottom: clamp(49px, calc(1.44vw + 29.27px), 57px);
|
||||
}
|
||||
|
||||
.campaign-hero-ally--lula {
|
||||
left: clamp(164px, calc(32.31vw - 277.4px), 343px);
|
||||
--campaign-ally-bottom: 0px;
|
||||
}
|
||||
|
||||
.campaign-hero-content {
|
||||
--campaign-hero-content-right: clamp(212px, calc(1.44vw + 192.27px), 220px);
|
||||
padding-top: clamp(106px, calc(15.16vw - 101.1px), 190px);
|
||||
padding-bottom: clamp(7px, calc(24.32px - 0.9vw), 12px);
|
||||
}
|
||||
|
||||
.campaign-hero-title {
|
||||
width: clamp(392px, calc(38.81vw - 138.1px), 607px);
|
||||
font-size: clamp(36px, calc(2.17vw + 6.41px), 48px);
|
||||
}
|
||||
|
||||
.campaign-hero-copy {
|
||||
width: clamp(418px, calc(26.71vw + 53.05px), 566px);
|
||||
margin-top: clamp(19.6px, calc(3.83vw - 32.68px), 40.8px);
|
||||
font-size: clamp(18px, calc(1.08vw + 3.2px), 24px);
|
||||
}
|
||||
|
||||
.campaign-hero-actions {
|
||||
margin-top: clamp(29px, calc(6.68vw - 62.23px), 66px);
|
||||
gap: clamp(24px, calc(0.36vw + 19.07px), 26px);
|
||||
}
|
||||
|
||||
.campaign-hero-action {
|
||||
width: clamp(158px, calc(2.89vw + 118.55px), 174px);
|
||||
min-height: clamp(60px, calc(1.08vw + 45.2px), 66px);
|
||||
height: auto;
|
||||
font-size: clamp(18px, calc(0.36vw + 13.07px), 20px);
|
||||
}
|
||||
|
||||
.campaign-hero-accolades {
|
||||
margin-top: clamp(169px, calc(5.87vw + 88.76px), 201.5px);
|
||||
margin-left: clamp(719px, calc(73.83vw - 289.5px), 1128px);
|
||||
font-size: clamp(11px, calc(0.36vw + 7.07px), 14px);
|
||||
line-height: 1.2;
|
||||
}
|
||||
|
||||
.campaign-proof-list {
|
||||
padding-top: clamp(30px, calc(1.08vw + 19.2px), 40px);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -4,31 +4,32 @@ const SUPPORT_URL = 'https://apoiar.me/jorgesolla'
|
|||
|
||||
const allyImages = [
|
||||
{
|
||||
id: 'rui',
|
||||
src: '/RUI%20-%202-2.avif',
|
||||
width: 177,
|
||||
height: 265,
|
||||
className: 'left-[-22px] top-[144px] h-[265px] w-[177px] lg:left-[-35px] lg:top-[238px] lg:z-0',
|
||||
sizes: '(min-width: 1366px) calc(6.14vw + 93px), 177px',
|
||||
},
|
||||
{
|
||||
id: 'wagner',
|
||||
src: '/WAGNER%20-%202-9%20final.avif',
|
||||
width: 177,
|
||||
height: 265,
|
||||
className:
|
||||
'left-[-69px] top-[148px] h-[265px] w-[177px] lg:left-[-75px] lg:top-[278px] lg:z-[1]',
|
||||
sizes: '(min-width: 1366px) calc(6.14vw + 93px), 177px',
|
||||
},
|
||||
{
|
||||
id: 'jeronimo',
|
||||
src: '/Jeronimo.avif',
|
||||
width: 177,
|
||||
height: 265,
|
||||
className:
|
||||
'left-[224px] top-[140px] h-[265px] w-[177px] lg:left-[84px] lg:top-[249px] lg:z-[1]',
|
||||
sizes: '(min-width: 1366px) calc(6.14vw + 93px), 177px',
|
||||
},
|
||||
{
|
||||
id: 'lula',
|
||||
src: '/Lula.avif',
|
||||
width: 216,
|
||||
height: 213,
|
||||
className:
|
||||
'left-[262px] top-[179px] h-[213px] w-[216px] lg:left-[-8px] lg:top-[308px] lg:z-[2] lg:h-[235px] lg:w-[238px]',
|
||||
sizes: '(min-width: 1366px) calc(8.3vw + 125px), (min-width: 1024px) 238px, 216px',
|
||||
},
|
||||
]
|
||||
|
||||
|
|
@ -36,9 +37,9 @@ export const CampaignHero = () => (
|
|||
<section
|
||||
aria-labelledby="campaign-title"
|
||||
data-home-section="hero"
|
||||
className="relative h-[745px] overflow-hidden bg-(--pt-red) text-white max-[383px]:h-[780px] lg:h-[543px]"
|
||||
className="campaign-hero relative overflow-hidden bg-(--pt-red) text-white"
|
||||
>
|
||||
<div className="relative mx-auto h-full w-full max-w-[393px] lg:max-w-[1024px]">
|
||||
<div className="campaign-hero-stage relative mx-auto h-full w-full">
|
||||
<div
|
||||
role="img"
|
||||
aria-label="Jorge Solla 1313 — candidato a deputado federal"
|
||||
|
|
@ -57,43 +58,41 @@ export const CampaignHero = () => (
|
|||
alt=""
|
||||
width={image.width}
|
||||
height={image.height}
|
||||
sizes="(min-width: 1024px) 238px, 216px"
|
||||
sizes={image.sizes}
|
||||
loading="eager"
|
||||
className={`absolute max-w-none object-contain ${image.className}`}
|
||||
className={`campaign-hero-ally campaign-hero-ally--${image.id} absolute max-w-none object-contain`}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
|
||||
<div className="absolute top-[53px] left-1/2 z-20 h-[469px] w-[422px] -translate-x-1/2 overflow-hidden lg:top-[26px] lg:left-[153px] lg:h-[517px] lg:w-[465px] lg:translate-x-0">
|
||||
<div className="campaign-hero-portrait absolute z-20 overflow-hidden">
|
||||
<Image
|
||||
src="/JOA00162.avif"
|
||||
alt="Jorge Solla, candidato a deputado federal pela Bahia"
|
||||
width={495}
|
||||
height={742}
|
||||
sizes="(min-width: 1024px) 495px, 449px"
|
||||
sizes="(min-width: 1720px) 747px, (min-width: 1280px) 595px, (min-width: 1024px) 495px, 449px"
|
||||
priority
|
||||
className="absolute -top-[17px] left-px h-[673px] w-[449px] max-w-none object-contain lg:-top-[19px] lg:h-[742px] lg:w-[495px]"
|
||||
className="campaign-hero-portrait-image absolute h-auto max-w-none object-contain"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div
|
||||
data-mobile-hero-overlay
|
||||
className="absolute top-[300px] left-1/2 z-20 h-[245px] w-screen -translate-x-1/2 bg-[linear-gradient(to_bottom,transparent_0%,rgba(162,28,28,0.5)_38%,#a21c1c_78%)] lg:hidden"
|
||||
className="campaign-hero-overlay absolute z-20 bg-[linear-gradient(to_bottom,transparent_0%,rgba(162,28,28,0.5)_38%,#a21c1c_78%)]"
|
||||
/>
|
||||
|
||||
<div className="absolute top-[462px] left-0 z-30 w-full lg:top-[106px] lg:right-[47px] lg:left-auto lg:w-[392px]">
|
||||
<div className="campaign-hero-content relative z-30">
|
||||
<h1
|
||||
id="campaign-title"
|
||||
aria-label="UM MANDATO DO TAMANHO DA BAHIA"
|
||||
className="m-0 border-0 p-0 text-center font-[family-name:var(--font-exo2)] text-[32px] leading-[1.12] tracking-[-0.02em] text-balance uppercase lg:text-right lg:text-[36px] lg:leading-[1.2]"
|
||||
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>
|
||||
</h1>
|
||||
</div>
|
||||
|
||||
<div className="absolute top-[547px] left-0 z-30 w-full lg:static">
|
||||
<p className="m-0 ml-6 w-[calc(100%_-_66px)] text-left font-sans text-[14px] leading-[1.2] uppercase lg:absolute lg:top-[212px] lg:right-[47px] lg:z-30 lg:ml-0 lg:w-[418px] lg:text-right lg:text-[18px]">
|
||||
<p className="campaign-hero-copy m-0 text-left font-sans leading-[1.2] uppercase">
|
||||
Médico sanitarista.{' '}
|
||||
<strong className="font-extrabold text-(--pt-yellow)">Criou o SAMU 192</strong> e o{' '}
|
||||
<strong className="font-extrabold">Brasil Sorridente</strong>. Já comandou a saúde em
|
||||
|
|
@ -101,15 +100,15 @@ export const CampaignHero = () => (
|
|||
à educação.
|
||||
</p>
|
||||
|
||||
<div className="mt-5 mr-[18px] flex items-stretch justify-end gap-2.5 lg:absolute lg:top-[349px] lg:right-[47px] lg:z-30 lg:mt-0 lg:mr-0 lg:justify-start lg:gap-6">
|
||||
<div className="campaign-hero-actions flex items-stretch justify-start">
|
||||
<a
|
||||
href="#bandeiras"
|
||||
aria-label="Conhecer bandeiras"
|
||||
data-cta="secondary"
|
||||
className="campaign-action-feedback inline-flex min-h-11 w-[145px] flex-col items-center justify-center rounded-[10px] border-2 border-white/55 px-3 text-center font-[family-name:var(--font-exo2)] text-[17px] leading-[1.05] font-extrabold text-white no-underline hover:bg-white/10 focus-visible:ring-2 focus-visible:ring-white focus-visible:ring-offset-2 focus-visible:ring-offset-(--pt-red) focus-visible:outline-none lg:h-[60px] lg:w-[158px] lg:text-[18px]"
|
||||
className="campaign-action-feedback campaign-hero-action campaign-hero-action--secondary inline-flex min-h-11 flex-col items-center justify-center rounded-[10px] border-2 border-white/55 px-3 text-center font-[family-name:var(--font-exo2)] leading-[1.05] font-extrabold text-white no-underline hover:bg-white/10 focus-visible:ring-2 focus-visible:ring-white focus-visible:ring-offset-2 focus-visible:ring-offset-(--pt-red) focus-visible:outline-none"
|
||||
>
|
||||
Conhecer
|
||||
<small className="hidden text-[12px] leading-none font-semibold lg:block">
|
||||
<small className="campaign-hero-action-detail text-[12px] leading-none font-semibold">
|
||||
bandeiras
|
||||
</small>
|
||||
</a>
|
||||
|
|
@ -119,24 +118,28 @@ export const CampaignHero = () => (
|
|||
target="_blank"
|
||||
rel="noopener"
|
||||
data-cta="primary"
|
||||
className="campaign-action-feedback inline-flex min-h-11 w-[112px] flex-col items-center justify-center rounded-[10px] bg-(--pt-yellow) px-2 text-center font-[family-name:var(--font-exo2)] text-[17px] leading-[1.05] font-black text-(--pt-yellow-ink) no-underline hover:brightness-95 focus-visible:ring-2 focus-visible:ring-white focus-visible:ring-offset-2 focus-visible:ring-offset-(--pt-red) focus-visible:outline-none lg:h-[60px] lg:w-[158px] lg:text-[18px]"
|
||||
className="campaign-action-feedback campaign-hero-action campaign-hero-action--primary inline-flex min-h-11 flex-col items-center justify-center rounded-[10px] bg-(--pt-yellow) px-2 text-center font-[family-name:var(--font-exo2)] leading-[1.05] font-black text-(--pt-yellow-ink) no-underline hover:brightness-95 focus-visible:ring-2 focus-visible:ring-white focus-visible:ring-offset-2 focus-visible:ring-offset-(--pt-red) focus-visible:outline-none"
|
||||
>
|
||||
<span className="lg:hidden">Apoiar</span>
|
||||
<span className="hidden lg:inline">Quero apoiar</span>
|
||||
<small className="hidden text-[12px] leading-none font-semibold lg:block">
|
||||
<span className="campaign-hero-action-short">Apoiar</span>
|
||||
<span className="campaign-hero-action-long">Quero apoiar</span>
|
||||
<small className="campaign-hero-action-detail text-[12px] leading-none font-semibold">
|
||||
é rápido, 30 segundos
|
||||
</small>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="absolute right-[18px] bottom-3 z-30 flex flex-col items-end gap-0.5 text-right font-sans text-[10px] leading-3 text-white/80 lg:top-[494px] lg:right-auto lg:bottom-auto lg:left-[559px] lg:items-start lg:gap-2 lg:text-left lg:text-[12px] lg:leading-[15px]">
|
||||
<span aria-label="DIAP entre os 40 melhores da Câmara">
|
||||
<strong className="font-extrabold text-white">DIAP</strong> entre os 40 melhores da Câmara
|
||||
</span>
|
||||
<span aria-label="Mais votado do PT-BA em 2022">
|
||||
<strong className="font-extrabold text-white">Mais votado</strong> do PT-BA em 2022
|
||||
</span>
|
||||
<div className="campaign-hero-accolades flex flex-col font-sans text-white/80">
|
||||
<span aria-label="DIAP entre os 40 melhores da Câmara">
|
||||
<strong className="font-extrabold text-white">DIAP</strong> entre os 40 melhores da
|
||||
Câmara
|
||||
</span>
|
||||
<span
|
||||
aria-label="Mais votado do PT-BA em 2022"
|
||||
className="campaign-hero-accolade-secondary"
|
||||
>
|
||||
<strong className="font-extrabold text-white">Mais votado</strong> do PT-BA em 2022
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
|
|
|||
|
|
@ -86,6 +86,269 @@ test.describe('Frontend', () => {
|
|||
expect(actionsBox.y - (subtitleBox.y + subtitleBox.height)).toBeGreaterThanOrEqual(16)
|
||||
})
|
||||
|
||||
test('adapts the campaign first fold fluidly across the reference viewport sizes', async ({
|
||||
page,
|
||||
}) => {
|
||||
await page.goto('/')
|
||||
await expect(page).toHaveURL(/\/$/)
|
||||
|
||||
const measureFirstFold = async (width: number, height: number) => {
|
||||
await page.setViewportSize({ width, height })
|
||||
|
||||
return page.evaluate(() => {
|
||||
const hero = document.querySelector<HTMLElement>('[data-home-section="hero"]')
|
||||
const proof = document.querySelector<HTMLElement>('[data-home-section="proof"]')
|
||||
const scrollContainer = document.querySelector<HTMLElement>('[data-theme="campaign-site"]')
|
||||
if (!hero || !proof || !scrollContainer)
|
||||
throw new Error('A primeira dobra não foi montada.')
|
||||
|
||||
const box = (selector: string) => {
|
||||
const element = document.querySelector<HTMLElement>(selector)
|
||||
if (!element) throw new Error(`Elemento responsivo ausente: ${selector}`)
|
||||
const bounds = element.getBoundingClientRect()
|
||||
return { x: bounds.x, y: bounds.y, width: bounds.width }
|
||||
}
|
||||
const heroBounds = hero.getBoundingClientRect()
|
||||
|
||||
return {
|
||||
heroHeight: heroBounds.height,
|
||||
firstFoldHeight: heroBounds.height + proof.getBoundingClientRect().height,
|
||||
horizontalOverflow: scrollContainer.scrollWidth - scrollContainer.clientWidth,
|
||||
title: box('.campaign-hero-title'),
|
||||
portrait: box('.campaign-hero-portrait'),
|
||||
secondaryAction: box('[data-cta="secondary"]'),
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const penpotBoards = [
|
||||
{
|
||||
width: 393,
|
||||
height: 852,
|
||||
heroHeight: 745,
|
||||
firstFoldHeight: 833,
|
||||
title: [-5, 462, 392],
|
||||
portrait: [-6, 53, 422],
|
||||
secondaryAction: [108, 652, 145],
|
||||
},
|
||||
{
|
||||
width: 768,
|
||||
height: 1024,
|
||||
heroHeight: 901,
|
||||
firstFoldHeight: 1024,
|
||||
title: [121, 497, 537],
|
||||
portrait: [193, 88, 422],
|
||||
secondaryAction: [214, 774, 158],
|
||||
},
|
||||
{
|
||||
width: 1024,
|
||||
height: 900,
|
||||
heroHeight: 543,
|
||||
firstFoldHeight: 691,
|
||||
title: [585, 106, 392],
|
||||
portrait: [153, 26, 465],
|
||||
secondaryAction: [637, 349, 158],
|
||||
},
|
||||
{
|
||||
width: 1280,
|
||||
height: 800,
|
||||
heroHeight: 676,
|
||||
firstFoldHeight: 800,
|
||||
title: [738, 127, 392],
|
||||
portrait: [239, 84, 533],
|
||||
secondaryAction: [790, 370, 158],
|
||||
},
|
||||
{
|
||||
width: 1366,
|
||||
height: 768,
|
||||
heroHeight: 627,
|
||||
firstFoldHeight: 768,
|
||||
title: [762, 106, 392],
|
||||
portrait: [325, 9, 555],
|
||||
secondaryAction: [814, 349, 158],
|
||||
},
|
||||
{
|
||||
width: 1920,
|
||||
height: 1080,
|
||||
heroHeight: 871,
|
||||
firstFoldHeight: 1080,
|
||||
title: [1093, 190, 607],
|
||||
portrait: [524, 91, 702],
|
||||
secondaryAction: [1325, 556, 174],
|
||||
},
|
||||
]
|
||||
|
||||
for (const board of penpotBoards) {
|
||||
const measured = await measureFirstFold(board.width, board.height)
|
||||
expect(Math.abs(measured.heroHeight - board.heroHeight)).toBeLessThanOrEqual(2)
|
||||
expect(Math.abs(measured.firstFoldHeight - board.firstFoldHeight)).toBeLessThanOrEqual(2)
|
||||
expect(measured.horizontalOverflow).toBeLessThanOrEqual(1)
|
||||
|
||||
for (const key of ['title', 'portrait', 'secondaryAction'] as const) {
|
||||
const [x, y, width] = board[key]
|
||||
expect(Math.abs(measured[key].x - x)).toBeLessThanOrEqual(8)
|
||||
expect(Math.abs(measured[key].y - y)).toBeLessThanOrEqual(2)
|
||||
expect(Math.abs(measured[key].width - width)).toBeLessThanOrEqual(2)
|
||||
}
|
||||
}
|
||||
|
||||
const compact = [
|
||||
await measureFirstFold(393, 852),
|
||||
await measureFirstFold(580, 900),
|
||||
await measureFirstFold(768, 1024),
|
||||
]
|
||||
expect(compact[1].heroHeight).toBeGreaterThan(compact[0].heroHeight)
|
||||
expect(compact[1].heroHeight).toBeLessThan(compact[2].heroHeight)
|
||||
|
||||
const standardDesktop = [
|
||||
await measureFirstFold(1024, 900),
|
||||
await measureFirstFold(1152, 900),
|
||||
await measureFirstFold(1280, 800),
|
||||
]
|
||||
expect(standardDesktop[1].heroHeight).toBeGreaterThan(standardDesktop[0].heroHeight)
|
||||
expect(standardDesktop[1].heroHeight).toBeLessThan(standardDesktop[2].heroHeight)
|
||||
|
||||
const wideDesktop = [
|
||||
await measureFirstFold(1366, 768),
|
||||
await measureFirstFold(1600, 900),
|
||||
await measureFirstFold(1920, 1080),
|
||||
]
|
||||
expect(wideDesktop[1].heroHeight).toBeGreaterThan(wideDesktop[0].heroHeight)
|
||||
expect(wideDesktop[1].heroHeight).toBeLessThan(wideDesktop[2].heroHeight)
|
||||
|
||||
const aspectBoundary = [
|
||||
await measureFirstFold(1280, 747),
|
||||
await measureFirstFold(1280, 746),
|
||||
await measureFirstFold(1920, 1121),
|
||||
await measureFirstFold(1920, 1120),
|
||||
]
|
||||
expect(Math.abs(aspectBoundary[0].heroHeight - aspectBoundary[1].heroHeight)).toBeLessThan(2)
|
||||
expect(Math.abs(aspectBoundary[2].heroHeight - aspectBoundary[3].heroHeight)).toBeLessThan(2)
|
||||
})
|
||||
|
||||
test('anchors the desktop portraits to the hero floor without height-dependent scaling', async ({
|
||||
page,
|
||||
}) => {
|
||||
await page.goto('/')
|
||||
await expect(page).toHaveURL(/\/$/)
|
||||
|
||||
const measureComposition = async (width: number, height: number) => {
|
||||
await page.setViewportSize({ width, height })
|
||||
|
||||
return page.evaluate(() => {
|
||||
const bounds = (selector: string) => {
|
||||
const element = document.querySelector<HTMLElement>(selector)
|
||||
if (!element) throw new Error(`Elemento da composição ausente: ${selector}`)
|
||||
return element.getBoundingClientRect()
|
||||
}
|
||||
const hero = bounds('[data-home-section="hero"]')
|
||||
const stage = bounds('.campaign-hero-stage')
|
||||
const portrait = bounds('.campaign-hero-portrait')
|
||||
const lula = bounds('.campaign-hero-ally--lula')
|
||||
const wagner = bounds('.campaign-hero-ally--wagner')
|
||||
const title = bounds('.campaign-hero-title')
|
||||
|
||||
return {
|
||||
portrait: { left: portrait.left, width: portrait.width },
|
||||
portraitBottomGap: hero.bottom - portrait.bottom,
|
||||
lulaBottomGap: hero.bottom - lula.bottom,
|
||||
wagnerBottomGap: hero.bottom - wagner.bottom,
|
||||
portraitTitleGap: title.left - portrait.right,
|
||||
stageWidth: stage.width,
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const short = await measureComposition(1340, 70)
|
||||
const regular = await measureComposition(1340, 700)
|
||||
|
||||
expect(Math.abs(short.portrait.width - regular.portrait.width)).toBeLessThanOrEqual(1)
|
||||
expect(Math.abs(short.portrait.left - regular.portrait.left)).toBeLessThanOrEqual(1)
|
||||
|
||||
for (const composition of [short, regular]) {
|
||||
expect(Math.abs(composition.portraitBottomGap)).toBeLessThanOrEqual(1)
|
||||
expect(Math.abs(composition.lulaBottomGap)).toBeLessThanOrEqual(1)
|
||||
expect(Math.abs(composition.wagnerBottomGap)).toBeLessThanOrEqual(1)
|
||||
}
|
||||
|
||||
const ultraWide = await measureComposition(2358, 1030)
|
||||
expect(Math.abs(ultraWide.portraitBottomGap)).toBeLessThanOrEqual(1)
|
||||
expect(Math.abs(ultraWide.lulaBottomGap)).toBeLessThanOrEqual(1)
|
||||
expect(Math.abs(ultraWide.wagnerBottomGap)).toBeLessThanOrEqual(1)
|
||||
expect(ultraWide.portraitTitleGap).toBeLessThanOrEqual(64)
|
||||
expect(ultraWide.stageWidth).toBeLessThanOrEqual(1920)
|
||||
})
|
||||
|
||||
test('keeps the hero readable with WCAG text spacing overrides', async ({ page }) => {
|
||||
await page.goto('/')
|
||||
await expect(page).toHaveURL(/\/$/)
|
||||
await page.addStyleTag({
|
||||
content: `
|
||||
[data-home-section="hero"] :is(h1, p, a, small, span, strong) {
|
||||
line-height: 1.5 !important;
|
||||
letter-spacing: 0.12em !important;
|
||||
word-spacing: 0.16em !important;
|
||||
}
|
||||
[data-home-section="hero"] p { margin-bottom: 2em !important; }
|
||||
`,
|
||||
})
|
||||
|
||||
for (const viewport of [
|
||||
{ width: 320, height: 568 },
|
||||
{ width: 393, height: 852 },
|
||||
{ width: 768, height: 1024 },
|
||||
{ width: 1024, height: 597 },
|
||||
{ width: 1366, height: 768 },
|
||||
{ width: 1600, height: 600 },
|
||||
{ width: 1920, height: 840 },
|
||||
]) {
|
||||
await page.setViewportSize(viewport)
|
||||
const spacing = await page.evaluate(() => {
|
||||
const element = (selector: string) => {
|
||||
const match = document.querySelector<HTMLElement>(selector)
|
||||
if (!match) throw new Error(`Elemento ausente no teste de espaçamento: ${selector}`)
|
||||
return match
|
||||
}
|
||||
const bounds = (selector: string) => {
|
||||
return element(selector).getBoundingClientRect()
|
||||
}
|
||||
const hero = bounds('[data-home-section="hero"]')
|
||||
const title = bounds('.campaign-hero-title')
|
||||
const copy = bounds('.campaign-hero-copy')
|
||||
const actions = bounds('.campaign-hero-actions')
|
||||
const accolades = bounds('.campaign-hero-accolades')
|
||||
const secondaryAction = element('[data-cta="secondary"]')
|
||||
const primaryAction = element('[data-cta="primary"]')
|
||||
const scrollContainer = document.querySelector<HTMLElement>('[data-theme="campaign-site"]')
|
||||
if (!scrollContainer) throw new Error('Container da campanha ausente.')
|
||||
|
||||
const overlapArea = (first: DOMRect, second: DOMRect) =>
|
||||
Math.max(0, Math.min(first.right, second.right) - Math.max(first.left, second.left)) *
|
||||
Math.max(0, Math.min(first.bottom, second.bottom) - Math.max(first.top, second.top))
|
||||
|
||||
return {
|
||||
titleCopyGap: copy.top - title.bottom,
|
||||
copyActionsGap: actions.top - copy.bottom,
|
||||
actionsBottomGap: hero.bottom - actions.bottom,
|
||||
accoladesBottomGap: hero.bottom - accolades.bottom,
|
||||
actionsAccoladesOverlap: overlapArea(actions, accolades),
|
||||
primaryActionOverflow: primaryAction.scrollHeight - primaryAction.clientHeight,
|
||||
secondaryActionOverflow: secondaryAction.scrollHeight - secondaryAction.clientHeight,
|
||||
horizontalOverflow: scrollContainer.scrollWidth - scrollContainer.clientWidth,
|
||||
}
|
||||
})
|
||||
|
||||
expect(spacing.titleCopyGap).toBeGreaterThanOrEqual(0)
|
||||
expect(spacing.copyActionsGap).toBeGreaterThanOrEqual(0)
|
||||
expect(spacing.actionsBottomGap).toBeGreaterThanOrEqual(44)
|
||||
expect(spacing.accoladesBottomGap).toBeGreaterThanOrEqual(0)
|
||||
expect(spacing.actionsAccoladesOverlap).toBe(0)
|
||||
expect(spacing.primaryActionOverflow).toBeLessThanOrEqual(0)
|
||||
expect(spacing.secondaryActionOverflow).toBeLessThanOrEqual(0)
|
||||
expect(spacing.horizontalOverflow).toBeLessThanOrEqual(1)
|
||||
}
|
||||
})
|
||||
|
||||
test('auto-advances and keeps carousel controls synchronized', async ({ page }) => {
|
||||
await page.goto('/')
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue