+
+ The most popular
way to build Discord
bots.
@@ -39,14 +34,7 @@ export default async function handler() {
{
width: 1_200,
height: 630,
- fonts: [
- // { name: 'Inter', data: fontData[0], weight: 300, style: 'normal' },
- // { name: 'Inter', data: fontData[1], weight: 400, style: 'normal' },
- // { name: 'Inter', data: fontData[2], weight: 500, style: 'normal' },
- // { name: 'Inter', data: fontData[3], weight: 600, style: 'normal' },
- // { name: 'Inter', data: fontData[4], weight: 700, style: 'normal' },
- { name: 'Inter', data: fontData[0], weight: 900, style: 'normal' },
- ],
+ fonts: [{ name: 'Inter', data: fontData, weight: 900, style: 'normal' }],
},
);
}
diff --git a/apps/website/src/pages/api/og_model.tsx b/apps/website/src/pages/api/og_model.tsx
new file mode 100644
index 000000000..66ec4f1b2
--- /dev/null
+++ b/apps/website/src/pages/api/og_model.tsx
@@ -0,0 +1,170 @@
+/* eslint-disable react/no-unknown-property */
+import type { ApiItemKind } from '@microsoft/api-extractor-model';
+import { ImageResponse } from '@vercel/og';
+import type { NextRequest } from 'next/server';
+
+const fonts = Promise.all([
+ fetch(new URL('../../assets/fonts/Inter-Regular.ttf', import.meta.url)).then(async (res) => res.arrayBuffer()),
+ fetch(new URL('../../assets/fonts/Inter-Bold.ttf', import.meta.url)).then(async (res) => res.arrayBuffer()),
+]);
+
+function resolveIcon(icon: keyof typeof ApiItemKind, size = 88) {
+ switch (icon) {
+ case 'Class':
+ return (
+
+ );
+ case 'Enum':
+ return (
+
+ );
+ case 'EnumMember':
+ return (
+
+ );
+ case 'Interface':
+ return (
+
+ );
+ case 'TypeAlias':
+ return (
+
+ );
+ case 'Variable':
+ return (
+
+ );
+ case 'Property':
+ return (
+
+ );
+ default:
+ return (
+
+ );
+ }
+}
+
+export default async function handler(req: NextRequest) {
+ const fontData = await fonts;
+
+ const { searchParams } = new URL(req.url);
+
+ const hasPkg = searchParams.has('pkg');
+ const hasKind = searchParams.has('kind');
+ const hasName = searchParams.has('name');
+ const hasMethods = searchParams.has('methods');
+ const hasProps = searchParams.has('props');
+ const hasMembers = searchParams.has('members');
+ const pkg = hasPkg ? searchParams.get('pkg') : '';
+ const kind = hasKind ? searchParams.get('kind')! : 'Method';
+ const name = hasName ? searchParams.get('name')!.slice(0, 100) : 'My default name which is super long to overflow';
+ const methods = hasMethods ? searchParams.get('methods') : '';
+ const props = hasProps ? searchParams.get('props') : '';
+ const members = hasMembers ? searchParams.get('members') : '';
+
+ return new ImageResponse(
+ (
+
+
+
@discordjs/{pkg}
+
+
+ {resolveIcon(kind as keyof typeof ApiItemKind)}
+
+ {name}
+
+
+
+
+ {props ? (
+
+
{resolveIcon('Property', 36)}
+
+ {props}
+ Properties
+
+
+ ) : null}
+ {methods ? (
+
+
{resolveIcon('Method', 36)}
+
+ {methods}
+ Methods
+
+
+ ) : null}
+ {members ? (
+
+
{resolveIcon('EnumMember', 36)}
+
+ {members}
+ Members
+
+
+ ) : null}
+
+
+ discord.js
+
+
+
+
+
+ ),
+ {
+ width: 1_200,
+ height: 630,
+ fonts: [
+ { name: 'Inter', data: fontData[0], weight: 500, style: 'normal' },
+ { name: 'Inter', data: fontData[1], weight: 700, style: 'normal' },
+ ],
+ debug: false,
+ },
+ );
+}
+
+export const config = {
+ runtime: 'experimental-edge',
+};
diff --git a/apps/website/src/pages/docs/[...slug].tsx b/apps/website/src/pages/docs/[...slug].tsx
index 62edade89..3d11f7705 100644
--- a/apps/website/src/pages/docs/[...slug].tsx
+++ b/apps/website/src/pages/docs/[...slug].tsx
@@ -1,3 +1,4 @@
+/* eslint-disable no-case-declarations */
import { readFile } from 'node:fs/promises';
import { join } from 'node:path';
import process, { cwd } from 'node:process';
@@ -220,7 +221,45 @@ export const getStaticProps: GetStaticProps = async ({ params }) => {
}
};
-const member = (props?: ApiItemJSON | undefined) => {
+function resolveMember(packageName?: string | undefined, member?: SidebarLayoutProps['data']['member']) {
+ switch (member?.kind) {
+ case 'Class': {
+ const typedMember = member as ApiClassJSON;
+ return `?pkg=${packageName}&kind=${typedMember.kind}&name=${typedMember.name}&methods=${typedMember.methods.length}&props=${typedMember.properties.length}`;
+ }
+
+ case 'Function': {
+ const typedMember = member as ApiFunctionJSON;
+ return `?pkg=${packageName}&kind=${typedMember.kind}&name=${typedMember.name}`;
+ }
+
+ case 'Interface': {
+ const typedMember = member as ApiInterfaceJSON;
+ return `?pkg=${packageName}&kind=${typedMember.kind}&name=${typedMember.name}&methods=${typedMember.methods.length}&props=${typedMember.properties.length}`;
+ }
+
+ case 'TypeAlias': {
+ const typedMember = member as ApiTypeAliasJSON;
+ return `?pkg=${packageName}&kind=${typedMember.kind}&name=${typedMember.name}`;
+ }
+
+ case 'Variable': {
+ const typedMember = member as ApiVariableJSON;
+ return `?pkg=${packageName}&kind=${typedMember.kind}&name=${typedMember.name}`;
+ }
+
+ case 'Enum': {
+ const typedMember = member as ApiEnumJSON;
+ return `?pkg=${packageName}&kind=${typedMember.kind}&name=${typedMember.name}&members=${typedMember.members.length}`;
+ }
+
+ default: {
+ return `?pkg=${packageName}&kind=${member?.kind}&name=${member?.name}`;
+ }
+ }
+}
+
+function member(props?: ApiItemJSON | undefined) {
switch (props?.kind) {
case 'Class':
return
;
@@ -237,7 +276,7 @@ const member = (props?: ApiItemJSON | undefined) => {
default:
return
Cannot render that item type
;
}
-};
+}
export default function SlugPage(props: Partial
) {
const router = useRouter();
@@ -249,6 +288,10 @@ export default function SlugPage(props: Partial `${props.packageName ?? 'discord.js'}${props.data?.member?.name ? ` | ${props.data.member.name}` : ''}`,
[props.packageName, props.data?.member?.name],
);
+ const ogImage = useMemo(
+ () => resolveMember(props.packageName, props.data?.member),
+ [props.packageName, props.data?.member],
+ );
if (router.isFallback) {
return null;
@@ -268,6 +311,7 @@ export default function SlugPage(props: Partial
{name}
+
{member(props.data.member)}
>