Skip to content

Commit

Permalink
Merge pull request #33 from carbonplan/Shane98c/og-image-generation
Browse files Browse the repository at this point in the history
use dynamic og image for posts
  • Loading branch information
Shane98c authored Jan 9, 2025
2 parents 51a3634 + c6fbab4 commit 9f248ed
Show file tree
Hide file tree
Showing 4 changed files with 214 additions and 6 deletions.
1 change: 1 addition & 0 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,4 @@ export { default as Post } from './post'
export { default as PullQuote } from './pull-quote'
export { default as Supplement } from './supplement'
export { default as Tool } from './tool'
export { getBlogPostCard } from './og/blog-post'
180 changes: 180 additions & 0 deletions src/og/blog-post.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,180 @@
import React from 'react'
import { formatDate } from '@carbonplan/components'
import theme from '@carbonplan/theme'
import { getFonts } from './utils/get-og-fonts'

const FONTS = [
{ path: 'relative-medium-pro.woff', name: 'medium' },
{ path: 'relative-faux-book-pro.woff', name: 'faux' },
{ path: 'relative-mono-11-pitch-pro.woff', name: 'mono' },
]

const AUTHOR_COLORS = ['red', 'orange', 'yellow', 'pink']

export const BlogPostOG = ({ title, date, authors, forceWrapAuthors }) => {
const wrapAuthors = forceWrapAuthors || authors.length > 3

return (
<div
style={{
display: 'flex',
flexDirection: 'row',
justifyContent: 'space-between',
height: '100%',
width: '100%',
paddingLeft: '78px',
paddingRight: '78px',
paddingTop: '55px',
paddingBottom: '62px',
backgroundColor: theme.colors.background,
}}
>
<div
style={{
display: 'flex',
flexDirection: 'column',
justifyContent: 'space-between',
}}
id='left'
>
<div
style={{
display: 'flex',
flexDirection: 'column',
}}
id='upper'
>
<div
style={{
color: theme.colors.secondary,
fontFamily: 'faux',
fontSize: '34px',
letterSpacing: '0.07em',
marginTop: '2px',
}}
>
blog / carbonplan
</div>
<h1
style={{
maxWidth: '800px',
fontSize: '64px',
marginTop: '44px',
color: theme.colors.primary,
fontFamily: 'medium',
letterSpacing: '-0.015em',
lineHeight: '1.05',
}}
>
{title}
</h1>
</div>
<div
style={{
display: 'flex',
flexDirection: wrapAuthors ? 'row' : 'column',
flexWrap: 'wrap',
fontFamily: 'mono',
textTransform: 'uppercase',
fontSize: '34px',
marginBottom: '-6px',
lineHeight: '1.35',
letterSpacing: '0.07em',
maxWidth: '800px',
}}
>
{authors.map((author, i) => (
<div
key={author}
style={{
display: 'flex',
color: theme.colors[AUTHOR_COLORS[i % 4]],
}}
>
{author}
{i < authors.length - 1 && (
<span
style={{
color: theme.colors.primary,
marginLeft: '16px',
marginRight: '16px',
}}
>
+
</span>
)}
</div>
))}
</div>
</div>
<div
style={{
display: 'flex',
flexDirection: 'column',
justifyContent: 'space-between',
alignItems: 'flex-end',
height: '100%',
}}
id='right'
>
<svg
stroke='none'
fill={theme.colors.primary}
viewBox='0 0 32 32'
width='160'
height='160'
style={{ marginTop: '-10px', marginRight: '-10px' }}
>
<path d='M21.9395,14.9395 L17.5005,19.3785 L17.5005,7.0005 L14.5005,7.0005 L14.5005,19.3785 L10.0605,14.9395 L7.9395,17.0605 L14.9395,24.0605 C15.2325,24.3535 15.6165,24.5005 16.0005,24.5005 C16.3835,24.5005 16.7675,24.3535 17.0605,24.0605 L24.0605,17.0605 L21.9395,14.9395 Z'></path>
<path d='M27.5986,4 L22.8966,4 C26.5556,6.303 28.9996,10.366 28.9996,15 C28.9996,20.4 25.6896,25.039 20.9926,27 L26.5586,27 C29.8886,24.068 31.9996,19.785 31.9996,15 C31.9996,10.734 30.3196,6.868 27.5986,4'></path>
<path d='M3,15 C3,10.366 5.444,6.303 9.104,4 L4.401,4 C1.68,6.868 0,10.734 0,15 C0,19.785 2.112,24.068 5.441,27 L11.008,27 C6.311,25.039 3,20.4 3,15'></path>
</svg>

<div
style={{
fontFamily: 'mono',
textTransform: 'uppercase',
color: theme.colors.secondary,
fontSize: '34px',
letterSpacing: '0.07em',
transform: 'rotate(90deg)',
transformOrigin: 'right',
marginRight: '12px',
marginBottom: '-18px',
}}
>
{formatDate(date, {
month: 'short',
day: 'numeric',
year: 'numeric',
})}
</div>
</div>
</div>
)
}

export const getBlogPostCard = async ({
title,
date,
authors,
forceWrapAuthors,
}) => {
const fonts = await getFonts(FONTS)

return {
component: (
<BlogPostOG
title={title}
date={date}
authors={authors}
forceWrapAuthors={forceWrapAuthors}
/>
),
fonts,
options: {
width: 1200,
height: 630,
},
}
}
24 changes: 24 additions & 0 deletions src/og/utils/get-og-fonts.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
const fetchFont = async (fontPath) => {
const headers = new Headers({ Referer: 'https://carbonplan.org/' })
const res = await fetch(`https://fonts.carbonplan.org/relative/${fontPath}`, {
cache: 'force-cache',
headers,
})

if (!res.ok) throw new Error(`Failed to load ${fontPath} font: ${res.status}`)
return res.arrayBuffer()
}

export const getFonts = async (fonts) => {
try {
const fontData = await Promise.all(fonts.map(({ path }) => fetchFont(path)))

return fonts.map(({ name }, index) => ({
name,
data: fontData[index],
}))
} catch (error) {
console.error('Error loading fonts:', error)
throw error
}
}
15 changes: 9 additions & 6 deletions src/post.js
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ const Authors = ({ authors }) => {
)
}

const Post = ({ back = '/blog', children, meta, number, ...props }) => {
const Post = ({ back = '/blog', children, meta, number, id, ...props }) => {
const colors = ['red', 'orange', 'yellow', 'pink']
const avatars = meta.authors.map((d, i) => {
const color = colors[(number + i) % 4]
Expand All @@ -68,14 +68,17 @@ const Post = ({ back = '/blog', children, meta, number, ...props }) => {
return { id: name, src, color }
}
})
const notProduction = process.env.VERCEL_ENV !== 'production'
const baseUrl = notProduction ? '' : 'https://blog.carbonplan.org'
const cardUrl = meta.card
? `${prefix}/social/blog/${meta.card}.png`
: `${baseUrl}/api/og?id=${id}${
meta.forceWrapAuthors ? '&forceWrapAuthors=true' : ''
}`

return (
<Layout
card={
meta.card
? `${prefix}/social/blog/${meta.card}.png`
: 'https://images.carbonplan.org/social/blog.png'
}
card={cardUrl}
url={meta.path ? `https://carbonplan.org${meta.path}` : null}
description={meta.summary}
title={meta.title + ' – CarbonPlan'}
Expand Down

0 comments on commit 9f248ed

Please sign in to comment.