Last active
July 31, 2025 11:56
-
-
Save ja3nyc/0f851f06920850292a7bb27b698eec8f to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import { Resvg } from '@resvg/resvg-js'; | |
| import satori from 'satori'; | |
| import { opensansBold, opensansRegular } from './fonts'; | |
| export async function generateNoteOgImage({ | |
| title, | |
| subtitle, | |
| width = 1200, | |
| height = 630, | |
| }: { | |
| title: string; | |
| subtitle?: string; | |
| width?: number; | |
| height?: number; | |
| }): Promise<Buffer> { | |
| const svg = await satori( | |
| <div | |
| style={{ | |
| width: '100%', | |
| height: '100%', | |
| display: 'flex', | |
| flexDirection: 'column', | |
| justifyContent: 'space-between', | |
| padding: '60px', | |
| backgroundColor: '#ffffff', | |
| backgroundImage: `url(${process.env.NEXT_PUBLIC_NEW_SITE_URL}/og/og-bg-note.png)`, | |
| backgroundSize: 'cover', | |
| }} | |
| > | |
| <div | |
| style={{ | |
| display: 'flex', | |
| flexDirection: 'column', | |
| gap: '24px', | |
| maxWidth: '85%', | |
| }} | |
| > | |
| <div | |
| style={{ | |
| display: '-webkit-box', | |
| WebkitBoxOrient: 'vertical', | |
| WebkitLineClamp: 2, // Changed from 3 to 2 | |
| overflow: 'hidden', | |
| fontSize: title.length > 40 ? 64 : 80, | |
| fontWeight: 700, | |
| fontFamily: 'system-ui, sans-serif', | |
| letterSpacing: '-0.03em', | |
| color: '#000000', | |
| lineHeight: 1.1, | |
| wordBreak: 'break-word', | |
| textOverflow: 'ellipsis', // Add ellipsis for overflow | |
| }} | |
| > | |
| {title} | |
| </div> | |
| <div | |
| style={{ | |
| display: 'flex', | |
| fontSize: 36, | |
| fontWeight: 500, | |
| fontFamily: 'system-ui, sans-serif', | |
| color: '#4B5563', | |
| letterSpacing: '-0.01em', | |
| }} | |
| > | |
| #{subtitle} | |
| </div> | |
| </div> | |
| </div>, | |
| { | |
| width, | |
| height, | |
| fonts: [ | |
| { | |
| name: 'Open Sans', | |
| data: (await opensansRegular)!, | |
| weight: 700, | |
| style: 'normal', | |
| }, | |
| { | |
| name: 'Open Sans', | |
| data: (await opensansBold)!, | |
| weight: 900, | |
| style: 'normal', | |
| }, | |
| ], | |
| } | |
| ); | |
| const resvg = new Resvg(svg, { | |
| fitTo: { mode: 'width', value: width }, | |
| }); | |
| return resvg.render().asPng(); | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import { createServerFileRoute } from '@tanstack/react-start/server' | |
| import { getSupabaseServerClient } from '~/servers/supabase-server'; | |
| import { generateNoteOgImage } from '~/utils/generateOpengraphImage'; | |
| export const ServerRoute = createServerFileRoute('/api/og/$linkId').methods({ | |
| GET: async ({ params }) => { | |
| const supabase = getSupabaseServerClient() | |
| async function getNoteDetails(link: string) { | |
| // Check p_journals first | |
| const { data: journal } = await supabase | |
| .from('p_journals') | |
| .select('name') | |
| .eq('share_link', link) | |
| .single() | |
| if (journal?.name) { | |
| return journal.name | |
| } | |
| // If not found, check p_trade_notes | |
| const { data: tradeNote } = await supabase | |
| .from('p_trade_notes') | |
| .select('id') | |
| .eq('share_link', link) | |
| .single() | |
| return tradeNote ? 'Trade Note' : 'Shared Note' | |
| } | |
| const linkId = params.linkId; | |
| const title = await getNoteDetails(linkId) | |
| const image = await generateNoteOgImage({ title, subtitle: linkId }); | |
| return new Response(image, { | |
| headers: { | |
| 'Content-Type': 'image/png', | |
| 'Cache-Control': 'public, max-age=31536000, immutable', | |
| }, | |
| }); | |
| }, | |
| }) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| export const seo = ({ | |
| title, | |
| description, | |
| keywords, | |
| image, | |
| }: { | |
| title: string; | |
| description?: string; | |
| image?: string; | |
| keywords?: string; | |
| }) => { | |
| const tags = [ | |
| { title }, | |
| { name: 'description', content: description }, | |
| { name: 'keywords', content: keywords }, | |
| { name: 'twitter:title', content: title }, | |
| { name: 'twitter:description', content: description }, | |
| { name: 'twitter:creator', content: '@trycaltho' }, | |
| { name: 'twitter:site', content: 'Caltho' }, | |
| { name: 'og:type', content: 'website' }, | |
| { name: 'og:title', content: title }, | |
| { name: 'og:description', content: description }, | |
| ...(image | |
| ? [ | |
| { name: 'twitter:image', content: image }, | |
| { name: 'twitter:card', content: 'summary_large_image' }, | |
| { name: 'og:image', content: image }, | |
| ] | |
| : []), | |
| ]; | |
| return tags; | |
| }; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment