1
+ import { getCollection , type CollectionEntry } from 'astro:content' ;
2
+ import fs from 'fs' ;
3
+ import path from 'path' ;
4
+ import { ImageResponse } from '@vercel/og' ;
5
+ import OpenSans from '../../../lib/OpenSans-Regular.ttf'
6
+
7
+ interface Props {
8
+ params : { slug : string } ;
9
+ props : { post : CollectionEntry < 'blog' > } ;
10
+ }
11
+
12
+ export async function GET ( { props } : Props ) {
13
+ const { post } = props ;
14
+
15
+ // using custom font files
16
+ // const DmSansBold = fs.readFileSync(path.resolve('./fonts/DMSans-Bold.ttf'));
17
+ // const DmSansReqular = fs.readFileSync(
18
+ // path.resolve('./fonts/DMSans-Regular.ttf'),
19
+ // );
20
+
21
+ // post cover with Image is pretty tricky for dev and build phase
22
+ const postCover = fs . readFileSync (
23
+ process . env . NODE_ENV === 'development'
24
+ ? path . resolve (
25
+ post . data . cover . src . replace ( / \? .* / , '' ) . replace ( '/@fs' , '' ) ,
26
+ )
27
+ : path . resolve ( post . data . cover . src . replace ( '/' , 'dist/' ) ) ,
28
+ ) ;
29
+
30
+ // Astro doesn't support tsx endpoints so usign React-element objects
31
+ const html = {
32
+ type : 'div' ,
33
+ props : {
34
+ children : [
35
+ {
36
+ type : 'div' ,
37
+ props : {
38
+ // using tailwind
39
+ tw : 'w-[200px] h-[200px] flex rounded-3xl overflow-hidden' ,
40
+ children : [
41
+ {
42
+ type : 'img' ,
43
+ props : {
44
+ src : postCover . buffer ,
45
+ } ,
46
+ } ,
47
+ ] ,
48
+ } ,
49
+ } ,
50
+ {
51
+ type : 'div' ,
52
+ props : {
53
+ tw : 'pl-10 shrink flex' ,
54
+ children : [
55
+ {
56
+ type : 'div' ,
57
+ props : {
58
+ style : {
59
+ fontSize : '48px' ,
60
+ fontFamily : 'DM Sans Bold' ,
61
+ } ,
62
+ children : post . data . title ,
63
+ } ,
64
+ } ,
65
+ ] ,
66
+ } ,
67
+ } ,
68
+ {
69
+ type : 'div' ,
70
+ props : {
71
+ tw : 'absolute right-[40px] bottom-[40px] flex items-center' ,
72
+ children : [
73
+ {
74
+ type : 'div' ,
75
+ props : {
76
+ tw : 'text-blue-600 text-3xl' ,
77
+ style : {
78
+ fontFamily : 'DM Sans Bold' ,
79
+ } ,
80
+ children : 'Dzmitry Kozhukh' ,
81
+ } ,
82
+ } ,
83
+ {
84
+ type : 'div' ,
85
+ props : {
86
+ tw : 'px-2 text-3xl' ,
87
+ style : {
88
+ fontSize : '30px' ,
89
+ } ,
90
+ children : '|' ,
91
+ } ,
92
+ } ,
93
+ {
94
+ type : 'div' ,
95
+ props : {
96
+ tw : 'text-3xl' ,
97
+ children : 'Blog' ,
98
+ } ,
99
+ } ,
100
+ ] ,
101
+ } ,
102
+ } ,
103
+ ] ,
104
+ tw : 'w-full h-full flex items-center justify-center relative px-22' ,
105
+ style : {
106
+ background : '#f7f8e8' ,
107
+ fontFamily : 'DM Sans Regular' ,
108
+ } ,
109
+ } ,
110
+ } ;
111
+
112
+ return new ImageResponse ( html , {
113
+ width : 1200 ,
114
+ height : 600 ,
115
+ fonts : [
116
+ {
117
+ name : 'Open Sans' ,
118
+ data : Buffer . from ( OpenSans ) ,
119
+ style : 'normal'
120
+ }
121
+ ] ,
122
+ // fonts: [
123
+ // {
124
+ // name: 'DM Sans Bold',
125
+ // data: DmSansBold.buffer,
126
+ // style: 'normal',
127
+ // },
128
+ // {
129
+ // name: 'DM Sans Regular',
130
+ // data: DmSansReqular.buffer,
131
+ // style: 'normal',
132
+ // },
133
+ // ],
134
+ } ) ;
135
+ }
136
+
137
+ // to generate an image for each blog posts in a collection
138
+ export async function getStaticPaths ( ) {
139
+ const blogPosts = await getCollection ( 'blog' ) ;
140
+ return blogPosts . map ( ( post ) => ( {
141
+ params : { slug : post . slug } ,
142
+ props : { post } ,
143
+ } ) ) ;
144
+ }
0 commit comments