diff --git a/.gitignore b/.gitignore
index 4c4c649..8153fd8 100644
--- a/.gitignore
+++ b/.gitignore
@@ -5,3 +5,4 @@ public/
resources/
.DS_Store
+.vscode/
diff --git a/content/custom-commands/_index.md b/content/custom-commands/_index.md
new file mode 100644
index 0000000..02a9bae
--- /dev/null
+++ b/content/custom-commands/_index.md
@@ -0,0 +1,11 @@
++++
+archetype = "chapter"
+title = "Custom Commands"
+weight = 3
++++
+
+Custom Commands (CCs) allow you to develop your own commands and behaviors for your server. A command may be as simple
+as an autoresponder or employ a more complex system. A variety of triggers are available for custom commands and the
+custom template script provides a wide array of templates and functions for coding advanced commands.
+
+{{%children containerstyle="div" style="h2" description="true" %}}
diff --git a/content/custom-commands/command_editor_overview.png b/content/custom-commands/command_editor_overview.png
new file mode 100644
index 0000000..ab97d65
Binary files /dev/null and b/content/custom-commands/command_editor_overview.png differ
diff --git a/content/custom-commands/command_overview.png b/content/custom-commands/command_overview.png
new file mode 100644
index 0000000..0f502c6
Binary files /dev/null and b/content/custom-commands/command_overview.png differ
diff --git a/content/custom-commands/commands.md b/content/custom-commands/commands.md
new file mode 100644
index 0000000..764bd6f
--- /dev/null
+++ b/content/custom-commands/commands.md
@@ -0,0 +1,367 @@
++++
+title = 'Commands'
+weight = 1
++++
+
+The commands page displays all custom commands and allows you to add, delete, or edit custom commands and custom command
+groups.
+
+
+
+![Overview of the Commands page.](command_overview.png)
+
+
+
+**1** Create Custom Command **2** List of Commands in Selected Group **3** Edit this Custom Command **4** Delete this
+Custom Command **5** Run this Command Now **6** Selected Group **7** Group Tabs **8** Name of Selected Group **9**
+Delete Selected Group **10** Channel and Role Restrictions **11** Save group settings
+
+
+
+## Creating a Custom Command
+
+Clicking the Create Custom Command (**1**) will instantly create a new command within the selected group (**6**) then
+redirect you to the page to edit it.
+
+A new custom command has the default response:
+
+```go
+Edit this to change the output of the custom command {{.CCID}}!
+```
+
+It also assigns the command an ID determined by the number of commands you have created in the guild.
+
+{{% notice style="tip" title="Troubleshooting" %}}
+
+![Empty CC Discord Messages](empty_cc_1.png)
+
+If the bot is sending messages such as this in your server, you are likely accidentally triggering CCs with the default
+response. Check the commands page to find any CCs with empty responses.
+
+![An empty CC on the dashboard](empty_cc_2.png)
+
+{{% /notice %}}
+
+## Command List
+
+The commands page lists the commands (**2**) in the selected group (**6**). They are ordered by [ID](#id-and-name) and
+display their name (if set), [trigger type](#trigger-types), and trigger text (if applicable). You can expand the
+command by clicking on it, allowing you to preview the full, syntax-highlighted command response.
+
+### Delete a Command
+
+Deleting a custom command (**4**) will **permanently** delete the command after confirmation. This cannot be undone.
+
+### Run Now
+
+The Run now button (**5**) appears on [Interval trigger](#hourlyminute-interval) commands. It executes the command as
+long as it isn't disabled and a channel is selected, and redirects you to the edit command page for the command.
+
+Manually running an interval command reschedules all subsequent runs based off the current time.
+
+## Command Groups
+
+Command groups allow you to organize your custom commands and apply role and channel restrictions to multiple commands.
+
+The group tabs at the top of the page (**7**) allow you to switch to any of your created groups. The **+** button allows
+you to create a new group.
+
+### Editing a Group
+
+Selecting a group allows you to edit it. Any changes must be saved (**11**) to take effect.
+
+- **Name** (**8**): Name your custom command group (100 characters max).
+- **Delete group** (**9**): Permanently delete the group after confirmation.
+- **Role/Channel restrictions** (**10**): Restrict commands within the group based on roles or channels executed in.
+- **Save group settings** (**11**): Update the group with the new values.
+
+#### Role/Channel Restrictions
+
+Restricting a custom command (**10**) adds conditions for it to run A user who tries to run a custom command with the
+wrong roles/in the wrong channel will not trigger the response or an error.
+
+- Whitelisting roles or channels causes them to be required to run the command.
+- Blacklisted roles or channels will not be permitted to run the command.
+
+{{% notice style="note" %}}
+
+YAGPDB was raised well and honors a "no" when told "no". In other words, blacklists take precedence over whitelists.
+
+This is a relatively common trip-hazard, so take great care when you set up both whitelists and blacklists.
+
+{{% /notice %}}
+
+## Editing a Custom Command
+
+Editing a custom command (**3**) opens up a separate page for configuration.
+
+![Overview of the CC edit page.](command_editor_overview.png)
+
+
+
+**1** ID **2** Name **3** Trigger Type **4** Trigger Text **5** Case Sensitivity Toggle **6** Message Edits Trigger
+Toggle **7** Response **8** Add Response **9** Custom Command Group **10** Channel and Role Restrictions
+**11** Execution Statistics **12** Error Output Toggle **13** Enable Command Toggle **14** Save Command **15**
+Delete command button
+
+
+
+### ID and Name
+
+Custom Commands are identified by either their ID or their name.
+
+When a custom command is created, the system assigns it a numeric **ID** (**1**) starting at `1`. The number increases
+with each custom command created on your server. It is not based on the _current_ number of custom commands, but the
+total commands that have ever been created on the server. This ID is permanent, and cannot be changed or re-ordered.
+
+The ID may be used to identify a CC for a variety of purposes. Calling `{{ .CCID }}` within a command response will
+return its ID. You must target a CC ID for `execCC`. You can use run the `CustomCommands` command with a CC ID to
+retrieve info about that CC.
+
+{{% notice warning %}}
+
+Deleting a Custom Command does not allow its ID to be reassigned. If you delete a CC, its ID is lost forever.
+
+{{% /notice %}}
+
+A Custom Command's **name** (**2**), conversely, is defined by the user. It is an optional argument that can be used to
+identify the command in the control panel and with the `CustomCommands` command. Max 100 characters.
+
+### Triggers
+
+A trigger (**3**) defines what runs the command. Depending on the type of trigger you may also need to specify
+additional configuration. For example, most trigger types require a **Trigger** (**4**) field defining the text the
+command should match against new messages. Max 1000 characters.
+
+#### Trigger types
+
+##### Command
+
+Messages **starting with the prefix** for your server (- by default) _OR_ by mentioning the bot followed by the trigger
+text (**4**) will trigger the command.
+
+###### Example
+
+Trigger: `say`
+
+Matches:
+> -say
+>
+> -say hello
+>
+> @YAGPDB.xyz say hello
+
+Doesn't match:
+
+> say hello
+>
+> -sayl hello
+
+##### Starts With
+
+Messages **starting with** the trigger text (**4**) will trigger the command.
+
+##### Contains
+
+Messages **containing** the trigger text (**4**) will trigger the command.
+
+##### Regex
+
+Messages matching the trigger text (**4**) as a **[regex pattern](/reference/regex)** will trigger the command.
+
+##### Exact Match
+
+Messages which **exactly** match the trigger text (**4**) will trigger the command.
+
+##### Reaction
+
+Reactions to a message will trigger the command.
+
+Can specify **Added Only**, **Removed Only**, or **Both** to restrict which types of Reactions will trigger the command.
+
+{{% notice style="tip" title="Filtering Emojis" %}}
+
+You cannot specify which emojis the command will trigger on. If you'd like to limit which emojis run the code, you will
+need to write that code yourself in the response.
+
+Example:
+
+```go
+ {{ if eq .Reaction.Emoji.APIName "😀" "⭐️" }}
+ This is an allowed reaction!
+ {{ else if eq .Reaction.Emoji.APIName "🦆" }}
+ This is not an allowed reaction.
+ {{ end }}
+```
+
+{{% /notice %}}
+
+##### Hourly/Minute Interval
+
+Interval triggers will run the command at a set interval in the selected channel.
+
+The Member in context is nil, and functions relying on the Member context will fail. However, `exec` will run commands
+as the bot.
+
+![Overview of interval configuration options.](interval_trigger_options.png?width=60vw)
+
+
+
+Interval (**1**) sets how often the command will run in **hours** or **minutes**.
+
+Channel (**2**) specifies a channel to run the command in. The response will be sent to this channel.
+
+Excluding hours and/or weekdays (**3**) prevents the command from triggering during those hours or weekdays. **This uses
+UTC time**, not your local timezone.
+
+When editing an interval command, a **Run Now** button appears at the bottom of the page. It executes the command as
+long as it isn't disabled and a channel is selected.
+
+Manually running an interval command reschedules all subsequent runs based off the current time.
+
+{{% notice info %}}
+
+You must specify a channel to run interval commands in even if the command doesn't output a message.
+
+{{% /notice %}}
+
+#### Case Sensitivity
+
+Any commands which allow you to specify trigger text (ex. Command, Regex, Exact match, etc.) have a **Case sensitivity**
+toggle (**5**) which is off by default. A case-sensitive trigger `yagPDB` will trigger on "yagPDB" but not "yagpdb" or
+"YAGPDB".
+
+#### Edit Message Trigger
+
+This feature is [premium only](/premium).
+
+Commands which trigger on messages have a **Trigger on message edits** toggle (**6**) which is off by default. If a
+message is edited and matches the trigger text, it will trigger the command.
+
+The edited message toggle is an _additional_ trigger to the normal message trigger. If you'd like to _only_ trigger on
+message edits, you will need to conditional branch with `{{ .IsMessageEdit }}`.
+
+### Response
+
+The response (**7**) defines the message the bot will send once the command is triggered.
+
+Optionally define multiple responses which the bot will randomly select from when the command is run. Add a response
+with the plus button on the right of the response (**8**).
+
+The response supports the custom template script, allowing for more complex functionality such as assigning roles,
+getting data from users, sending messages to other channels, and more. Visit the Templates reference page to learn more.
+
+{{% button href="/reference/templates" style="transparent" %}}Templates{{% /button %}}
+
+{{% notice style="tip" title="Keeping your code safe" %}}
+
+It is recommended to save local copies of your custom commands. There is no way to recover deleted or overwritten CCs.
+Use an editor like **Vim**, **VS Code**, or **Notepad++** for the best coding experience.
+
+{{% /notice %}}
+
+### Custom Command Group
+
+Dropdown selection (**9**) to change which command group the command is in. Select `None` to ungroup the command.
+
+### Channel and Role Restrictions
+
+Restricting a custom command (**10**) adds conditions for it to run A user who tries to run a custom command with the
+wrong roles/in the wrong channel will not trigger the response or an error.
+
+A dropdown selection allows you to select a list of roles or channels, and the checkbox allows you to define the list as
+a blacklist or a whitelist.
+
+- Whitelisting roles or channels causes them to be required to run the command.
+- Blacklisted roles or channels will not be permitted to run the command.
+
+{{% notice info %}}
+
+Role restrictions are unrelated to user permissions. Having `Administrator` permissions will not override these
+restrictions.
+
+{{% /notice %}}
+
+#### CC Groups
+
+A user executing a command must pass both the overarching group's restrictions and the command restrictions.
+Command-specific whitelists will _not_ override the group restrictions.
+
+### Execution Statistics
+
+The execution statistics (**11**) show details about the custom command's executions. It's updated after the command
+runs.
+
+#### Last Error
+
+The most recent error which occurred running the command, UTC Timestamped. The error display is not cleared when the
+command runs successfully.
+
+#### Run Count
+
+A count of how many times the command executed the response. This counter increases even if the command errors, or does
+not send a response. It also increases if the command is run via `execCC`.
+
+The run count will not increase if the user who ran the command did not pass the restrictions.
+
+{{% notice style="tip" title="Troubleshooting" %}}
+
+If your command fails to run, check the run count. If the run count increases when you attempt to run the command, the
+issue is with your code. Otherwise, the issue may be with YAGPDB's permissions in your server, or incorrectly setup
+Role/Channel Restrictions in the command and/or command group.
+
+{{% /notice %}}
+
+#### Last Run
+
+A UTC Timestamp of the last time the command executed the response.
+
+#### Next Scheduled Run
+
+Only shown on Interval type commands. A UTC Timestamp of the next time the command is scheduled to run.
+
+### Output errors as command response
+
+This toggle (**12**) determines whether errors during command execution are sent in the command response after the
+command fails. Does not affect logging of Last Error to the statistics.
+
+### Command Enabled
+
+This toggle (**13**) enables the command. A disabled command will never run (not even with `execCC`) or count against
+the trigger limit.
+
+### Saving Your Command
+
+Saving (**14**) the command updates it with the new values if there are no errors.
+
+Alt + Shift + S also saves the custom command.
+
+A custom command **will not save** if there is an error in your input. Examples of errors which prevent you from saving:
+
+- There is a syntax error in the response
+- You have reached the maximum CC limit
+- You are attempting to save an empty response
+
+If you save a command with an interval trigger which has never been run, it will run instantly upon saving.
+
+{{% notice style="tip" title="Keeping your code safe" %}}
+
+It is recommended to code your custom command using a local editor on your device. You will not be able to save your
+code on the dashboard if there are syntax errors in your code. Use an editor like **Vim**, **VS Code**, or **Notepad++**
+for the best coding experience.
+
+{{% /notice %}}
+
+{{% notice warning %}}
+
+Custom commands do not autosave.
+
+{{% /notice %}}
+
+### Delete Current Command
+
+Deleting the custom command (**15**) will **permanently** delete the command after confirmation. This cannot be undone.
diff --git a/content/custom-commands/database.md b/content/custom-commands/database.md
new file mode 100644
index 0000000..28c1ebd
--- /dev/null
+++ b/content/custom-commands/database.md
@@ -0,0 +1,80 @@
++++
+title = 'Database'
+weight = 2
++++
+
+The Custom Command Database is used for persistent storage between custom command executions. The database page displays
+all database entries created by custom commands, allowing you to view details on or delete individual entries.
+
+
+
+![Overview of the Database page.](overview_database.png)
+
+
+
+**1** Entry ID **2** Created Timestamp **3** Updated Timestamp **4** Expiry Timestamp **5** User ID **6** Key **7**
+Value **8** Size of Value **9** Delete Entry **10** Page Navigation **11** Search Query **12** Search Bar
+
+
+
+## Entries
+
+### Entry ID
+
+The ID is assigned by the system and unique within YAGPDB's database. The database page is sorted by descending ID. You
+may search for a specific ID using the **Search Bar** (**11**) with ID **Query** (**10**).
+
+### Created Timestamp
+
+UTC timestamp of when the entry was created.
+
+### Updated Timestamp
+
+UTC timestamp of when the entry was updated. Increasing or setting a database value updates this timestamp.
+
+### Expiry Timestamp
+
+UTC timestamp of when the entry will expire. An expired entry will not be retrieved by database functions, but **will**
+appear on the database page.
+
+### User ID
+
+The user-defined ID of the entry (does not have to be a user's ID, accepts any int64). You may search for a specific ID
+using the **Search Bar** (**11**) with User ID **Query** (**10**).
+
+### Key
+
+The user-defined key of the entry. A key is a string, max 256 characters. You may search for a specific key using the
+**Search Bar** (**11**) with Key **Query** (**10**).
+
+### Value
+
+The serialized value of the database entry.
+
+### Size of Value
+
+Size of the value in bytes. YAGPDB database entries have a max value size of 100 kB.
+
+### Delete Entry
+
+Deletes the individual entry after confirmation. You may only delete one entry at a time.
+
+## Page Navigation
+
+Navigates to the next or previous page of entries. Each page lists 100 entries at a time.
+
+## Search Query
+
+Dropdown selection of the type of value to search by. Available options are ID, User ID, and Key.
+
+## Search Bar
+
+Number or Text to match against database entries. Results will only include entries that exactly match the search
+pattern.
+
+When searching for a Key, the search query supports PostgreSQL patterns.
+
+- `_` matches any single character.
+- `%` matches any sequence of zero or more characters.
+
+To search for any database entries whose Key contains `yagpdb`, use `%yagpdb%` as your search pattern.
diff --git a/content/custom-commands/empty_cc_1.png b/content/custom-commands/empty_cc_1.png
new file mode 100644
index 0000000..01e3c3d
Binary files /dev/null and b/content/custom-commands/empty_cc_1.png differ
diff --git a/content/custom-commands/empty_cc_2.png b/content/custom-commands/empty_cc_2.png
new file mode 100644
index 0000000..9329d08
Binary files /dev/null and b/content/custom-commands/empty_cc_2.png differ
diff --git a/content/custom-commands/interval_trigger_options.png b/content/custom-commands/interval_trigger_options.png
new file mode 100644
index 0000000..9171663
Binary files /dev/null and b/content/custom-commands/interval_trigger_options.png differ
diff --git a/content/custom-commands/overview_database.png b/content/custom-commands/overview_database.png
new file mode 100644
index 0000000..bc8c052
Binary files /dev/null and b/content/custom-commands/overview_database.png differ
diff --git a/hugo.toml b/hugo.toml
index db82970..3e673ce 100644
--- a/hugo.toml
+++ b/hugo.toml
@@ -7,6 +7,10 @@ title = 'YAGPDB Documentation v2'
uglyURLs = true
[markup]
+ [markup.tableOfContents]
+ # Some relatively important headers, like cc triggers, are on level 4;
+ # we want to have those in our table of contents, so we need to set this to 4.
+ endLevel = 4
[markup.goldmark]
[markup.goldmark.renderer]
# Enable HTML tags in Markdown
@@ -17,22 +21,13 @@ uglyURLs = true
path = 'github.com/McShelby/hugo-theme-relearn'
[outputs]
- home = [ "HTML", "SEARCH" ]
+ home = [ "html", "search", "searchpage" ]
[params]
themeVariant = [
- { identifier = "relearn-auto", name = "Relearn Light/Dark", auto = [] },
- { identifier = "relearn-light" },
- { identifier = "relearn-dark" },
- { identifier = "relearn-bright" },
- { identifier = "zen-auto", name = "Zen Light/Dark", auto = [ "zen-light", "zen-dark" ] },
- { identifier = "zen-light" },
- { identifier = "zen-dark" },
- { identifier = "neon" },
- { identifier = "learn" },
- { identifier = "blue" },
- { identifier = "green" },
- { identifier = "red" }
+ { identifier = "zen-auto", name = "Zen Light/Dark", auto = [ "zen-light", "zen-dark" ] },
+ { identifier = "zen-light" },
+ { identifier = "zen-dark" },
]
collapsibleMenu = true
diff --git a/layouts/partials/custom-header.html b/layouts/partials/custom-header.html
new file mode 100644
index 0000000..4f3e251
--- /dev/null
+++ b/layouts/partials/custom-header.html
@@ -0,0 +1 @@
+
diff --git a/static/css/menu.css b/static/css/menu.css
new file mode 100644
index 0000000..3761e56
--- /dev/null
+++ b/static/css/menu.css
@@ -0,0 +1,6 @@
+/* Increase the margin a little bit such that it doesn't look too crowded
+ * on the menu side bar.
+ */
+#R-topics {
+ margin-left: 0.5em;
+}