diff --git a/.gitignore b/.gitignore index 33c81de..067a097 100644 --- a/.gitignore +++ b/.gitignore @@ -50,6 +50,11 @@ npm-cache/ # Marketing book cover (raster; see docs/guides/static-assets.md) !public/assets/marketing/community-rules-cover.png +# Open Graph 1200×630 share images (`npm run generate:og-images`) +!public/assets/marketing/og-image.png +!public/assets/marketing/og-image-templates.png +!public/content/blog/*-og.png + # Visual regression snapshots (allow these) !tests/e2e/visual-regression.spec.ts-snapshots/ !tests/e2e/visual-regression.spec.ts-snapshots/*.png diff --git a/app/(app)/create/templates/page.tsx b/app/(app)/create/templates/page.tsx index 02dc4ad..0691fed 100644 --- a/app/(app)/create/templates/page.tsx +++ b/app/(app)/create/templates/page.tsx @@ -1,13 +1,19 @@ import type { Metadata } from "next"; import messages from "../../../../messages/en/index"; import { listRuleTemplatesFromDb } from "../../../../lib/server/ruleTemplates"; -import { routeMetadata } from "../../../../lib/siteMetadata"; +import { + routeMetadata, + templatesShareImages, +} from "../../../../lib/siteMetadata"; import { gridEntriesForFullCatalogWithFallback } from "../../../../lib/templates/templateGridPresentation"; import { CREATE_ROUTES } from "../utils/createFlowPaths"; import { CreateFlowTemplatesPageClient } from "./CreateFlowTemplatesPageClient"; export const metadata: Metadata = routeMetadata(CREATE_ROUTES.templatesPicker, { title: messages.metadata.templates.title, + openGraph: { + images: templatesShareImages(), + }, }); /** In-flow template catalog after review “Create from template”. */ diff --git a/app/(marketing)/blog/[slug]/page.tsx b/app/(marketing)/blog/[slug]/page.tsx index d76dd6c..de90f28 100644 --- a/app/(marketing)/blog/[slug]/page.tsx +++ b/app/(marketing)/blog/[slug]/page.tsx @@ -8,7 +8,10 @@ import { getRelatedBlogPosts, } from "../../../../lib/content"; import { logger } from "../../../../lib/logger"; -import { routeMetadata } from "../../../../lib/siteMetadata"; +import { + articleShareImages, + routeMetadata, +} from "../../../../lib/siteMetadata"; import messages from "../../../../messages/en/index"; import ContentBanner from "../../../components/sections/ContentBanner"; import AskOrganizer from "../../../components/sections/AskOrganizer"; @@ -70,6 +73,11 @@ export async function generateMetadata({ }); } + const articleImages = articleShareImages( + slug, + post.frontmatter.title, + ); + return routeMetadata(`/blog/${slug}`, { title: post.frontmatter.title, description: post.frontmatter.description, @@ -82,6 +90,7 @@ export async function generateMetadata({ authors: [post.frontmatter.author], url: `/blog/${slug}`, siteName: messages.metadata.siteName, + ...(articleImages ? { images: articleImages } : {}), }, twitter: { card: "summary_large_image", diff --git a/app/(marketing)/templates/page.tsx b/app/(marketing)/templates/page.tsx index f0dcc26..344ae01 100644 --- a/app/(marketing)/templates/page.tsx +++ b/app/(marketing)/templates/page.tsx @@ -1,12 +1,18 @@ import type { Metadata } from "next"; import messages from "../../../messages/en/index"; import { listRuleTemplatesFromDb } from "../../../lib/server/ruleTemplates"; -import { routeMetadata } from "../../../lib/siteMetadata"; +import { + routeMetadata, + templatesShareImages, +} from "../../../lib/siteMetadata"; import { gridEntriesForFullCatalogWithFallback } from "../../../lib/templates/templateGridPresentation"; import TemplatesPageClient from "./TemplatesPageClient"; export const metadata: Metadata = routeMetadata("/templates", { title: messages.metadata.templates.title, + openGraph: { + images: templatesShareImages(), + }, }); export default async function TemplatesPage() { diff --git a/app/components/navigation/Top/Top.container.tsx b/app/components/navigation/Top/Top.container.tsx index abf8eb8..45dfcfd 100644 --- a/app/components/navigation/Top/Top.container.tsx +++ b/app/components/navigation/Top/Top.container.tsx @@ -168,8 +168,8 @@ const TopContainer = memo( return (