Spaces:
Running
Running
import { zValidator } from '@hono/zod-validator'; | |
import { Hono } from 'hono'; | |
import { ImageResponse } from 'workers-og'; | |
import { z } from 'zod'; | |
import type { HonoEnv } from '../app'; | |
const getBriefOpenGraph = (opts: { title: string; date: Date; totalArticles: number; totalSources: number }) => | |
` | |
<div style="display: flex; width: 100%; height: 100%; background-color: white"> | |
<div | |
style=" | |
display: flex; | |
height: 100%; | |
width: 100%; | |
align-items: center; | |
justify-content: center; | |
letter-spacing: -0.02em; | |
font-weight: 700; | |
position: relative; | |
" | |
> | |
<div style="right: 42px; top: 42px; position: absolute; display: flex; align-items: center"> | |
<span style="margin-left: 8px; font-size: 25px; font-weight: normal; letter-spacing: normal"> | |
${opts.date.toLocaleDateString('en-US', { month: 'long', day: 'numeric', year: 'numeric' })} | |
</span> | |
</div> | |
<div style="left: 42px; bottom: 42px; position: absolute; display: flex; align-items: center"> | |
<span style="margin-left: 8px; font-size: 25px; font-weight: normal; letter-spacing: normal"> | |
Intelligence brief 路 ${opts.totalArticles} articles 路 ${opts.totalSources} sources | |
</span> | |
</div> | |
<div style="right: 42px; bottom: 42px; position: absolute; display: flex; align-items: center"> | |
<span style="margin-left: 8px; font-size: 25px; font-weight: normal; letter-spacing: normal"> news.iliane.xyz </span> | |
</div> | |
<div | |
style=" | |
display: flex; | |
flex-wrap: wrap; | |
justify-content: center; | |
padding: 10px 25px; | |
margin: 0 42px; | |
font-size: 60px; | |
width: auto; | |
max-width: 1000px; | |
text-align: center; | |
background-color: white; | |
color: black; | |
line-height: 1.4; | |
" | |
> | |
${decodeURIComponent(opts.title.trim())} | |
</div> | |
</div> | |
</div>`; | |
const getHomeOpenGraph = () => ` | |
<div style="display: flex; width: 100%; height: 100%; background-color: white"> | |
<div | |
style=" | |
display: flex; | |
flex-direction: column; | |
height: 100%; | |
width: 100%; | |
align-items: center; | |
justify-content: center; | |
letter-spacing: -0.02em; | |
font-weight: 700; | |
position: relative; | |
" | |
> | |
<div | |
style=" | |
display: flex; | |
flex-wrap: wrap; | |
justify-content: center; | |
padding: 10px 25px; | |
margin: 0 42px; | |
font-size: 110px; | |
width: auto; | |
max-width: 600px; | |
text-align: center; | |
background-color: white; | |
color: black; | |
line-height: 1.4; | |
" | |
> | |
Meridian | |
</div> | |
<div | |
style=" | |
display: flex; | |
flex-wrap: wrap; | |
justify-content: center; | |
padding: 10px 25px; | |
margin: 0 42px; | |
font-size: 35px; | |
width: auto; | |
max-width: 900px; | |
text-align: center; | |
background-color: white; | |
color: black; | |
font-weight: 100; | |
" | |
> | |
a daily brief of everything important happening that i care about, with actual analysis beyond headlines | |
</div> | |
</div> | |
</div>`; | |
const route = new Hono<HonoEnv>() | |
.get('/default', async c => { | |
const response = new ImageResponse(getHomeOpenGraph(), { width: 1200, height: 630 }); | |
response.headers.set('Cache-Control', 'public, max-age=86400'); // Cache for 1 day | |
return response; | |
}) | |
.get( | |
'/brief', | |
zValidator( | |
'query', | |
z.object({ | |
title: z.string(), | |
date: z.string().transform(val => new Date(Number.parseInt(val))), | |
articles: z.string().transform(val => Number.parseInt(val)), | |
sources: z.string().transform(val => Number.parseInt(val)), | |
}) | |
), | |
async c => { | |
const query = c.req.valid('query'); | |
const response = new ImageResponse( | |
getBriefOpenGraph({ | |
title: query.title, | |
date: query.date, | |
totalArticles: query.articles, | |
totalSources: query.sources, | |
}), | |
{ width: 1200, height: 630 } | |
); | |
// Cache brief images for longer since they don't change much despite having params | |
response.headers.set('Cache-Control', 'public, max-age=86400, stale-while-revalidate=43200'); | |
return response; | |
} | |
); | |
export default route; | |