Skip to content

Commit

Permalink
Improve open graph image of website
Browse files Browse the repository at this point in the history
  • Loading branch information
fabian-hiller committed Jan 9, 2024
1 parent 7ad1ead commit 5c59402
Show file tree
Hide file tree
Showing 4 changed files with 97 additions and 121 deletions.
21 changes: 21 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions website/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
"eslint-plugin-qwik": "1.1.5",
"gray-matter": "^4.0.3",
"netlify-cli": "^15.0.0",
"og-img": "^0.1.0",
"postcss": "^8.4.27",
"prettier": "2.8.8",
"rehype-external-links": "^2.1.0",
Expand Down
2 changes: 1 addition & 1 deletion website/src/components/Head.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ export const Head = component$(() => {
)}&description=${encodeURIComponent(
head.meta.find((item) => item.name === 'description')
?.content || ''
)}`
)}&path=${location.url.pathname.split('/')[1]}`
}
/>

Expand Down
194 changes: 74 additions & 120 deletions website/src/routes/og-image/index.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
import type { RequestHandler } from '@builder.io/qwik-city';
import { Resvg, initWasm } from '@resvg/resvg-wasm';
import satori from 'satori';

let wasmPromise: Promise<void> | undefined;
import { ImageResponse, html } from 'og-img';

async function getFontData(fileName: string) {
const resposne = await fetch(
Expand All @@ -12,9 +9,10 @@ async function getFontData(fileName: string) {
}

export const onGet: RequestHandler = async ({ send, url }) => {
// Get title and description from search params
// Get data from search params
const title = url.searchParams.get('title');
const description = url.searchParams.get('description') || 'valibot.dev';
const description = url.searchParams.get('description');
const path = url.searchParams.get('path');

// Create Lexend 400 font object
const lexend400 = {
Expand All @@ -40,131 +38,87 @@ export const onGet: RequestHandler = async ({ send, url }) => {
weight: 500,
} as const;

// Generate SVG string using Satori
const svg = title
? // If title is available, return SVG with text
await satori(
{
type: 'div',
props: {
tw: 'flex h-full w-full flex-col justify-between bg-gray-900 p-16',
style: { fontFamily: 'Lexend' },
children: [
{
type: 'div',
props: {
tw: 'flex items-center',
children: [
{
type: 'img',
props: {
tw: 'w-16 h-16',
src: `${
import.meta.env.PUBLIC_WEBSITE_URL
}/icon-192px.png`,
},
},
{
type: 'div',
props: {
tw: 'text-4xl font-medium text-slate-300 ml-4',
style: { fontFamily: 'Lexend Exa' },
children: 'Valibot',
},
},
],
},
},
{
type: 'div',
props: {
tw: 'flex flex-col',
children: [
{
type: 'h1',
props: {
tw: 'max-w-[80%] text-6xl font-medium leading-normal text-slate-200',
style: {
overflow: 'hidden',
textOverflow: 'ellipsis',
whiteSpace: 'nowrap',
},
children: title,
},
},
{
type: 'p',
props: {
tw: 'text-4xl text-slate-400 leading-loose',
children:
description.length > 110
? description.slice(0, 110).trimEnd() + '...'
: description,
},
},
],
},
},
],
},
},
// If title is available, return image with text
if (title) {
send(
new ImageResponse(
html`
<div
tw="flex h-full w-full flex-col justify-between bg-gray-900 p-16"
style="font-family: 'Lexend'"
>
<div tw="flex items-center justify-between">
<div tw="flex items-center">
<img
tw="w-16 h-16"
src="${import.meta.env.PUBLIC_WEBSITE_URL}/icon-192px.png"
/>
<div
tw="text-4xl font-medium text-slate-300 ml-4"
style="font-family: 'Lexend Exa'"
>
Valibot
</div>
</div>
<div
tw="max-w-[50%] text-4xl text-slate-500"
style="overflow: hidden; text-overflow: ellipsis; white-space: nowrap"
>
valibot.dev${path ? `/` + path : ''}
</div>
</div>
<div tw="flex flex-col">
<h1
tw="max-w-[80%] text-6xl font-medium leading-normal text-slate-200"
style="overflow: hidden; text-overflow: ellipsis; white-space: nowrap"
>
${title}
</h1>
<p
tw="text-4xl text-slate-400 leading-loose"
style="${description ? '' : 'display: none'}}"
>
${description
? description.length > 110
? description.slice(0, 110).trimEnd() + '...'
: description
: ''}
</p>
</div>
</div>
`,
{
width: 1200,
height: 630,
fonts: [lexend400, lexend500, lexendExa500],
}
)
: // Otherwise, return SVG with logo
await satori(
{
type: 'div',
props: {
tw: 'flex h-full w-full items-center justify-center bg-gray-900',
style: { fontFamily: 'Lexend Exa' },
children: {
type: 'div',
props: {
tw: 'flex items-center',
children: [
{
type: 'img',
props: {
tw: 'w-36 h-36',
src: `${
import.meta.env.PUBLIC_WEBSITE_URL
}/icon-192px.png`,
},
},
{
type: 'div',
props: {
tw: 'text-8xl font-medium text-slate-300 ml-10',
children: 'Valibot',
},
},
],
},
},
},
},
);

// Otherwise, return image just with logo
} else {
send(
new ImageResponse(
html`
<div
tw="flex h-full w-full items-center justify-center bg-gray-900"
style="font-family: 'Lexend Exa'"
>
<div tw="flex items-center">
<img
tw="w-36 h-36"
src="${import.meta.env.PUBLIC_WEBSITE_URL}/icon-192px.png"
/>
<div tw="text-8xl font-medium text-slate-300 ml-10">Valibot</div>
</div>
</div>
`,
{
width: 1200,
height: 630,
fonts: [lexendExa500],
}
);

// Lazy initialize WebAssembly module
if (!wasmPromise) {
wasmPromise = initWasm(
fetch('https://unpkg.com/@resvg/resvg-wasm/index_bg.wasm')
)
);
}
await wasmPromise;

// Convert SVG string to PNG image
const image = new Resvg(svg).render().asPng();

// Send PNG image as response
send(new Response(image, { headers: { 'content-type': 'image/png' } }));
};

0 comments on commit 5c59402

Please sign in to comment.