feat(home): ofertas que vendem o título, WhatsApp no hero e menu do celular acessível
Três ofertas (site que traz pedidos pelo WhatsApp, sistema para tirar a operação da planilha, revisão de sistema existente) com miniatura e formulário com o tipo escolhido; botão principal do hero abre o WhatsApp; moldura da SEV no hero do celular; menu fecha ao navegar, Esc, foco preso incluindo a barra de cookies e espaço para ela; CinematicHome como componente de servidor com ilha cliente; /ia com H1 de oferta e cartão do que você recebe; botão flutuante em aside com transform; AVIF antes de WebP; copy sem repetir contato direto.
This commit is contained in:
1 parent
de6af74a0c
commit
f8545cd442
44 files changed
+2286
-571
No files matched your search
@@ -1,4 +1,4 @@
|
||||
import { fireEvent, render, screen } from "@testing-library/react";
|
||||
import { render, screen } from "@testing-library/react";
|
||||
|
||||
import Hero from "./Hero";
|
||||
|
||||
@@ -18,20 +18,30 @@ describe("Hero", () => {
|
||||
jest.restoreAllMocks();
|
||||
});
|
||||
|
||||
it("routes project conversations to contact without opening an external service", () => {
|
||||
it("opens WhatsApp straight from the main button, with the subject of the home, while 'Ver projetos entregues' stays secondary", () => {
|
||||
render(<Hero />);
|
||||
|
||||
const contactLink = screen.getByRole("link", {
|
||||
name: /conversar/i,
|
||||
});
|
||||
expect(contactLink).toHaveAttribute("href", "/#contact");
|
||||
expect(contactLink).not.toHaveAttribute("target", "_blank");
|
||||
fireEvent.click(contactLink);
|
||||
expect(window.open).not.toHaveBeenCalled();
|
||||
expect(screen.getByRole("link", { name: /ver projetos/i })).toHaveAttribute(
|
||||
"href",
|
||||
"/cases",
|
||||
expect(contactLink).toHaveAccessibleName("Conversar sobre meu projeto");
|
||||
expect(contactLink.getAttribute("href")).toMatch(
|
||||
/^https:\/\/wa\.me\/\d+\?/,
|
||||
);
|
||||
expect(contactLink).toHaveAttribute("target", "_blank");
|
||||
expect(contactLink).toHaveAttribute("rel", "noopener noreferrer");
|
||||
const text = new URL(
|
||||
contactLink.getAttribute("href") ?? "",
|
||||
).searchParams.get("text");
|
||||
expect(text).toBe(
|
||||
"Olá, Evandro! Quero conversar sobre um site ou sistema para a minha empresa. Contato iniciado pelo site evandro.dev.br.",
|
||||
);
|
||||
// o botão primário é o único com o fundo limão; o secundário é contorno
|
||||
expect(contactLink.className).toContain("bg-[var(--slash)]");
|
||||
const projects = screen.getByRole("link", { name: /ver projetos/i });
|
||||
expect(projects).toHaveAttribute("href", "/cases");
|
||||
expect(projects.className).not.toContain("bg-[var(--slash)]");
|
||||
expect(projects).not.toHaveAttribute("target");
|
||||
});
|
||||
|
||||
it("keeps the headline as one readable sentence despite the per-word animation", () => {
|
||||
@@ -119,13 +129,31 @@ describe("Hero", () => {
|
||||
for (const image of images) {
|
||||
expect(image).toHaveAttribute("loading", "lazy");
|
||||
}
|
||||
expect(images[0]).toHaveAttribute(
|
||||
"src",
|
||||
"/videos/sev-modaintima/desktop.webp",
|
||||
);
|
||||
// pelo otimizador do next/image: o endereço original vai no parâmetro `url`
|
||||
const original = (image: Element) =>
|
||||
new URL(
|
||||
image.getAttribute("src") ?? "",
|
||||
"http://localhost",
|
||||
).searchParams.get("url");
|
||||
expect(original(images[0])).toBe("/videos/sev-modaintima/desktop.webp");
|
||||
expect(images[0]).toHaveAccessibleName(
|
||||
"Site da SEV Moda Íntima aberto no computador",
|
||||
);
|
||||
expect(images[1]).toHaveAttribute("src", "/videos/as-servicos/mobile.webp");
|
||||
expect(original(images[1])).toBe("/videos/as-servicos/mobile.webp");
|
||||
});
|
||||
|
||||
it("shows a small phone frame with the mobile poster of SEV below the buttons on small screens", () => {
|
||||
render(<Hero clients={clients} />);
|
||||
|
||||
const small = screen.getByTestId("hero-work-mobile");
|
||||
expect(small).toHaveClass("lg:hidden");
|
||||
const image = small.querySelector("img") as HTMLImageElement;
|
||||
expect(image).toHaveAccessibleName(
|
||||
"Site da SEV Moda Íntima aberto no celular",
|
||||
);
|
||||
const buttons = screen.getByRole("link", { name: /ver projetos/i });
|
||||
expect(
|
||||
buttons.compareDocumentPosition(small) & Node.DOCUMENT_POSITION_FOLLOWING,
|
||||
).toBeTruthy();
|
||||
});
|
||||
});
|
||||
Reference in new issue
Block a user