Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .prettierignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
src/content/docs/**/*
4 changes: 2 additions & 2 deletions astro.config.mts
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,8 @@ export default defineConfig({
autogenerate: { directory: "installing" }
},
{
label: "Plugin Development",
autogenerate: { directory: "plugins" }
label: "Storing Data",
autogenerate: { directory: "storing-data" }
}
]
})
Expand Down
3 changes: 3 additions & 0 deletions pnpm-workspace.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
onlyBuiltDependencies:
- esbuild
- sharp
Binary file added src/assets/screenshots/settings/boolean.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/assets/screenshots/settings/select.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/assets/screenshots/settings/slider.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/assets/screenshots/settings/string.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
title: Creating Plugins
title: Your First Plugin
description: How to create plugins for Vencord
---

Expand Down
2 changes: 1 addition & 1 deletion src/content/docs/intro.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,4 @@ This documentation will cover topics like:
- How to setup your development environment
- The plugin structure and all the available plugin APIs
- How to reverse engineer and understand Discord code to find which functions you need to use or patch
- And much more!
- And much more!
4 changes: 0 additions & 4 deletions src/content/docs/plugins/submission.md

This file was deleted.

60 changes: 60 additions & 0 deletions src/content/docs/storing-data/accessing-settings.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
---
title: Access/Set Setting Value
description: How to get the value of a setting programmatically
sidebar:
order: 2
---

Declaring settings is nice. However, what's even nicer is to access them and actually do things with them in your plugin.

The `settings` constant has a `store` property, containing a key-value store of each setting. Assuming that you properly followed the
documentation, you should be able to access it from anywhere in your `index.ts(x)` file as it should be on the top-level.

So, assuming the following setting:

```json
settingName: {
type: OptionType.STRING,
placeholder: "Optional example value that will be shown if setting is unset",
default: "Sensible default value for that setting. Optional"
}
```

using `settings.store.settingName` should return its value.

## Access from another file

First, mark the `settings` constant as an export:

```ts ins="export"
export const settings = definePluginSettings({
/* ... */
});
```

then import it from the other file.

```ts
import { settings } from ".";
```

## Set a setting programmatically

You may also need to edit a setting from your plugin code. To do so, simply set the `settings.store.settingName` value to whatever you'd like:

```ts
settings.store.settingName = "Hello world";
console.log(settings.store.settingName); // Hello world
```

## useSettings hook

If you are writing UI, you might want it to update dynamically based on a setting value.

In this case, you can use the `useSettings` hook:

```ts
import { useSettings } from "@api/Settings";

const dynamicSettings = useSettings(["plugins.MyCoolPlugin"]).plugins["MyCoolPlugin"];
```
31 changes: 31 additions & 0 deletions src/content/docs/storing-data/datastore.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
---
title: DataStore
description: Store data that isn't configuration
sidebar:
order: 3
---

Vencord has a key-value store named `DataStore`, that allows you to store any data that can't be considered "settings".

This data is not backed up to Vencloud if Cloud Sync is on or exported in setting exports.

## How to use

:::note
DataStore's API is async, which means that you'll want to work in async functions.

Because of that, if you want to use DataStore in a React component, you have to use [an effect](https://react.dev/reference/react/useEffect), as React components cannot be async.
:::

First, import DataStore:
```ts
import * as DataStore from "@api/DataStore";
```

Then, you can get or set data! It's that easy.

```ts
await DataStore.get("key");

await DataStore.set("key", value);
```
56 changes: 56 additions & 0 deletions src/content/docs/storing-data/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
---
title: The Settings API
description: Add settings to your plugin
sidebar:
order: 0
---

To improve the user experience, Vencord offers a settings API that you can use to store plugin configuration.

Plugin settings stored using the settings API are also automatically backed up to Vencloud and in local backups made
by users. Therefore, avoid storing sensitive information in them.

## Get started

Import the `definePluginSettings` function from `@api/settings`.

Then, create a `settings` constant at the top-level and pass it the result of `definePluginSettings`, and pass that constant
to your plugin definition.


```ts ins="settings: definePluginSettings({ })" ins="import { definePluginSettings } from "@api/Settings";"
import { definePluginSettings } from "@api/Settings";

const settings = definePluginSettings({ });

export default definePlugin({
name: "MyCoolPlugin",
description: "I am very cute!",
authors: [Devs.author],
settings
});
```

## Define settings

In the `definePluginSettings` object, you can add settings in this format:
```json
settingName: {
type: OptionType.STRING/NUMBER/BOOLEAN...,

description: "Short description of the setting",

restartNeeded: false,
hidden: false // Use this for internal settings
}
```

:::tip
Your setting's key will also be the user-facing name for the setting, and should be in `camelCase` (first word lowercase, others start with uppercase, no spaces).

Vencord will turn the key into a Title Case name. Keep this in mind while naming your settings.
:::

:::note
A full list of option types and their respective properties is available in the Option Types page.
:::
137 changes: 137 additions & 0 deletions src/content/docs/storing-data/option-types.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
---
title: Option Types
description: The different option types available
sidebar:
order: 1
---

Here are the various option types that are available for you to use, along with their specific properties.

## Common

You will find yourself using these setting types the most frequently.

### String

Use the string type for text values.

```json
settingName: {
type: OptionType.STRING,
placeholder: "Optional example value that will be shown if setting is unset",
default: ""
}
```

![Screenshot of a string setting](../../../assets/screenshots/settings/string.png)

### Number

Use the number type for numeric values. Visually, it looks the same as the string type, but has validation to make sure that only a number is entered.

```json
settingName: {
type: OptionType.NUMBER,
placeholder: "Optional example value that will be shown if setting is unset",
default: 1
}
```

### BigInt

Use the number type for numeric values **that do not fit in an integer**. You might need this type to store Discord user/channel/guild IDs or similar
large values. If you do not need that, use the `NUMBER` type. Visually, it looks the same as the string type, but has validation to make sure that only a number is entered.

```json
settingName: {
type: OptionType.BIGINT,
placeholder: "Optional example value that will be shown if setting is unset",
default: 1015060230222131221n
}
```

### Boolean

Use the boolean type for toggles, and more generally, true/false values.

```json
settingName: {
type: OptionType.BOOLEAN,
default: true/false
}
```

![Screenshot of a boolean setting](../../../assets/screenshots/settings/boolean.png)

### Select

Use the select type to show multiple pre-defined options. It is highly recommended that you set a default value for a better user experience.

```json
settingName: {
type: OptionType.SELECT
options: [
{
label: "Option 1",
value: "option1",
default: true
},
{
label: "Option 2",
value: "option2",
}
]
}
```

![Screenshot of a select setting](../../../assets/screenshots/settings/select.png)

:::tip
Notice how we pass `default: true` to the default setting.

Also, the `label` will be shown to the user, while the `value` will be returned when accessing the
setting from your plugin.
:::

### Slider

Use the select type to show multiple pre-defined options. If you do not set a default value, it will be set to `0`.

```json
settingName: {
type: OptionType.SLIDER
markers: [0, 20, 40, 60, 80, 100],

// Forces user to stick to the markers.
// If false, allows them to set a value between.
stickToMarkers: true/false
}
```

![Screenshot of a slider setting](../../../assets/screenshots/settings/slider.png)

## Advanced

If you'd like to have a custom UI for a specific setting, or store an internal setting, you will need these types.

### Custom

Custom settings can store any type and are not displayed in the settings UI. They can only be set programmatically. Of course, they can have a `default` value.

```json
settingName: {
type: OptionType.CUSTOM
}
```

### Component

With the component type, you can show a fully customizable React component.

```tsx
settingName: {
type: OptionType.COMPONENT,
component: () => <>
<Button>Here is a button</Button>
</> // This must be a React component.
}
54 changes: 40 additions & 14 deletions src/style/custom.css
Original file line number Diff line number Diff line change
Expand Up @@ -3,27 +3,53 @@
--sl-color-accent-low: #430922;
--sl-color-accent: #c00065;
--sl-color-accent-high: #fab0c6;
--sl-color-white: #ffffff;
--sl-color-gray-1: #eeeeee;
--sl-color-gray-2: #c2c2c2;
--sl-color-gray-3: #8b8b8b;
--sl-color-white: #e2d5be;
--sl-color-gray-1: #d3869b;
--sl-color-gray-2: #faefdb;
--sl-color-gray-3: #faefdb;
--sl-color-gray-4: #585858;
--sl-color-gray-5: #383838;
--sl-color-gray-6: #272727;
--sl-color-black: #181818;

--sl-color-blue: #458588;
--sl-color-blue-low: hsl(from var(--sl-color-blue) h s 20%);
--sl-color-blue-high: hsl(from var(--sl-color-blue) h s 80%);
--sl-color-purple: #b16286;
--sl-color-purple-low: hsl(from var(--sl-color-purple) h s 20%);
--sl-color-purple-high: hsl(from var(--sl-color-purple) h s 80%);
--sl-color-orange: #d65d0e;
--sl-color-orange-low: hsl(from var(--sl-color-orange) h s 20%);
--sl-color-orange-high: hsl(from var(--sl-color-orange) h s 80%);
--sl-color-red: #cc241d;
--sl-color-red-low: hsl(from var(--sl-color-red) h s 20%);
--sl-color-red-high: hsl(from var(--sl-color-red) h s 80%);
}
/* Light mode colors. */
:root[data-theme="light"] {
--sl-color-accent-low: #fec5d5;
--sl-color-accent: #c30067;
--sl-color-accent: #945e80;
--sl-color-accent-high: #600030;
--sl-color-white: #181818;
--sl-color-gray-1: #272727;
--sl-color-gray-2: #383838;
--sl-color-gray-3: #585858;
--sl-color-gray-4: #8b8b8b;
--sl-color-gray-5: #c2c2c2;
--sl-color-gray-6: #eeeeee;
--sl-color-gray-7: #f6f6f6;
--sl-color-black: #ffffff;
--sl-color-white: #644735;
--sl-color-gray-1: #644735;
--sl-color-gray-2: #796051;
--sl-color-gray-3: #796c63;
--sl-color-gray-4: #beb795;
--sl-color-gray-5: #beb795;
--sl-color-gray-6: #ddd5b3;
--sl-color-gray-7: #f5edca;
--sl-color-black: #f9f5d7;

--sl-color-blue: #458588;
--sl-color-blue-low: hsl(from var(--sl-color-blue) h s 90%);
--sl-color-blue-high: hsl(from var(--sl-color-blue) h s 20%);
--sl-color-purple: #b16286;
--sl-color-purple-low: hsl(from var(--sl-color-purple) h s 90%);
--sl-color-purple-high: hsl(from var(--sl-color-purple) h s 20%);
--sl-color-orange: #d65d0e;
--sl-color-orange-low: hsl(from var(--sl-color-orange) h s 90%);
--sl-color-orange-high: hsl(from var(--sl-color-orange) h s 20%);
--sl-color-red: #cc241d;
--sl-color-red-low: hsl(from var(--sl-color-red) h s 90%);
--sl-color-red-high: hsl(from var(--sl-color-red) h s 20%);
}