diff --git a/apps/marketing/src/app/(marketing)/blog/[post]/opengraph/route.tsx b/apps/marketing/src/app/(marketing)/blog/[post]/opengraph/route.tsx new file mode 100644 index 000000000..906ee18cd --- /dev/null +++ b/apps/marketing/src/app/(marketing)/blog/[post]/opengraph/route.tsx @@ -0,0 +1,77 @@ +import { ImageResponse } from 'next/og'; +import { NextResponse } from 'next/server'; + +import { allBlogPosts } from 'contentlayer/generated'; + +export const runtime = 'edge'; + +const contentType = 'image/png'; + +const IMAGE_SIZE = { + width: 1200, + height: 630, +}; + +type BlogPostOpenGraphImageProps = { + params: { post: string }; +}; + +export async function GET(_request: Request, { params }: BlogPostOpenGraphImageProps) { + const blogPost = allBlogPosts.find((post) => post._raw.flattenedPath === `blog/${params.post}`); + + if (!blogPost) { + return NextResponse.json({ error: 'Not found' }, { status: 404 }); + } + + // The long urls are needed for a compiler optimisation on the Next.js side, lifting this up + // to a constant will break og image generation. + const [interBold, interRegular, backgroundImage, logoImage] = await Promise.all([ + fetch(new URL('@documenso/assets/fonts/inter-bold.ttf', import.meta.url)).then(async (res) => + res.arrayBuffer(), + ), + fetch(new URL('@documenso/assets/fonts/inter-regular.ttf', import.meta.url)).then(async (res) => + res.arrayBuffer(), + ), + fetch(new URL('@documenso/assets/images/background-blog-og.png', import.meta.url)).then( + async (res) => res.arrayBuffer(), + ), + fetch(new URL('@documenso/assets/logo.png', import.meta.url)).then(async (res) => + res.arrayBuffer(), + ), + ]); + + return new ImageResponse( + ( +
Written by {blogPost.authorName}
+