💄 Custom og-image for blog posts (#814)

This commit is contained in:
Luke Vella 2023-08-17 10:02:05 +01:00 committed by GitHub
parent a9e41b2f0d
commit c24af3d808
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 253 additions and 11 deletions

View file

@ -20,6 +20,7 @@
"@svgr/webpack": "^6.5.1",
"@tailwindcss/typography": "^0.5.9",
"@vercel/analytics": "^0.1.8",
"@vercel/og": "^0.5.11",
"autoprefixer": "^10.4.13",
"class-variance-authority": "^0.6.0",
"dayjs": "^1.11.7",
@ -31,7 +32,7 @@
"lodash": "^4.17.21",
"nanoid": "^4.0.0",
"next-i18next": "^13.0.3",
"next-seo": "^5.15.0",
"next-seo": "^6.1.0",
"react-i18next": "^12.1.4",
"react-use": "^17.4.0",
"remark": "^14.0.3",
@ -39,7 +40,6 @@
"typescript": "^4.9.4"
},
"devDependencies": {
"cross-env": "^7.0.3",
"@next/bundle-analyzer": "^12.3.4",
"@rallly/tsconfig": "*",
"@types/accept-language-parser": "^1.5.3",
@ -53,6 +53,7 @@
"@typescript-eslint/eslint-plugin": "^5.21.0",
"@typescript-eslint/parser": "^5.50.0",
"cheerio": "^1.0.0-rc.12",
"cross-env": "^7.0.3",
"eslint": "^7.26.0",
"eslint-config-next": "^13.0.1",
"eslint-config-turbo": "^0.0.9",

Binary file not shown.

Binary file not shown.

View file

@ -0,0 +1,80 @@
/* eslint-disable @next/next/no-img-element */
import { ImageResponse } from "@vercel/og";
import { NextRequest } from "next/server";
export const config = {
runtime: "edge",
};
const regularFont = fetch(
new URL("/public/static/fonts/inter-regular.ttf", import.meta.url),
).then((res) => res.arrayBuffer());
const boldFont = fetch(
new URL("/public/static/fonts/inter-bold.ttf", import.meta.url),
).then((res) => res.arrayBuffer());
export default async function handler(req: NextRequest) {
const [regularFontData, boldFontData] = await Promise.all([
regularFont,
boldFont,
]);
const { searchParams } = req.nextUrl;
const title = searchParams.get("title");
const excerpt = searchParams.get("excerpt");
const type = searchParams.get("type");
return new ImageResponse(
(
<div
style={{
height: "100%",
width: "100%",
display: "flex",
flexDirection: "column",
alignItems: "center",
justifyContent: "center",
backgroundColor: "white",
}}
>
<div tw="bg-gray-50 h-full flex-col w-full px-18 py-16 flex">
<div tw="mb-16 flex justify-between">
<div tw="flex justify-between items-center w-full">
<img
alt="Rallly"
src="https://rallly.co/logo-color.svg"
height={64}
/>
<div tw="flex text-gray-800 text-3xl tracking-tight font-bold">
<span tw="bg-gray-200 px-6 py-3 rounded-full">{type}</span>
</div>
</div>
</div>
<h2 tw="flex flex-col text-7xl leading-tight font-bold tracking-tight text-gray-900 text-left">
<span>{title}</span>
</h2>
{excerpt ? (
<p tw="text-4xl leading-relaxed text-gray-500">{excerpt}</p>
) : null}
</div>
</div>
),
{
width: 1200,
height: 630,
fonts: [
{
name: "Inter",
data: regularFontData,
weight: 400,
},
{
name: "Inter",
data: boldFontData,
weight: 700,
},
],
},
);
}

View file

@ -1,10 +1,12 @@
import { ArrowLeftIcon } from "@rallly/icons";
import { absoluteUrl } from "@rallly/utils";
import { GetStaticPropsContext } from "next";
import ErrorPage from "next/error";
import Head from "next/head";
import Image from "next/image";
import Link from "next/link";
import { useRouter } from "next/router";
import { NextSeo } from "next-seo";
import PostBody from "@/components/blog/post-body";
import PostHeader from "@/components/blog/post-header";
@ -28,6 +30,29 @@ const Page: NextPageWithLayout<Props> = ({ post }) => {
return (
<div>
<NextSeo
openGraph={{
images: [
{
url:
`${absoluteUrl()}/_next/image?w=1200&q=100&url=${encodeURIComponent(
`/api/og-image`,
)}` +
encodeURIComponent(
`?type=${encodeURIComponent(
"Blog",
)}&title=${encodeURIComponent(
post.title,
)}&excerpt=${encodeURIComponent(post.excerpt)}`,
),
width: 1200,
height: 630,
alt: post.title,
type: "image/png",
},
],
}}
/>
<nav className="mb-2">
<Link
className="text-muted-foreground hover:text-primary inline-flex items-center gap-x-2 text-sm font-medium"
@ -39,7 +64,6 @@ const Page: NextPageWithLayout<Props> = ({ post }) => {
<article>
<Head>
<title>{post.title}</title>
<meta property="og:image" content={post.ogImage?.url} />
</Head>
<PostHeader title={post.title} date={post.date} />
<PostBody content={post.content} />
@ -79,9 +103,8 @@ export async function getStaticProps(ctx: GetStaticPropsContext) {
"date",
"slug",
"author",
"excerpt",
"content",
"ogImage",
"coverImage",
]);
const content = await markdownToHtml(post.content || "");

View file

@ -25,9 +25,6 @@ export type Post = {
title: string;
date: string;
coverImage?: string;
excerpt?: string;
ogImage?: {
url: string;
};
excerpt: string;
content: string;
};