mirror of
https://github.com/sern-handler/website
synced 2026-06-06 01:16:47 +00:00
feat: add og image generation
This commit is contained in:
@@ -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",
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
3
src/content.ts
Normal file
@@ -0,0 +1,3 @@
|
||||
import { getCollection } from "astro:content";
|
||||
|
||||
export const allPages = await getCollection("docs");
|
||||
@@ -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";
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
---
|
||||
title: Build
|
||||
description: Build your bot using the sern CLI tool
|
||||
---
|
||||
|
||||
```sh
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
---
|
||||
title: Clear
|
||||
description: Clear and reset your commands, both globally and per guild
|
||||
---
|
||||
|
||||
```sh
|
||||
|
||||
@@ -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`
|
||||
[33m❯[0m sern extra
|
||||
[90m# Choose which extra feature from the prompt, such as this:[0m
|
||||
[33m✔[0m What extra feature do you want to add? [90m›[0m Dockerfile (TypeScript)
|
||||
```
|
||||
```
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
---
|
||||
title: Publish
|
||||
description: Publish your commands to Discord
|
||||
---
|
||||
|
||||
```sh
|
||||
|
||||
@@ -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 :)
|
||||
|
||||
@@ -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`.
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
---
|
||||
title: Autocomplete
|
||||
description: Implementing autocomplete in your commands
|
||||
sidebar:
|
||||
order: 9
|
||||
---
|
||||
|
||||
@@ -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
|
||||
---
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
---
|
||||
title: Conclusion
|
||||
description: Thank you for reading the sern guide
|
||||
sidebar:
|
||||
order: 12
|
||||
---
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
---
|
||||
title: Dependency Injection
|
||||
description: Customize your bot's utilities and structures
|
||||
sidebar:
|
||||
order: 10
|
||||
---
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
---
|
||||
title: First Command
|
||||
description: How to create your first sern command module
|
||||
sidebar:
|
||||
order: 5
|
||||
---
|
||||
|
||||
@@ -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`.
|
||||
:::
|
||||
:::
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
---
|
||||
title: Goal
|
||||
description: sern's goal is to make bot development easier and more efficient
|
||||
sidebar:
|
||||
order: 1
|
||||
---
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
---
|
||||
title: Good to Know
|
||||
description: Helpful tips for sern bot development
|
||||
sidebar:
|
||||
order: 13
|
||||
---
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
---
|
||||
title: New Project
|
||||
description: Create a new project with @sern/bot
|
||||
sidebar:
|
||||
order: 2
|
||||
---
|
||||
|
||||
@@ -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.
|
||||
:::
|
||||
:::
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
---
|
||||
title: Services
|
||||
description: Using services in your project, and how to wire them together.
|
||||
sidebar:
|
||||
order: 8
|
||||
---
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
---
|
||||
title: Transition from v2 to v3
|
||||
description: Transitioning from v2 to v3 of sern
|
||||
sidebar:
|
||||
order: 4
|
||||
---
|
||||
|
||||
@@ -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).
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
---
|
||||
title: Project Layout
|
||||
description: The layout of a sern project
|
||||
sidebar:
|
||||
order: 1
|
||||
---
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
---
|
||||
title: Command
|
||||
title: Command
|
||||
description: The command module in sern
|
||||
sidebar:
|
||||
order: 1
|
||||
---
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
---
|
||||
title: Event
|
||||
title: Event
|
||||
description: The event module in sern
|
||||
sidebar:
|
||||
order: 2
|
||||
---
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
---
|
||||
title: Plugins
|
||||
title: Plugins
|
||||
description: A plugin in sern
|
||||
sidebar:
|
||||
order: 3
|
||||
---
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
---
|
||||
title: Presence
|
||||
title: Presence
|
||||
description: Set the presence of your bot
|
||||
sidebar:
|
||||
order: 4
|
||||
---
|
||||
|
||||
@@ -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" />
|
||||
|
||||
52
src/pages/open-graph/[...path].ts
Normal file
52
src/pages/open-graph/[...path].ts
Normal 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",
|
||||
],
|
||||
}),
|
||||
});
|
||||
BIN
src/pages/open-graph/_assets/fonts/inter-400-normal.ttf
Normal file
BIN
src/pages/open-graph/_assets/fonts/inter-400-normal.ttf
Normal file
Binary file not shown.
BIN
src/pages/open-graph/_assets/fonts/satoshi-black.otf
Normal file
BIN
src/pages/open-graph/_assets/fonts/satoshi-black.otf
Normal file
Binary file not shown.
BIN
src/pages/open-graph/_assets/logo.png
Normal file
BIN
src/pages/open-graph/_assets/logo.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 7.5 KiB |
15
src/utils/ogImage.ts
Normal file
15
src/utils/ogImage.ts
Normal 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;
|
||||
};
|
||||
@@ -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({
|
||||
|
||||
Reference in New Issue
Block a user