Skip to content
This repository was archived by the owner on May 20, 2025. It is now read-only.

Commit 17f408e

Browse files
committed
dynamic open graph for all routes
1 parent 437716f commit 17f408e

File tree

5 files changed

+138
-24
lines changed

5 files changed

+138
-24
lines changed

docs/index.mdx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
---
2-
title: Pages and Layouts
3-
description: Create your first page and shared layout with the Pages Router.
2+
title: Nitric Docs
3+
description: Build cloud backends that run anywhere, fast.
44
---
55

66
<HomeHeader

public/images/open_graph.png

-308 KB
Loading

src/app/[[...slug]]/page.tsx

Lines changed: 23 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { BASE_URL } from '@/lib/constants'
55
import { allDocs } from '@/content'
66
import { getNavInfo } from '@/lib/getNavInfo'
77
import { title } from 'radash'
8+
import { OpenGraph } from 'next/dist/lib/metadata/types/opengraph-types'
89

910
export async function generateMetadata({
1011
params,
@@ -18,22 +19,6 @@ export async function generateMetadata({
1819
return
1920
}
2021

21-
let ogImages = [
22-
{
23-
url: `${BASE_URL}/images/open_graph.png`,
24-
alt: 'Nitric Docs',
25-
},
26-
]
27-
28-
if (doc.image && doc.image_alt) {
29-
ogImages = [
30-
{
31-
url: doc.image,
32-
alt: doc.image_alt,
33-
},
34-
]
35-
}
36-
3722
const { navItem } = getNavInfo(doc)
3823

3924
let seoTitle = doc.slug
@@ -44,15 +29,31 @@ export async function generateMetadata({
4429
seoTitle = `${navItem.breadcrumbParentItem.title}: ${navItem.title}`
4530
}
4631

32+
const openGraph: OpenGraph = {
33+
siteName: 'Nitric Docs',
34+
locale: 'en_US',
35+
url: `${BASE_URL}/docs/${doc.slug}`,
36+
images: [
37+
{
38+
url: `${BASE_URL}/docs/og?title=${encodeURIComponent(doc.title || 'Nitric Docs')}&description=${encodeURIComponent(doc.description || '')}`,
39+
alt: 'Nitric Docs',
40+
},
41+
],
42+
}
43+
44+
if (doc.image && doc.image_alt) {
45+
openGraph.images = [
46+
{
47+
url: doc.image,
48+
alt: doc.image_alt,
49+
},
50+
]
51+
}
52+
4753
return {
4854
title: seoTitle,
4955
description: doc.description,
50-
openGraph: {
51-
siteName: 'Nitric Docs',
52-
locale: 'en_US',
53-
url: `${BASE_URL}/docs/${doc.slug}`,
54-
images: ogImages,
55-
},
56+
openGraph,
5657
twitter: {
5758
card: 'summary_large_image',
5859
},

src/app/og/route.tsx

Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
import { BASE_URL } from '@/lib/constants'
2+
import { ImageResponse } from 'next/og'
3+
import { NextRequest } from 'next/server'
4+
5+
export const runtime = 'edge'
6+
7+
const size = {
8+
width: 1200,
9+
height: 630,
10+
}
11+
12+
// Image generation
13+
export async function GET(req: NextRequest) {
14+
const { searchParams } = req.nextUrl
15+
// ?title=<title>
16+
const hasTitle = searchParams.has('title')
17+
const title = hasTitle
18+
? searchParams.get('title')?.slice(0, 100)
19+
: 'Nitric Docs'
20+
21+
const hasDescription = searchParams.has('description')
22+
23+
const description = hasDescription
24+
? searchParams.get('description')?.slice(0, 100)
25+
: 'Docs for the Nitric cloud application framework.'
26+
27+
const imageBaseUrl = req.headers.get('host')?.startsWith('localhost')
28+
? `http://${req.headers.get('host')}`
29+
: `https://${req.headers.get('host')}`
30+
31+
// Font
32+
const soraBold = fetch(
33+
new URL('../../assets/Sora-Bold.ttf', import.meta.url),
34+
).then((res) => res.arrayBuffer())
35+
36+
return new ImageResponse(
37+
(
38+
// ImageResponse JSX element
39+
<div
40+
style={{
41+
backgroundColor: '#121118',
42+
backgroundSize: '150px 150px',
43+
height: '100%',
44+
width: '100%',
45+
display: 'flex',
46+
textAlign: 'center',
47+
alignItems: 'center',
48+
justifyContent: 'center',
49+
flexDirection: 'column',
50+
flexWrap: 'nowrap',
51+
position: 'relative',
52+
}}
53+
>
54+
<div
55+
style={{
56+
display: 'flex',
57+
alignItems: 'center',
58+
alignContent: 'center',
59+
justifyContent: 'center',
60+
justifyItems: 'center',
61+
}}
62+
>
63+
{/* eslint-disable-next-line @next/next/no-img-element */}
64+
<img alt="Nitric" src={`${BASE_URL}/docs/images/open_graph.png`} />
65+
</div>
66+
<div
67+
style={{
68+
width: '500px',
69+
display: 'flex',
70+
flexDirection: 'column',
71+
gap: 10,
72+
left: '79px',
73+
top: '230px',
74+
bottom: '156px',
75+
position: 'absolute',
76+
color: 'white',
77+
fontSize: '50px',
78+
fontFamily: 'Sora',
79+
lineHeight: '120%',
80+
fontWeight: 700,
81+
textAlign: 'left',
82+
}}
83+
>
84+
{title}
85+
<div
86+
style={{
87+
color: '#A1A1AA',
88+
fontSize: '28px',
89+
fontWeight: 500,
90+
}}
91+
>
92+
{description}
93+
</div>
94+
</div>
95+
<br />
96+
</div>
97+
),
98+
// ImageResponse options
99+
{
100+
// For convenience, we can re-use the exported opengraph-image
101+
// size config to also set the ImageResponse's width and height.
102+
...size,
103+
fonts: [
104+
{
105+
name: 'Sora',
106+
data: await soraBold,
107+
style: 'normal',
108+
weight: 600,
109+
},
110+
],
111+
},
112+
)
113+
}

src/assets/Sora-Bold.ttf

56.4 KB
Binary file not shown.

0 commit comments

Comments
 (0)