Files
nextjs-notion-starter-kit/pages/api/social-image.tsx
Travis Fischer 623eaa43b5 🗂
2022-10-14 18:22:05 -04:00

173 lines
4.5 KiB
TypeScript

import * as React from 'react'
import { ImageResponse } from '@vercel/og'
import { NextRequest } from 'next/server'
import { NotionPageInfo } from 'lib/types'
import { host, api } from 'lib/config'
const interRegularFontP = fetch(
new URL('../../public/fonts/Inter-Regular.ttf', import.meta.url)
).then((res) => res.arrayBuffer())
const interBoldFontP = fetch(
new URL('../../public/fonts/Inter-SemiBold.ttf', import.meta.url)
).then((res) => res.arrayBuffer())
export const config = {
runtime: 'experimental-edge'
}
export default async function OGImage(req: NextRequest) {
const [interRegularFont, interBoldFont] = await Promise.all([
interRegularFontP,
interBoldFontP
])
const { searchParams } = new URL(req.url)
const pageId = searchParams.get('id')
if (!pageId) {
return new Response('Invalid notion page id', { status: 400 })
}
const pageInfoRes = await fetch(`${host}${api.getNotionPageInfo}`, {
method: 'POST',
body: JSON.stringify({ pageId }),
headers: { 'Content-Type': 'application/json' }
})
const pageInfo: NotionPageInfo = await pageInfoRes.json()
return new ImageResponse(
(
<div
style={{
position: 'relative',
width: '100%',
height: '100%',
display: 'flex',
flexDirection: 'column',
backgroundColor: '#1F2027',
alignItems: 'center',
justifyContent: 'center',
fontFamily: '"Inter", sans-serif',
color: 'black'
}}
>
{pageInfo.image && (
<img
src={pageInfo.image}
style={{
position: 'absolute',
width: '100%',
height: '100%',
objectFit: 'cover',
// TODO: satori doesn't support background-size: cover and seems to
// have inconsistent support for filter + transform to get rid of the
// blurred edges. For now, we'll go without a blur filter on the
// background, but Satori is still very new, so hopefully we can re-add
// the blur soon.
// backgroundImage: pageInfo.image
// ? `url(${pageInfo.image})`
// : undefined,
// backgroundSize: '100% 100%'
// TODO: pageInfo.imageObjectPosition
filter: 'blur(8px)',
transform: 'scale(1.05)'
}}
/>
)}
<div
style={{
position: 'relative',
width: 900,
height: 450,
display: 'flex',
flexDirection: 'column',
border: '16px solid rgba(0,0,0,0.3)',
borderRadius: 8,
zIndex: '1'
}}
>
<div
style={{
width: '100%',
height: '100%',
display: 'flex',
flexDirection: 'column',
justifyContent: 'space-around',
backgroundColor: '#fff',
padding: 24,
alignItems: 'center',
textAlign: 'center'
}}
>
{pageInfo.detail && (
<div style={{ fontSize: 32, opacity: 0 }}>{pageInfo.detail}</div>
)}
<div
style={{
fontSize: 70,
fontWeight: 700,
fontFamily: 'Inter'
}}
>
{pageInfo.title}
</div>
{pageInfo.detail && (
<div style={{ fontSize: 32, opacity: 0.6 }}>
{pageInfo.detail}
</div>
)}
</div>
</div>
{pageInfo.authorImage && (
<div
style={{
position: 'absolute',
top: 32,
left: 104,
height: 128,
width: 128,
display: 'flex',
borderRadius: '50%',
border: '4px solid #fff',
zIndex: '5'
}}
>
<img
src={pageInfo.authorImage}
style={{
width: '100%',
height: '100%'
// transform: 'scale(1.04)'
}}
/>
</div>
)}
</div>
),
{
width: 1200,
height: 600,
fonts: [
{
name: 'Inter',
data: interRegularFont,
style: 'normal',
weight: 400
},
{
name: 'Inter',
data: interBoldFont,
style: 'normal',
weight: 700
}
]
}
)
}