feat(home): posicionamento com prova, menu sem recarregar e WhatsApp em todo o site

H1 'Sites e sistemas que trazem pedidos pelo WhatsApp e tiram sua operação da planilha.'; HeroWork maior com a SEV; menu Cases, Serviços, Como trabalho, Sobre e IA com next/link e pré-carregamento no hover; menu do celular em tela cheia; WhatsApp flutuante e no rodapé com a mensagem da rota; rodapé em todas as páginas; FAQ da home; /ia como oferta de revisão de app feito com IA; formulário com noscript, validação do mailto e plano B do pop-up; cartões sem foco indevido; sem a fonte Monument.
This commit is contained in:
Evandro Fonseca Junior committed 2026-10-14 14:15:25 -03:00
1 parent e80f73d075
commit 10f170abf4
56 files changed
+3099 -906

No files matched your search

+38 -30
View File
@@ -1,18 +1,41 @@
import type { Metadata, Viewport } from "next";
import { Geist_Mono, Space_Grotesk } from "next/font/google";
import localFont from "next/font/local";
import type { ReactNode } from "react";
import { safeJsonLd } from "@/lib/jsonld";
import { buildPersonJsonLd, buildWebSiteJsonLd } from "@/lib/seo";
import { siteUrl } from "@/lib/site-content";
import {
caseStudies,
serviceHubLinks,
servicePages,
siteUrl,
} from "@/lib/site-content";
import type { WhatsAppContexts } from "@/lib/whatsapp";
import CinematicOverlays from "./components/cinematic/CinematicOverlays";
import FloatingWhatsApp from "./components/FloatingWhatsApp";
import Footer from "./components/Footer";
import GoogleAnalytics from "./components/GoogleAnalytics";
import { Header } from "./components/Header";
import "./globals.css";
// O CSS da vitrine (molduras de navegador e de celular, vitrine animada) vem uma vez só, aqui, depois do global.
// Importado por cada componente que o usa, ele era pré-carregado pelos links do menu em páginas que não o usam
// (aviso de CSS pré-carregado e não usado).
import "./components/showcase/showcase.css";
const defaultTitle = "Sistemas sob medida para empresas | Evandro.dev.br";
const titleSuffix = " | Evandro.dev.br";
/** Título da home: o `title.default` não passa pelo template, então leva o sufixo. Com ele, no máximo 60 caracteres. */
const defaultTitle = `Sites e sistemas em Joinville e SC${titleSuffix}`;
const seoDescription =
"Sistemas web, aplicativos e integrações sob medida, do negócio à produção, com Evandro Fonseca Junior. Base em Santa Catarina, atendimento remoto.";
"Sites com pedido pelo WhatsApp e sistemas que tiram sua operação da planilha. Base em Garuva, SC; atendimento em Joinville e remoto em todo o Brasil.";
/** Para o WhatsApp falar do serviço ou do case da página aberta: só nomes, sem o conteúdo pesado das páginas. */
const whatsAppContexts: WhatsAppContexts = {
services: Object.fromEntries(
servicePages.map((service) => [service.slug, service.navLabel]),
),
cases: Object.fromEntries(
caseStudies.map((caseStudy) => [caseStudy.id, caseStudy.title]),
),
};
const spaceGrotesk = Space_Grotesk({
subsets: ["latin"],
@@ -28,27 +51,10 @@ const geistMono = Geist_Mono({
variable: "--font-geist-mono",
});
const monumentExtended = localFont({
src: [
{
path: "../public/fonts/MonumentExtended-Regular.otf",
weight: "400",
style: "normal",
},
{
path: "../public/fonts/MonumentExtended-Ultrabold.otf",
weight: "800",
style: "normal",
},
],
display: "swap",
variable: "--font-monument-extended",
});
export const metadata: Metadata = {
title: {
default: defaultTitle,
template: "%s | Evandro Fonseca Junior",
template: `%s${titleSuffix}`,
},
description: seoDescription,
authors: [{ name: "Evandro Fonseca Junior" }],
@@ -57,9 +63,6 @@ export const metadata: Metadata = {
applicationName: "Evandro.dev.br",
category: "Technology",
metadataBase: new URL(siteUrl),
alternates: {
canonical: "/",
},
formatDetection: {
email: false,
address: false,
@@ -77,7 +80,7 @@ export const metadata: Metadata = {
url: "/opengraph-image",
width: 1200,
height: 630,
alt: "Evandro.dev.br | Sistemas sob medida para empresas",
alt: "Evandro.dev.br | Sites e sistemas para empresas",
},
],
},
@@ -89,7 +92,7 @@ export const metadata: Metadata = {
images: [
{
url: "/opengraph-image",
alt: "Evandro.dev.br | Sistemas sob medida para empresas",
alt: "Evandro.dev.br | Sites e sistemas para empresas",
},
],
},
@@ -126,14 +129,14 @@ export default function RootLayout({ children }: Readonly<RootLayoutProps>) {
return (
<html
lang="pt-BR"
className={`${spaceGrotesk.variable} ${geistMono.variable} ${monumentExtended.variable}`}
className={`${spaceGrotesk.variable} ${geistMono.variable}`}
>
<head>
{/* Set arrival policy before native restoration and client-side layout changes. */}
<style id="arrival-scroll-policy">{`html { scroll-behavior: auto !important; }`}</style>
{/* Sem JavaScript as animações de entrada (opacity:0 inline vindo do servidor e palavras de título em CSS) não rodam: tudo precisa aparecer. */}
<noscript>
<style>{`[style*="opacity:0"],[style*="clip-path"]{opacity:1!important;transform:none!important;clip-path:none!important}.text-reveal-word{opacity:1!important;transform:none!important}`}</style>
<style>{`[style*="opacity:0"],[style*="clip-path"]{opacity:1!important;transform:none!important;clip-path:none!important}.text-reveal-word{opacity:1!important;transform:none!important}.js-only{display:none!important}`}</style>
</noscript>
<script>{`
addEventListener("load", () => {
@@ -161,11 +164,16 @@ export default function RootLayout({ children }: Readonly<RootLayoutProps>) {
</a>
{/* Aviso de cookies logo depois do "pular": fica cedo na ordem do Tab, ainda que fixo no rodapé da tela. */}
<GoogleAnalytics />
<Header />
<Header whatsAppContexts={whatsAppContexts} />
<CinematicOverlays />
<div id="main-content" tabIndex={-1}>
{children}
</div>
{/* Rodapé de todas as páginas; z-10 o mantém acima das cenas da home (relative z-0). */}
<div className="relative z-10">
<Footer serviceLinks={serviceHubLinks} />
</div>
<FloatingWhatsApp contexts={whatsAppContexts} />
</body>
</html>
);