diff --git a/apps/landing/package.json b/apps/landing/package.json
index 41cbb88c4..214c5b0b9 100644
--- a/apps/landing/package.json
+++ b/apps/landing/package.json
@@ -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",
diff --git a/apps/landing/public/static/fonts/inter-bold.ttf b/apps/landing/public/static/fonts/inter-bold.ttf
new file mode 100644
index 000000000..8e82c70d1
Binary files /dev/null and b/apps/landing/public/static/fonts/inter-bold.ttf differ
diff --git a/apps/landing/public/static/fonts/inter-regular.ttf b/apps/landing/public/static/fonts/inter-regular.ttf
new file mode 100644
index 000000000..8d4eebf20
Binary files /dev/null and b/apps/landing/public/static/fonts/inter-regular.ttf differ
diff --git a/apps/landing/src/pages/api/og-image.tsx b/apps/landing/src/pages/api/og-image.tsx
new file mode 100644
index 000000000..9c3364133
--- /dev/null
+++ b/apps/landing/src/pages/api/og-image.tsx
@@ -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(
+ (
+
+
+
+
+

+
+ {type}
+
+
+
+
+ {title}
+
+ {excerpt ? (
+
{excerpt}
+ ) : null}
+
+
+ ),
+ {
+ width: 1200,
+ height: 630,
+ fonts: [
+ {
+ name: "Inter",
+ data: regularFontData,
+ weight: 400,
+ },
+ {
+ name: "Inter",
+ data: boldFontData,
+ weight: 700,
+ },
+ ],
+ },
+ );
+}
diff --git a/apps/landing/src/pages/blog/[slug].tsx b/apps/landing/src/pages/blog/[slug].tsx
index bf965eb1e..efb676638 100644
--- a/apps/landing/src/pages/blog/[slug].tsx
+++ b/apps/landing/src/pages/blog/[slug].tsx
@@ -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 = ({ post }) => {
return (
+