+17
app/[slug]/opengraph-image.tsx
+17
app/[slug]/opengraph-image.tsx
···
1
+
import { readFile } from "node:fs/promises";
2
+
import matter from "gray-matter";
3
+
import { size, contentType, generatePostImage } from "../../og/generateImage";
4
+
5
+
export const dynamic = "force-static";
6
+
export const alt = "Overreacted";
7
+
export { size, contentType };
8
+
9
+
export default async function Image({ params }) {
10
+
const { slug } = await params;
11
+
const filename = "./public/" + slug + "/index.md";
12
+
const file = await readFile(filename, "utf8");
13
+
const { data } = matter(file);
14
+
return generatePostImage({ title: data.title });
15
+
}
16
+
17
+
export { generateStaticParams } from "./page";
+4
app/layout.js
+4
app/layout.js
+9
app/opengraph-image.tsx
+9
app/opengraph-image.tsx
og/Merriweather-Italic.ttf
og/Merriweather-Italic.ttf
This is a binary file and will not be displayed.
og/Merriweather-Regular.ttf
og/Merriweather-Regular.ttf
This is a binary file and will not be displayed.
og/Montserrat-ExtraBold.ttf
og/Montserrat-ExtraBold.ttf
This is a binary file and will not be displayed.
+174
og/generateImage.js
+174
og/generateImage.js
···
1
+
import { ImageResponse } from "next/og";
2
+
import { readFile } from "node:fs/promises";
3
+
import { join } from "node:path";
4
+
5
+
export const size = {
6
+
width: 1200,
7
+
height: 630,
8
+
};
9
+
10
+
export const contentType = "image/png";
11
+
12
+
export async function generateHomeImage() {
13
+
return generateImage(
14
+
<div
15
+
style={{
16
+
display: "flex",
17
+
width: "100%",
18
+
height: "100%",
19
+
backgroundColor: "rgb(40, 44, 53)",
20
+
color: "white",
21
+
}}
22
+
>
23
+
<div
24
+
style={{
25
+
display: "flex",
26
+
fontSize: 150,
27
+
width: "100%",
28
+
height: "100%",
29
+
flexDirection: "column",
30
+
justifyContent: "center",
31
+
alignItems: "center",
32
+
gap: 80,
33
+
}}
34
+
>
35
+
<span
36
+
style={{
37
+
backgroundImage: "linear-gradient(45deg, #ffb3d8, #cbb6ff)",
38
+
backgroundClip: "text",
39
+
WebkitBackgroundClip: "text",
40
+
color: "transparent",
41
+
}}
42
+
>
43
+
overreacted
44
+
</span>
45
+
<span
46
+
style={{
47
+
fontFamily: "Merriweather",
48
+
fontStyle: "italic",
49
+
fontSize: 60,
50
+
alignItems: "center",
51
+
}}
52
+
>
53
+
by
54
+
<img
55
+
alt="Dan Abramov"
56
+
src="https://github.com/gaearon.png"
57
+
style={{
58
+
height: 120,
59
+
width: 120,
60
+
borderRadius: "50%",
61
+
marginLeft: 20,
62
+
}}
63
+
/>
64
+
</span>
65
+
</div>
66
+
</div>,
67
+
);
68
+
}
69
+
70
+
export async function generatePostImage({ title }) {
71
+
return generateImage(
72
+
<div
73
+
style={{
74
+
padding: 40,
75
+
display: "flex",
76
+
flexDirection: "column",
77
+
width: "100%",
78
+
height: "100%",
79
+
backgroundColor: "rgb(40, 44, 53)",
80
+
color: "white",
81
+
}}
82
+
>
83
+
<div
84
+
style={{
85
+
display: "flex",
86
+
fontSize: 40,
87
+
width: "100%",
88
+
justifyContent: "space-between",
89
+
alignItems: "center",
90
+
paddingBottom: 20,
91
+
}}
92
+
>
93
+
<span
94
+
style={{
95
+
backgroundImage: "linear-gradient(45deg, #ffb3d8, #cbb6ff)",
96
+
backgroundClip: "text",
97
+
WebkitBackgroundClip: "text",
98
+
color: "transparent",
99
+
fontSize: 60,
100
+
}}
101
+
>
102
+
overreacted
103
+
</span>
104
+
<span
105
+
style={{
106
+
fontFamily: "Merriweather",
107
+
fontStyle: "italic",
108
+
fontSize: 35,
109
+
alignItems: "center",
110
+
}}
111
+
>
112
+
by
113
+
<img
114
+
alt="Dan Abramov"
115
+
src="https://github.com/gaearon.png"
116
+
style={{
117
+
height: 80,
118
+
width: 80,
119
+
borderRadius: "50%",
120
+
marginLeft: 20,
121
+
}}
122
+
/>
123
+
</span>
124
+
</div>
125
+
<div
126
+
style={{
127
+
fontSize: 90,
128
+
display: "flex",
129
+
alignItems: "center",
130
+
flex: 1,
131
+
paddingBottom: 30,
132
+
}}
133
+
>
134
+
{title}
135
+
</div>
136
+
</div>,
137
+
);
138
+
}
139
+
140
+
async function generateImage(jsx) {
141
+
return new ImageResponse(jsx, {
142
+
...size,
143
+
fonts: [
144
+
{
145
+
name: "Montserrat",
146
+
data: await montserratExtraBold,
147
+
style: "normal",
148
+
weight: 900,
149
+
},
150
+
{
151
+
name: "Merriweather",
152
+
data: await merriweatherRegular,
153
+
style: "normal",
154
+
weight: 500,
155
+
},
156
+
{
157
+
name: "Merriweather",
158
+
data: await merriweatherItalic,
159
+
style: "italic",
160
+
weight: 500,
161
+
},
162
+
],
163
+
});
164
+
}
165
+
166
+
const montserratExtraBold = readFile(
167
+
join(process.cwd(), "og/Montserrat-ExtraBold.ttf"),
168
+
);
169
+
const merriweatherRegular = readFile(
170
+
join(process.cwd(), "og/Merriweather-Regular.ttf"),
171
+
);
172
+
const merriweatherItalic = readFile(
173
+
join(process.cwd(), "og/Merriweather-Italic.ttf"),
174
+
);