feat: revamp portfolio with case studies, curriculo page, and local SEO
Adds dynamic case study and curriculo routes, project health monitoring for live demo status, and strengthens local SEO (structured data, service-area targeting for Garuva/Joinville/Curitiba, a dedicated "criação de sites" service page) so search results better match the professional title (Engenheiro da Computação) and experience (5 anos). Co-Authored-By: Claude Sonnet 5 <[email protected]>
This commit is contained in:
1 parent
9236fdd685
commit
d76bbf5974
41 files changed
+1359
-492
No files matched your search
@@ -0,0 +1,146 @@
|
||||
import type { Metadata } from "next";
|
||||
import Link from "next/link";
|
||||
import { notFound } from "next/navigation";
|
||||
import { caseStudies, siteName, siteUrl } from "@/lib/site-content";
|
||||
|
||||
interface CasePageProps {
|
||||
params: Promise<{ slug: string }>;
|
||||
}
|
||||
|
||||
export function generateStaticParams() {
|
||||
return caseStudies.map((caseStudy) => ({ slug: caseStudy.id }));
|
||||
}
|
||||
|
||||
export async function generateMetadata({
|
||||
params,
|
||||
}: CasePageProps): Promise<Metadata> {
|
||||
const { slug } = await params;
|
||||
const caseStudy = caseStudies.find((item) => item.id === slug);
|
||||
|
||||
if (!caseStudy) return { title: `Case não encontrado | ${siteName}` };
|
||||
|
||||
const url = `${siteUrl}/cases/${caseStudy.id}`;
|
||||
return {
|
||||
title: `${caseStudy.title}: ${caseStudy.subtitle} | ${siteName}`,
|
||||
description: caseStudy.summary,
|
||||
alternates: { canonical: url },
|
||||
openGraph: {
|
||||
title: caseStudy.title,
|
||||
description: caseStudy.summary,
|
||||
url,
|
||||
siteName,
|
||||
type: "article",
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
export default async function CasePage({ params }: CasePageProps) {
|
||||
const { slug } = await params;
|
||||
const caseStudy = caseStudies.find((item) => item.id === slug);
|
||||
if (!caseStudy) notFound();
|
||||
|
||||
const url = `${siteUrl}/cases/${caseStudy.id}`;
|
||||
const jsonLd = {
|
||||
"@context": "https://schema.org",
|
||||
"@graph": [
|
||||
{
|
||||
"@type": "Article",
|
||||
headline: caseStudy.title,
|
||||
description: caseStudy.summary,
|
||||
mainEntityOfPage: url,
|
||||
author: { "@id": `${siteUrl}/#person` },
|
||||
about: caseStudy.stack,
|
||||
},
|
||||
{
|
||||
"@type": "BreadcrumbList",
|
||||
itemListElement: [
|
||||
{ "@type": "ListItem", position: 1, name: "Inicio", item: siteUrl },
|
||||
{
|
||||
"@type": "ListItem",
|
||||
position: 2,
|
||||
name: "Cases",
|
||||
item: `${siteUrl}/cases`,
|
||||
},
|
||||
{
|
||||
"@type": "ListItem",
|
||||
position: 3,
|
||||
name: caseStudy.title,
|
||||
item: url,
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
return (
|
||||
<main>
|
||||
<script
|
||||
type="application/ld+json"
|
||||
dangerouslySetInnerHTML={{ __html: JSON.stringify(jsonLd) }}
|
||||
/>
|
||||
<article>
|
||||
<section className="ds-section ds-section-dark">
|
||||
<div className="ds-section-shell max-w-[960px]">
|
||||
<p className="ds-eyebrow">Case de engenharia de software</p>
|
||||
<h1 className="ds-section-title text-white">
|
||||
{caseStudy.title}: {caseStudy.subtitle}
|
||||
</h1>
|
||||
<p className="ds-copy max-w-[68ch] !text-[rgba(255,255,255,.78)]">
|
||||
{caseStudy.summary}
|
||||
</p>
|
||||
<p className="mt-sp-6 text-[15px] leading-8 text-white">
|
||||
{caseStudy.impact}
|
||||
</p>
|
||||
<div className="mt-sp-8 flex flex-wrap gap-sp-3">
|
||||
{caseStudy.demoUrl && (
|
||||
<a
|
||||
className="ds-link ds-link-accent"
|
||||
href={caseStudy.demoUrl}
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
>
|
||||
Abrir demonstração
|
||||
</a>
|
||||
)}
|
||||
{caseStudy.githubUrl && (
|
||||
<a
|
||||
className="ds-link ds-link-muted"
|
||||
href={caseStudy.githubUrl}
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
>
|
||||
Ver código
|
||||
</a>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<section className="ds-section">
|
||||
<div className="ds-section-shell max-w-[960px]">
|
||||
<h2 className="ds-section-title">Tecnologias e contexto técnico</h2>
|
||||
<p className="ds-section-description">
|
||||
Este case demonstra como aplico engenharia de software a produtos
|
||||
com requisitos de performance, integração e operação, para
|
||||
empresas do Norte de Santa Catarina, Curitiba e atuação remota.
|
||||
</p>
|
||||
<ul className="ds-tags mt-sp-6">
|
||||
{caseStudy.stack.map((item) => (
|
||||
<li key={item} className="ds-tag">
|
||||
{item}
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
<div className="mt-sp-10 flex flex-wrap gap-sp-3">
|
||||
<Link className="ds-link ds-link-accent" href="/curriculo">
|
||||
Ver currículo profissional
|
||||
</Link>
|
||||
<Link className="ds-link ds-link-muted" href="/servicos">
|
||||
Ver serviços de engenharia
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</article>
|
||||
</main>
|
||||
);
|
||||
}
|
||||
+45
-14
@@ -1,8 +1,8 @@
|
||||
import type { Metadata } from "next";
|
||||
import Link from "next/link";
|
||||
import { caseStudies, siteName, siteUrl } from "@/lib/site-content";
|
||||
import HeroBackground from "@/app/components/cinematic/HeroBackground";
|
||||
import MagneticButton from "@/app/components/cinematic/MagneticButton";
|
||||
import { caseStudies, siteName, siteUrl } from "@/lib/site-content";
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: `Cases de Engenharia de Software, Next.js e IoT | ${siteName}`,
|
||||
@@ -39,9 +39,21 @@ export default function CasesPage() {
|
||||
"@type": "ListItem",
|
||||
position: index + 1,
|
||||
name: caseStudy.title,
|
||||
url: caseStudy.demoUrl ?? caseStudy.githubUrl ?? `${siteUrl}/cases`,
|
||||
url: `${siteUrl}/cases/${caseStudy.id}`,
|
||||
})),
|
||||
},
|
||||
{
|
||||
"@type": "BreadcrumbList",
|
||||
itemListElement: [
|
||||
{ "@type": "ListItem", position: 1, name: "Inicio", item: siteUrl },
|
||||
{
|
||||
"@type": "ListItem",
|
||||
position: 2,
|
||||
name: "Cases",
|
||||
item: `${siteUrl}/cases`,
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
@@ -61,8 +73,9 @@ export default function CasesPage() {
|
||||
Cases em software, Next.js, integracoes e produtos conectados.
|
||||
</h1>
|
||||
<p className="ds-copy max-w-[64ch] !text-[rgba(255,255,255,0.78)]">
|
||||
Esta pagina organiza projetos com leitura mais indexavel e comercial, conectando stack,
|
||||
contexto tecnico e tipo de problema resolvido.
|
||||
Esta pagina organiza projetos com leitura mais indexavel e
|
||||
comercial, conectando stack, contexto tecnico e tipo de problema
|
||||
resolvido.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
@@ -81,32 +94,50 @@ export default function CasesPage() {
|
||||
</p>
|
||||
<ul className="ds-tags mt-sp-6">
|
||||
{caseStudy.stack.map((item) => (
|
||||
<MagneticButton key={item} as="li" className="ds-tag" strength={0.15}>
|
||||
<li key={item} className="ds-tag">
|
||||
{item}
|
||||
</MagneticButton>
|
||||
</li>
|
||||
))}
|
||||
</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
|
||||
</Link>
|
||||
{caseStudy.demoUrl ? (
|
||||
<MagneticButton as="a" href={caseStudy.demoUrl} className="ds-link ds-link-accent" target="_blank" rel="noreferrer" strength={0.25}>
|
||||
<MagneticButton
|
||||
as="a"
|
||||
href={caseStudy.demoUrl}
|
||||
className="ds-link ds-link-muted"
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
strength={0.25}
|
||||
>
|
||||
Abrir projeto
|
||||
</MagneticButton>
|
||||
) : null}
|
||||
{caseStudy.githubUrl ? (
|
||||
<MagneticButton as="a" href={caseStudy.githubUrl} className="ds-link ds-link-muted" target="_blank" rel="noreferrer" strength={0.2}>
|
||||
Ver codigo
|
||||
</MagneticButton>
|
||||
) : null}
|
||||
</div>
|
||||
</article>
|
||||
))}
|
||||
</div>
|
||||
|
||||
<div className="mt-sp-10 flex flex-wrap gap-sp-3">
|
||||
<MagneticButton as="a" href="/servicos" className="ds-link ds-link-accent" strength={0.25}>
|
||||
<MagneticButton
|
||||
as="a"
|
||||
href="/servicos"
|
||||
className="ds-link ds-link-accent"
|
||||
strength={0.25}
|
||||
>
|
||||
Ver servicos
|
||||
</MagneticButton>
|
||||
<MagneticButton as="a" href="/#contact" className="ds-link ds-link-muted" strength={0.2}>
|
||||
<MagneticButton
|
||||
as="a"
|
||||
href="/#contact"
|
||||
className="ds-link ds-link-muted"
|
||||
strength={0.2}
|
||||
>
|
||||
Ir para contato
|
||||
</MagneticButton>
|
||||
</div>
|
||||
|
||||
Reference in new issue
Block a user