feat(servicos): topo, entregáveis e cases por serviço, assunto próprio no WhatsApp e títulos curtos
This commit is contained in:
1 parent
cf360041bd
commit
2fd8b063d9
33 files changed
+1578
-300
No files matched your search
@@ -1,7 +1,7 @@
|
||||
import { ImageResponse } from "next/og";
|
||||
import { OG_CONTENT_TYPE, OG_SIZE, OgCard } from "@/lib/og-card";
|
||||
|
||||
export const alt = "Revisão de app feito com IA";
|
||||
export const alt = "Revisão de sistema e de app feito com IA";
|
||||
export const size = OG_SIZE;
|
||||
export const contentType = OG_CONTENT_TYPE;
|
||||
|
||||
@@ -9,7 +9,7 @@ export default function Image() {
|
||||
return new ImageResponse(
|
||||
<OgCard
|
||||
eyebrow="IA no desenvolvimento"
|
||||
title="Revisão de app feito com IA"
|
||||
title="Revisão de sistema e de app feito com IA"
|
||||
description="Falhas de acesso a dados, o que aproveitar, o que refazer e um orçamento para pôr em produção."
|
||||
/>,
|
||||
OG_SIZE,
|
||||
|
||||
+26
-6
@@ -1,18 +1,24 @@
|
||||
import { render, screen, within } from "@testing-library/react";
|
||||
import { offerLabels } from "@/lib/offer-labels";
|
||||
import AiPage, { metadata } from "./page";
|
||||
|
||||
it("uses a short search title: with the layout suffix it fits in 44 characters", () => {
|
||||
it("uses a short search title: up to 44 characters, and 60 with the layout suffix", () => {
|
||||
// o template de app/layout.tsx acrescenta " | Evandro.dev.br"
|
||||
const suffix = " | Evandro.dev.br";
|
||||
expect(metadata.title).toBe("Revisão de app feito com IA");
|
||||
expect(`${metadata.title}${suffix}`.length).toBeLessThanOrEqual(44);
|
||||
expect(metadata.title).toBe("Revisão de sistema e de app feito com IA");
|
||||
expect(String(metadata.title).length).toBeLessThanOrEqual(44);
|
||||
expect(`${metadata.title}${suffix}`.length).toBeLessThanOrEqual(60);
|
||||
expect(metadata).toMatchObject({
|
||||
description: expect.any(String),
|
||||
alternates: { canonical: "https://evandro.dev.br/ia" },
|
||||
});
|
||||
// como nas outras páginas, o título da prévia de compartilhamento é o mesmo da busca, sem o sufixo
|
||||
expect(metadata.openGraph?.title).toBe("Revisão de app feito com IA");
|
||||
expect(metadata.twitter?.title).toBe("Revisão de app feito com IA");
|
||||
expect(metadata.openGraph?.title).toBe(
|
||||
"Revisão de sistema e de app feito com IA",
|
||||
);
|
||||
expect(metadata.twitter?.title).toBe(
|
||||
"Revisão de sistema e de app feito com IA",
|
||||
);
|
||||
});
|
||||
|
||||
it("uses no lime outside the contact actions (the quote on the paper background is ink)", () => {
|
||||
@@ -75,7 +81,7 @@ it("has breadcrumb navigation back to the home", () => {
|
||||
within(breadcrumb).getByRole("link", { name: "Início" }),
|
||||
).toHaveAttribute("href", "/");
|
||||
expect(
|
||||
within(breadcrumb).getByText("Revisão de app feito com IA"),
|
||||
within(breadcrumb).getByText(offerLabels.revisao.name),
|
||||
).toHaveAttribute("aria-current", "page");
|
||||
});
|
||||
|
||||
@@ -232,3 +238,17 @@ it("keeps the incident news collapsed in a <details>, closed by default", () =>
|
||||
.closest("details"),
|
||||
).toBeNull();
|
||||
});
|
||||
|
||||
it("names the review like the offer on the home: the trail and the structured data use the offer name, not the search title", () => {
|
||||
const { container } = render(<AiPage />);
|
||||
|
||||
const script = container.querySelector('script[type="application/ld+json"]');
|
||||
const data = JSON.parse(script?.textContent ?? "{}");
|
||||
const breadcrumb = data["@graph"].find(
|
||||
(node: { "@type": string }) => node["@type"] === "BreadcrumbList",
|
||||
);
|
||||
expect(
|
||||
breadcrumb.itemListElement.map(({ name }: { name: string }) => name),
|
||||
).toEqual(["Início", offerLabels.revisao.name]);
|
||||
expect(offerLabels.revisao.name).toBe("Revisão de sistema que já existe");
|
||||
});
|
||||
+8
-4
@@ -8,13 +8,17 @@ import {
|
||||
import HoverPrefetchLink from "@/app/components/HoverPrefetchLink";
|
||||
import WhatsAppLink from "@/app/components/WhatsAppLink";
|
||||
import { safeJsonLd } from "@/lib/jsonld";
|
||||
import { offerLabels } from "@/lib/offer-labels";
|
||||
import { buildBreadcrumbList, buildPageSocialMetadata } from "@/lib/seo";
|
||||
import { siteUrl } from "@/lib/site-content";
|
||||
import { AI_REVIEW_SUBJECT } from "@/lib/whatsapp";
|
||||
|
||||
const pageUrl = `${siteUrl}/ia`;
|
||||
/** Curto de propósito: o template de app/layout.tsx acrescenta " | Evandro.dev.br" e o conjunto cabe em 44 caracteres. */
|
||||
const pageTitle = "Revisão de app feito com IA";
|
||||
/**
|
||||
* Título para busca: até 44 caracteres, e 60 com o " | Evandro.dev.br" que o template de app/layout.tsx acrescenta. Cobre a oferta
|
||||
* (revisão de sistema) e a busca por app feito com IA. O nome da oferta, o mesmo da home, é o da trilha e dos dados estruturados.
|
||||
*/
|
||||
const pageTitle = "Revisão de sistema e de app feito com IA";
|
||||
const pageDescription =
|
||||
"Fez um app com Lovable, Bolt ou Replit? Eu reviso as falhas de acesso a dados, separo o que aproveitar do que refazer e faço o orçamento para a produção.";
|
||||
/** Entra na frase "Quero conversar sobre {assunto}." da mensagem do WhatsApp (a mesma do botão flutuante em /ia). */
|
||||
@@ -167,7 +171,7 @@ export default function AiPage() {
|
||||
"@graph": [
|
||||
buildBreadcrumbList(pageUrl, [
|
||||
["Início", siteUrl],
|
||||
["Revisão de app feito com IA", pageUrl],
|
||||
[offerLabels.revisao.name, pageUrl],
|
||||
] as const),
|
||||
],
|
||||
};
|
||||
@@ -181,7 +185,7 @@ export default function AiPage() {
|
||||
<Breadcrumb
|
||||
items={[
|
||||
{ label: "Início", href: "/" },
|
||||
{ label: "Revisão de app feito com IA", href: "/ia" },
|
||||
{ label: offerLabels.revisao.name, href: "/ia" },
|
||||
]}
|
||||
/>
|
||||
<div className="grid items-center gap-sp-8 lg:grid-cols-[minmax(0,1.1fr)_minmax(0,0.9fr)] lg:gap-sp-12">
|
||||
|
||||
Reference in new issue
Block a user