Skip to content

Commit abc7fcf

Browse files
authored
feat: brand Open Graph social cards and extend page coverage (#623)
- Replace the placeholder emoji and indigo gradient with the LibreChat logo - Map card colors to the neutral shadcn theme tokens from global.css - Bundle Geist (Regular + SemiBold) read from disk instead of fetched at render time, eliminating cold-start render failures - Add branded cards to the authors and about pages, which previously fell back to the generic default image
1 parent 8cd99d5 commit abc7fcf

4 files changed

Lines changed: 44 additions & 24 deletions

File tree

‎app/about/page.tsx‎

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,12 +20,19 @@ import { baseOptions } from '@/app/layout.config'
2020
import FooterMenu from '@/components/FooterMenu'
2121
import Discord from '@/components/icons/discord'
2222
import X from '@/components/icons/x'
23+
import { ogImageUrl } from '@/lib/og'
2324
import type { Metadata } from 'next'
2425

2526
export const metadata: Metadata = {
2627
title: 'About LibreChat',
2728
description:
2829
'LibreChat is a free, open-source AI platform that brings together all your AI conversations in one unified, customizable interface.',
30+
openGraph: {
31+
title: 'About LibreChat',
32+
description:
33+
'LibreChat is a free, open-source AI platform that brings together all your AI conversations in one unified, customizable interface.',
34+
images: [ogImageUrl({ title: 'About LibreChat' })],
35+
},
2936
}
3037

3138
async function getGitHubData(): Promise<{

‎app/api/og/route.tsx‎

Lines changed: 35 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,30 @@
11
import { 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
*/
814
export 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+
1028
const 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
}

‎app/authors/page.tsx‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import Image from 'next/image'
22
import Link from 'next/link'
33
import { authors } from '@/lib/authors'
4+
import { ogImageUrl } from '@/lib/og'
45
import type { Metadata } from 'next'
56

67
export const metadata: Metadata = {
@@ -9,6 +10,7 @@ export const metadata: Metadata = {
910
openGraph: {
1011
title: 'Authors | LibreChat',
1112
description: 'Get to know the talented people behind LibreChat.',
13+
images: [ogImageUrl({ title: 'Authors' })],
1214
},
1315
}
1416

‎lib/fonts/Geist-SemiBold.ttf‎

70.4 KB
Binary file not shown.

0 commit comments

Comments
 (0)