11import { ImageResponse } from 'next/og'
2+ import { readFileSync } from 'node:fs'
3+ import { join } from 'node:path'
24
35/**
46 * On-demand Open Graph image generator. Renders a 1200x630 branded social card
57 * with the page title and section, so every shared link gets a unique preview.
68 * Called via lib/og.ts `ogImageUrl()` from page metadata; CDN-cached by URL.
9+ *
10+ * Brand assets (Geist fonts + the LibreChat logo) are read from disk once at
11+ * module load — no network fetch at render time, so cold starts can't fail.
12+ * Colors mirror the neutral shadcn theme tokens in app/global.css (.dark).
713 */
814export const runtime = 'nodejs'
915
16+ const FONTS_DIR = join ( process . cwd ( ) , 'lib/fonts' )
17+ const geistRegular = readFileSync ( join ( FONTS_DIR , 'Geist-Regular.ttf' ) )
18+ const geistSemiBold = readFileSync ( join ( FONTS_DIR , 'Geist-SemiBold.ttf' ) )
19+ const logoSrc = `data:image/png;base64,${ readFileSync (
20+ join ( process . cwd ( ) , 'public/librechat.png' ) ,
21+ ) . toString ( 'base64' ) } `
22+
23+ // app/global.css .dark tokens (hsl 0 0% L → hex), the site's neutral palette.
24+ const BACKGROUND = '#0a0a0a' // --background
25+ const FOREGROUND = '#fafafa' // --foreground
26+ const MUTED_FOREGROUND = '#8c8c8c' // --muted-foreground
27+
1028const TYPE_LABELS : Record < string , string > = {
1129 docs : 'Documentation' ,
1230 blog : 'Blog' ,
@@ -34,38 +52,24 @@ export function GET(request: Request) {
3452 flexDirection : 'column' ,
3553 justifyContent : 'space-between' ,
3654 padding : '80px' ,
37- backgroundColor : '#0a0a0a' ,
38- backgroundImage :
39- 'radial-gradient(circle at 18% 0%, rgba(99,102,241,0.22), transparent 45%), radial-gradient(circle at 100% 100%, rgba(56,189,248,0.16), transparent 45%)' ,
40- color : '#fafafa' ,
41- fontFamily : 'sans-serif' ,
55+ backgroundColor : BACKGROUND ,
56+ color : FOREGROUND ,
57+ fontFamily : 'Geist' ,
4258 } }
4359 >
4460 { /* Brand */ }
4561 < div style = { { display : 'flex' , alignItems : 'center' , gap : '20px' } } >
46- < div
47- style = { {
48- display : 'flex' ,
49- alignItems : 'center' ,
50- justifyContent : 'center' ,
51- width : '64px' ,
52- height : '64px' ,
53- borderRadius : '16px' ,
54- background : 'linear-gradient(135deg, #6366f1, #38bdf8)' ,
55- fontSize : '40px' ,
56- } }
57- >
58- 🪶
59- </ div >
60- < div style = { { fontSize : '34px' , fontWeight : 700 , letterSpacing : '-0.02em' } } > LibreChat</ div >
62+ { /* eslint-disable-next-line @next/next/no-img-element */ }
63+ < img src = { logoSrc } width = { 64 } height = { 64 } alt = "" />
64+ < div style = { { fontSize : '34px' , fontWeight : 600 , letterSpacing : '-0.02em' } } > LibreChat</ div >
6165 </ div >
6266
6367 { /* Title */ }
6468 < div
6569 style = { {
6670 display : 'flex' ,
6771 fontSize,
68- fontWeight : 700 ,
72+ fontWeight : 600 ,
6973 lineHeight : 1.1 ,
7074 letterSpacing : '-0.03em' ,
7175 maxWidth : '1000px' ,
@@ -81,22 +85,29 @@ export function GET(request: Request) {
8185 alignItems : 'center' ,
8286 justifyContent : 'space-between' ,
8387 fontSize : '26px' ,
84- color : '#a1a1aa' ,
88+ color : MUTED_FOREGROUND ,
8589 } }
8690 >
8791 < div
8892 style = { {
8993 display : 'flex' ,
9094 textTransform : 'uppercase' ,
9195 letterSpacing : '0.12em' ,
92- fontWeight : 600 ,
96+ fontWeight : 400 ,
9397 } }
9498 >
9599 { label }
96100 </ div >
97101 < div style = { { display : 'flex' } } > www.librechat.ai</ div >
98102 </ div >
99103 </ div > ,
100- { width : 1200 , height : 630 } ,
104+ {
105+ width : 1200 ,
106+ height : 630 ,
107+ fonts : [
108+ { name : 'Geist' , data : geistRegular , weight : 400 , style : 'normal' } ,
109+ { name : 'Geist' , data : geistSemiBold , weight : 600 , style : 'normal' } ,
110+ ] ,
111+ } ,
101112 )
102113}
0 commit comments