feat: add og image generation

This commit is contained in:
DuroCodes
2024-05-25 17:34:13 -04:00
parent 79cbe92934
commit 5ac909e1aa
40 changed files with 128 additions and 19 deletions

View File

@@ -12,6 +12,8 @@ const { VALIDATE_LINKS } = loadEnv(process.env.NODE_ENV, process.cwd(), "");
const validateLinks = VALIDATE_LINKS === "true";
export default defineConfig({
// TODO: Change this whenever site is deployed to `sern.dev`
site: 'https:/deploy-preview-66--sern-docs.netlify.app',
integrations: [
starlight({
title: "sern",

BIN
bun.lockb

Binary file not shown.

View File

@@ -21,6 +21,8 @@
"@lunariajs/core": "^0.0.32",
"@lunariajs/starlight": "^0.0.6",
"astro": "4.9.1",
"astro-og-canvas": "^0.5.0",
"canvaskit-wasm": "^0.39.1",
"sharp": "^0.32.5",
"starlight-blog": "^0.7.1",
"starlight-links-validator": "^0.8.0",
@@ -35,4 +37,4 @@
"prettier-plugin-astro": "^0.13.0",
"prettier-plugin-tailwindcss": "^0.5.14"
}
}
}

View File

@@ -1,3 +1,4 @@
import { GITHUB_URL } from '~/utils/consts.ts';
import { $ } from "bun";
await $`rm -rf sern-handler && git clone https://github.com/sern-handler/handler sern-handler && cd sern-handler && bun install`;
await $`rm -rf sern-handler && git clone ${GITHUB_URL}/handler sern-handler && cd sern-handler && bun install`;

3
src/content.ts Normal file
View File

@@ -0,0 +1,3 @@
import { getCollection } from "astro:content";
export const allPages = await getCollection("docs");

View File

@@ -1,4 +1,4 @@
import { defineCollection } from "astro:content";
import { defineCollection, getCollection } from "astro:content";
import { docsSchema } from "@astrojs/starlight/schema";
import { blogSchema } from "starlight-blog/schema";

View File

@@ -1,5 +1,6 @@
---
title: About the CLI
description: The CLI is your pocketknife for discord bot development. It'll have all features necessary for developing and shipping to production.
---
Publish commands to the API, install plugins, and use other tools provided by our cli.

View File

@@ -1,5 +1,6 @@
---
title: Build
description: Build your bot using the sern CLI tool
---
```sh

View File

@@ -1,5 +1,6 @@
---
title: Clear
description: Clear and reset your commands, both globally and per guild
---
```sh

View File

@@ -1,5 +1,6 @@
---
title: Extra
description: Add extra features to your sern project
---
```sh
@@ -23,4 +24,4 @@ You can use this command to install things such as a `Dockerfile`
 sern extra
# Choose which extra feature from the prompt, such as this:
✔ What extra feature do you want to add?  Dockerfile (TypeScript)
```
```

View File

@@ -1,5 +1,6 @@
---
title: Publish
description: Publish your commands to Discord
---
```sh

View File

@@ -1,9 +1,9 @@
---
title: Choosing an IDE
description: Choose an IDE for sern bot development
---
Choosing an IDE is a matter of personal preference. They make programming easier. The following are some
suggestions for choosing an IDE:
Choosing an IDE is a matter of personal preference. They make programming easier. The following are some suggestions for choosing an IDE:
- [Visual Studio Code](https://code.visualstudio.com)
- We have an [snippet extension](https://marketplace.visualstudio.com/items?itemName=SrIzan.sern-snippets) to help automate development :)

View File

@@ -1,5 +1,6 @@
---
title: Preparing to Code
description: Prepare your environment for sern bot development
---
After installing an IDE, you need to install `node`. Node is necessary to use `sern`, as it's based on `Discord.js`.

View File

@@ -1,5 +1,6 @@
---
title: Autocomplete
description: Implementing autocomplete in your commands
sidebar:
order: 9
---

View File

@@ -1,5 +1,6 @@
---
title: CLI
description: The CLI is your plug to the sern ecosystem — install plugins, extra utilities, and more.
sidebar:
order: 3
---

View File

@@ -1,5 +1,6 @@
---
title: Conclusion
description: Thank you for reading the sern guide
sidebar:
order: 12
---

View File

@@ -1,5 +1,6 @@
---
title: Dependency Injection
description: Customize your bot's utilities and structures
sidebar:
order: 10
---

View File

@@ -1,5 +1,6 @@
---
title: First Command
description: How to create your first sern command module
sidebar:
order: 5
---

View File

@@ -1,5 +1,6 @@
---
title: First Event
description: How to create your first sern event module
sidebar:
order: 6
---
@@ -71,4 +72,4 @@ export default eventModule({
:::note
Make sure that the `emitter` property matches the name of the dependency you passed into `makeDependencies`.
:::
:::

View File

@@ -1,5 +1,6 @@
---
title: Goal
description: sern's goal is to make bot development easier and more efficient
sidebar:
order: 1
---

View File

@@ -1,5 +1,6 @@
---
title: Good to Know
description: Helpful tips for sern bot development
sidebar:
order: 13
---

View File

@@ -1,5 +1,6 @@
---
title: New Project
description: Create a new project with @sern/bot
sidebar:
order: 2
---

View File

@@ -1,5 +1,6 @@
---
title: Plugins
description: Reduce code repetition with sern plugins
sidebar:
order: 7
---
@@ -115,4 +116,4 @@ Calling `controller.stop()` notifies sern that this command should not be run, a
:::tip
Event Plugins are good for filtering, preconditions, parsing.
:::
:::

View File

@@ -1,5 +1,6 @@
---
title: Sern Emitter
description: How to use the SernEmitter class for event handling
sidebar:
order: 11
---
@@ -18,4 +19,4 @@ import { Steps } from '@astrojs/starlight/components';
You can put these and other event listeners into [event modules](/v3/guide/walkthrough/first-event)!
You can view all events in the [`SernEventsMapping`](/v3/api/interfaces/serneventsmapping) interface.
You can view all events in the [`SernEventsMapping`](/v3/api/interfaces/serneventsmapping) interface.

View File

@@ -1,5 +1,6 @@
---
title: Services
description: Using services in your project, and how to wire them together.
sidebar:
order: 8
---

View File

@@ -1,5 +1,6 @@
---
title: Transition from v2 to v3
description: Transitioning from v2 to v3 of sern
sidebar:
order: 4
---

View File

@@ -1,5 +1,6 @@
---
title: Getting Started
description: Get started with the sern framework
sidebar:
order: 2
---
@@ -7,6 +8,7 @@ sidebar:
import PackageManagers from '~/components/PackageManagers.astro';
<PackageManagers command="create" text="@sern/bot"/>
Once you've used this command, follow the interactive prompts to create your new project.
If you need help, feel free to ask on our [Discord](https://sern.dev/discord).

View File

@@ -1,11 +1,15 @@
---
title: Modules
description: Learn how to create modules for your sern bot
sidebar:
order: 2
---
## Introduction
sern operates with modules. At its core, Modules contain a `type` field and `execute`, with some code to possibly run before
executing.
### Modules
We'll walk you through creating your first command module.
@@ -31,22 +35,22 @@ export default commandModule({
await ctx.reply("Pong 🏓");
},
});
```
:::tip
Run `sern commands publish` so discord registers it to your application correctly.
:::
import { Tabs, TabItem } from '@astrojs/starlight/components';
## Modal
So, lets say you want to make a command module that listens to modals.
:::tip
Keep in mind, you'll need to send a modal with a custom id of `dm-me`. This example below is the response to a modal being sent.
:::
<Tabs syncKey="language-preference">
<TabItem value="js" label="Send Modal">
```js title="src/commands/ping.js"

View File

@@ -1,5 +1,6 @@
---
title: Project Layout
description: The layout of a sern project
sidebar:
order: 1
---

View File

@@ -1,5 +1,6 @@
---
title: Command
title: Command
description: The command module in sern
sidebar:
order: 1
---

View File

@@ -1,5 +1,6 @@
---
title: Event
title: Event
description: The event module in sern
sidebar:
order: 2
---

View File

@@ -1,5 +1,6 @@
---
title: Plugins
title: Plugins
description: A plugin in sern
sidebar:
order: 3
---

View File

@@ -1,5 +1,6 @@
---
title: Presence
title: Presence
description: Set the presence of your bot
sidebar:
order: 4
---

View File

@@ -1,6 +1,10 @@
---
import type { Props } from "@astrojs/starlight/props";
import StarlightHead from "@astrojs/starlight/components/Head.astro";
import { getOgImage } from "~/utils/ogImage";
const ogImageUrl = getOgImage(Astro.url.pathname, !!Astro.props.isFallback);
const imageSrc = new URL(ogImageUrl ?? "/sern-logo.png", Astro.site);
---
<StarlightHead {...Astro.props}><slot /></StarlightHead>
@@ -12,7 +16,7 @@ import StarlightHead from "@astrojs/starlight/components/Head.astro";
<meta property="og:url" content="https://sern.dev" />
<meta property="og:type" content="website" />
<meta property="og:image:alt" content="sern logo" />
<meta property="og:image" content="/sern-logo.png" />
<meta property="og:image" content={imageSrc} />
<meta property="og:image:height" content="512" />
<meta property="og:image:width" content="1024" />
<meta name="theme-color" content="#F25186" />
@@ -25,6 +29,6 @@ import StarlightHead from "@astrojs/starlight/components/Head.astro";
name="twitter:description"
content="A modular, customizable, fast Discord.js framework to streamline bot development"
/>
<meta name="twitter:image" content="/sern-logo.png" />
<meta name="twitter:image" content={imageSrc} />
<meta name="twitter:url" content="https://sern.dev" />
<meta property="twitter:site" content="@sern-handler" />

View File

@@ -0,0 +1,52 @@
import { OGImageRoute } from "astro-og-canvas";
import { allPages } from "~/content";
const pages = Object.fromEntries(
allPages.map(({ id, slug, data }) => [id, { slug, data }]),
);
export const { getStaticPaths, GET } = OGImageRoute({
param: "path",
pages,
getSlug: (path) =>
`${path.replace(/^\/src\/pages\//, "").replace(/\.[^.]*$/, "")}.webp`.replace(
/\/index\.webp$/,
".webp",
),
getImageOptions: async (_, { data }: (typeof pages)[string]) => ({
format: "WEBP",
quality: 90,
title: data.title,
description: data.description,
logo: {
path: "./src/pages/open-graph/_assets/logo.png",
size: [450],
},
border: {
color: [233, 186, 194],
width: 32,
},
padding: 80,
bgGradient: [[23, 24, 28]],
font: {
title: {
size: 72,
lineHeight: 1.2,
families: ["Satoshi", "sans-serif"],
weight: "Medium",
color: [233, 186, 194],
},
description: {
size: 42,
lineHeight: 1.2,
families: ["Inter", "sans-serif"],
weight: "Normal",
color: [255, 255, 255],
},
},
fonts: [
"./src/pages/open-graph/_assets/fonts/satoshi-black.otf",
"./src/pages/open-graph/_assets/fonts/inter-400-normal.ttf",
],
}),
});

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.5 KiB

15
src/utils/ogImage.ts Normal file
View File

@@ -0,0 +1,15 @@
import type { GetStaticPathsOptions, GetStaticPathsResult } from "astro";
import { getStaticPaths } from "~/pages/open-graph/[...path]";
const routes = (await getStaticPaths(
{} as GetStaticPathsOptions,
)) as GetStaticPathsResult;
const paths = new Set(routes.map(({ params }) => params.path));
export const getOgImage = (path: string, isFallback: boolean) => {
let imagePath = path.replace(/^\//, "").replace(/\/$/, "") + ".webp";
if (isFallback) imagePath = "en" + imagePath.slice(imagePath.indexOf("/"));
if (paths.has(imagePath)) return "/open-graph/" + imagePath;
};

View File

@@ -3,8 +3,8 @@ import { z } from "astro/zod";
export type Result<Ok, Err> =
| { ok: true; value: Ok }
| { ok: false; error: Err };
export const Ok = <Ok>(value: Ok) => ({ ok: true, value } as const);
export const Err = <Err>(error: Err) => ({ ok: false, error } as const);
export const Ok = <Ok>(value: Ok) => ({ ok: true, value }) as const;
export const Err = <Err>(error: Err) => ({ ok: false, error }) as const;
export type Contributor = z.infer<typeof ContributorSchema>;
export const ContributorSchema = z.object({