feat(cases): prova certa por serviço, páginas internas com trabalho no topo
Diagnóstico sem case que não cabe; desktop com o GCC Installer como projeto próprio; IoT com o Twins Lab e a nota da Apolo. Mosaico de pôsteres em /servicos e /cases, faixa baixa em uma coluna no currículo, privacidade e laboratório; Laboratório como lista compacta; SEV começando por catálogo, pedido no WhatsApp e painel; Joinville e SC nos títulos; imagens do LCP com fetchPriority e sizes reais; pré-carregamento só no hover; 404 com Open Graph próprio.
This commit is contained in:
1 parent
7b633f0f4a
commit
de6af74a0c
37 files changed
+1062
-254
No files matched your search
@@ -92,6 +92,7 @@ it("builds a canonical service with only the verified service area", () => {
|
||||
provider: { "@id": SEO_IDS.person },
|
||||
areaServed: [
|
||||
{ "@type": "City", name: "Garuva" },
|
||||
{ "@type": "City", name: "Joinville" },
|
||||
{ "@type": "AdministrativeArea", name: "Norte de Santa Catarina" },
|
||||
],
|
||||
});
|
||||
|
||||
@@ -76,6 +76,7 @@ export function buildServiceJsonLd(service: ServicePageContent) {
|
||||
provider: { "@id": SEO_IDS.person },
|
||||
areaServed: [
|
||||
{ "@type": "City", name: "Garuva" },
|
||||
{ "@type": "City", name: "Joinville" },
|
||||
{
|
||||
"@type": "AdministrativeArea",
|
||||
name: "Norte de Santa Catarina",
|
||||
|
||||
+50
-12
@@ -100,16 +100,57 @@ it("maps each service to its client cases", () => {
|
||||
"lavacao-047",
|
||||
"sc-plus",
|
||||
]);
|
||||
expect(getService("arquitetura-de-software").relatedCaseIds).toEqual([
|
||||
"sev-modaintima",
|
||||
]);
|
||||
// GCC Installer é Python/Tkinter: não combina com um serviço de Tauri e Rust
|
||||
expect(getService("tauri-rust").relatedCaseIds).toEqual([]);
|
||||
// nenhum case de cliente é um diagnóstico de sistema: o serviço fica só com a experiência na Apolo
|
||||
expect(getService("arquitetura-de-software").relatedCaseIds).toEqual([]);
|
||||
expect(getService("arquitetura-de-software").caseRelevance).toEqual({});
|
||||
// o GCC Installer é um app para Windows (em Python): entra no serviço de desktop como projeto próprio
|
||||
expect(getService("tauri-rust").relatedCaseIds).toEqual(["gcc-installer"]);
|
||||
expect(getService("integracao-hardware-software-iot").relatedCaseIds).toEqual(
|
||||
["twins-lab"],
|
||||
);
|
||||
});
|
||||
|
||||
it("says what the Next.js service cases really prove: sites built by me, not a diagnosis", () => {
|
||||
const { caseRelevance } = getService("consultoria-nextjs");
|
||||
for (const id of ["sev-modaintima", "lavacao-047"]) {
|
||||
expect(caseRelevance[id]).toMatch(/construí em Next\.js 16/);
|
||||
expect(caseRelevance[id]).not.toMatch(/diagn|conheço por dentro/i);
|
||||
}
|
||||
});
|
||||
|
||||
it("is honest that the desktop case is a Windows app made in Python, not in Tauri", () => {
|
||||
expect(getService("tauri-rust").caseRelevance["gcc-installer"]).toMatch(
|
||||
/Windows.*Python/,
|
||||
);
|
||||
});
|
||||
|
||||
it("places the services in Joinville and SC instead of only 'em Garuva'", () => {
|
||||
expect(getService("criacao-de-sites").metaTitle).toBe(
|
||||
"Criação de sites em Joinville e SC",
|
||||
);
|
||||
for (const service of servicePages) {
|
||||
expect(service.metaTitle).not.toMatch(/em Garuva/);
|
||||
expect(service.metaDescription).toMatch(/Garuva e Joinville \(SC\)/);
|
||||
}
|
||||
});
|
||||
|
||||
it("opens the case lists with what sells: the catalog, the order by WhatsApp and the panel", () => {
|
||||
const deliveries =
|
||||
caseStudies.find(({ id }) => id === "sev-modaintima")?.deliveries ?? [];
|
||||
const [catalog, whatsapp, panel] = deliveries;
|
||||
expect(catalog).toMatch(/^Catálogo por tamanho/);
|
||||
expect(whatsapp).toMatch(/^Pedido pelo WhatsApp/);
|
||||
expect(panel).toMatch(/^Painel para a loja cadastrar as peças/);
|
||||
// a vitrine com animações, que era a primeira, vai para o fim
|
||||
expect(deliveries[deliveries.length - 1]).toMatch(
|
||||
/^Uma vitrine com animações/,
|
||||
);
|
||||
// a animação da Lavação também não abre a lista
|
||||
expect(
|
||||
caseStudies.find(({ id }) => id === "lavacao-047")?.deliveries[0],
|
||||
).toMatch(/^Tabela de preços/);
|
||||
});
|
||||
|
||||
it("puts client cases before laboratory cases when listing related work", () => {
|
||||
expect(
|
||||
getRelatedCases(["twins-lab", "lavacao-047", "sev-modaintima"]).map(
|
||||
@@ -128,14 +169,11 @@ it("derives the exact related service set from the existing relationship", () =>
|
||||
.map(({ slug }) => slug)
|
||||
.sort(),
|
||||
).toEqual(
|
||||
[
|
||||
"criacao-de-sites",
|
||||
"engenharia-de-software",
|
||||
"consultoria-nextjs",
|
||||
"arquitetura-de-software",
|
||||
].sort(),
|
||||
["criacao-de-sites", "engenharia-de-software", "consultoria-nextjs"].sort(),
|
||||
);
|
||||
expect(getRelatedServices("gcc-installer")).toEqual([]);
|
||||
expect(getRelatedServices("gcc-installer").map(({ slug }) => slug)).toEqual([
|
||||
"tauri-rust",
|
||||
]);
|
||||
});
|
||||
|
||||
it("resolves every declared related case ID", () => {
|
||||
|
||||
+25
-25
@@ -8,7 +8,7 @@ export interface ServicePageContent {
|
||||
slug: string;
|
||||
navLabel: string;
|
||||
eyebrow: string;
|
||||
/** Título para busca, separado do h1: até 44 caracteres, e 60 com o sufixo " | Evandro.dev.br" (17) que o layout acrescenta. */
|
||||
/** Título para busca, separado do h1: até 43 caracteres, e 60 com o sufixo " | Evandro.dev.br" (17) que o layout acrescenta. */
|
||||
metaTitle: string;
|
||||
/** Descrição para busca, com até 155 caracteres. */
|
||||
metaDescription: string;
|
||||
@@ -41,7 +41,7 @@ export interface CaseStudyContent {
|
||||
title: string;
|
||||
/** Tipo do projeto, em poucas palavras. */
|
||||
subtitle: string;
|
||||
/** Título para busca, separado do h1: até 44 caracteres, e 60 com o sufixo " | Evandro.dev.br" (17) que o layout acrescenta. */
|
||||
/** Título para busca, separado do h1: até 43 caracteres, e 60 com o sufixo " | Evandro.dev.br" (17) que o layout acrescenta. */
|
||||
metaTitle: string;
|
||||
/** Descrição para busca, com até 155 caracteres. */
|
||||
metaDescription: string;
|
||||
@@ -74,9 +74,9 @@ export const servicePages: ServicePageContent[] = [
|
||||
slug: "criacao-de-sites",
|
||||
navLabel: "Sites profissionais",
|
||||
eyebrow: "Presença digital",
|
||||
metaTitle: "Criação de sites para empresas em Garuva",
|
||||
metaTitle: "Criação de sites em Joinville e SC",
|
||||
metaDescription:
|
||||
"Site profissional para apresentar sua empresa e levar o cliente ao WhatsApp. Feito em Garuva-SC, com atendimento em Joinville e remoto no Brasil.",
|
||||
"Site profissional para apresentar sua empresa e levar o cliente ao WhatsApp. Atendimento em Garuva e Joinville (SC) e remoto em todo o Brasil.",
|
||||
headline: "Um site que explica seu negócio.",
|
||||
answer:
|
||||
"Crio sites para apresentar sua empresa, mostrar o que você oferece e facilitar o contato. O projeto considera leitura no celular e no computador, conteúdo, páginas e funcionalidades combinadas antes do desenvolvimento.",
|
||||
@@ -145,7 +145,7 @@ export const servicePages: ServicePageContent[] = [
|
||||
eyebrow: "Engenharia de software",
|
||||
metaTitle: "Sistemas web e aplicativos sob medida",
|
||||
metaDescription:
|
||||
"Sistema web ou aplicativo sob medida para organizar pedidos, clientes e rotinas. Desenvolvedor em Garuva-SC, atende Joinville e remoto no Brasil.",
|
||||
"Sistema web ou aplicativo sob medida para organizar pedidos, clientes e rotinas. Atendimento em Garuva e Joinville (SC) e remoto em todo o Brasil.",
|
||||
headline: "Sistemas e apps para o seu trabalho.",
|
||||
answer:
|
||||
"Desenvolvo sistemas web, usados no navegador, e aplicativos mobile para celular. Também conecto ferramentas e evoluo sistemas existentes. Definimos juntos os usuários, as funções, as plataformas atendidas e a primeira entrega útil para o negócio.",
|
||||
@@ -210,7 +210,7 @@ export const servicePages: ServicePageContent[] = [
|
||||
eyebrow: "Consultoria Next.js",
|
||||
metaTitle: "Consultoria Next.js para site ou sistema",
|
||||
metaDescription:
|
||||
"Descubra por que seu site ou sistema Next.js está lento ou com falhas e receba um plano de correção claro. Garuva-SC, Joinville e remoto no Brasil.",
|
||||
"Descubra por que seu site ou sistema Next.js está lento ou com falhas e receba um plano de correção. Garuva e Joinville (SC), remoto em todo o Brasil.",
|
||||
headline: "Seu projeto Next.js pode funcionar melhor.",
|
||||
answer:
|
||||
"Analiso sites e sistemas feitos em Next.js para entender lentidão, falhas ou dificuldades de manutenção. Você recebe prioridades explicadas, um plano de correção e, quando contratado, a implementação das melhorias.",
|
||||
@@ -247,9 +247,9 @@ export const servicePages: ServicePageContent[] = [
|
||||
relatedCaseIds: ["sev-modaintima", "lavacao-047", "sc-plus"],
|
||||
caseRelevance: {
|
||||
"sev-modaintima":
|
||||
"Um projeto em Next.js 16 com catálogo, busca, estoque e painel, que conheço por dentro.",
|
||||
"Uma loja que construí em Next.js 16, com catálogo, busca, estoque e painel.",
|
||||
"lavacao-047":
|
||||
"Um projeto em Next.js 16 em que o conteúdo do painel alimenta a página, o sitemap e os dados para os buscadores.",
|
||||
"Um site que construí em Next.js 16, em que o conteúdo do painel alimenta a página, o sitemap e os dados para os buscadores.",
|
||||
"sc-plus":
|
||||
"Uma página em Next.js 15 com título, descrição, endereço canônico e dados estruturados para os buscadores.",
|
||||
},
|
||||
@@ -277,7 +277,7 @@ export const servicePages: ServicePageContent[] = [
|
||||
eyebrow: "Aplicativos desktop",
|
||||
metaTitle: "Aplicativos desktop para Windows e Linux",
|
||||
metaDescription:
|
||||
"Aplicativo desktop para Windows e Linux que automatiza tarefas no computador da empresa. Desenvolvedor em Garuva-SC, atendimento remoto no Brasil.",
|
||||
"Aplicativo desktop para Windows e Linux que automatiza tarefas no computador da empresa. Garuva e Joinville (SC), atendimento remoto em todo o Brasil.",
|
||||
headline: "Aplicativos para Windows e Linux.",
|
||||
answer:
|
||||
"Desenvolvo aplicativos desktop para trabalhar no computador, lidar com arquivos e integrar recursos locais. Windows e Linux são as plataformas atendidas; as versões e distribuições compatíveis são combinadas em cada projeto.",
|
||||
@@ -316,8 +316,11 @@ export const servicePages: ServicePageContent[] = [
|
||||
"Integração com o sistema",
|
||||
],
|
||||
ctaLabel: "Conversar sobre meu aplicativo desktop",
|
||||
relatedCaseIds: [],
|
||||
caseRelevance: {},
|
||||
relatedCaseIds: ["gcc-installer"],
|
||||
caseRelevance: {
|
||||
"gcc-installer":
|
||||
"Um aplicativo para Windows feito por mim, em Python e não em Tauri: lista as versões do compilador, instala e ajusta o PATH em uma única janela.",
|
||||
},
|
||||
faq: [
|
||||
{
|
||||
question: "O mesmo aplicativo pode funcionar em Windows e Linux?",
|
||||
@@ -342,7 +345,7 @@ export const servicePages: ServicePageContent[] = [
|
||||
eyebrow: "Hardware, software e IoT",
|
||||
metaTitle: "Integração de equipamentos e sistemas (IoT)",
|
||||
metaDescription:
|
||||
"Leve os dados dos seus equipamentos para um painel e acompanhe a operação sem anotações manuais. Garuva-SC, Joinville e remoto no Brasil.",
|
||||
"Leve os dados dos seus equipamentos para um painel e acompanhe a operação sem anotações manuais. Garuva e Joinville (SC), remoto em todo o Brasil.",
|
||||
headline: "Dados dos equipamentos no seu sistema.",
|
||||
answer:
|
||||
"Conecto equipamentos e software para transformar leituras e eventos em informação útil para a operação. Primeiro vemos o que cada dispositivo permite acessar; a integração segue essas interfaces e os requisitos de segurança e funcionamento.",
|
||||
@@ -407,7 +410,7 @@ export const servicePages: ServicePageContent[] = [
|
||||
eyebrow: "Diagnóstico e decisão",
|
||||
metaTitle: "Diagnóstico e arquitetura de software",
|
||||
metaDescription:
|
||||
"Entenda por que seu sistema ficou difícil de mudar e decida o que corrigir, manter ou trocar. Diagnóstico com plano, de Garuva-SC para todo o Brasil.",
|
||||
"Entenda por que seu sistema ficou difícil de mudar e decida o que corrigir, manter ou trocar. Garuva e Joinville (SC), remoto em todo o Brasil.",
|
||||
headline: "Entenda o problema antes de mudar tudo.",
|
||||
answer:
|
||||
"Analiso como um sistema está organizado e por que ficou difícil de manter ou evoluir. Você recebe um diagnóstico explicado, prioridades e um plano de mudança para decidir o que corrigir, preservar ou substituir.",
|
||||
@@ -447,11 +450,8 @@ export const servicePages: ServicePageContent[] = [
|
||||
"Sistemas críticos",
|
||||
],
|
||||
ctaLabel: "Conversar sobre um diagnóstico",
|
||||
relatedCaseIds: ["sev-modaintima"],
|
||||
caseRelevance: {
|
||||
"sev-modaintima":
|
||||
"Uma loja completa, com catálogo, pedidos, estoque e painel, em que as decisões técnicas estão explicadas no case.",
|
||||
},
|
||||
relatedCaseIds: [],
|
||||
caseRelevance: {},
|
||||
experienceNote:
|
||||
"Desde 2022 desenvolvo sistemas internos, aplicativos e APIs na Apolo Energia e participo do planejamento e da arquitetura de novas soluções. Por serem sistemas de uso interno, não há link nem detalhes públicos.",
|
||||
faq: [
|
||||
@@ -492,12 +492,12 @@ export const caseStudies: CaseStudyContent[] = [
|
||||
problem:
|
||||
"A loja vende moda íntima em várias peças e tamanhos. A cliente precisa achar o que procura entre as opções e escolher a medida certa, e o pedido segue pelo WhatsApp, com o frete calculado pela distância. A loja, por sua vez, precisa saber o que ainda tem de cada tamanho.",
|
||||
deliveries: [
|
||||
"Uma vitrine com animações que dão destaque aos produtos e deixam a navegação agradável.",
|
||||
"Filtros e busca inteligente: a cliente encontra o que procura e os itens mais relevantes aparecem primeiro.",
|
||||
"Catálogo por tamanho, com filtros e busca: a cliente encontra a peça, escolhe a medida e vê primeiro os itens mais relevantes.",
|
||||
"Pedido pelo WhatsApp: a cliente escolhe os produtos no site e envia o pedido para a loja.",
|
||||
"Frete calculado pela distância até o endereço da cliente.",
|
||||
"Painel administrativo para a loja cadastrar produtos, acompanhar pedidos e controlar o estoque.",
|
||||
"Painel para a loja cadastrar as peças, acompanhar os pedidos e controlar o estoque.",
|
||||
"Estoque controlado por tamanho, para cada medida ter a sua quantidade.",
|
||||
"Frete calculado pela distância até o endereço da cliente.",
|
||||
"Uma vitrine com animações que dão destaque aos produtos e deixam a navegação agradável.",
|
||||
],
|
||||
stack: [
|
||||
"Next.js 16",
|
||||
@@ -538,8 +538,8 @@ export const caseStudies: CaseStudyContent[] = [
|
||||
"Painel do dono: ele altera preços, textos, fotos e o mapa sozinho, e a mudança aparece no site sem nova publicação.",
|
||||
"Galeria de trabalhos por serviço, para o cliente ver o resultado antes de chamar.",
|
||||
"Mapa de localização, para o cliente achar a lavação.",
|
||||
"Uma animação de rolagem que leva o carro do sujo ao brilho e perguntas frequentes montadas com os dados reais do negócio.",
|
||||
"Informações organizadas para o Google e para assistentes de IA entenderem o que a lavação faz e onde fica.",
|
||||
"Uma animação de rolagem que leva o carro do sujo ao brilho e perguntas frequentes montadas com os dados reais do negócio.",
|
||||
],
|
||||
stack: [
|
||||
"Next.js 16",
|
||||
@@ -667,8 +667,8 @@ export const caseStudies: CaseStudyContent[] = [
|
||||
"A instituição tem várias áreas de atuação e projetos. Quem chega pela primeira vez precisa entender o que ela faz e saber como entrar em contato. Sem um endereço próprio, isso não fica reunido em um só lugar.",
|
||||
deliveries: [
|
||||
"Uma página própria que apresenta a instituição, as áreas de atuação e os projetos.",
|
||||
"Uma seção de apoiadores e de participação, para quem quer apoiar ou participar.",
|
||||
"Contato direto na própria página.",
|
||||
"Uma seção de apoiadores e de participação, para quem quer apoiar ou participar.",
|
||||
"Título, descrição e imagem de compartilhamento próprios, para o link aparecer bem nos buscadores e nas redes.",
|
||||
"Dados estruturados que ajudam o Google a entender de quem é a página.",
|
||||
],
|
||||
@@ -726,8 +726,8 @@ export const caseStudies: CaseStudyContent[] = [
|
||||
problem:
|
||||
"A empresa reúne duas frentes bem diferentes: a engenharia física, de um lado, e o software, do outro. Em um site comum, as duas podem virar uma lista de serviços sem relação entre si. O desafio era mostrar as duas na mesma história, de um jeito que prenda a atenção de quem rola a página e que continue leve em celulares e conexões mais simples.",
|
||||
deliveries: [
|
||||
"Uma cena 3D que acompanha a rolagem: casa, instalação elétrica e placa-mãe aparecem desenhadas em linhas.",
|
||||
"As duas frentes da empresa, a física e a digital, aparecem na mesma história visual.",
|
||||
"Uma cena 3D que acompanha a rolagem: casa, instalação elétrica e placa-mãe aparecem desenhadas em linhas.",
|
||||
"A qualidade da cena se ajusta ao aparelho: celulares, conexões mais simples e quem prefere menos movimento recebem uma versão mais leve.",
|
||||
"Um painel para controle de projetos, desenvolvido junto com a primeira página do site.",
|
||||
],
|
||||
|
||||
Reference in new issue
Block a user