Files
portifolio-evandrodevbr/app/servicos/_components/ServiceHero.tsx
T
evandro c7d09d63d4
CI / audit (push) Successful in 10m38s
CI / verify (push) Successful in 13m10s
CI / deploy (push) Successful in 1m50s
CI / e2e (push) Successful in 18m48s
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.
2026-11-10 03:48:25 -03:00

92 lines
3.1 KiB
TypeScript

import {
compactHero,
heroWithMediaGrid,
} from "@/app/cases/_components/hero-styles";
import { Breadcrumb } from "@/app/components/Breadcrumb";
import {
pageTop,
primaryButton,
secondaryButtonDark,
} from "@/app/components/button-styles";
import { PagePiece } from "@/app/components/PagePiece";
import WhatsAppLink from "@/app/components/WhatsAppLink";
import { buttonLabels, type ServicePageContent } from "@/lib/site-content";
import { ServiceDiagram } from "./ServiceDiagram";
import { ServiceHeroCover } from "./ServiceHeroCover";
import type { ServiceHeroData } from "./service-page";
/**
* Topo da página do serviço: trilha, título, resposta, botão de contato e, na coluna ao lado, a capa do case escolhido
* ou o esquema de fluxo. Sem nenhum dos dois, o topo é uma coluna só e mais baixo; com `heroLoop`, a peça de blocos
* ocupa a coluna ao lado de 1024 px em diante, sem mudar a altura do topo.
*/
export function ServiceHero({
service,
hero,
}: {
service: ServicePageContent;
hero: ServiceHeroData;
}) {
const { heroCase, heroDevice, diagram, hasHeroSide, hasCaseCards } = hero;
const loop = hasHeroSide ? undefined : service.heroLoop;
return (
<section
className={`ds-section ds-section-dark ${pageTop} ${
hasHeroSide ? "" : compactHero
}`}
>
<div
className={`ds-section-shell ${hasHeroSide || loop ? heroWithMediaGrid : ""}`}
>
<div className="min-w-0 max-w-[860px]">
<Breadcrumb
items={[
{ label: "Início", href: "/" },
{ label: "Serviços", href: "/servicos" },
{ label: service.navLabel, href: `/servicos/${service.slug}` },
]}
/>
<h1 className="ds-section-title max-w-[22ch] text-balance text-white">
{service.headline}
</h1>
<p className="ds-copy max-w-[64ch] !text-[rgba(255,255,255,0.78)]">
{service.answer}
</p>
<div className="mt-sp-8 flex flex-wrap gap-sp-3">
<WhatsAppLink
service={service.whatsappSubject}
placement="service_detail_hero"
className={primaryButton}
>
{buttonLabels.whatsapp}
</WhatsAppLink>
{hasCaseCards ? (
<a href="#casos-relacionados" className={secondaryButtonDark}>
Ver projetos parecidos
</a>
) : null}
</div>
<p className="mt-sp-4 text-[15px] leading-6 text-white/70">
O botão abre uma conversa no WhatsApp, sem formulário. Garuva e
Joinville (SC) · atendimento remoto em todo o Brasil.
</p>
</div>
{diagram ? (
<ServiceDiagram kind={diagram} />
) : loop ? (
<PagePiece loop={loop} />
) : (
<ServiceHeroCover
caseStudy={heroCase}
device={heroDevice}
relevance={
heroCase ? service.caseRelevance[heroCase.id] : undefined
}
/>
)}
</div>
</section>
);
}