seo: project pages — canonical URLs, keywords, Twitter card, Service JSON-LD structured data
This commit is contained in:
parent
b822dbee40
commit
575dc752df
1 changed files with 50 additions and 3 deletions
|
|
@ -20,12 +20,42 @@ export async function generateMetadata({
|
|||
if (!project) return { title: "Project Not Found" };
|
||||
|
||||
return {
|
||||
title: `${project.client} | Zachary Gaetano`,
|
||||
title: `${project.client} | Zachary Gaetano — Broadcast Systems Integration`,
|
||||
description: project.summary,
|
||||
keywords: [
|
||||
...project.technologies,
|
||||
project.category,
|
||||
project.client,
|
||||
"broadcast systems integration",
|
||||
"Zachary Gaetano",
|
||||
"Wild Dragon",
|
||||
"Washington DC",
|
||||
"broadcast facility design",
|
||||
],
|
||||
alternates: {
|
||||
canonical: `https://www.wilddragon.net/projects/${slug}`,
|
||||
},
|
||||
openGraph: {
|
||||
title: `${project.client} | Zachary Gaetano`,
|
||||
description: project.summary,
|
||||
images: [{ url: project.thumbnail }],
|
||||
url: `https://www.wilddragon.net/projects/${slug}`,
|
||||
siteName: "Wild Dragon",
|
||||
type: "website",
|
||||
locale: "en_US",
|
||||
images: [
|
||||
{
|
||||
url: project.thumbnail,
|
||||
width: 1200,
|
||||
height: 630,
|
||||
alt: `${project.client} — ${project.category}`,
|
||||
},
|
||||
],
|
||||
},
|
||||
twitter: {
|
||||
card: "summary_large_image",
|
||||
title: `${project.client} | Zachary Gaetano`,
|
||||
description: project.summary,
|
||||
images: [project.thumbnail],
|
||||
},
|
||||
};
|
||||
}
|
||||
|
|
@ -42,6 +72,18 @@ export default async function ProjectPage({
|
|||
notFound();
|
||||
}
|
||||
|
||||
const structuredData = {
|
||||
"@context": "https://schema.org",
|
||||
"@type": "Service",
|
||||
name: project.title,
|
||||
description: project.summary,
|
||||
serviceType: project.category,
|
||||
provider: {
|
||||
"@id": "https://www.wilddragon.net/#organization",
|
||||
},
|
||||
areaServed: "United States",
|
||||
};
|
||||
|
||||
// Find previous and next projects for navigation
|
||||
const currentIndex = projects.findIndex((p) => p.slug === project.slug);
|
||||
const prevProject = currentIndex > 0 ? projects[currentIndex - 1] : null;
|
||||
|
|
@ -50,6 +92,11 @@ export default async function ProjectPage({
|
|||
|
||||
return (
|
||||
<main className="min-h-screen bg-white">
|
||||
<script
|
||||
type="application/ld+json"
|
||||
dangerouslySetInnerHTML={{ __html: JSON.stringify(structuredData) }}
|
||||
/>
|
||||
|
||||
{/* Header bar */}
|
||||
<nav className="fixed top-0 left-0 right-0 z-50 bg-white/95 backdrop-blur-lg shadow-sm py-3.5">
|
||||
<div className="max-w-6xl mx-auto px-6 flex items-center justify-between">
|
||||
|
|
@ -95,7 +142,7 @@ export default async function ProjectPage({
|
|||
<div className="relative h-64 md:h-[28rem] overflow-hidden">
|
||||
<Image
|
||||
src={project.thumbnail}
|
||||
alt={project.title}
|
||||
alt={`${project.client} — ${project.category} broadcast facility`}
|
||||
fill
|
||||
className="object-cover"
|
||||
sizes="100vw"
|
||||
|
|
|
|||
Loading…
Reference in a new issue