diff --git a/app/ambassador-program/page.tsx b/app/ambassador-program/page.tsx index dd91f48..00ee58b 100644 --- a/app/ambassador-program/page.tsx +++ b/app/ambassador-program/page.tsx @@ -1,12 +1,13 @@ import type { Metadata } from "next" import { Button, Card, Eyebrow, PageHero, Panel, Section, SectionHeading } from "@/components/site/page-kit" +import { withSocial } from "@/lib/seo" -export const metadata: Metadata = { +export const metadata: Metadata = withSocial({ alternates: { canonical: "/ambassador-program" }, title: "Campus Ambassador Program", description: "Lead Dev Weekends on your campus. Activate your university community, unlock mentor access and deliver career outcomes with playbooks, support and recognition.", -} +}) const APPLICATION_URL = "https://forms.gle/k8JtSqSh2SWVMwJ4A" const CONTACT_EMAIL = "info@devweekends.com" diff --git a/app/ambassadors/page.tsx b/app/ambassadors/page.tsx index ec7ff86..efe752b 100644 --- a/app/ambassadors/page.tsx +++ b/app/ambassadors/page.tsx @@ -1,12 +1,13 @@ import type { Metadata } from "next" import AmbassadorsClient from "./ambassadorsClient" +import { withSocial } from "@/lib/seo" -export const metadata: Metadata = { +export const metadata: Metadata = withSocial({ alternates: { canonical: "/ambassadors" }, title: "Ambassadors", description: "Meet the people who represent and grow the Dev Weekends community around the world.", -} +}) export default function AmbassadorsPage() { return diff --git a/app/api-docs/page.tsx b/app/api-docs/page.tsx index 3022994..62d6f20 100644 --- a/app/api-docs/page.tsx +++ b/app/api-docs/page.tsx @@ -1,3 +1,12 @@ +import type { Metadata } from "next" +import { withSocial } from "@/lib/seo" + +export const metadata: Metadata = withSocial({ + title: "API documentation", + description: "Where to find the machine-readable API description and health status for devweekends.com.", + alternates: { canonical: "/api-docs" }, +}) + export default function ApiDocsPage() { return (
diff --git a/app/blog/[slug]/page.tsx b/app/blog/[slug]/page.tsx index 0ac62f7..d95d287 100644 --- a/app/blog/[slug]/page.tsx +++ b/app/blog/[slug]/page.tsx @@ -7,10 +7,20 @@ import Link from "next/link"; import { ArticleBody } from "@/components/content/article-body"; import { formatDate } from "@/components/content/format-date"; import { Button, Eyebrow, container } from "@/components/site/page-kit"; +import { SITE_NAME, blogPostingJsonLd, jsonLdString, withSocial } from "@/lib/seo"; const backLink = "inline-flex min-h-11 items-center text-[15px] font-medium text-[#5C5C5C] transition-colors hover:text-[#0A0A0A]"; +export function generateStaticParams() { + const dir = path.join(process.cwd(), "content", "blog"); + if (!fs.existsSync(dir)) return []; + return fs + .readdirSync(dir) + .filter((f) => f.endsWith(".md")) + .map((f) => ({ slug: f.replace(/\.md$/, "") })); +} + export async function generateMetadata({ params, }: { @@ -21,19 +31,22 @@ export async function generateMetadata({ if (!fs.existsSync(filePath)) return { title: "Post not found", robots: { index: false } }; const { data } = matter(fs.readFileSync(filePath, "utf-8")); const date = data.date ? new Date(data.date) : undefined; - return { + return withSocial({ title: data.title, description: data.description, alternates: { canonical: `/blog/${slug}` }, openGraph: { type: "article", + siteName: SITE_NAME, + locale: "en_US", title: data.title, description: data.description, url: `/blog/${slug}`, publishedTime: date && !Number.isNaN(date.getTime()) ? date.toISOString() : undefined, images: data.image ? [{ url: data.image }] : undefined, }, - }; + twitter: data.image ? { images: [data.image] } : undefined, + }); } export default async function BlogPost({ @@ -76,8 +89,17 @@ export default async function BlogPost({ const fit: "cover" | "contain" = data.imageFit ?? (slug === "gsoc" ? "contain" : "cover"); + const jsonLd = blogPostingJsonLd({ + slug, + title: data.title, + description: data.description, + date: data.date, + image: data.image, + }); + return (
+