feat(seo): add a generated 1200x630 OG image (Gitea #4)
Social-sharing previews had no image — layout.tsx's OG/Twitter tags existed but pointed at nothing. Adds src/app/opengraph-image.tsx using next/og's ImageResponse to render a branded card (paw mark, wordmark, tagline) at request time instead of shipping a static asset, and switches twitter.card to summary_large_image now that there's an image for it to show.
This commit is contained in:
1 parent
efdf407642
commit
e47eed3a9d
2 files changed
+106
-1
No files matched your search
+1
-1
@@ -25,7 +25,7 @@ export const metadata: Metadata = {
|
||||
type: "website",
|
||||
},
|
||||
twitter: {
|
||||
card: "summary",
|
||||
card: "summary_large_image",
|
||||
title: "PawFeed",
|
||||
description: "The social platform where pets are the stars.",
|
||||
},
|
||||
|
||||
@@ -0,0 +1,105 @@
|
||||
import { ImageResponse } from "next/og";
|
||||
|
||||
export const alt = "PawFeed — the social platform where pets are the stars.";
|
||||
export const size = { width: 1200, height: 630 };
|
||||
export const contentType = "image/png";
|
||||
|
||||
// Simple 1-big-pad + 4-toes paw print, built from plain positioned circles —
|
||||
// Satori's CSS support doesn't need raw SVG for a shape this simple.
|
||||
function PawMark({ scale = 1, opacity = 1 }: { scale?: number; opacity?: number }) {
|
||||
const s = (n: number) => n * scale;
|
||||
return (
|
||||
<div style={{ position: "relative", width: s(340), height: s(340), opacity, display: "flex" }}>
|
||||
<div
|
||||
style={{
|
||||
position: "absolute",
|
||||
left: s(70),
|
||||
top: s(140),
|
||||
width: s(200),
|
||||
height: s(170),
|
||||
borderRadius: "50% 50% 45% 45%",
|
||||
background: "#FFFFFF",
|
||||
}}
|
||||
/>
|
||||
<div style={{ position: "absolute", left: s(30), top: s(30), width: s(90), height: s(110), borderRadius: "50%", background: "#FFFFFF" }} />
|
||||
<div style={{ position: "absolute", left: s(140), top: s(0), width: s(90), height: s(115), borderRadius: "50%", background: "#FFFFFF" }} />
|
||||
<div style={{ position: "absolute", left: s(250), top: s(30), width: s(90), height: s(110), borderRadius: "50%", background: "#FFFFFF" }} />
|
||||
<div style={{ position: "absolute", left: s(-20), top: s(120), width: s(80), height: s(100), borderRadius: "50%", background: "#FFFFFF" }} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default function Image() {
|
||||
return new ImageResponse(
|
||||
(
|
||||
<div
|
||||
style={{
|
||||
width: "100%",
|
||||
height: "100%",
|
||||
display: "flex",
|
||||
background: "linear-gradient(135deg, #FB923C 0%, #F97316 45%, #C2410C 100%)",
|
||||
position: "relative",
|
||||
}}
|
||||
>
|
||||
{/* Decorative oversized paw mark bleeding off the right edge — depth/layering */}
|
||||
<div style={{ position: "absolute", right: -60, top: -40, display: "flex" }}>
|
||||
<PawMark scale={2.05} opacity={0.16} />
|
||||
</div>
|
||||
|
||||
{/* Content column */}
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
justifyContent: "center",
|
||||
paddingLeft: 96,
|
||||
paddingRight: 96,
|
||||
width: "100%",
|
||||
height: "100%",
|
||||
}}
|
||||
>
|
||||
<div style={{ display: "flex", alignItems: "center", marginBottom: 28 }}>
|
||||
<PawMark scale={0.62} />
|
||||
</div>
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
fontSize: 132,
|
||||
fontWeight: 800,
|
||||
color: "#FFFFFF",
|
||||
letterSpacing: -3,
|
||||
lineHeight: 1,
|
||||
}}
|
||||
>
|
||||
PawFeed
|
||||
</div>
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
fontSize: 40,
|
||||
fontWeight: 500,
|
||||
color: "#FFF7ED",
|
||||
marginTop: 22,
|
||||
maxWidth: 820,
|
||||
}}
|
||||
>
|
||||
Where pets are the stars.
|
||||
</div>
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
fontSize: 26,
|
||||
fontWeight: 600,
|
||||
color: "#FFEDD5",
|
||||
marginTop: 44,
|
||||
letterSpacing: 1,
|
||||
}}
|
||||
>
|
||||
pawfeed.org
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
),
|
||||
{ ...size }
|
||||
);
|
||||
}
|
||||
Reference in new issue
Block a user