seo: add per-project OG image generator via next/og (pre-renders all 7 project cards at build time)
This commit is contained in:
parent
9d88b52429
commit
2e92e45ee6
1 changed files with 123 additions and 0 deletions
123
src/app/projects/[slug]/opengraph-image.tsx
Normal file
123
src/app/projects/[slug]/opengraph-image.tsx
Normal file
|
|
@ -0,0 +1,123 @@
|
||||||
|
import { ImageResponse } from "next/og";
|
||||||
|
import { projects } from "@/data/projects";
|
||||||
|
|
||||||
|
export const size = { width: 1200, height: 630 };
|
||||||
|
export const contentType = "image/png";
|
||||||
|
|
||||||
|
export function generateStaticParams() {
|
||||||
|
return projects.map((p) => ({ slug: p.slug }));
|
||||||
|
}
|
||||||
|
|
||||||
|
export default async function Image({
|
||||||
|
params,
|
||||||
|
}: {
|
||||||
|
params: Promise<{ slug: string }>;
|
||||||
|
}) {
|
||||||
|
const { slug } = await params;
|
||||||
|
const project = projects.find((p) => p.slug === slug);
|
||||||
|
|
||||||
|
if (!project) {
|
||||||
|
return new ImageResponse(
|
||||||
|
<div style={{ background: "#0a0a0a", width: "100%", height: "100%" }} />,
|
||||||
|
{ ...size }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new ImageResponse(
|
||||||
|
(
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
background: "#0a0a0a",
|
||||||
|
width: "100%",
|
||||||
|
height: "100%",
|
||||||
|
display: "flex",
|
||||||
|
flexDirection: "column",
|
||||||
|
alignItems: "flex-start",
|
||||||
|
justifyContent: "center",
|
||||||
|
padding: "80px 80px",
|
||||||
|
position: "relative",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{/* Brand mark top-left */}
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
position: "absolute",
|
||||||
|
top: 56,
|
||||||
|
left: 80,
|
||||||
|
fontSize: 12,
|
||||||
|
color: "#404040",
|
||||||
|
letterSpacing: "0.25em",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
WILD DRAGON
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* URL bottom-right */}
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
position: "absolute",
|
||||||
|
bottom: 56,
|
||||||
|
right: 80,
|
||||||
|
fontSize: 16,
|
||||||
|
color: "#404040",
|
||||||
|
letterSpacing: "0.08em",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
wilddragon.net
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Accent bar */}
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
width: 48,
|
||||||
|
height: 3,
|
||||||
|
background: "#3b82f6",
|
||||||
|
marginBottom: 36,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
|
||||||
|
{/* Client name */}
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
fontSize: 68,
|
||||||
|
fontWeight: 700,
|
||||||
|
color: "#ffffff",
|
||||||
|
lineHeight: 1.05,
|
||||||
|
marginBottom: 28,
|
||||||
|
maxWidth: 900,
|
||||||
|
letterSpacing: "-0.5px",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{project.client}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Category + Year row */}
|
||||||
|
<div style={{ display: "flex", alignItems: "center", gap: 20 }}>
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
padding: "10px 20px",
|
||||||
|
background: "rgba(59,130,246,0.12)",
|
||||||
|
color: "#3b82f6",
|
||||||
|
borderRadius: 8,
|
||||||
|
fontSize: 16,
|
||||||
|
fontWeight: 500,
|
||||||
|
border: "1px solid rgba(59,130,246,0.2)",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{project.category}
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
fontSize: 16,
|
||||||
|
color: "#525252",
|
||||||
|
letterSpacing: "0.05em",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{project.year}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
),
|
||||||
|
{ ...size }
|
||||||
|
);
|
||||||
|
}
|
||||||
Loading…
Reference in a new issue