Skip to content

Commit cf59644

Browse files
authored
feat: add blog with SEO-optimized content (0xa3k5#176)
1 parent 2b5da77 commit cf59644

File tree

13 files changed

+2414
-1
lines changed

13 files changed

+2414
-1
lines changed

apps/website/src/app/@modal/(.)[type]/[id]/page.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ const metadataMap: Record<TType, TMetadata[]> = {
1717
exchange: exchanges,
1818
}
1919

20+
const VALID_TYPES = new Set(['tokens', 'networks', 'wallets', 'exchanges'])
21+
2022
export default function Modal({
2123
params,
2224
}: {
@@ -25,7 +27,7 @@ export default function Modal({
2527
const router = useRouter()
2628
const { type, id } = params
2729

28-
if (!type) {
30+
if (!type || !VALID_TYPES.has(type)) {
2931
return null
3032
}
3133

Lines changed: 251 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,251 @@
1+
import { ImageResponse } from '@vercel/og'
2+
import { getPostBySlug, getAllSlugs } from '../lib/blog'
3+
4+
export const size = {
5+
width: 1200,
6+
height: 630,
7+
}
8+
export const contentType = 'image/png'
9+
10+
export function generateStaticParams() {
11+
const slugs = getAllSlugs()
12+
return slugs.map((slug) => ({ slug }))
13+
}
14+
15+
export default async function Image({ params }: { params: { slug: string } }) {
16+
const { slug } = params
17+
const post = getPostBySlug(slug)
18+
19+
const [geistBold, geistRegular] = await Promise.all([
20+
fetch(
21+
'https://cdn.jsdelivr.net/npm/@fontsource/geist-mono@5.0.3/files/geist-mono-latin-600-normal.woff',
22+
).then((res) => res.arrayBuffer()),
23+
fetch(
24+
'https://cdn.jsdelivr.net/npm/@fontsource/geist-mono@5.0.3/files/geist-mono-latin-400-normal.woff',
25+
).then((res) => res.arrayBuffer()),
26+
])
27+
28+
if (!post) {
29+
return new ImageResponse(
30+
<div
31+
style={{
32+
width: '100%',
33+
height: '100%',
34+
display: 'flex',
35+
alignItems: 'center',
36+
justifyContent: 'center',
37+
background: '#080808',
38+
color: '#fff',
39+
fontSize: 48,
40+
fontFamily: 'Geist Mono, monospace',
41+
}}
42+
>
43+
Post Not Found
44+
</div>,
45+
{
46+
...size,
47+
fonts: [
48+
{
49+
name: 'Geist Mono',
50+
data: geistBold,
51+
weight: 600,
52+
style: 'normal',
53+
},
54+
],
55+
},
56+
)
57+
}
58+
59+
const { frontmatter } = post
60+
61+
return new ImageResponse(
62+
<div
63+
style={{
64+
height: '100%',
65+
width: '100%',
66+
display: 'flex',
67+
flexDirection: 'column',
68+
justifyContent: 'space-between',
69+
backgroundColor: '#080808',
70+
fontFamily: 'Geist Mono, monospace',
71+
padding: '80px',
72+
position: 'relative',
73+
}}
74+
>
75+
{/* Grid lines */}
76+
<div
77+
style={{
78+
position: 'absolute',
79+
top: 0,
80+
left: 0,
81+
right: 0,
82+
bottom: 0,
83+
display: 'flex',
84+
}}
85+
>
86+
<hr
87+
style={{
88+
position: 'absolute',
89+
top: '80px',
90+
left: '0',
91+
width: '100%',
92+
height: '1px',
93+
opacity: 0.1,
94+
backgroundColor: 'rgba(255, 255, 255, 0.3)',
95+
}}
96+
/>
97+
<hr
98+
style={{
99+
position: 'absolute',
100+
bottom: '80px',
101+
left: '0',
102+
width: '100%',
103+
height: '1px',
104+
opacity: 0.1,
105+
backgroundColor: 'rgba(255, 255, 255, 0.3)',
106+
}}
107+
/>
108+
<hr
109+
style={{
110+
position: 'absolute',
111+
top: '0',
112+
left: '80px',
113+
width: '1px',
114+
height: '100%',
115+
opacity: 0.1,
116+
backgroundColor: 'rgba(255, 255, 255, 0.3)',
117+
}}
118+
/>
119+
<hr
120+
style={{
121+
position: 'absolute',
122+
top: '0',
123+
right: '80px',
124+
width: '1px',
125+
height: '100%',
126+
opacity: 0.1,
127+
backgroundColor: 'rgba(255, 255, 255, 0.3)',
128+
}}
129+
/>
130+
</div>
131+
132+
{/* Top section */}
133+
<div
134+
style={{
135+
display: 'flex',
136+
flexDirection: 'column',
137+
gap: '16px',
138+
zIndex: 1,
139+
}}
140+
>
141+
<div
142+
style={{
143+
display: 'flex',
144+
alignItems: 'center',
145+
gap: '16px',
146+
}}
147+
>
148+
<div
149+
style={{
150+
backgroundColor: '#FF3D00',
151+
width: '4px',
152+
height: '32px',
153+
}}
154+
/>
155+
<span
156+
style={{
157+
fontSize: '20px',
158+
color: '#FF3D00',
159+
fontWeight: 400,
160+
letterSpacing: '0.1em',
161+
textTransform: 'uppercase',
162+
}}
163+
>
164+
Web3 Icons Blog
165+
</span>
166+
</div>
167+
<h1
168+
style={{
169+
fontSize: frontmatter.title.length > 50 ? '44px' : '56px',
170+
fontWeight: 600,
171+
color: 'white',
172+
margin: 0,
173+
lineHeight: 1.2,
174+
maxWidth: '900px',
175+
}}
176+
>
177+
{frontmatter.title}
178+
</h1>
179+
</div>
180+
181+
{/* Bottom section */}
182+
<div
183+
style={{
184+
display: 'flex',
185+
alignItems: 'center',
186+
justifyContent: 'space-between',
187+
zIndex: 1,
188+
}}
189+
>
190+
<div
191+
style={{
192+
display: 'flex',
193+
alignItems: 'center',
194+
gap: '24px',
195+
}}
196+
>
197+
<span style={{ fontSize: '20px', color: '#666' }}>
198+
{frontmatter.date}
199+
</span>
200+
<span style={{ fontSize: '20px', color: '#333' }}>·</span>
201+
<span style={{ fontSize: '20px', color: '#666' }}>
202+
{frontmatter.author}
203+
</span>
204+
</div>
205+
206+
<div
207+
style={{
208+
display: 'flex',
209+
alignItems: 'center',
210+
gap: '12px',
211+
}}
212+
>
213+
<svg
214+
width="40"
215+
height="40"
216+
viewBox="0 0 40 40"
217+
fill="none"
218+
xmlns="http://www.w3.org/2000/svg"
219+
>
220+
<path
221+
d="M20.504 10.9687L34.9516 19.7118C35.7554 20.1982 35.7554 21.3643 34.9516 21.8507L20.504 30.5938C19.9076 30.9547 19.1312 30.758 18.7785 30.1566L13.652 21.4135C13.4231 21.0231 13.4231 20.5394 13.652 20.149L18.7785 11.4059C19.1312 10.8045 19.9076 10.6078 20.504 10.9687Z"
222+
fill="#FF3D00"
223+
/>
224+
<path
225+
d="M3.66877 20.1186L15.2855 11.715C15.8317 11.3199 16.5302 11.9502 16.1931 12.534L11.7014 20.3125C11.5898 20.5059 11.5898 20.7441 11.7014 20.9375L16.1931 28.7161C16.5302 29.2998 15.8317 29.9301 15.2855 29.535L3.66877 21.1314C3.32387 20.8819 3.32387 20.3681 3.66877 20.1186Z"
226+
fill="#FF3D00"
227+
/>
228+
</svg>
229+
<span style={{ fontSize: '20px', color: '#666' }}>web3icons.io</span>
230+
</div>
231+
</div>
232+
</div>,
233+
{
234+
...size,
235+
fonts: [
236+
{
237+
name: 'Geist Mono',
238+
data: geistBold,
239+
weight: 600,
240+
style: 'normal',
241+
},
242+
{
243+
name: 'Geist Mono',
244+
data: geistRegular,
245+
weight: 400,
246+
style: 'normal',
247+
},
248+
],
249+
},
250+
)
251+
}

0 commit comments

Comments
 (0)