feat(site): blocos 3D da marca, novas ofertas e hero mais abrangente
Hero e movimento - cena 3D em tempo real com os blocos da marca (kit feito no Blender, 3d/blocos.py): marca, tela, integrações e dados; segue a rolagem, tem vida em repouso, reage ao cursor e, parada no topo, passa sozinha pelos estados com legenda - três níveis de aparelho (full, lite, static); sem WebGL fica o pôster - título novo: "Sites e sistemas sob medida para o jeito que a sua empresa trabalha." - faixa de clientes com o ramo, linha do primeiro passo, hero alinhado às seções - rótulos digitados, entrada dos blocos, cortina de blocos entre páginas e capa compartilhada entre a lista de cases e o case Ofertas - atendimento no WhatsApp com IA e nota fiscal para a reforma tributária (páginas de serviço, cartões da home, formulário e aviso com data de validade) - página /ia atualizada, com fontes - peças 3D em loop nos cartões e topos de página (3d/pecas.py) Design - hover por papel (bloco nos botões, barra nos links), rótulos sem caixa alta - um destino por rótulo: "Falar sobre meu projeto" leva ao formulário, "Chamar no WhatsApp" abre o WhatsApp - logo montado em blocos, 404 redesenhado, grades sem célula vazia - ícones do PWA e manifesto novos Specs em specs/, contexto de design em DESIGN.md e PRODUCT.md.
This commit is contained in:
1 parent
4671837c44
commit
c7d09d63d4
165 files changed
+7940
-3790
No files matched your search
@@ -126,7 +126,7 @@ describe("CasePage: caminhos que o teste principal não cobre", () => {
|
||||
expect(screen.queryByText("Serviços ligados a este projeto")).toBeNull();
|
||||
// o NutriScan tem "Como ficou", mas o botão de contato é um só, o do fecho (sem dois seguidos)
|
||||
const contacts = screen.getAllByRole("link", {
|
||||
name: "Falar sobre meu projeto",
|
||||
name: "Chamar no WhatsApp",
|
||||
});
|
||||
expect(contacts).toHaveLength(1);
|
||||
expect(contacts[0]).toBeVisible();
|
||||
|
||||
@@ -62,8 +62,8 @@ function readJsonLdEntities(container: HTMLElement): Record<string, unknown>[] {
|
||||
|
||||
/**
|
||||
* Nenhum link para /#contact nem para o GitHub; o contato é o WhatsApp com o contexto do case, com o mesmo rótulo
|
||||
* ("Falar sobre meu projeto") no case de cliente e no de laboratório. A mensagem é a mesma frase nos dois, a do cabeçalho:
|
||||
* `similarProjectSubject(título)`. Um botão só por página (o do fecho): sem dois "Falar sobre meu projeto" seguidos.
|
||||
* ("Chamar no WhatsApp") no case de cliente e no de laboratório. A mensagem é a mesma frase nos dois, a do cabeçalho:
|
||||
* `similarProjectSubject(título)`. Um botão só por página (o do fecho): sem dois "Chamar no WhatsApp" seguidos.
|
||||
*/
|
||||
function expectContactAndNoDeadLinks(caseStudy: { id: string; title: string }) {
|
||||
const hrefs = screen
|
||||
@@ -72,7 +72,7 @@ function expectContactAndNoDeadLinks(caseStudy: { id: string; title: string }) {
|
||||
expect(hrefs).not.toContain("/#contact");
|
||||
expect(hrefs.some((href) => /github/i.test(href))).toBe(false);
|
||||
|
||||
const ctas = screen.getAllByRole("link", { name: buttonLabels.contact });
|
||||
const ctas = screen.getAllByRole("link", { name: buttonLabels.whatsapp });
|
||||
expect(ctas).toHaveLength(1);
|
||||
for (const cta of ctas) {
|
||||
const destination = new URL(cta.getAttribute("href") ?? "");
|
||||
@@ -179,13 +179,13 @@ it("renders a client case in the sales order, with media, contact and collapsed
|
||||
const capabilitiesSection = sectionHeadings[4].closest("section");
|
||||
expect(
|
||||
within(capabilitiesSection as HTMLElement).queryByRole("link", {
|
||||
name: buttonLabels.contact,
|
||||
name: buttonLabels.whatsapp,
|
||||
}),
|
||||
).toBeNull();
|
||||
const closingSection = sectionHeadings[5].closest("section");
|
||||
expect(closingSection).toContainElement(
|
||||
within(closingSection as HTMLElement).getByRole("link", {
|
||||
name: buttonLabels.contact,
|
||||
name: buttonLabels.whatsapp,
|
||||
}),
|
||||
);
|
||||
for (const capability of caseStudy.capabilities ?? []) {
|
||||
@@ -371,10 +371,10 @@ it("writes what the client can do now right after 'Como ficou', with no contact
|
||||
expect(items.length).toBeLessThanOrEqual(3);
|
||||
// sem número inventado
|
||||
expect(items.join(" ")).not.toMatch(/\d/);
|
||||
// o único botão de contato é o do fecho, depois da lista: não há dois "Falar sobre meu projeto" seguidos
|
||||
// o único botão de contato é o do fecho, depois da lista: não há dois "Chamar no WhatsApp" seguidos
|
||||
expect(
|
||||
within(capabilitiesSection as HTMLElement).queryByRole("link", {
|
||||
name: buttonLabels.contact,
|
||||
name: buttonLabels.whatsapp,
|
||||
}),
|
||||
).toBeNull();
|
||||
const closingSection = screen
|
||||
@@ -386,7 +386,7 @@ it("writes what the client can do now right after 'Como ficou', with no contact
|
||||
expect(capabilitiesSection?.nextElementSibling).toBe(closingSection);
|
||||
expect(
|
||||
within(closingSection as HTMLElement).getAllByRole("link", {
|
||||
name: buttonLabels.contact,
|
||||
name: buttonLabels.whatsapp,
|
||||
}),
|
||||
).toHaveLength(1);
|
||||
unmount();
|
||||
@@ -477,7 +477,7 @@ it("shows at most two related services, as cards under the contact button", asyn
|
||||
screen.queryByRole("link", { name: /^Ver serviço relacionado:/ }),
|
||||
).toBeNull();
|
||||
// o botão do fecho (o único) vem antes dos cartões
|
||||
const contact = screen.getByRole("link", { name: buttonLabels.contact });
|
||||
const contact = screen.getByRole("link", { name: buttonLabels.whatsapp });
|
||||
expect(isBefore(contact, cards[0])).toBe(true);
|
||||
unmount();
|
||||
|
||||
@@ -748,7 +748,7 @@ it("lists client cases with a cover first, then the laboratory, and keeps the sc
|
||||
expect(hrefs).not.toContain("/#contact");
|
||||
expect(hrefs.some((href) => /github/i.test(href))).toBe(false);
|
||||
expect(hrefs).toContain("/servicos");
|
||||
const cta = screen.getByRole("link", { name: buttonLabels.contact });
|
||||
const cta = screen.getByRole("link", { name: buttonLabels.whatsapp });
|
||||
expect(new URL(cta.getAttribute("href") ?? "").origin).toBe("https://wa.me");
|
||||
|
||||
const visibleBreadcrumb = screen.getByRole("navigation", {
|
||||
|
||||
Reference in new issue
Block a user