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