feat: harden portfolio and add SEO foundations
This commit is contained in:
1 parent
b079afdd73
commit
62bcfbd8fa
121 files changed
+7769
-10469
No files matched your search
@@ -1,12 +1,13 @@
|
||||
import type { Metadata } from "next";
|
||||
import Link from "next/link";
|
||||
import { notFound } from "next/navigation";
|
||||
import HeroBackground from "@/app/components/cinematic/HeroBackground";
|
||||
import MagneticButton from "@/app/components/cinematic/MagneticButton";
|
||||
import { safeJsonLd } from "@/lib/jsonld";
|
||||
import { buildBreadcrumbList, buildServiceJsonLd } from "@/lib/seo";
|
||||
import {
|
||||
getRelatedCases,
|
||||
getServicePage,
|
||||
regionCities,
|
||||
servicePages,
|
||||
siteName,
|
||||
siteUrl,
|
||||
@@ -71,54 +72,12 @@ export default async function ServicePage({ params }: ServicePageProps) {
|
||||
const jsonLd = {
|
||||
"@context": "https://schema.org",
|
||||
"@graph": [
|
||||
{
|
||||
"@type": "Service",
|
||||
"@id": `${pageUrl}#service`,
|
||||
name: service.navLabel,
|
||||
description: service.metaDescription,
|
||||
serviceType: service.navLabel,
|
||||
provider: {
|
||||
"@type": "Person",
|
||||
name: "Evandro Fonseca Junior",
|
||||
url: siteUrl,
|
||||
},
|
||||
areaServed: [
|
||||
...regionCities.map((name) => ({ "@type": "City", name })),
|
||||
{ "@type": "AdministrativeArea", name: "Norte de Santa Catarina" },
|
||||
{
|
||||
"@type": "Country",
|
||||
name: "Brasil",
|
||||
},
|
||||
{
|
||||
"@type": "Place",
|
||||
name: "Remote worldwide",
|
||||
},
|
||||
],
|
||||
url: pageUrl,
|
||||
},
|
||||
{
|
||||
"@type": "BreadcrumbList",
|
||||
itemListElement: [
|
||||
{
|
||||
"@type": "ListItem",
|
||||
position: 1,
|
||||
name: "Início",
|
||||
item: siteUrl,
|
||||
},
|
||||
{
|
||||
"@type": "ListItem",
|
||||
position: 2,
|
||||
name: "Serviços",
|
||||
item: `${siteUrl}/servicos`,
|
||||
},
|
||||
{
|
||||
"@type": "ListItem",
|
||||
position: 3,
|
||||
name: service.navLabel,
|
||||
item: pageUrl,
|
||||
},
|
||||
],
|
||||
},
|
||||
buildServiceJsonLd(service),
|
||||
buildBreadcrumbList(pageUrl, [
|
||||
["Início", siteUrl],
|
||||
["Serviços", `${siteUrl}/servicos`],
|
||||
[service.navLabel, pageUrl],
|
||||
] as const),
|
||||
],
|
||||
};
|
||||
|
||||
@@ -130,12 +89,37 @@ export default async function ServicePage({ params }: ServicePageProps) {
|
||||
<HeroBackground />
|
||||
<div className="ds-section-shell relative z-10">
|
||||
<div className="max-w-[860px]">
|
||||
<nav aria-label="Breadcrumb" className="mb-sp-6">
|
||||
<ol className="flex flex-wrap items-center gap-sp-2 text-sm">
|
||||
<li>
|
||||
<Link className="ds-link ds-link-muted" href="/">
|
||||
Início
|
||||
</Link>
|
||||
</li>
|
||||
<li className="flex items-center gap-sp-2">
|
||||
<span aria-hidden="true">/</span>
|
||||
<Link className="ds-link ds-link-muted" href="/servicos">
|
||||
Serviços
|
||||
</Link>
|
||||
</li>
|
||||
<li className="flex items-center gap-sp-2">
|
||||
<span aria-hidden="true">/</span>
|
||||
<Link
|
||||
aria-current="page"
|
||||
className="ds-link ds-link-muted"
|
||||
href={`/servicos/${service.slug}`}
|
||||
>
|
||||
{service.navLabel}
|
||||
</Link>
|
||||
</li>
|
||||
</ol>
|
||||
</nav>
|
||||
<p className="ds-eyebrow">{service.eyebrow}</p>
|
||||
<h1 className="ds-section-title max-w-[14ch] text-balance text-white">
|
||||
{service.headline}
|
||||
</h1>
|
||||
<p className="ds-copy max-w-[64ch] !text-[rgba(255,255,255,0.78)]">
|
||||
{service.intro}
|
||||
{service.answer}
|
||||
</p>
|
||||
<div className="mt-sp-8 flex flex-wrap gap-sp-3">
|
||||
<MagneticButton
|
||||
@@ -268,6 +252,12 @@ export default async function ServicePage({ params }: ServicePageProps) {
|
||||
))}
|
||||
</ul>
|
||||
<div className="mt-sp-6 flex flex-wrap gap-sp-3">
|
||||
<Link
|
||||
href={`/cases/${caseStudy.id}`}
|
||||
className="ds-link ds-link-accent"
|
||||
>
|
||||
Ler case: {caseStudy.title}
|
||||
</Link>
|
||||
{caseStudy.demoUrl ? (
|
||||
<a
|
||||
href={caseStudy.demoUrl}
|
||||
|
||||
Reference in new issue
Block a user