Compare commits
2 commits
b79b102833
...
acccc963ae
| Author | SHA1 | Date | |
|---|---|---|---|
| acccc963ae | |||
| 77084203c6 |
369 changed files with 4749 additions and 7361 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
|
@ -22,4 +22,4 @@ lerna-debug.log*
|
||||||
src/userplugins
|
src/userplugins
|
||||||
|
|
||||||
ExtensionCache/
|
ExtensionCache/
|
||||||
/settings
|
settings/
|
||||||
|
|
|
||||||
9
.vscode/settings.json
vendored
9
.vscode/settings.json
vendored
|
|
@ -13,14 +13,11 @@
|
||||||
"typescript.format.semicolons": "insert",
|
"typescript.format.semicolons": "insert",
|
||||||
"typescript.preferences.quoteStyle": "double",
|
"typescript.preferences.quoteStyle": "double",
|
||||||
"javascript.preferences.quoteStyle": "double",
|
"javascript.preferences.quoteStyle": "double",
|
||||||
|
|
||||||
"gitlens.remotes": [
|
"gitlens.remotes": [
|
||||||
{
|
{
|
||||||
"domain": "codeberg.org",
|
"domain": "codeberg.org",
|
||||||
"type": "Gitea"
|
"type": "Gitea"
|
||||||
}
|
}
|
||||||
],
|
]
|
||||||
"css.format.spaceAroundSelectorSeparator": true,
|
}
|
||||||
"[css]": {
|
|
||||||
"editor.defaultFormatter": "vscode.css-language-features"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
||||||
17
README.md
17
README.md
|
|
@ -1,21 +1,26 @@
|
||||||
|
# A fork. A fork. We're a fork.
|
||||||
|
|
||||||
|
|
||||||
# Vencord
|
# Vencord
|
||||||
|
|
||||||

|
|
||||||
[](https://codeberg.org/Vee/cord)
|
[](https://codeberg.org/Vee/cord)
|
||||||
|
|
||||||
The cutest Discord client mod
|
The cutest Discord client mod
|
||||||
|
|
||||||

|
|  |
|
||||||
|
| :--------------------------------------------------------------------------------------------------: |
|
||||||
|
| A screenshot of vencord showcasing the [vencord-theme](https://github.com/synqat/vencord-theme) |
|
||||||
|
|
||||||
## Features
|
## Features
|
||||||
|
|
||||||
- Easy to install
|
- Super easy to install (Download Installer, open, click install button, done)
|
||||||
- [100+ built in plugins](https://vencord.dev/plugins)
|
- 100+ plugins built in: [See a list](https://vencord.dev/plugins)
|
||||||
|
- Some highlights: SpotifyControls, MessageLogger, Experiments, GameActivityToggle, Translate, NoTrack, QuickReply, Free Emotes/Stickers, PermissionsViewer, CustomCommands, ShowHiddenChannels, PronounDB
|
||||||
- Fairly lightweight despite the many inbuilt plugins
|
- Fairly lightweight despite the many inbuilt plugins
|
||||||
- Excellent Browser Support: Run Vencord in your Browser via extension or UserScript
|
- Excellent Browser Support: Run Vencord in your Browser via extension or UserScript
|
||||||
- Works on any Discord branch: Stable, Canary or PTB all work
|
- Works on any Discord branch: Stable, Canary or PTB all work (though for the best experience I recommend stable!)
|
||||||
- Custom CSS and Themes: Inbuilt css editor with support to import any css files (including BetterDiscord themes)
|
- Custom CSS and Themes: Inbuilt css editor with support to import any css files (including BetterDiscord themes)
|
||||||
- Privacy friendly: blocks Discord analytics & crash reporting out of the box and has no telemetry
|
- Privacy friendly, blocks Discord analytics & crash reporting out of the box and has no telemetry
|
||||||
- Maintained very actively, broken plugins are usually fixed within 12 hours
|
- Maintained very actively, broken plugins are usually fixed within 12 hours
|
||||||
- Settings sync: Keep your plugins and their settings synchronised between devices / apps (optional)
|
- Settings sync: Keep your plugins and their settings synchronised between devices / apps (optional)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -20,13 +20,16 @@
|
||||||
/// <reference path="../src/globals.d.ts" />
|
/// <reference path="../src/globals.d.ts" />
|
||||||
|
|
||||||
import monacoHtmlLocal from "file://monacoWin.html?minify";
|
import monacoHtmlLocal from "file://monacoWin.html?minify";
|
||||||
|
import monacoHtmlCdn from "file://../src/main/monacoWin.html?minify";
|
||||||
import * as DataStore from "../src/api/DataStore";
|
import * as DataStore from "../src/api/DataStore";
|
||||||
import { debounce, localStorage } from "../src/utils";
|
import { debounce } from "../src/utils";
|
||||||
import { EXTENSION_BASE_URL } from "../src/utils/web-metadata";
|
import { EXTENSION_BASE_URL } from "../src/utils/web-metadata";
|
||||||
import { getTheme, Theme } from "../src/utils/discord";
|
import { getTheme, Theme } from "../src/utils/discord";
|
||||||
import { getThemeInfo } from "../src/main/themes";
|
import { getThemeInfo } from "../src/main/themes";
|
||||||
import { Settings } from "../src/Vencord";
|
import { Settings } from "../src/Vencord";
|
||||||
import { getStylusWebStoreUrl } from "@utils/web";
|
|
||||||
|
// Discord deletes this so need to store in variable
|
||||||
|
const { localStorage } = window;
|
||||||
|
|
||||||
// listeners for ipc.on
|
// listeners for ipc.on
|
||||||
const cssListeners = new Set<(css: string) => void>();
|
const cssListeners = new Set<(css: string) => void>();
|
||||||
|
|
@ -42,13 +45,12 @@ window.VencordNative = {
|
||||||
themes: {
|
themes: {
|
||||||
uploadTheme: (fileName: string, fileData: string) => DataStore.set(fileName, fileData, themeStore),
|
uploadTheme: (fileName: string, fileData: string) => DataStore.set(fileName, fileData, themeStore),
|
||||||
deleteTheme: (fileName: string) => DataStore.del(fileName, themeStore),
|
deleteTheme: (fileName: string) => DataStore.del(fileName, themeStore),
|
||||||
|
getThemesDir: async () => "",
|
||||||
getThemesList: () => DataStore.entries(themeStore).then(entries =>
|
getThemesList: () => DataStore.entries(themeStore).then(entries =>
|
||||||
entries.map(([name, css]) => getThemeInfo(css, name.toString()))
|
entries.map(([name, css]) => getThemeInfo(css, name.toString()))
|
||||||
),
|
),
|
||||||
getThemeData: (fileName: string) => DataStore.get(fileName, themeStore),
|
getThemeData: (fileName: string) => DataStore.get(fileName, themeStore),
|
||||||
getSystemValues: async () => ({}),
|
getSystemValues: async () => ({}),
|
||||||
|
|
||||||
openFolder: async () => Promise.reject("themes:openFolder is not supported on web"),
|
|
||||||
},
|
},
|
||||||
|
|
||||||
native: {
|
native: {
|
||||||
|
|
@ -75,14 +77,6 @@ window.VencordNative = {
|
||||||
addThemeChangeListener: NOOP,
|
addThemeChangeListener: NOOP,
|
||||||
openFile: NOOP_ASYNC,
|
openFile: NOOP_ASYNC,
|
||||||
async openEditor() {
|
async openEditor() {
|
||||||
if (IS_USERSCRIPT) {
|
|
||||||
const shouldOpenWebStore = confirm("QuickCSS is not supported on the Userscript. You can instead use the Stylus extension.\n\nDo you want to open the Stylus web store page?");
|
|
||||||
if (shouldOpenWebStore) {
|
|
||||||
window.open(getStylusWebStoreUrl(), "_blank");
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const features = `popup,width=${Math.min(window.innerWidth, 1000)},height=${Math.min(window.innerHeight, 1000)}`;
|
const features = `popup,width=${Math.min(window.innerWidth, 1000)},height=${Math.min(window.innerHeight, 1000)}`;
|
||||||
const win = open("about:blank", "VencordQuickCss", features);
|
const win = open("about:blank", "VencordQuickCss", features);
|
||||||
if (!win) {
|
if (!win) {
|
||||||
|
|
@ -98,7 +92,7 @@ window.VencordNative = {
|
||||||
? "vs-light"
|
? "vs-light"
|
||||||
: "vs-dark";
|
: "vs-dark";
|
||||||
|
|
||||||
win.document.write(monacoHtmlLocal);
|
win.document.write(IS_EXTENSION ? monacoHtmlLocal : monacoHtmlCdn);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
@ -112,9 +106,8 @@ window.VencordNative = {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
set: async (s: Settings) => localStorage.setItem("VencordSettings", JSON.stringify(s)),
|
set: async (s: Settings) => localStorage.setItem("VencordSettings", JSON.stringify(s)),
|
||||||
openFolder: async () => Promise.reject("settings:openFolder is not supported on web"),
|
getSettingsDir: async () => "LocalStorage"
|
||||||
},
|
},
|
||||||
|
|
||||||
pluginHelpers: {} as any,
|
pluginHelpers: {} as any,
|
||||||
csp: {} as any,
|
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
"name": "vencord",
|
"name": "vencord",
|
||||||
"private": "true",
|
"private": "true",
|
||||||
"version": "1.13.0",
|
"version": "1.12.2",
|
||||||
"description": "The cutest Discord client mod",
|
"description": "The cutest Discord client mod",
|
||||||
"homepage": "https://github.com/Vendicated/Vencord#readme",
|
"homepage": "https://github.com/Vendicated/Vencord#readme",
|
||||||
"bugs": {
|
"bugs": {
|
||||||
|
|
@ -53,8 +53,8 @@
|
||||||
"@types/react": "^19.0.10",
|
"@types/react": "^19.0.10",
|
||||||
"@types/react-dom": "^19.0.4",
|
"@types/react-dom": "^19.0.4",
|
||||||
"@types/yazl": "^2.4.5",
|
"@types/yazl": "^2.4.5",
|
||||||
"@vencord/discord-types": "link:packages/discord-types",
|
|
||||||
"diff": "^7.0.0",
|
"diff": "^7.0.0",
|
||||||
|
"discord-types": "^1.3.26",
|
||||||
"esbuild": "^0.25.1",
|
"esbuild": "^0.25.1",
|
||||||
"eslint": "9.20.1",
|
"eslint": "9.20.1",
|
||||||
"eslint-import-resolver-alias": "^1.1.2",
|
"eslint-import-resolver-alias": "^1.1.2",
|
||||||
|
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
Hint: https://docs.discord.food is an incredible resource and allows you to copy paste complete enums and interfaces
|
|
||||||
|
|
@ -1,165 +0,0 @@
|
||||||
GNU LESSER GENERAL PUBLIC LICENSE
|
|
||||||
Version 3, 29 June 2007
|
|
||||||
|
|
||||||
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
|
|
||||||
Everyone is permitted to copy and distribute verbatim copies
|
|
||||||
of this license document, but changing it is not allowed.
|
|
||||||
|
|
||||||
|
|
||||||
This version of the GNU Lesser General Public License incorporates
|
|
||||||
the terms and conditions of version 3 of the GNU General Public
|
|
||||||
License, supplemented by the additional permissions listed below.
|
|
||||||
|
|
||||||
0. Additional Definitions.
|
|
||||||
|
|
||||||
As used herein, "this License" refers to version 3 of the GNU Lesser
|
|
||||||
General Public License, and the "GNU GPL" refers to version 3 of the GNU
|
|
||||||
General Public License.
|
|
||||||
|
|
||||||
"The Library" refers to a covered work governed by this License,
|
|
||||||
other than an Application or a Combined Work as defined below.
|
|
||||||
|
|
||||||
An "Application" is any work that makes use of an interface provided
|
|
||||||
by the Library, but which is not otherwise based on the Library.
|
|
||||||
Defining a subclass of a class defined by the Library is deemed a mode
|
|
||||||
of using an interface provided by the Library.
|
|
||||||
|
|
||||||
A "Combined Work" is a work produced by combining or linking an
|
|
||||||
Application with the Library. The particular version of the Library
|
|
||||||
with which the Combined Work was made is also called the "Linked
|
|
||||||
Version".
|
|
||||||
|
|
||||||
The "Minimal Corresponding Source" for a Combined Work means the
|
|
||||||
Corresponding Source for the Combined Work, excluding any source code
|
|
||||||
for portions of the Combined Work that, considered in isolation, are
|
|
||||||
based on the Application, and not on the Linked Version.
|
|
||||||
|
|
||||||
The "Corresponding Application Code" for a Combined Work means the
|
|
||||||
object code and/or source code for the Application, including any data
|
|
||||||
and utility programs needed for reproducing the Combined Work from the
|
|
||||||
Application, but excluding the System Libraries of the Combined Work.
|
|
||||||
|
|
||||||
1. Exception to Section 3 of the GNU GPL.
|
|
||||||
|
|
||||||
You may convey a covered work under sections 3 and 4 of this License
|
|
||||||
without being bound by section 3 of the GNU GPL.
|
|
||||||
|
|
||||||
2. Conveying Modified Versions.
|
|
||||||
|
|
||||||
If you modify a copy of the Library, and, in your modifications, a
|
|
||||||
facility refers to a function or data to be supplied by an Application
|
|
||||||
that uses the facility (other than as an argument passed when the
|
|
||||||
facility is invoked), then you may convey a copy of the modified
|
|
||||||
version:
|
|
||||||
|
|
||||||
a) under this License, provided that you make a good faith effort to
|
|
||||||
ensure that, in the event an Application does not supply the
|
|
||||||
function or data, the facility still operates, and performs
|
|
||||||
whatever part of its purpose remains meaningful, or
|
|
||||||
|
|
||||||
b) under the GNU GPL, with none of the additional permissions of
|
|
||||||
this License applicable to that copy.
|
|
||||||
|
|
||||||
3. Object Code Incorporating Material from Library Header Files.
|
|
||||||
|
|
||||||
The object code form of an Application may incorporate material from
|
|
||||||
a header file that is part of the Library. You may convey such object
|
|
||||||
code under terms of your choice, provided that, if the incorporated
|
|
||||||
material is not limited to numerical parameters, data structure
|
|
||||||
layouts and accessors, or small macros, inline functions and templates
|
|
||||||
(ten or fewer lines in length), you do both of the following:
|
|
||||||
|
|
||||||
a) Give prominent notice with each copy of the object code that the
|
|
||||||
Library is used in it and that the Library and its use are
|
|
||||||
covered by this License.
|
|
||||||
|
|
||||||
b) Accompany the object code with a copy of the GNU GPL and this license
|
|
||||||
document.
|
|
||||||
|
|
||||||
4. Combined Works.
|
|
||||||
|
|
||||||
You may convey a Combined Work under terms of your choice that,
|
|
||||||
taken together, effectively do not restrict modification of the
|
|
||||||
portions of the Library contained in the Combined Work and reverse
|
|
||||||
engineering for debugging such modifications, if you also do each of
|
|
||||||
the following:
|
|
||||||
|
|
||||||
a) Give prominent notice with each copy of the Combined Work that
|
|
||||||
the Library is used in it and that the Library and its use are
|
|
||||||
covered by this License.
|
|
||||||
|
|
||||||
b) Accompany the Combined Work with a copy of the GNU GPL and this license
|
|
||||||
document.
|
|
||||||
|
|
||||||
c) For a Combined Work that displays copyright notices during
|
|
||||||
execution, include the copyright notice for the Library among
|
|
||||||
these notices, as well as a reference directing the user to the
|
|
||||||
copies of the GNU GPL and this license document.
|
|
||||||
|
|
||||||
d) Do one of the following:
|
|
||||||
|
|
||||||
0) Convey the Minimal Corresponding Source under the terms of this
|
|
||||||
License, and the Corresponding Application Code in a form
|
|
||||||
suitable for, and under terms that permit, the user to
|
|
||||||
recombine or relink the Application with a modified version of
|
|
||||||
the Linked Version to produce a modified Combined Work, in the
|
|
||||||
manner specified by section 6 of the GNU GPL for conveying
|
|
||||||
Corresponding Source.
|
|
||||||
|
|
||||||
1) Use a suitable shared library mechanism for linking with the
|
|
||||||
Library. A suitable mechanism is one that (a) uses at run time
|
|
||||||
a copy of the Library already present on the user's computer
|
|
||||||
system, and (b) will operate properly with a modified version
|
|
||||||
of the Library that is interface-compatible with the Linked
|
|
||||||
Version.
|
|
||||||
|
|
||||||
e) Provide Installation Information, but only if you would otherwise
|
|
||||||
be required to provide such information under section 6 of the
|
|
||||||
GNU GPL, and only to the extent that such information is
|
|
||||||
necessary to install and execute a modified version of the
|
|
||||||
Combined Work produced by recombining or relinking the
|
|
||||||
Application with a modified version of the Linked Version. (If
|
|
||||||
you use option 4d0, the Installation Information must accompany
|
|
||||||
the Minimal Corresponding Source and Corresponding Application
|
|
||||||
Code. If you use option 4d1, you must provide the Installation
|
|
||||||
Information in the manner specified by section 6 of the GNU GPL
|
|
||||||
for conveying Corresponding Source.)
|
|
||||||
|
|
||||||
5. Combined Libraries.
|
|
||||||
|
|
||||||
You may place library facilities that are a work based on the
|
|
||||||
Library side by side in a single library together with other library
|
|
||||||
facilities that are not Applications and are not covered by this
|
|
||||||
License, and convey such a combined library under terms of your
|
|
||||||
choice, if you do both of the following:
|
|
||||||
|
|
||||||
a) Accompany the combined library with a copy of the same work based
|
|
||||||
on the Library, uncombined with any other library facilities,
|
|
||||||
conveyed under the terms of this License.
|
|
||||||
|
|
||||||
b) Give prominent notice with the combined library that part of it
|
|
||||||
is a work based on the Library, and explaining where to find the
|
|
||||||
accompanying uncombined form of the same work.
|
|
||||||
|
|
||||||
6. Revised Versions of the GNU Lesser General Public License.
|
|
||||||
|
|
||||||
The Free Software Foundation may publish revised and/or new versions
|
|
||||||
of the GNU Lesser General Public License from time to time. Such new
|
|
||||||
versions will be similar in spirit to the present version, but may
|
|
||||||
differ in detail to address new problems or concerns.
|
|
||||||
|
|
||||||
Each version is given a distinguishing version number. If the
|
|
||||||
Library as you received it specifies that a certain numbered version
|
|
||||||
of the GNU Lesser General Public License "or any later version"
|
|
||||||
applies to it, you have the option of following the terms and
|
|
||||||
conditions either of that published version or of any later version
|
|
||||||
published by the Free Software Foundation. If the Library as you
|
|
||||||
received it does not specify a version number of the GNU Lesser
|
|
||||||
General Public License, you may choose any version of the GNU Lesser
|
|
||||||
General Public License ever published by the Free Software Foundation.
|
|
||||||
|
|
||||||
If the Library as you received it specifies that a proxy can decide
|
|
||||||
whether future versions of the GNU Lesser General Public License shall
|
|
||||||
apply, that proxy's public statement of acceptance of any version is
|
|
||||||
permanent authorization for you to choose that version for the
|
|
||||||
Library.
|
|
||||||
|
|
@ -1,42 +0,0 @@
|
||||||
# Discord Types
|
|
||||||
|
|
||||||
This package provides TypeScript types for the Webpack modules of Discord's web app.
|
|
||||||
|
|
||||||
While it was primarily created for Vencord, other client mods could also benefit from this, so it is published as a standalone package!
|
|
||||||
|
|
||||||
## Installation
|
|
||||||
|
|
||||||
```bash
|
|
||||||
npm install -D @vencord/discord-types
|
|
||||||
yarn add -D @vencord/discord-types
|
|
||||||
pnpm add -D @vencord/discord-types
|
|
||||||
```
|
|
||||||
|
|
||||||
## Example Usage
|
|
||||||
|
|
||||||
```ts
|
|
||||||
import type { UserStore } from "@vencord/discord-types";
|
|
||||||
|
|
||||||
const userStore: UserStore = findStore("UserStore"); // findStore is up to you to implement, this library only provides types and no runtime code
|
|
||||||
```
|
|
||||||
|
|
||||||
## Enums
|
|
||||||
|
|
||||||
This library also exports some const enums that you can use from Typescript code:
|
|
||||||
```ts
|
|
||||||
import { ApplicationCommandType } from "@vencord/discord-types/enums";
|
|
||||||
|
|
||||||
console.log(ApplicationCommandType.CHAT_INPUT); // 1
|
|
||||||
```
|
|
||||||
|
|
||||||
### License
|
|
||||||
|
|
||||||
This package is licensed under the [LGPL-3.0](./LICENSE) (or later) license.
|
|
||||||
|
|
||||||
A very short summary of the license is that you can use this package as a library in both open source and closed source projects,
|
|
||||||
similar to an MIT-licensed project.
|
|
||||||
However, if you modify the code of this package, you must release source code of your modified version under the same license.
|
|
||||||
|
|
||||||
### Credit
|
|
||||||
|
|
||||||
This package was inspired by Swishilicous' [discord-types](https://www.npmjs.com/package/discord-types) package.
|
|
||||||
|
|
@ -1,30 +0,0 @@
|
||||||
export const enum ActivityType {
|
|
||||||
PLAYING = 0,
|
|
||||||
STREAMING = 1,
|
|
||||||
LISTENING = 2,
|
|
||||||
WATCHING = 3,
|
|
||||||
CUSTOM_STATUS = 4,
|
|
||||||
COMPETING = 5,
|
|
||||||
HANG_STATUS = 6
|
|
||||||
}
|
|
||||||
|
|
||||||
export const enum ActivityFlags {
|
|
||||||
INSTANCE = 1 << 0,
|
|
||||||
JOIN = 1 << 1,
|
|
||||||
/** @deprecated */
|
|
||||||
SPECTATE = 1 << 2,
|
|
||||||
/** @deprecated */
|
|
||||||
JOIN_REQUEST = 1 << 3,
|
|
||||||
SYNC = 1 << 4,
|
|
||||||
PLAY = 1 << 5,
|
|
||||||
PARTY_PRIVACY_FRIENDS = 1 << 6,
|
|
||||||
PARTY_PRIVACY_VOICE_CHANNEL = 1 << 7,
|
|
||||||
EMBEDDED = 1 << 8,
|
|
||||||
CONTEXTLESS = 1 << 9
|
|
||||||
}
|
|
||||||
|
|
||||||
export const enum ActivityStatusDisplayType {
|
|
||||||
NAME = 0,
|
|
||||||
STATE = 1,
|
|
||||||
DETAILS = 2
|
|
||||||
}
|
|
||||||
|
|
@ -1,15 +0,0 @@
|
||||||
export const enum ChannelType {
|
|
||||||
GUILD_TEXT = 0,
|
|
||||||
DM = 1,
|
|
||||||
GUILD_VOICE = 2,
|
|
||||||
GROUP_DM = 3,
|
|
||||||
GUILD_CATEGORY = 4,
|
|
||||||
GUILD_ANNOUNCEMENT = 5,
|
|
||||||
ANNOUNCEMENT_THREAD = 10,
|
|
||||||
PUBLIC_THREAD = 11,
|
|
||||||
PRIVATE_THREAD = 12,
|
|
||||||
GUILD_STAGE_VOICE = 13,
|
|
||||||
GUILD_DIRECTORY = 14,
|
|
||||||
GUILD_FORUM = 15,
|
|
||||||
GUILD_MEDIA = 16
|
|
||||||
}
|
|
||||||
|
|
@ -1,32 +0,0 @@
|
||||||
export const enum ApplicationCommandOptionType {
|
|
||||||
SUB_COMMAND = 1,
|
|
||||||
SUB_COMMAND_GROUP = 2,
|
|
||||||
STRING = 3,
|
|
||||||
INTEGER = 4,
|
|
||||||
BOOLEAN = 5,
|
|
||||||
USER = 6,
|
|
||||||
CHANNEL = 7,
|
|
||||||
ROLE = 8,
|
|
||||||
MENTIONABLE = 9,
|
|
||||||
NUMBER = 10,
|
|
||||||
ATTACHMENT = 11,
|
|
||||||
}
|
|
||||||
|
|
||||||
export const enum ApplicationCommandInputType {
|
|
||||||
BUILT_IN = 0,
|
|
||||||
BUILT_IN_TEXT = 1,
|
|
||||||
BUILT_IN_INTEGRATION = 2,
|
|
||||||
BOT = 3,
|
|
||||||
PLACEHOLDER = 4,
|
|
||||||
}
|
|
||||||
|
|
||||||
export const enum ApplicationCommandType {
|
|
||||||
CHAT_INPUT = 1,
|
|
||||||
USER = 2,
|
|
||||||
MESSAGE = 3,
|
|
||||||
}
|
|
||||||
|
|
||||||
export const enum ApplicationIntegrationType {
|
|
||||||
GUILD_INSTALL = 0,
|
|
||||||
USER_INSTALL = 1
|
|
||||||
}
|
|
||||||
|
|
@ -1,5 +0,0 @@
|
||||||
export * from "./activity";
|
|
||||||
export * from "./channel";
|
|
||||||
export * from "./commands";
|
|
||||||
export * from "./messages";
|
|
||||||
export * from "./misc";
|
|
||||||
|
|
@ -1,596 +0,0 @@
|
||||||
export const enum StickerType {
|
|
||||||
/** an official sticker in a pack */
|
|
||||||
STANDARD = 1,
|
|
||||||
/** a sticker uploaded to a guild for the guild's members */
|
|
||||||
GUILD = 2
|
|
||||||
}
|
|
||||||
|
|
||||||
export const enum StickerFormatType {
|
|
||||||
PNG = 1,
|
|
||||||
APNG = 2,
|
|
||||||
LOTTIE = 3,
|
|
||||||
GIF = 4
|
|
||||||
}
|
|
||||||
|
|
||||||
export const enum MessageType {
|
|
||||||
/**
|
|
||||||
* A default message (see below)
|
|
||||||
*
|
|
||||||
* Value: 0
|
|
||||||
* Name: DEFAULT
|
|
||||||
* Rendered Content: "{content}"
|
|
||||||
* Deletable: true
|
|
||||||
*/
|
|
||||||
DEFAULT = 0,
|
|
||||||
/**
|
|
||||||
* A message sent when a user is added to a group DM or thread
|
|
||||||
*
|
|
||||||
* Value: 1
|
|
||||||
* Name: RECIPIENT_ADD
|
|
||||||
* Rendered Content: "{author} added {mentions [0] } to the {group/thread}."
|
|
||||||
* Deletable: false
|
|
||||||
*/
|
|
||||||
RECIPIENT_ADD = 1,
|
|
||||||
/**
|
|
||||||
* A message sent when a user is removed from a group DM or thread
|
|
||||||
*
|
|
||||||
* Value: 2
|
|
||||||
* Name: RECIPIENT_REMOVE
|
|
||||||
* Rendered Content: "{author} removed {mentions [0] } from the {group/thread}."
|
|
||||||
* Deletable: false
|
|
||||||
*/
|
|
||||||
RECIPIENT_REMOVE = 2,
|
|
||||||
/**
|
|
||||||
* A message sent when a user creates a call in a private channel
|
|
||||||
*
|
|
||||||
* Value: 3
|
|
||||||
* Name: CALL
|
|
||||||
* Rendered Content: participated ? "{author} started a call{ended ? " that lasted {duration}" : " — Join the call"}." : "You missed a call from {author} that lasted {duration}."
|
|
||||||
* Deletable: false
|
|
||||||
*/
|
|
||||||
CALL = 3,
|
|
||||||
/**
|
|
||||||
* A message sent when a group DM or thread's name is changed
|
|
||||||
*
|
|
||||||
* Value: 4
|
|
||||||
* Name: CHANNEL_NAME_CHANGE
|
|
||||||
* Rendered Content: "{author} changed the {is_forum ? "post title" : "channel name"}: {content} "
|
|
||||||
* Deletable: false
|
|
||||||
*/
|
|
||||||
CHANNEL_NAME_CHANGE = 4,
|
|
||||||
/**
|
|
||||||
* A message sent when a group DM's icon is changed
|
|
||||||
*
|
|
||||||
* Value: 5
|
|
||||||
* Name: CHANNEL_ICON_CHANGE
|
|
||||||
* Rendered Content: "{author} changed the channel icon."
|
|
||||||
* Deletable: false
|
|
||||||
*/
|
|
||||||
CHANNEL_ICON_CHANGE = 5,
|
|
||||||
/**
|
|
||||||
* A message sent when a message is pinned in a channel
|
|
||||||
*
|
|
||||||
* Value: 6
|
|
||||||
* Name: CHANNEL_PINNED_MESSAGE
|
|
||||||
* Rendered Content: "{author} pinned a message to this channel."
|
|
||||||
* Deletable: true
|
|
||||||
*/
|
|
||||||
CHANNEL_PINNED_MESSAGE = 6,
|
|
||||||
/**
|
|
||||||
* A message sent when a user joins a guild
|
|
||||||
*
|
|
||||||
* Value: 7
|
|
||||||
* Name: USER_JOIN
|
|
||||||
* Rendered Content: See user join message type , obtained via the formula timestamp_ms % 13
|
|
||||||
* Deletable: true
|
|
||||||
*/
|
|
||||||
USER_JOIN = 7,
|
|
||||||
/**
|
|
||||||
* A message sent when a user subscribes to (boosts) a guild
|
|
||||||
*
|
|
||||||
* Value: 8
|
|
||||||
* Name: PREMIUM_GUILD_SUBSCRIPTION
|
|
||||||
* Rendered Content: "{author} just boosted the server{content ? " {content} times"}!"
|
|
||||||
* Deletable: true
|
|
||||||
*/
|
|
||||||
PREMIUM_GUILD_SUBSCRIPTION = 8,
|
|
||||||
/**
|
|
||||||
* A message sent when a user subscribes to (boosts) a guild to tier 1
|
|
||||||
*
|
|
||||||
* Value: 9
|
|
||||||
* Name: PREMIUM_GUILD_SUBSCRIPTION_TIER_1
|
|
||||||
* Rendered Content: "{author} just boosted the server{content ? " {content} times"}! {guild} has achieved Level 1! "
|
|
||||||
* Deletable: true
|
|
||||||
*/
|
|
||||||
PREMIUM_GUILD_SUBSCRIPTION_TIER_1 = 9,
|
|
||||||
/**
|
|
||||||
* A message sent when a user subscribes to (boosts) a guild to tier 2
|
|
||||||
*
|
|
||||||
* Value: 10
|
|
||||||
* Name: PREMIUM_GUILD_SUBSCRIPTION_TIER_2
|
|
||||||
* Rendered Content: "{author} just boosted the server{content ? " {content} times"}! {guild} has achieved Level 2! "
|
|
||||||
* Deletable: true
|
|
||||||
*/
|
|
||||||
PREMIUM_GUILD_SUBSCRIPTION_TIER_2 = 10,
|
|
||||||
/**
|
|
||||||
* A message sent when a user subscribes to (boosts) a guild to tier 3
|
|
||||||
*
|
|
||||||
* Value: 11
|
|
||||||
* Name: PREMIUM_GUILD_SUBSCRIPTION_TIER_3
|
|
||||||
* Rendered Content: "{author} just boosted the server{content ? " {content} times"}! {guild} has achieved Level 3! "
|
|
||||||
* Deletable: true
|
|
||||||
*/
|
|
||||||
PREMIUM_GUILD_SUBSCRIPTION_TIER_3 = 11,
|
|
||||||
/**
|
|
||||||
* A message sent when a news channel is followed
|
|
||||||
*
|
|
||||||
* Value: 12
|
|
||||||
* Name: CHANNEL_FOLLOW_ADD
|
|
||||||
* Rendered Content: "{author} has added {content} to this channel. Its most important updates will show up here."
|
|
||||||
* Deletable: true
|
|
||||||
*/
|
|
||||||
CHANNEL_FOLLOW_ADD = 12,
|
|
||||||
/**
|
|
||||||
* A message sent when a guild is disqualified from discovery
|
|
||||||
*
|
|
||||||
* Value: 14
|
|
||||||
* Name: GUILD_DISCOVERY_DISQUALIFIED
|
|
||||||
* Rendered Content: "This server has been removed from Server Discovery because it no longer passes all the requirements. Check Server Settings for more details."
|
|
||||||
* Deletable: true
|
|
||||||
*/
|
|
||||||
GUILD_DISCOVERY_DISQUALIFIED = 14,
|
|
||||||
/**
|
|
||||||
* A message sent when a guild requalifies for discovery
|
|
||||||
*
|
|
||||||
* Value: 15
|
|
||||||
* Name: GUILD_DISCOVERY_REQUALIFIED
|
|
||||||
* Rendered Content: "This server is eligible for Server Discovery again and has been automatically relisted!"
|
|
||||||
* Deletable: true
|
|
||||||
*/
|
|
||||||
GUILD_DISCOVERY_REQUALIFIED = 15,
|
|
||||||
/**
|
|
||||||
* A message sent when a guild has failed discovery requirements for a week
|
|
||||||
*
|
|
||||||
* Value: 16
|
|
||||||
* Name: GUILD_DISCOVERY_GRACE_PERIOD_INITIAL_WARNING
|
|
||||||
* Rendered Content: "This server has failed Discovery activity requirements for 1 week. If this server fails for 4 weeks in a row, it will be automatically removed from Discovery."
|
|
||||||
* Deletable: true
|
|
||||||
*/
|
|
||||||
GUILD_DISCOVERY_GRACE_PERIOD_INITIAL_WARNING = 16,
|
|
||||||
/**
|
|
||||||
* A message sent when a guild has failed discovery requirements for 3 weeks
|
|
||||||
*
|
|
||||||
* Value: 17
|
|
||||||
* Name: GUILD_DISCOVERY_GRACE_PERIOD_FINAL_WARNING
|
|
||||||
* Rendered Content: "This server has failed Discovery activity requirements for 3 weeks in a row. If this server fails for 1 more week, it will be removed from Discovery."
|
|
||||||
* Deletable: true
|
|
||||||
*/
|
|
||||||
GUILD_DISCOVERY_GRACE_PERIOD_FINAL_WARNING = 17,
|
|
||||||
/**
|
|
||||||
* A message sent when a thread is created
|
|
||||||
*
|
|
||||||
* Value: 18
|
|
||||||
* Name: THREAD_CREATED
|
|
||||||
* Rendered Content: "{author} started a thread: {content} . See all threads."
|
|
||||||
* Deletable: true
|
|
||||||
*/
|
|
||||||
THREAD_CREATED = 18,
|
|
||||||
/**
|
|
||||||
* A message sent when a user replies to a message
|
|
||||||
*
|
|
||||||
* Value: 19
|
|
||||||
* Name: REPLY
|
|
||||||
* Rendered Content: "{content}"
|
|
||||||
* Deletable: true
|
|
||||||
*/
|
|
||||||
REPLY = 19,
|
|
||||||
/**
|
|
||||||
* A message sent when a user uses a slash command
|
|
||||||
*
|
|
||||||
* Value: 20
|
|
||||||
* Name: CHAT_INPUT_COMMAND
|
|
||||||
* Rendered Content: "{content}"
|
|
||||||
* Deletable: true
|
|
||||||
*/
|
|
||||||
CHAT_INPUT_COMMAND = 20,
|
|
||||||
/**
|
|
||||||
* A message sent when a thread starter message is added to a thread
|
|
||||||
*
|
|
||||||
* Value: 21
|
|
||||||
* Name: THREAD_STARTER_MESSAGE
|
|
||||||
* Rendered Content: "{referenced_message?.content}" ?? "Sorry, we couldn't load the first message in this thread"
|
|
||||||
* Deletable: false
|
|
||||||
*/
|
|
||||||
THREAD_STARTER_MESSAGE = 21,
|
|
||||||
/**
|
|
||||||
* A message sent to remind users to invite friends to a guild
|
|
||||||
*
|
|
||||||
* Value: 22
|
|
||||||
* Name: GUILD_INVITE_REMINDER
|
|
||||||
* Rendered Content: "Wondering who to invite?\nStart by inviting anyone who can help you build the server!"
|
|
||||||
* Deletable: true
|
|
||||||
*/
|
|
||||||
GUILD_INVITE_REMINDER = 22,
|
|
||||||
/**
|
|
||||||
* A message sent when a user uses a context menu command
|
|
||||||
*
|
|
||||||
* Value: 23
|
|
||||||
* Name: CONTEXT_MENU_COMMAND
|
|
||||||
* Rendered Content: "{content}"
|
|
||||||
* Deletable: true
|
|
||||||
*/
|
|
||||||
CONTEXT_MENU_COMMAND = 23,
|
|
||||||
/**
|
|
||||||
* A message sent when auto moderation takes an action
|
|
||||||
*
|
|
||||||
* Value: 24
|
|
||||||
* Name: AUTO_MODERATION_ACTION
|
|
||||||
* Rendered Content: Special embed rendered from embeds[0]
|
|
||||||
* Deletable: true 1
|
|
||||||
*/
|
|
||||||
AUTO_MODERATION_ACTION = 24,
|
|
||||||
/**
|
|
||||||
* A message sent when a user purchases or renews a role subscription
|
|
||||||
*
|
|
||||||
* Value: 25
|
|
||||||
* Name: ROLE_SUBSCRIPTION_PURCHASE
|
|
||||||
* Rendered Content: "{author} {is_renewal ? "renewed" : "joined"} {role_subscription.tier_name} and has been a subscriber of {guild} for {role_subscription.total_months_subscribed} month(?s)!"
|
|
||||||
* Deletable: true
|
|
||||||
*/
|
|
||||||
ROLE_SUBSCRIPTION_PURCHASE = 25,
|
|
||||||
/**
|
|
||||||
* A message sent when a user is upsold to a premium interaction
|
|
||||||
*
|
|
||||||
* Value: 26
|
|
||||||
* Name: INTERACTION_PREMIUM_UPSELL
|
|
||||||
* Rendered Content: "{content}"
|
|
||||||
* Deletable: true
|
|
||||||
*/
|
|
||||||
INTERACTION_PREMIUM_UPSELL = 26,
|
|
||||||
/**
|
|
||||||
* A message sent when a stage channel starts
|
|
||||||
*
|
|
||||||
* Value: 27
|
|
||||||
* Name: STAGE_START
|
|
||||||
* Rendered Content: "{author} started {content} "
|
|
||||||
* Deletable: true
|
|
||||||
*/
|
|
||||||
STAGE_START = 27,
|
|
||||||
/**
|
|
||||||
* A message sent when a stage channel ends
|
|
||||||
*
|
|
||||||
* Value: 28
|
|
||||||
* Name: STAGE_END
|
|
||||||
* Rendered Content: "{author} ended {content} "
|
|
||||||
* Deletable: true
|
|
||||||
*/
|
|
||||||
STAGE_END = 28,
|
|
||||||
/**
|
|
||||||
* A message sent when a user starts speaking in a stage channel
|
|
||||||
*
|
|
||||||
* Value: 29
|
|
||||||
* Name: STAGE_SPEAKER
|
|
||||||
* Rendered Content: "{author} is now a speaker."
|
|
||||||
* Deletable: true
|
|
||||||
*/
|
|
||||||
STAGE_SPEAKER = 29,
|
|
||||||
/**
|
|
||||||
* A message sent when a user raises their hand in a stage channel
|
|
||||||
*
|
|
||||||
* Value: 30
|
|
||||||
* Name: STAGE_RAISE_HAND
|
|
||||||
* Rendered Content: "{author} requested to speak."
|
|
||||||
* Deletable: true
|
|
||||||
*/
|
|
||||||
STAGE_RAISE_HAND = 30,
|
|
||||||
/**
|
|
||||||
* A message sent when a stage channel's topic is changed
|
|
||||||
*
|
|
||||||
* Value: 31
|
|
||||||
* Name: STAGE_TOPIC
|
|
||||||
* Rendered Content: "{author} changed the Stage topic: {content} "
|
|
||||||
* Deletable: true
|
|
||||||
*/
|
|
||||||
STAGE_TOPIC = 31,
|
|
||||||
/**
|
|
||||||
* A message sent when a user purchases an application premium subscription
|
|
||||||
*
|
|
||||||
* Value: 32
|
|
||||||
* Name: GUILD_APPLICATION_PREMIUM_SUBSCRIPTION
|
|
||||||
* Rendered Content: "{author} upgraded {application ?? "a deleted application"} to premium for this server!"
|
|
||||||
* Deletable: true
|
|
||||||
*/
|
|
||||||
GUILD_APPLICATION_PREMIUM_SUBSCRIPTION = 32,
|
|
||||||
/**
|
|
||||||
* A message sent when a user gifts a premium (Nitro) referral
|
|
||||||
*
|
|
||||||
* Value: 35
|
|
||||||
* Name: PREMIUM_REFERRAL
|
|
||||||
* Rendered Content: "{content}"
|
|
||||||
* Deletable: true
|
|
||||||
*/
|
|
||||||
PREMIUM_REFERRAL = 35,
|
|
||||||
/**
|
|
||||||
* A message sent when a user enabled lockdown for the guild
|
|
||||||
*
|
|
||||||
* Value: 36
|
|
||||||
* Name: GUILD_INCIDENT_ALERT_MODE_ENABLED
|
|
||||||
* Rendered Content: "{author} enabled security actions until {content}."
|
|
||||||
* Deletable: true
|
|
||||||
*/
|
|
||||||
GUILD_INCIDENT_ALERT_MODE_ENABLED = 36,
|
|
||||||
/**
|
|
||||||
* A message sent when a user disables lockdown for the guild
|
|
||||||
*
|
|
||||||
* Value: 37
|
|
||||||
* Name: GUILD_INCIDENT_ALERT_MODE_DISABLED
|
|
||||||
* Rendered Content: "{author} disabled security actions."
|
|
||||||
* Deletable: true
|
|
||||||
*/
|
|
||||||
GUILD_INCIDENT_ALERT_MODE_DISABLED = 37,
|
|
||||||
/**
|
|
||||||
* A message sent when a user reports a raid for the guild
|
|
||||||
*
|
|
||||||
* Value: 38
|
|
||||||
* Name: GUILD_INCIDENT_REPORT_RAID
|
|
||||||
* Rendered Content: "{author} reported a raid in {guild}."
|
|
||||||
* Deletable: true
|
|
||||||
*/
|
|
||||||
GUILD_INCIDENT_REPORT_RAID = 38,
|
|
||||||
/**
|
|
||||||
* A message sent when a user reports a false alarm for the guild
|
|
||||||
*
|
|
||||||
* Value: 39
|
|
||||||
* Name: GUILD_INCIDENT_REPORT_FALSE_ALARM
|
|
||||||
* Rendered Content: "{author} reported a false alarm in {guild}."
|
|
||||||
* Deletable: true
|
|
||||||
*/
|
|
||||||
GUILD_INCIDENT_REPORT_FALSE_ALARM = 39,
|
|
||||||
/**
|
|
||||||
* A message sent when no one sends a message in the current channel for 1 hour
|
|
||||||
*
|
|
||||||
* Value: 40
|
|
||||||
* Name: GUILD_DEADCHAT_REVIVE_PROMPT
|
|
||||||
* Rendered Content: "{content}"
|
|
||||||
* Deletable: true
|
|
||||||
*/
|
|
||||||
GUILD_DEADCHAT_REVIVE_PROMPT = 40,
|
|
||||||
/**
|
|
||||||
* A message sent when a user buys another user a gift
|
|
||||||
*
|
|
||||||
* Value: 41
|
|
||||||
* Name: CUSTOM_GIFT
|
|
||||||
* Rendered Content: Special embed rendered from embeds[0].url and gift_info
|
|
||||||
* Deletable: true
|
|
||||||
*/
|
|
||||||
CUSTOM_GIFT = 41,
|
|
||||||
/**
|
|
||||||
* Value: 42
|
|
||||||
* Name: GUILD_GAMING_STATS_PROMPT
|
|
||||||
* Rendered Content: "{content}"
|
|
||||||
* Deletable: true
|
|
||||||
*/
|
|
||||||
GUILD_GAMING_STATS_PROMPT = 42,
|
|
||||||
/**
|
|
||||||
* A message sent when a user purchases a guild product
|
|
||||||
*
|
|
||||||
* Value: 44
|
|
||||||
* Name: PURCHASE_NOTIFICATION
|
|
||||||
* Rendered Content: "{author} has purchased {purchase_notification.guild_product_purchase.product_name}!"
|
|
||||||
* Deletable: true
|
|
||||||
*/
|
|
||||||
PURCHASE_NOTIFICATION = 44,
|
|
||||||
/**
|
|
||||||
* A message sent when a poll is finalized
|
|
||||||
*
|
|
||||||
* Value: 46
|
|
||||||
* Name: POLL_RESULT
|
|
||||||
* Rendered Content: Special embed rendered from embeds[0]
|
|
||||||
* Deletable: true
|
|
||||||
*/
|
|
||||||
POLL_RESULT = 46,
|
|
||||||
/**
|
|
||||||
* A message sent by the Discord Updates account when a new changelog is posted
|
|
||||||
*
|
|
||||||
* Value: 47
|
|
||||||
* Name: CHANGELOG
|
|
||||||
* Rendered Content: "{content}"
|
|
||||||
* Deletable: true
|
|
||||||
*/
|
|
||||||
CHANGELOG = 47,
|
|
||||||
/**
|
|
||||||
* A message sent when a Nitro promotion is triggered
|
|
||||||
*
|
|
||||||
* Value: 48
|
|
||||||
* Name: NITRO_NOTIFICATION
|
|
||||||
* Rendered Content: Special embed rendered from content
|
|
||||||
* Deletable: true
|
|
||||||
*/
|
|
||||||
NITRO_NOTIFICATION = 48,
|
|
||||||
/**
|
|
||||||
* A message sent when a voice channel is linked to a lobby
|
|
||||||
*
|
|
||||||
* Value: 49
|
|
||||||
* Name: CHANNEL_LINKED_TO_LOBBY
|
|
||||||
* Rendered Content: "{content}"
|
|
||||||
* Deletable: true
|
|
||||||
*/
|
|
||||||
CHANNEL_LINKED_TO_LOBBY = 49,
|
|
||||||
/**
|
|
||||||
* A local-only ephemeral message sent when a user is prompted to gift Nitro to a friend on their friendship anniversary
|
|
||||||
*
|
|
||||||
* Value: 50
|
|
||||||
* Name: GIFTING_PROMPT
|
|
||||||
* Rendered Content: Special embed
|
|
||||||
* Deletable: true
|
|
||||||
*/
|
|
||||||
GIFTING_PROMPT = 50,
|
|
||||||
/**
|
|
||||||
* A local-only message sent when a user receives an in-game message NUX
|
|
||||||
*
|
|
||||||
* Value: 51
|
|
||||||
* Name: IN_GAME_MESSAGE_NUX
|
|
||||||
* Rendered Content: "{author} messaged you from {application.name}. In-game chat may not include rich messaging features such as images, polls, or apps. Learn More "
|
|
||||||
* Deletable: true
|
|
||||||
*/
|
|
||||||
IN_GAME_MESSAGE_NUX = 51,
|
|
||||||
/**
|
|
||||||
* A message sent when a user accepts a guild join request
|
|
||||||
*
|
|
||||||
* Value: 52
|
|
||||||
* Name: GUILD_JOIN_REQUEST_ACCEPT_NOTIFICATION 2
|
|
||||||
* Rendered Content: "{join_request.user}'s application to {content} was approved! Welcome!"
|
|
||||||
* Deletable: true
|
|
||||||
*/
|
|
||||||
GUILD_JOIN_REQUEST_ACCEPT_NOTIFICATION = 52,
|
|
||||||
/**
|
|
||||||
* A message sent when a user rejects a guild join request
|
|
||||||
*
|
|
||||||
* Value: 53
|
|
||||||
* Name: GUILD_JOIN_REQUEST_REJECT_NOTIFICATION 2
|
|
||||||
* Rendered Content: "{join_request.user}'s application to {content} was rejected."
|
|
||||||
* Deletable: true
|
|
||||||
*/
|
|
||||||
GUILD_JOIN_REQUEST_REJECT_NOTIFICATION = 53,
|
|
||||||
/**
|
|
||||||
* A message sent when a user withdraws a guild join request
|
|
||||||
*
|
|
||||||
* Value: 54
|
|
||||||
* Name: GUILD_JOIN_REQUEST_WITHDRAWN_NOTIFICATION 2
|
|
||||||
* Rendered Content: "{join_request.user}'s application to {content} has been withdrawn."
|
|
||||||
* Deletable: true
|
|
||||||
*/
|
|
||||||
GUILD_JOIN_REQUEST_WITHDRAWN_NOTIFICATION = 54,
|
|
||||||
/**
|
|
||||||
* A message sent when a user upgrades to HD streaming
|
|
||||||
*
|
|
||||||
* Value: 55
|
|
||||||
* Name: HD_STREAMING_UPGRADED
|
|
||||||
* Rendered Content: "{author} activated HD Splash Potion "
|
|
||||||
* Deletable: true
|
|
||||||
*/
|
|
||||||
HD_STREAMING_UPGRADED = 55,
|
|
||||||
/**
|
|
||||||
* A message sent when a user resolves a moderation report by deleting the offending message
|
|
||||||
*
|
|
||||||
* Value: 58
|
|
||||||
* Name: REPORT_TO_MOD_DELETED_MESSAGE
|
|
||||||
* Rendered Content: "{author} deleted the message"
|
|
||||||
* Deletable: true
|
|
||||||
*/
|
|
||||||
REPORT_TO_MOD_DELETED_MESSAGE = 58,
|
|
||||||
/**
|
|
||||||
* A message sent when a user resolves a moderation report by timing out the offending user
|
|
||||||
*
|
|
||||||
* Value: 59
|
|
||||||
* Name: REPORT_TO_MOD_TIMEOUT_USER
|
|
||||||
* Rendered Content: "{author} timed out {mentions [0] }"
|
|
||||||
* Deletable: true
|
|
||||||
*/
|
|
||||||
REPORT_TO_MOD_TIMEOUT_USER = 59,
|
|
||||||
/**
|
|
||||||
* A message sent when a user resolves a moderation report by kicking the offending user
|
|
||||||
*
|
|
||||||
* Value: 60
|
|
||||||
* Name: REPORT_TO_MOD_KICK_USER
|
|
||||||
* Rendered Content: "{author} kicked {mentions [0] }"
|
|
||||||
* Deletable: true
|
|
||||||
*/
|
|
||||||
REPORT_TO_MOD_KICK_USER = 60,
|
|
||||||
/**
|
|
||||||
* A message sent when a user resolves a moderation report by banning the offending user
|
|
||||||
*
|
|
||||||
* Value: 61
|
|
||||||
* Name: REPORT_TO_MOD_BAN_USER
|
|
||||||
* Rendered Content: "{author} banned {mentions [0] }"
|
|
||||||
* Deletable: true
|
|
||||||
*/
|
|
||||||
REPORT_TO_MOD_BAN_USER = 61,
|
|
||||||
/**
|
|
||||||
* A message sent when a user resolves a moderation report
|
|
||||||
*
|
|
||||||
* Value: 62
|
|
||||||
* Name: REPORT_TO_MOD_CLOSED_REPORT
|
|
||||||
* Rendered Content: "{author} resolved this flag"
|
|
||||||
* Deletable: true
|
|
||||||
*/
|
|
||||||
REPORT_TO_MOD_CLOSED_REPORT = 62,
|
|
||||||
/**
|
|
||||||
* A message sent when a user adds a new emoji to a guild
|
|
||||||
*
|
|
||||||
* Value: 63
|
|
||||||
* Name: EMOJI_ADDED
|
|
||||||
* Rendered Content: "{author} added a new emoji, {content} :{emoji.name}: "
|
|
||||||
* Deletable: true
|
|
||||||
*/
|
|
||||||
EMOJI_ADDED = 63,
|
|
||||||
}
|
|
||||||
|
|
||||||
export const enum MessageFlags {
|
|
||||||
/**
|
|
||||||
* Message has been published to subscribed channels (via Channel Following)
|
|
||||||
*
|
|
||||||
* Value: 1 << 0
|
|
||||||
*/
|
|
||||||
CROSSPOSTED = 1 << 0,
|
|
||||||
/**
|
|
||||||
* Message originated from a message in another channel (via Channel Following)
|
|
||||||
*/
|
|
||||||
IS_CROSSPOST = 1 << 1,
|
|
||||||
/**
|
|
||||||
* Embeds will not be included when serializing this message
|
|
||||||
*/
|
|
||||||
SUPPRESS_EMBEDS = 1 << 2,
|
|
||||||
/**
|
|
||||||
* Source message for this crosspost has been deleted (via Channel Following)
|
|
||||||
*/
|
|
||||||
SOURCE_MESSAGE_DELETED = 1 << 3,
|
|
||||||
/**
|
|
||||||
* Message came from the urgent message system
|
|
||||||
*/
|
|
||||||
URGENT = 1 << 4,
|
|
||||||
/**
|
|
||||||
* Message has an associated thread, with the same ID as the message
|
|
||||||
*/
|
|
||||||
HAS_THREAD = 1 << 5,
|
|
||||||
/**
|
|
||||||
* Message is only visible to the user who invoked the interaction
|
|
||||||
*/
|
|
||||||
EPHEMERAL = 1 << 6,
|
|
||||||
/**
|
|
||||||
* Message is an interaction response and the bot is "thinking"
|
|
||||||
*/
|
|
||||||
LOADING = 1 << 7,
|
|
||||||
/**
|
|
||||||
* Some roles were not mentioned and added to the thread
|
|
||||||
*/
|
|
||||||
FAILED_TO_MENTION_SOME_ROLES_IN_THREAD = 1 << 8,
|
|
||||||
/**
|
|
||||||
* Message is hidden from the guild's feed
|
|
||||||
*/
|
|
||||||
GUILD_FEED_HIDDEN = 1 << 9,
|
|
||||||
/**
|
|
||||||
* Message contains a link that impersonates Discord
|
|
||||||
*/
|
|
||||||
SHOULD_SHOW_LINK_NOT_DISCORD_WARNING = 1 << 10,
|
|
||||||
/**
|
|
||||||
* Message will not trigger push and desktop notifications
|
|
||||||
*/
|
|
||||||
SUPPRESS_NOTIFICATIONS = 1 << 12,
|
|
||||||
/**
|
|
||||||
* Message's audio attachment is rendered as a voice message
|
|
||||||
*/
|
|
||||||
IS_VOICE_MESSAGE = 1 << 13,
|
|
||||||
/**
|
|
||||||
* Message has a forwarded message snapshot attached
|
|
||||||
*/
|
|
||||||
HAS_SNAPSHOT = 1 << 14,
|
|
||||||
/**
|
|
||||||
* Message contains components from version 2 of the UI kit
|
|
||||||
*/
|
|
||||||
IS_COMPONENTS_V2 = 1 << 15,
|
|
||||||
/**
|
|
||||||
* Message was triggered by the social layer integration
|
|
||||||
*/
|
|
||||||
SENT_BY_SOCIAL_LAYER_INTEGRATION = 1 << 16,
|
|
||||||
}
|
|
||||||
|
|
@ -1,4 +0,0 @@
|
||||||
export const enum CloudUploadPlatform {
|
|
||||||
REACT_NATIVE = 0,
|
|
||||||
WEB = 1,
|
|
||||||
}
|
|
||||||
|
|
@ -1,19 +0,0 @@
|
||||||
{
|
|
||||||
"name": "@vencord/discord-types",
|
|
||||||
"author": "Vencord Contributors",
|
|
||||||
"description": "Typescript definitions for the webpack modules of the Discord Web app",
|
|
||||||
"version": "1.0.0",
|
|
||||||
"license": "LGPL-3.0-or-later",
|
|
||||||
"types": "src/index.d.ts",
|
|
||||||
"type": "module",
|
|
||||||
"repository": {
|
|
||||||
"type": "git",
|
|
||||||
"url": "git+https://github.com/Vendicated/Vencord.git",
|
|
||||||
"directory": "packages/discord-types"
|
|
||||||
},
|
|
||||||
"dependencies": {
|
|
||||||
"@types/react": "^19.0.10",
|
|
||||||
"moment": "^2.22.2",
|
|
||||||
"type-fest": "^4.41.0"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
16
packages/discord-types/src/classes.d.ts
vendored
16
packages/discord-types/src/classes.d.ts
vendored
|
|
@ -1,16 +0,0 @@
|
||||||
export interface ButtonWrapperClasses {
|
|
||||||
hoverScale: string;
|
|
||||||
buttonWrapper: string;
|
|
||||||
button: string;
|
|
||||||
iconMask: string;
|
|
||||||
buttonContent: string;
|
|
||||||
icon: string;
|
|
||||||
pulseIcon: string;
|
|
||||||
pulseButton: string;
|
|
||||||
notificationDot: string;
|
|
||||||
sparkleContainer: string;
|
|
||||||
sparkleStar: string;
|
|
||||||
sparklePlus: string;
|
|
||||||
sparkle: string;
|
|
||||||
active: string;
|
|
||||||
}
|
|
||||||
36
packages/discord-types/src/common/Activity.d.ts
vendored
36
packages/discord-types/src/common/Activity.d.ts
vendored
|
|
@ -1,36 +0,0 @@
|
||||||
import { ActivityFlags, ActivityStatusDisplayType, ActivityType } from "../../enums";
|
|
||||||
|
|
||||||
export interface ActivityAssets {
|
|
||||||
large_image?: string;
|
|
||||||
large_text?: string;
|
|
||||||
small_image?: string;
|
|
||||||
small_text?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ActivityButton {
|
|
||||||
label: string;
|
|
||||||
url: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface Activity {
|
|
||||||
name: string;
|
|
||||||
application_id: string;
|
|
||||||
type: ActivityType;
|
|
||||||
state?: string;
|
|
||||||
state_url?: string;
|
|
||||||
details?: string;
|
|
||||||
details_url?: string;
|
|
||||||
url?: string;
|
|
||||||
flags: ActivityFlags;
|
|
||||||
status_display_type?: ActivityStatusDisplayType;
|
|
||||||
timestamps?: {
|
|
||||||
start?: number;
|
|
||||||
end?: number;
|
|
||||||
};
|
|
||||||
assets?: ActivityAssets;
|
|
||||||
buttons?: string[];
|
|
||||||
metadata?: {
|
|
||||||
button_urls?: Array<string>;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
@ -1,23 +0,0 @@
|
||||||
import { User } from "./User";
|
|
||||||
|
|
||||||
export interface Application {
|
|
||||||
id: string;
|
|
||||||
name: string;
|
|
||||||
description?: string | null;
|
|
||||||
type: number | null;
|
|
||||||
icon: string | null | undefined;
|
|
||||||
is_discoverable: boolean;
|
|
||||||
is_monetized: boolean;
|
|
||||||
is_verified: boolean;
|
|
||||||
bot?: User;
|
|
||||||
deeplink_uri?: string;
|
|
||||||
flags?: number;
|
|
||||||
privacy_policy_url?: string;
|
|
||||||
terms_of_service_url?: string;
|
|
||||||
install_params?: ApplicationInstallParams;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ApplicationInstallParams {
|
|
||||||
permissions: string | null;
|
|
||||||
scopes: string[];
|
|
||||||
}
|
|
||||||
83
packages/discord-types/src/common/Channel.d.ts
vendored
83
packages/discord-types/src/common/Channel.d.ts
vendored
|
|
@ -1,83 +0,0 @@
|
||||||
import { DiscordRecord } from "./Record";
|
|
||||||
|
|
||||||
export class Channel extends DiscordRecord {
|
|
||||||
constructor(channel: object);
|
|
||||||
application_id: number | undefined;
|
|
||||||
bitrate: number;
|
|
||||||
defaultAutoArchiveDuration: number | undefined;
|
|
||||||
flags: number;
|
|
||||||
guild_id: string;
|
|
||||||
icon: string;
|
|
||||||
id: string;
|
|
||||||
lastMessageId: string;
|
|
||||||
lastPinTimestamp: string | undefined;
|
|
||||||
member: unknown;
|
|
||||||
memberCount: number | undefined;
|
|
||||||
memberIdsPreview: string[] | undefined;
|
|
||||||
memberListId: unknown;
|
|
||||||
messageCount: number | undefined;
|
|
||||||
name: string;
|
|
||||||
nicks: Record<string, unknown>;
|
|
||||||
nsfw: boolean;
|
|
||||||
originChannelId: unknown;
|
|
||||||
ownerId: string;
|
|
||||||
parent_id: string;
|
|
||||||
permissionOverwrites: {
|
|
||||||
[role: string]: {
|
|
||||||
id: string;
|
|
||||||
type: number;
|
|
||||||
deny: bigint;
|
|
||||||
allow: bigint;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
position: number;
|
|
||||||
rateLimitPerUser: number;
|
|
||||||
rawRecipients: {
|
|
||||||
id: string;
|
|
||||||
avatar: string;
|
|
||||||
username: string;
|
|
||||||
public_flags: number;
|
|
||||||
discriminator: string;
|
|
||||||
}[];
|
|
||||||
recipients: string[];
|
|
||||||
rtcRegion: string;
|
|
||||||
threadMetadata: {
|
|
||||||
locked: boolean;
|
|
||||||
archived: boolean;
|
|
||||||
invitable: boolean;
|
|
||||||
createTimestamp: string | undefined;
|
|
||||||
autoArchiveDuration: number;
|
|
||||||
archiveTimestamp: string | undefined;
|
|
||||||
};
|
|
||||||
topic: string;
|
|
||||||
type: number;
|
|
||||||
userLimit: number;
|
|
||||||
videoQualityMode: undefined;
|
|
||||||
|
|
||||||
get accessPermissions(): bigint;
|
|
||||||
get lastActiveTimestamp(): number;
|
|
||||||
|
|
||||||
computeLurkerPermissionsAllowList(): unknown;
|
|
||||||
getApplicationId(): unknown;
|
|
||||||
getGuildId(): string;
|
|
||||||
getRecipientId(): unknown;
|
|
||||||
hasFlag(flag: number): boolean;
|
|
||||||
isActiveThread(): boolean;
|
|
||||||
isArchivedThread(): boolean;
|
|
||||||
isCategory(): boolean;
|
|
||||||
isDM(): boolean;
|
|
||||||
isDirectory(): boolean;
|
|
||||||
isForumChannel(): boolean;
|
|
||||||
isGroupDM(): boolean;
|
|
||||||
isGuildStageVoice(): boolean;
|
|
||||||
isGuildVoice(): boolean;
|
|
||||||
isListenModeCapable(): boolean;
|
|
||||||
isManaged(): boolean;
|
|
||||||
isMultiUserDM(): boolean;
|
|
||||||
isNSFW(): boolean;
|
|
||||||
isOwner(): boolean;
|
|
||||||
isPrivate(): boolean;
|
|
||||||
isSystemDM(): boolean;
|
|
||||||
isThread(): boolean;
|
|
||||||
isVocal(): boolean;
|
|
||||||
}
|
|
||||||
64
packages/discord-types/src/common/Guild.d.ts
vendored
64
packages/discord-types/src/common/Guild.d.ts
vendored
|
|
@ -1,64 +0,0 @@
|
||||||
import { Role } from './Role';
|
|
||||||
import { DiscordRecord } from './Record';
|
|
||||||
|
|
||||||
// copy(Object.keys(findByProps("CREATOR_MONETIZABLE")).map(JSON.stringify).join("|"))
|
|
||||||
export type GuildFeatures =
|
|
||||||
"INVITE_SPLASH" | "VIP_REGIONS" | "VANITY_URL" | "MORE_EMOJI" | "MORE_STICKERS" | "MORE_SOUNDBOARD" | "VERIFIED" | "COMMERCE" | "DISCOVERABLE" | "COMMUNITY" | "FEATURABLE" | "NEWS" | "HUB" | "PARTNERED" | "ANIMATED_ICON" | "BANNER" | "ENABLED_DISCOVERABLE_BEFORE" | "WELCOME_SCREEN_ENABLED" | "MEMBER_VERIFICATION_GATE_ENABLED" | "PREVIEW_ENABLED" | "ROLE_SUBSCRIPTIONS_ENABLED" | "ROLE_SUBSCRIPTIONS_AVAILABLE_FOR_PURCHASE" | "CREATOR_MONETIZABLE" | "CREATOR_MONETIZABLE_PROVISIONAL" | "CREATOR_MONETIZABLE_WHITEGLOVE" | "CREATOR_MONETIZABLE_DISABLED" | "CREATOR_MONETIZABLE_RESTRICTED" | "CREATOR_STORE_PAGE" | "CREATOR_MONETIZABLE_PENDING_NEW_OWNER_ONBOARDING" | "PRODUCTS_AVAILABLE_FOR_PURCHASE" | "GUILD_WEB_PAGE_VANITY_URL" | "THREADS_ENABLED" | "THREADS_ENABLED_TESTING" | "NEW_THREAD_PERMISSIONS" | "ROLE_ICONS" | "TEXT_IN_STAGE_ENABLED" | "TEXT_IN_VOICE_ENABLED" | "HAS_DIRECTORY_ENTRY" | "ANIMATED_BANNER" | "LINKED_TO_HUB" | "EXPOSED_TO_ACTIVITIES_WTP_EXPERIMENT" | "GUILD_HOME_DEPRECATION_OVERRIDE" | "GUILD_HOME_TEST" | "GUILD_HOME_OVERRIDE" | "GUILD_ONBOARDING" | "GUILD_ONBOARDING_EVER_ENABLED" | "GUILD_ONBOARDING_HAS_PROMPTS" | "GUILD_SERVER_GUIDE" | "INTERNAL_EMPLOYEE_ONLY" | "AUTO_MODERATION" | "INVITES_DISABLED" | "BURST_REACTIONS" | "SOUNDBOARD" | "SHARD" | "ACTIVITY_FEED_ENABLED_BY_USER" | "ACTIVITY_FEED_DISABLED_BY_USER" | "SUMMARIES_ENABLED_GA" | "LEADERBOARD_ENABLED" | "SUMMARIES_ENABLED_BY_USER" | "SUMMARIES_OPT_OUT_EXPERIENCE" | "CHANNEL_ICON_EMOJIS_GENERATED" | "NON_COMMUNITY_RAID_ALERTS" | "RAID_ALERTS_DISABLED" | "AUTOMOD_TRIGGER_USER_PROFILE" | "ENABLED_MODERATION_EXPERIENCE_FOR_NON_COMMUNITY" | "GUILD_PRODUCTS_ALLOW_ARCHIVED_FILE" | "CLAN" | "MEMBER_VERIFICATION_MANUAL_APPROVAL" | "FORWARDING_DISABLED" | "MEMBER_VERIFICATION_ROLLOUT_TEST" | "AUDIO_BITRATE_128_KBPS" | "AUDIO_BITRATE_256_KBPS" | "AUDIO_BITRATE_384_KBPS" | "VIDEO_BITRATE_ENHANCED" | "MAX_FILE_SIZE_50_MB" | "MAX_FILE_SIZE_100_MB" | "GUILD_TAGS" | "ENHANCED_ROLE_COLORS" | "PREMIUM_TIER_3_OVERRIDE" | "REPORT_TO_MOD_PILOT" | "TIERLESS_BOOSTING_SYSTEM_MESSAGE";
|
|
||||||
export type GuildPremiumFeatures =
|
|
||||||
"ANIMATED_ICON" | "STAGE_CHANNEL_VIEWERS_150" | "ROLE_ICONS" | "GUILD_TAGS" | "BANNER" | "MAX_FILE_SIZE_50_MB" | "VIDEO_QUALITY_720_60FPS" | "STAGE_CHANNEL_VIEWERS_50" | "VIDEO_QUALITY_1080_60FPS" | "MAX_FILE_SIZE_100_MB" | "VANITY_URL" | "VIDEO_BITRATE_ENHANCED" | "STAGE_CHANNEL_VIEWERS_300" | "AUDIO_BITRATE_128_KBPS" | "ANIMATED_BANNER" | "TIERLESS_BOOSTING" | "ENHANCED_ROLE_COLORS" | "INVITE_SPLASH" | "AUDIO_BITRATE_256_KBPS" | "AUDIO_BITRATE_384_KBPS";
|
|
||||||
|
|
||||||
export class Guild extends DiscordRecord {
|
|
||||||
constructor(guild: object);
|
|
||||||
afkChannelId: string | undefined;
|
|
||||||
afkTimeout: number;
|
|
||||||
applicationCommandCounts: {
|
|
||||||
0: number;
|
|
||||||
1: number;
|
|
||||||
2: number;
|
|
||||||
};
|
|
||||||
application_id: unknown;
|
|
||||||
banner: string | undefined;
|
|
||||||
defaultMessageNotifications: number;
|
|
||||||
description: string | undefined;
|
|
||||||
discoverySplash: string | undefined;
|
|
||||||
explicitContentFilter: number;
|
|
||||||
features: Set<GuildFeatures>;
|
|
||||||
homeHeader: string | undefined;
|
|
||||||
hubType: unknown;
|
|
||||||
icon: string | undefined;
|
|
||||||
id: string;
|
|
||||||
joinedAt: Date;
|
|
||||||
latestOnboardingQuestionId: string | undefined;
|
|
||||||
maxMembers: number;
|
|
||||||
maxStageVideoChannelUsers: number;
|
|
||||||
maxVideoChannelUsers: number;
|
|
||||||
mfaLevel: number;
|
|
||||||
moderatorReporting: unknown;
|
|
||||||
name: string;
|
|
||||||
nsfwLevel: number;
|
|
||||||
ownerConfiguredContentLevel: number;
|
|
||||||
ownerId: string;
|
|
||||||
preferredLocale: string;
|
|
||||||
premiumFeatures: {
|
|
||||||
additionalEmojiSlots: number;
|
|
||||||
additionalSoundSlots: number;
|
|
||||||
additionalStickerSlots: number;
|
|
||||||
features: Array<GuildPremiumFeatures>;
|
|
||||||
};
|
|
||||||
premiumProgressBarEnabled: boolean;
|
|
||||||
premiumSubscriberCount: number;
|
|
||||||
premiumTier: number;
|
|
||||||
profile: {
|
|
||||||
badge: string | undefined;
|
|
||||||
tag: string | undefined;
|
|
||||||
} | undefined;
|
|
||||||
publicUpdatesChannelId: string | undefined;
|
|
||||||
roles: Record<string, Role>;
|
|
||||||
rulesChannelId: string | undefined;
|
|
||||||
safetyAlertsChannelId: string | undefined;
|
|
||||||
splash: string | undefined;
|
|
||||||
systemChannelFlags: number;
|
|
||||||
systemChannelId: string | undefined;
|
|
||||||
vanityURLCode: string | undefined;
|
|
||||||
verificationLevel: number;
|
|
||||||
}
|
|
||||||
|
|
@ -1,26 +0,0 @@
|
||||||
export interface GuildMember {
|
|
||||||
avatar: string | undefined;
|
|
||||||
avatarDecoration: string | undefined;
|
|
||||||
banner: string | undefined;
|
|
||||||
bio: string;
|
|
||||||
colorRoleId: string | undefined;
|
|
||||||
colorString: string;
|
|
||||||
colorStrings: {
|
|
||||||
primaryColor: string | undefined;
|
|
||||||
secondaryColor: string | undefined;
|
|
||||||
tertiaryColor: string | undefined;
|
|
||||||
};
|
|
||||||
communicationDisabledUntil: string | undefined;
|
|
||||||
flags: number;
|
|
||||||
fullProfileLoadedTimestamp: number;
|
|
||||||
guildId: string;
|
|
||||||
highestRoleId: string;
|
|
||||||
hoistRoleId: string;
|
|
||||||
iconRoleId: string;
|
|
||||||
isPending: boolean | undefined;
|
|
||||||
joinedAt: string | undefined;
|
|
||||||
nick: string | undefined;
|
|
||||||
premiumSince: string | undefined;
|
|
||||||
roles: string[];
|
|
||||||
userId: string;
|
|
||||||
}
|
|
||||||
12
packages/discord-types/src/common/Record.d.ts
vendored
12
packages/discord-types/src/common/Record.d.ts
vendored
|
|
@ -1,12 +0,0 @@
|
||||||
type Updater = (value: any) => any;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Common Record class extended by various Discord data structures, like User, Channel, Guild, etc.
|
|
||||||
*/
|
|
||||||
export class DiscordRecord {
|
|
||||||
toJS(): Record<string, any>;
|
|
||||||
|
|
||||||
set(key: string, value: any): this;
|
|
||||||
merge(data: Record<string, any>): this;
|
|
||||||
update(key: string, defaultValueOrUpdater: Updater | any, updater?: Updater): this;
|
|
||||||
}
|
|
||||||
33
packages/discord-types/src/common/Role.d.ts
vendored
33
packages/discord-types/src/common/Role.d.ts
vendored
|
|
@ -1,33 +0,0 @@
|
||||||
export interface Role {
|
|
||||||
color: number;
|
|
||||||
colorString: string | undefined;
|
|
||||||
colorStrings: {
|
|
||||||
primaryColor: string | undefined;
|
|
||||||
secondaryColor: string | undefined;
|
|
||||||
tertiaryColor: string | undefined;
|
|
||||||
};
|
|
||||||
colors: {
|
|
||||||
primary_color: number | undefined;
|
|
||||||
secondary_color: number | undefined;
|
|
||||||
tertiary_color: number | undefined;
|
|
||||||
};
|
|
||||||
flags: number;
|
|
||||||
hoist: boolean;
|
|
||||||
icon: string | undefined;
|
|
||||||
id: string;
|
|
||||||
managed: boolean;
|
|
||||||
mentionable: boolean;
|
|
||||||
name: string;
|
|
||||||
originalPosition: number;
|
|
||||||
permissions: bigint;
|
|
||||||
position: number;
|
|
||||||
/**
|
|
||||||
* probably incomplete
|
|
||||||
*/
|
|
||||||
tags: {
|
|
||||||
bot_id: string;
|
|
||||||
integration_id: string;
|
|
||||||
premium_subscriber: unknown;
|
|
||||||
} | undefined;
|
|
||||||
unicodeEmoji: string | undefined;
|
|
||||||
}
|
|
||||||
65
packages/discord-types/src/common/User.d.ts
vendored
65
packages/discord-types/src/common/User.d.ts
vendored
|
|
@ -1,65 +0,0 @@
|
||||||
// TODO: a lot of optional params can also be null, not just undef
|
|
||||||
|
|
||||||
import { DiscordRecord } from "./Record";
|
|
||||||
|
|
||||||
export class User extends DiscordRecord {
|
|
||||||
constructor(user: object);
|
|
||||||
accentColor: number;
|
|
||||||
avatar: string;
|
|
||||||
banner: string | null | undefined;
|
|
||||||
bio: string;
|
|
||||||
bot: boolean;
|
|
||||||
desktop: boolean;
|
|
||||||
discriminator: string;
|
|
||||||
email: string | undefined;
|
|
||||||
flags: number;
|
|
||||||
globalName: string | undefined;
|
|
||||||
guildMemberAvatars: Record<string, string>;
|
|
||||||
id: string;
|
|
||||||
mfaEnabled: boolean;
|
|
||||||
mobile: boolean;
|
|
||||||
nsfwAllowed: boolean | undefined;
|
|
||||||
phone: string | undefined;
|
|
||||||
premiumType: number | undefined;
|
|
||||||
premiumUsageFlags: number;
|
|
||||||
publicFlags: number;
|
|
||||||
purchasedFlags: number;
|
|
||||||
system: boolean;
|
|
||||||
username: string;
|
|
||||||
verified: boolean;
|
|
||||||
|
|
||||||
get createdAt(): Date;
|
|
||||||
get hasPremiumPerks(): boolean;
|
|
||||||
get tag(): string;
|
|
||||||
get usernameNormalized(): string;
|
|
||||||
|
|
||||||
addGuildAvatarHash(guildId: string, avatarHash: string): User;
|
|
||||||
getAvatarSource(guildId: string, canAnimate?: boolean): { uri: string; };
|
|
||||||
getAvatarURL(guildId?: string | null, t?: unknown, canAnimate?: boolean): string;
|
|
||||||
hasAvatarForGuild(guildId: string): boolean;
|
|
||||||
hasDisabledPremium(): boolean;
|
|
||||||
hasFlag(flag: number): boolean;
|
|
||||||
hasFreePremium(): boolean;
|
|
||||||
hasHadSKU(e: unknown): boolean;
|
|
||||||
hasPremiumUsageFlag(flag: number): boolean;
|
|
||||||
hasPurchasedFlag(flag: number): boolean;
|
|
||||||
hasUrgentMessages(): boolean;
|
|
||||||
isClaimed(): boolean;
|
|
||||||
isLocalBot(): boolean;
|
|
||||||
isNonUserBot(): boolean;
|
|
||||||
isPhoneVerified(): boolean;
|
|
||||||
isStaff(): boolean;
|
|
||||||
isSystemUser(): boolean;
|
|
||||||
isVerifiedBot(): boolean;
|
|
||||||
removeGuildAvatarHash(guildId: string): User;
|
|
||||||
toString(): string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface UserJSON {
|
|
||||||
avatar: string;
|
|
||||||
avatarDecoration: unknown | undefined;
|
|
||||||
discriminator: string;
|
|
||||||
id: string;
|
|
||||||
publicFlags: number;
|
|
||||||
username: string;
|
|
||||||
}
|
|
||||||
9
packages/discord-types/src/common/index.d.ts
vendored
9
packages/discord-types/src/common/index.d.ts
vendored
|
|
@ -1,9 +0,0 @@
|
||||||
export * from "./Activity";
|
|
||||||
export * from "./Application";
|
|
||||||
export * from "./Channel";
|
|
||||||
export * from "./Guild";
|
|
||||||
export * from "./GuildMember";
|
|
||||||
export * from "./messages";
|
|
||||||
export * from "./Role";
|
|
||||||
export * from "./User";
|
|
||||||
export * from "./Record";
|
|
||||||
|
|
@ -1,61 +0,0 @@
|
||||||
import { Channel } from "../Channel";
|
|
||||||
import { Guild } from "../Guild";
|
|
||||||
import { Promisable } from "type-fest";
|
|
||||||
import { ApplicationCommandInputType, ApplicationCommandOptionType, ApplicationCommandType } from "../../../enums";
|
|
||||||
|
|
||||||
export interface CommandContext {
|
|
||||||
channel: Channel;
|
|
||||||
guild?: Guild;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface CommandOption {
|
|
||||||
name: string;
|
|
||||||
displayName?: string;
|
|
||||||
type: ApplicationCommandOptionType;
|
|
||||||
description: string;
|
|
||||||
displayDescription?: string;
|
|
||||||
required?: boolean;
|
|
||||||
options?: CommandOption[];
|
|
||||||
choices?: Array<ChoicesOption>;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ChoicesOption {
|
|
||||||
label: string;
|
|
||||||
value: string;
|
|
||||||
name: string;
|
|
||||||
displayName?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface CommandReturnValue {
|
|
||||||
content: string;
|
|
||||||
// TODO: implement
|
|
||||||
// cancel?: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface CommandArgument {
|
|
||||||
type: ApplicationCommandOptionType;
|
|
||||||
name: string;
|
|
||||||
value: string;
|
|
||||||
focused: undefined;
|
|
||||||
options: CommandArgument[];
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface Command {
|
|
||||||
id?: string;
|
|
||||||
applicationId?: string;
|
|
||||||
type?: ApplicationCommandType;
|
|
||||||
inputType?: ApplicationCommandInputType;
|
|
||||||
plugin?: string;
|
|
||||||
|
|
||||||
name: string;
|
|
||||||
untranslatedName?: string;
|
|
||||||
displayName?: string;
|
|
||||||
description: string;
|
|
||||||
untranslatedDescription?: string;
|
|
||||||
displayDescription?: string;
|
|
||||||
|
|
||||||
options?: CommandOption[];
|
|
||||||
predicate?(ctx: CommandContext): boolean;
|
|
||||||
|
|
||||||
execute(args: CommandArgument[], ctx: CommandContext): Promisable<void | CommandReturnValue>;
|
|
||||||
}
|
|
||||||
|
|
@ -1,70 +0,0 @@
|
||||||
export interface Embed {
|
|
||||||
author?: {
|
|
||||||
name: string;
|
|
||||||
url: string;
|
|
||||||
iconURL: string | undefined;
|
|
||||||
iconProxyURL: string | undefined;
|
|
||||||
};
|
|
||||||
color: string;
|
|
||||||
fields: [];
|
|
||||||
id: string;
|
|
||||||
image?: {
|
|
||||||
height: number;
|
|
||||||
width: number;
|
|
||||||
url: string;
|
|
||||||
proxyURL: string;
|
|
||||||
};
|
|
||||||
provider?: {
|
|
||||||
name: string;
|
|
||||||
url: string | undefined;
|
|
||||||
};
|
|
||||||
rawDescription: string;
|
|
||||||
rawTitle: string;
|
|
||||||
referenceId: unknown;
|
|
||||||
timestamp: string;
|
|
||||||
thumbnail?: {
|
|
||||||
height: number;
|
|
||||||
proxyURL: string | undefined;
|
|
||||||
url: string;
|
|
||||||
width: number;
|
|
||||||
};
|
|
||||||
type: string;
|
|
||||||
url: string | undefined;
|
|
||||||
video?: {
|
|
||||||
height: number;
|
|
||||||
width: number;
|
|
||||||
url: string;
|
|
||||||
proxyURL: string | undefined;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface EmbedJSON {
|
|
||||||
author?: {
|
|
||||||
name: string;
|
|
||||||
url: string;
|
|
||||||
icon_url: string;
|
|
||||||
proxy_icon_url: string;
|
|
||||||
};
|
|
||||||
title: string;
|
|
||||||
color: string;
|
|
||||||
description: string;
|
|
||||||
type: string;
|
|
||||||
url: string | undefined;
|
|
||||||
provider?: {
|
|
||||||
name: string;
|
|
||||||
url: string;
|
|
||||||
};
|
|
||||||
timestamp: string;
|
|
||||||
thumbnail?: {
|
|
||||||
height: number;
|
|
||||||
width: number;
|
|
||||||
url: string;
|
|
||||||
proxy_url: string | undefined;
|
|
||||||
};
|
|
||||||
video?: {
|
|
||||||
height: number;
|
|
||||||
width: number;
|
|
||||||
url: string;
|
|
||||||
proxy_url: string | undefined;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
@ -1,42 +0,0 @@
|
||||||
export type Emoji = CustomEmoji | UnicodeEmoji;
|
|
||||||
|
|
||||||
export interface CustomEmoji {
|
|
||||||
type: 1;
|
|
||||||
allNamesString: string;
|
|
||||||
animated: boolean;
|
|
||||||
available: boolean;
|
|
||||||
guildId: string;
|
|
||||||
id: string;
|
|
||||||
managed: boolean;
|
|
||||||
name: string;
|
|
||||||
originalName?: string;
|
|
||||||
require_colons: boolean;
|
|
||||||
roles: string[];
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface UnicodeEmoji {
|
|
||||||
type: 0;
|
|
||||||
diversityChildren: Record<any, any>;
|
|
||||||
emojiObject: {
|
|
||||||
names: string[];
|
|
||||||
surrogates: string;
|
|
||||||
unicodeVersion: number;
|
|
||||||
};
|
|
||||||
index: number;
|
|
||||||
surrogates: string;
|
|
||||||
uniqueName: string;
|
|
||||||
useSpriteSheet: boolean;
|
|
||||||
get allNamesString(): string;
|
|
||||||
get animated(): boolean;
|
|
||||||
get defaultDiversityChild(): any;
|
|
||||||
get hasDiversity(): boolean | undefined;
|
|
||||||
get hasDiversityParent(): boolean | undefined;
|
|
||||||
get hasMultiDiversity(): boolean | undefined;
|
|
||||||
get hasMultiDiversityParent(): boolean | undefined;
|
|
||||||
get managed(): boolean;
|
|
||||||
get name(): string;
|
|
||||||
get names(): string[];
|
|
||||||
get optionallyDiverseSequence(): string | undefined;
|
|
||||||
get unicodeVersion(): number;
|
|
||||||
get url(): string;
|
|
||||||
}
|
|
||||||
|
|
@ -1,204 +0,0 @@
|
||||||
import { CommandOption } from './Commands';
|
|
||||||
import { User, UserJSON } from '../User';
|
|
||||||
import { Embed, EmbedJSON } from './Embed';
|
|
||||||
import { DiscordRecord } from "../Record";
|
|
||||||
import { MessageFlags, MessageType, StickerFormatType } from "../../../enums";
|
|
||||||
|
|
||||||
/*
|
|
||||||
* TODO: looks like discord has moved over to Date instead of Moment;
|
|
||||||
*/
|
|
||||||
export class Message extends DiscordRecord {
|
|
||||||
constructor(message: object);
|
|
||||||
activity: unknown;
|
|
||||||
application: unknown;
|
|
||||||
applicationId: string | unknown;
|
|
||||||
attachments: MessageAttachment[];
|
|
||||||
author: User;
|
|
||||||
blocked: boolean;
|
|
||||||
bot: boolean;
|
|
||||||
call: {
|
|
||||||
duration: moment.Duration;
|
|
||||||
endedTimestamp: moment.Moment;
|
|
||||||
participants: string[];
|
|
||||||
};
|
|
||||||
channel_id: string;
|
|
||||||
/**
|
|
||||||
* NOTE: not fully typed
|
|
||||||
*/
|
|
||||||
codedLinks: {
|
|
||||||
code?: string;
|
|
||||||
type: string;
|
|
||||||
}[];
|
|
||||||
colorString: unknown;
|
|
||||||
components: unknown[];
|
|
||||||
content: string;
|
|
||||||
customRenderedContent: unknown;
|
|
||||||
editedTimestamp: Date;
|
|
||||||
embeds: Embed[];
|
|
||||||
flags: MessageFlags;
|
|
||||||
giftCodes: string[];
|
|
||||||
id: string;
|
|
||||||
interaction: {
|
|
||||||
id: string;
|
|
||||||
name: string;
|
|
||||||
type: number;
|
|
||||||
user: User;
|
|
||||||
}[] | undefined;
|
|
||||||
interactionData: {
|
|
||||||
application_command: {
|
|
||||||
application_id: string;
|
|
||||||
default_member_permissions: unknown;
|
|
||||||
default_permission: boolean;
|
|
||||||
description: string;
|
|
||||||
dm_permission: unknown;
|
|
||||||
id: string;
|
|
||||||
name: string;
|
|
||||||
options: CommandOption[];
|
|
||||||
permissions: unknown[];
|
|
||||||
type: number;
|
|
||||||
version: string;
|
|
||||||
};
|
|
||||||
attachments: MessageAttachment[];
|
|
||||||
guild_id: string | undefined;
|
|
||||||
id: string;
|
|
||||||
name: string;
|
|
||||||
options: {
|
|
||||||
focused: unknown;
|
|
||||||
name: string;
|
|
||||||
type: number;
|
|
||||||
value: string;
|
|
||||||
}[];
|
|
||||||
type: number;
|
|
||||||
version: string;
|
|
||||||
}[];
|
|
||||||
interactionError: unknown[];
|
|
||||||
isSearchHit: boolean;
|
|
||||||
loggingName: unknown;
|
|
||||||
mentionChannels: string[];
|
|
||||||
mentionEveryone: boolean;
|
|
||||||
mentionRoles: string[];
|
|
||||||
mentioned: boolean;
|
|
||||||
mentions: string[];
|
|
||||||
messageReference: {
|
|
||||||
guild_id?: string;
|
|
||||||
channel_id: string;
|
|
||||||
message_id: string;
|
|
||||||
} | undefined;
|
|
||||||
messageSnapshots: {
|
|
||||||
message: Message;
|
|
||||||
}[];
|
|
||||||
nick: unknown; // probably a string
|
|
||||||
nonce: string | undefined;
|
|
||||||
pinned: boolean;
|
|
||||||
reactions: MessageReaction[];
|
|
||||||
state: string;
|
|
||||||
stickerItems: {
|
|
||||||
format_type: StickerFormatType;
|
|
||||||
id: string;
|
|
||||||
name: string;
|
|
||||||
}[];
|
|
||||||
stickers: unknown[];
|
|
||||||
timestamp: moment.Moment;
|
|
||||||
tts: boolean;
|
|
||||||
type: MessageType;
|
|
||||||
webhookId: string | undefined;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Doesn't actually update the original message; it just returns a new message instance with the added reaction.
|
|
||||||
*/
|
|
||||||
addReaction(emoji: ReactionEmoji, fromCurrentUser: boolean): Message;
|
|
||||||
/**
|
|
||||||
* Searches each reaction and if the provided string has an index above -1 it'll return the reaction object.
|
|
||||||
*/
|
|
||||||
getReaction(name: string): MessageReaction;
|
|
||||||
/**
|
|
||||||
* Doesn't actually update the original message; it just returns the message instance without the reaction searched with the provided emoji object.
|
|
||||||
*/
|
|
||||||
removeReactionsForEmoji(emoji: ReactionEmoji): Message;
|
|
||||||
/**
|
|
||||||
* Doesn't actually update the original message; it just returns the message instance without the reaction.
|
|
||||||
*/
|
|
||||||
removeReaction(emoji: ReactionEmoji, fromCurrentUser: boolean): Message;
|
|
||||||
|
|
||||||
getChannelId(): string;
|
|
||||||
hasFlag(flag: MessageFlags): boolean;
|
|
||||||
isCommandType(): boolean;
|
|
||||||
isEdited(): boolean;
|
|
||||||
isSystemDM(): boolean;
|
|
||||||
|
|
||||||
/** Vencord added */
|
|
||||||
deleted?: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** A smaller Message object found in FluxDispatcher and elsewhere. */
|
|
||||||
export interface MessageJSON {
|
|
||||||
attachments: MessageAttachment[];
|
|
||||||
author: UserJSON;
|
|
||||||
channel_id: string;
|
|
||||||
components: unknown[];
|
|
||||||
content: string;
|
|
||||||
edited_timestamp: string;
|
|
||||||
embeds: EmbedJSON[];
|
|
||||||
flags: number;
|
|
||||||
guild_id: string | undefined;
|
|
||||||
id: string;
|
|
||||||
loggingName: unknown;
|
|
||||||
member: {
|
|
||||||
avatar: string | undefined;
|
|
||||||
communication_disabled_until: string | undefined;
|
|
||||||
deaf: boolean;
|
|
||||||
hoisted_role: string | undefined;
|
|
||||||
is_pending: boolean;
|
|
||||||
joined_at: string;
|
|
||||||
mute: boolean;
|
|
||||||
nick: string | boolean;
|
|
||||||
pending: boolean;
|
|
||||||
premium_since: string | undefined;
|
|
||||||
roles: string[];
|
|
||||||
} | undefined;
|
|
||||||
mention_everyone: boolean;
|
|
||||||
mention_roles: string[];
|
|
||||||
mentions: UserJSON[];
|
|
||||||
message_reference: {
|
|
||||||
guild_id?: string;
|
|
||||||
channel_id: string;
|
|
||||||
message_id: string;
|
|
||||||
} | undefined;
|
|
||||||
nonce: string | undefined;
|
|
||||||
pinned: boolean;
|
|
||||||
referenced_message: MessageJSON | undefined;
|
|
||||||
state: string;
|
|
||||||
timestamp: string;
|
|
||||||
tts: boolean;
|
|
||||||
type: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface MessageAttachment {
|
|
||||||
filename: string;
|
|
||||||
id: string;
|
|
||||||
proxy_url: string;
|
|
||||||
size: number;
|
|
||||||
spoiler: boolean;
|
|
||||||
url: string;
|
|
||||||
content_type?: string;
|
|
||||||
width?: number;
|
|
||||||
height?: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ReactionEmoji {
|
|
||||||
id: string | undefined;
|
|
||||||
name: string;
|
|
||||||
animated: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface MessageReaction {
|
|
||||||
count: number;
|
|
||||||
emoji: ReactionEmoji;
|
|
||||||
me: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Object.keys(findByProps("REPLYABLE")).map(JSON.stringify).join("|")
|
|
||||||
export type MessageTypeSets = Record<
|
|
||||||
"UNDELETABLE" | "GUILD_DISCOVERY_STATUS" | "USER_MESSAGE" | "NOTIFIABLE_SYSTEM_MESSAGE" | "REPLYABLE" | "FORWARDABLE" | "REFERENCED_MESSAGE_AVAILABLE" | "AVAILABLE_IN_GUILD_FEED" | "DEADCHAT_PROMPTS" | "NON_COLLAPSIBLE" | "NON_PARSED" | "AUTOMOD_INCIDENT_ACTIONS" | "SELF_MENTIONABLE_SYSTEM" | "SCHEDULABLE",
|
|
||||||
Set<MessageType>
|
|
||||||
>;
|
|
||||||
|
|
@ -1,35 +0,0 @@
|
||||||
import { StickerFormatType, StickerType } from "../../../enums";
|
|
||||||
|
|
||||||
interface BaseSticker {
|
|
||||||
asset: string;
|
|
||||||
available: boolean;
|
|
||||||
description: string;
|
|
||||||
format_type: StickerFormatType;
|
|
||||||
id: string;
|
|
||||||
name: string;
|
|
||||||
sort_value?: number;
|
|
||||||
/** a comma separated string */
|
|
||||||
tags: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface PackSticker extends BaseSticker {
|
|
||||||
pack_id: string;
|
|
||||||
type: StickerType.STANDARD;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface GuildSticker extends BaseSticker {
|
|
||||||
guild_id: string;
|
|
||||||
type: StickerType.GUILD;
|
|
||||||
}
|
|
||||||
|
|
||||||
export type Sticker = PackSticker | GuildSticker;
|
|
||||||
|
|
||||||
export interface PremiumStickerPack {
|
|
||||||
banner_asset_id?: string;
|
|
||||||
cover_sticker_id?: string;
|
|
||||||
description: string;
|
|
||||||
id: string;
|
|
||||||
name: string;
|
|
||||||
sku_id: string;
|
|
||||||
stickers: PackSticker[];
|
|
||||||
}
|
|
||||||
|
|
@ -1,5 +0,0 @@
|
||||||
export * from "./Commands";
|
|
||||||
export * from "./Message";
|
|
||||||
export * from "./Embed";
|
|
||||||
export * from "./Emoji";
|
|
||||||
export * from "./Sticker";
|
|
||||||
30
packages/discord-types/src/flux.d.ts
vendored
30
packages/discord-types/src/flux.d.ts
vendored
|
|
@ -1,30 +0,0 @@
|
||||||
import { FluxStore } from "./stores/FluxStore";
|
|
||||||
|
|
||||||
export class FluxEmitter {
|
|
||||||
constructor();
|
|
||||||
|
|
||||||
changeSentinel: number;
|
|
||||||
changedStores: Set<FluxStore>;
|
|
||||||
isBatchEmitting: boolean;
|
|
||||||
isDispatching: boolean;
|
|
||||||
isPaused: boolean;
|
|
||||||
pauseTimer: NodeJS.Timeout | null;
|
|
||||||
reactChangedStores: Set<FluxStore>;
|
|
||||||
|
|
||||||
batched(batch: (...args: any[]) => void): void;
|
|
||||||
destroy(): void;
|
|
||||||
emit(): void;
|
|
||||||
emitNonReactOnce(): void;
|
|
||||||
emitReactOnce(): void;
|
|
||||||
getChangeSentinel(): number;
|
|
||||||
getIsPaused(): boolean;
|
|
||||||
injectBatchEmitChanges(batch: (...args: any[]) => void): void;
|
|
||||||
markChanged(store: FluxStore): void;
|
|
||||||
pause(): void;
|
|
||||||
resume(): void;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface Flux {
|
|
||||||
Store: typeof FluxStore;
|
|
||||||
Emitter: FluxEmitter;
|
|
||||||
}
|
|
||||||
22
packages/discord-types/src/fluxEvents.d.ts
vendored
22
packages/discord-types/src/fluxEvents.d.ts
vendored
File diff suppressed because one or more lines are too long
10
packages/discord-types/src/index.d.ts
vendored
10
packages/discord-types/src/index.d.ts
vendored
|
|
@ -1,10 +0,0 @@
|
||||||
export * from "./common";
|
|
||||||
export * from "./classes";
|
|
||||||
export * from "./components";
|
|
||||||
export * from "./flux";
|
|
||||||
export * from "./fluxEvents";
|
|
||||||
export * from "./menu";
|
|
||||||
export * from "./modules";
|
|
||||||
export * from "./stores";
|
|
||||||
export * from "./utils";
|
|
||||||
export * as Webpack from "../webpack";
|
|
||||||
|
|
@ -1,74 +0,0 @@
|
||||||
import EventEmitter from "events";
|
|
||||||
import { CloudUploadPlatform } from "../../enums";
|
|
||||||
|
|
||||||
interface BaseUploadItem {
|
|
||||||
platform: CloudUploadPlatform;
|
|
||||||
id?: string;
|
|
||||||
origin?: string;
|
|
||||||
isThumbnail?: boolean;
|
|
||||||
clip?: unknown;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ReactNativeUploadItem extends BaseUploadItem {
|
|
||||||
platform: CloudUploadPlatform.REACT_NATIVE;
|
|
||||||
uri: string;
|
|
||||||
filename?: string;
|
|
||||||
mimeType?: string;
|
|
||||||
durationSecs?: number;
|
|
||||||
waveform?: string;
|
|
||||||
isRemix?: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface WebUploadItem extends BaseUploadItem {
|
|
||||||
platform: CloudUploadPlatform.WEB;
|
|
||||||
file: File;
|
|
||||||
}
|
|
||||||
|
|
||||||
export type CloudUploadItem = ReactNativeUploadItem | WebUploadItem;
|
|
||||||
|
|
||||||
export class CloudUpload extends EventEmitter {
|
|
||||||
constructor(item: CloudUploadItem, channelId: string, showLargeMessageDialog?: boolean, reactNativeFileIndex?: number);
|
|
||||||
|
|
||||||
channelId: string;
|
|
||||||
classification: string;
|
|
||||||
clip: unknown;
|
|
||||||
contentHash: unknown;
|
|
||||||
currentSize: number;
|
|
||||||
description: string | null;
|
|
||||||
durationSecs: number | undefined;
|
|
||||||
etag: string | undefined;
|
|
||||||
error: unknown;
|
|
||||||
filename: string;
|
|
||||||
id: string;
|
|
||||||
isImage: boolean;
|
|
||||||
isRemix: boolean | undefined;
|
|
||||||
isThumbnail: boolean;
|
|
||||||
isVideo: boolean;
|
|
||||||
item: {
|
|
||||||
file: File;
|
|
||||||
platform: CloudUploadPlatform;
|
|
||||||
origin: string;
|
|
||||||
};
|
|
||||||
loaded: number;
|
|
||||||
mimeType: string;
|
|
||||||
origin: string;
|
|
||||||
postCompressionSize: number | undefined;
|
|
||||||
preCompressionSize: number;
|
|
||||||
responseUrl: string;
|
|
||||||
sensitive: boolean;
|
|
||||||
showLargeMessageDialog: boolean;
|
|
||||||
spoiler: boolean;
|
|
||||||
startTime: number;
|
|
||||||
status: "NOT_STARTED" | "STARTED" | "UPLOADING" | "ERROR" | "COMPLETED" | "CANCELLED" | "REMOVED_FROM_MSG_DRAFT";
|
|
||||||
uniqueId: string;
|
|
||||||
uploadedFilename: string;
|
|
||||||
waveform: string | undefined;
|
|
||||||
|
|
||||||
// there are many more methods than just these but I didn't find them particularly useful
|
|
||||||
upload(): Promise<void>;
|
|
||||||
cancel(): void;
|
|
||||||
delete(): Promise<void>;
|
|
||||||
getSize(): number;
|
|
||||||
maybeConvertToWebP(): Promise<void>;
|
|
||||||
removeFromMsgDraft(): void;
|
|
||||||
}
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
export * from "./CloudUpload";
|
|
||||||
|
|
@ -1,11 +0,0 @@
|
||||||
import { FluxStore } from "..";
|
|
||||||
|
|
||||||
export class AuthenticationStore extends FluxStore {
|
|
||||||
/**
|
|
||||||
* Gets the id of the current user
|
|
||||||
*/
|
|
||||||
getId(): string;
|
|
||||||
|
|
||||||
// This Store has a lot more methods related to everything Auth, but they really should
|
|
||||||
// not be needed, so they are not typed
|
|
||||||
}
|
|
||||||
|
|
@ -1,24 +0,0 @@
|
||||||
import { Channel, FluxStore } from "..";
|
|
||||||
|
|
||||||
export class ChannelStore extends FluxStore {
|
|
||||||
getChannel(channelId: string): Channel;
|
|
||||||
getBasicChannel(channelId: string): Channel | undefined;
|
|
||||||
hasChannel(channelId: string): boolean;
|
|
||||||
|
|
||||||
getChannelIds(guildId?: string | null): string[];
|
|
||||||
getMutableBasicGuildChannelsForGuild(guildId: string): Record<string, Channel>;
|
|
||||||
getMutableGuildChannelsForGuild(guildId: string): Record<string, Channel>;
|
|
||||||
getAllThreadsForGuild(guildId: string): Channel[];
|
|
||||||
getAllThreadsForParent(channelId: string): Channel[];
|
|
||||||
|
|
||||||
getDMFromUserId(userId: string): string;
|
|
||||||
getDMChannelFromUserId(userId: string): Channel | undefined;
|
|
||||||
getDMUserIds(): string[];
|
|
||||||
getMutableDMsByUserIds(): Record<string, string>;
|
|
||||||
getMutablePrivateChannels(): Record<string, Channel>;
|
|
||||||
getSortedPrivateChannels(): Channel[];
|
|
||||||
|
|
||||||
getGuildChannelsVersion(guildId: string): number;
|
|
||||||
getPrivateChannelsVersion(): number;
|
|
||||||
getInitialOverlayState(): Record<string, Channel>;
|
|
||||||
}
|
|
||||||
|
|
@ -1,43 +0,0 @@
|
||||||
import { FluxStore } from "..";
|
|
||||||
|
|
||||||
export enum DraftType {
|
|
||||||
ChannelMessage = 0,
|
|
||||||
ThreadSettings = 1,
|
|
||||||
FirstThreadMessage = 2,
|
|
||||||
ApplicationLauncherCommand = 3,
|
|
||||||
Poll = 4,
|
|
||||||
SlashCommand = 5,
|
|
||||||
ForwardContextMessage = 6
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface Draft {
|
|
||||||
timestamp: number;
|
|
||||||
draft: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ThreadSettingsDraft {
|
|
||||||
timestamp: number;
|
|
||||||
parentMessageId?: string;
|
|
||||||
name?: string;
|
|
||||||
isPrivate?: boolean;
|
|
||||||
parentChannelId?: string;
|
|
||||||
location?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export type ChannelDrafts = {
|
|
||||||
[DraftType.ThreadSettings]: ThreadSettingsDraft;
|
|
||||||
} & {
|
|
||||||
[key in Exclude<DraftType, DraftType.ThreadSettings>]: Draft;
|
|
||||||
};
|
|
||||||
|
|
||||||
export type UserDrafts = Partial<Record<string, ChannelDrafts>>;
|
|
||||||
export type DraftState = Partial<Record<string, UserDrafts>>;
|
|
||||||
|
|
||||||
export class DraftStore extends FluxStore {
|
|
||||||
getState(): DraftState;
|
|
||||||
getRecentlyEditedDrafts(type: DraftType): Array<Draft & { channelId: string; }>;
|
|
||||||
getDraft(channelId: string, type: DraftType): string;
|
|
||||||
|
|
||||||
getThreadSettings(channelId: string): ThreadSettingsDraft | null | undefined;
|
|
||||||
getThreadDraftWithParentMessageId(parentMessageId: string): ThreadSettingsDraft | null | undefined;
|
|
||||||
}
|
|
||||||
|
|
@ -1,57 +0,0 @@
|
||||||
import { Channel, CustomEmoji, Emoji, FluxStore } from "..";
|
|
||||||
|
|
||||||
export class EmojiStore extends FluxStore {
|
|
||||||
getCustomEmojiById(id?: string | null): CustomEmoji | undefined;
|
|
||||||
getUsableCustomEmojiById(id?: string | null): CustomEmoji | undefined;
|
|
||||||
getGuilds(): Record<string, {
|
|
||||||
id: string;
|
|
||||||
get emojis(): CustomEmoji[];
|
|
||||||
get rawEmojis(): CustomEmoji[];
|
|
||||||
get usableEmojis(): CustomEmoji[];
|
|
||||||
get emoticons(): any[];
|
|
||||||
getEmoji(id: string): CustomEmoji | undefined;
|
|
||||||
isUsable(emoji: CustomEmoji): boolean;
|
|
||||||
}>;
|
|
||||||
getGuildEmoji(guildId?: string | null): CustomEmoji[];
|
|
||||||
getNewlyAddedEmoji(guildId?: string | null): CustomEmoji[];
|
|
||||||
getTopEmoji(guildId?: string | null): CustomEmoji[];
|
|
||||||
getTopEmojisMetadata(guildId?: string | null): {
|
|
||||||
emojiIds: string[];
|
|
||||||
topEmojisTTL: number;
|
|
||||||
};
|
|
||||||
hasPendingUsage(): boolean;
|
|
||||||
hasUsableEmojiInAnyGuild(): boolean;
|
|
||||||
searchWithoutFetchingLatest(data: any): any;
|
|
||||||
getSearchResultsOrder(...args: any[]): any;
|
|
||||||
getState(): {
|
|
||||||
pendingUsages: { key: string, timestamp: number; }[];
|
|
||||||
};
|
|
||||||
searchWithoutFetchingLatest(data: {
|
|
||||||
channel: Channel;
|
|
||||||
query: string;
|
|
||||||
count?: number;
|
|
||||||
intention: number;
|
|
||||||
includeExternalGuilds?: boolean;
|
|
||||||
matchComparator?(name: string): boolean;
|
|
||||||
}): Record<"locked" | "unlocked", Emoji[]>;
|
|
||||||
|
|
||||||
getDisambiguatedEmojiContext(): {
|
|
||||||
backfillTopEmojis: Record<any, any>;
|
|
||||||
customEmojis: Record<string, CustomEmoji>;
|
|
||||||
emojisById: Record<string, CustomEmoji>;
|
|
||||||
emojisByName: Record<string, CustomEmoji>;
|
|
||||||
emoticonRegex: RegExp | null;
|
|
||||||
emoticonsByName: Record<string, any>;
|
|
||||||
escapedEmoticonNames: string;
|
|
||||||
favoriteNamesAndIds?: any;
|
|
||||||
favorites?: any;
|
|
||||||
frequentlyUsed?: any;
|
|
||||||
groupedCustomEmojis: Record<string, CustomEmoji[]>;
|
|
||||||
guildId?: string;
|
|
||||||
isFavoriteEmojiWithoutFetchingLatest(e: Emoji): boolean;
|
|
||||||
newlyAddedEmoji: Record<string, CustomEmoji[]>;
|
|
||||||
topEmojis?: any;
|
|
||||||
unicodeAliases: Record<string, string>;
|
|
||||||
get favoriteEmojisWithoutFetchingLatest(): Emoji[];
|
|
||||||
};
|
|
||||||
}
|
|
||||||
44
packages/discord-types/src/stores/FluxStore.d.ts
vendored
44
packages/discord-types/src/stores/FluxStore.d.ts
vendored
|
|
@ -1,44 +0,0 @@
|
||||||
import { FluxDispatcher, FluxEvents } from "..";
|
|
||||||
|
|
||||||
type Callback = () => void;
|
|
||||||
|
|
||||||
/*
|
|
||||||
For some reason, this causes type errors when you try to destructure it:
|
|
||||||
```ts
|
|
||||||
interface FluxEvent {
|
|
||||||
type: FluxEvents;
|
|
||||||
[key: string]: any;
|
|
||||||
}
|
|
||||||
```
|
|
||||||
*/
|
|
||||||
export type FluxEvent = any;
|
|
||||||
|
|
||||||
export type ActionHandler = (event: FluxEvent) => void;
|
|
||||||
export type ActionHandlers = Partial<Record<FluxEvents, ActionHandler>>;
|
|
||||||
|
|
||||||
export class FluxStore {
|
|
||||||
constructor(dispatcher: FluxDispatcher, actionHandlers?: ActionHandlers);
|
|
||||||
|
|
||||||
getName(): string;
|
|
||||||
|
|
||||||
addChangeListener(callback: Callback): void;
|
|
||||||
/** Listener will be removed once the callback returns false. */
|
|
||||||
addConditionalChangeListener(callback: () => boolean, preemptive?: boolean): void;
|
|
||||||
addReactChangeListener(callback: Callback): void;
|
|
||||||
removeChangeListener(callback: Callback): void;
|
|
||||||
removeReactChangeListener(callback: Callback): void;
|
|
||||||
|
|
||||||
doEmitChanges(event: FluxEvent): void;
|
|
||||||
emitChange(): void;
|
|
||||||
|
|
||||||
getDispatchToken(): string;
|
|
||||||
initialize(): void;
|
|
||||||
initializeIfNeeded(): void;
|
|
||||||
/** this is a setter */
|
|
||||||
mustEmitChanges(actionHandler: ActionHandler | undefined): void;
|
|
||||||
registerActionHandlers(actionHandlers: ActionHandlers): void;
|
|
||||||
syncWith(stores: FluxStore[], callback: Callback, timeout?: number): void;
|
|
||||||
waitFor(...stores: FluxStore[]): void;
|
|
||||||
|
|
||||||
static getAll(): FluxStore[];
|
|
||||||
}
|
|
||||||
|
|
@ -1,27 +0,0 @@
|
||||||
import { FluxStore, GuildMember } from "..";
|
|
||||||
|
|
||||||
export class GuildMemberStore extends FluxStore {
|
|
||||||
/** @returns Format: [guildId-userId: Timestamp (string)] */
|
|
||||||
getCommunicationDisabledUserMap(): Record<string, string>;
|
|
||||||
getCommunicationDisabledVersion(): number;
|
|
||||||
|
|
||||||
getMutableAllGuildsAndMembers(): Record<string, Record<string, GuildMember>>;
|
|
||||||
|
|
||||||
getMember(guildId: string, userId: string): GuildMember | null;
|
|
||||||
getTrueMember(guildId: string, userId: string): GuildMember | null;
|
|
||||||
getMemberIds(guildId: string): string[];
|
|
||||||
getMembers(guildId: string): GuildMember[];
|
|
||||||
|
|
||||||
getCachedSelfMember(guildId: string): GuildMember | null;
|
|
||||||
getSelfMember(guildId: string): GuildMember | null;
|
|
||||||
getSelfMemberJoinedAt(guildId: string): Date | null;
|
|
||||||
|
|
||||||
getNick(guildId: string, userId: string): string | null;
|
|
||||||
getNicknameGuildsMapping(userId: string): Record<string, string[]>;
|
|
||||||
getNicknames(userId: string): string[];
|
|
||||||
|
|
||||||
isMember(guildId: string, userId: string): boolean;
|
|
||||||
isMember(guildId: string, userId: string): boolean;
|
|
||||||
isGuestOrLurker(guildId: string, userId: string): boolean;
|
|
||||||
isCurrentUserGuest(guildId: string): boolean;
|
|
||||||
}
|
|
||||||
|
|
@ -1,8 +0,0 @@
|
||||||
import { FluxStore, Role } from "..";
|
|
||||||
|
|
||||||
// TODO: add the rest of the methods for GuildRoleStore
|
|
||||||
export class GuildRoleStore extends FluxStore {
|
|
||||||
getRole(guildId: string, roleId: string): Role;
|
|
||||||
getSortedRoles(guildId: string): Role[];
|
|
||||||
getRolesSnapshot(guildId: string): Record<string, Role>;
|
|
||||||
}
|
|
||||||
|
|
@ -1,8 +0,0 @@
|
||||||
import { Guild, FluxStore } from "..";
|
|
||||||
|
|
||||||
export class GuildStore extends FluxStore {
|
|
||||||
getGuild(guildId: string): Guild;
|
|
||||||
getGuildCount(): number;
|
|
||||||
getGuilds(): Record<string, Guild>;
|
|
||||||
getGuildIds(): string[];
|
|
||||||
}
|
|
||||||
|
|
@ -1,13 +0,0 @@
|
||||||
import { MessageJSON, FluxStore, Message } from "..";
|
|
||||||
|
|
||||||
export class MessageStore extends FluxStore {
|
|
||||||
getMessage(channelId: string, messageId: string): Message;
|
|
||||||
/** @returns This return object is fucking huge; I'll type it later. */
|
|
||||||
getMessages(channelId: string): unknown;
|
|
||||||
getRawMessages(channelId: string): Record<string | number, MessageJSON>;
|
|
||||||
hasCurrentUserSentMessage(channelId: string): boolean;
|
|
||||||
hasPresent(channelId: string): boolean;
|
|
||||||
isLoadingMessages(channelId: string): boolean;
|
|
||||||
jumpedMessageId(channelId: string): string | undefined;
|
|
||||||
whenReady(channelId: string, callback: () => void): void;
|
|
||||||
}
|
|
||||||
|
|
@ -1,26 +0,0 @@
|
||||||
import { FluxStore } from "..";
|
|
||||||
|
|
||||||
export class RelationshipStore extends FluxStore {
|
|
||||||
getFriendIDs(): string[];
|
|
||||||
getIgnoredIDs(): string[];
|
|
||||||
getBlockedIDs(): string[];
|
|
||||||
|
|
||||||
getPendingCount(): number;
|
|
||||||
getRelationshipCount(): number;
|
|
||||||
|
|
||||||
/** Related to friend nicknames. */
|
|
||||||
getNickname(userId: string): string;
|
|
||||||
/** @returns Enum value from constants.RelationshipTypes */
|
|
||||||
getRelationshipType(userId: string): number;
|
|
||||||
isFriend(userId: string): boolean;
|
|
||||||
isBlocked(userId: string): boolean;
|
|
||||||
isIgnored(userId: string): boolean;
|
|
||||||
/**
|
|
||||||
* @see {@link isBlocked}
|
|
||||||
* @see {@link isIgnored}
|
|
||||||
*/
|
|
||||||
isBlockedOrIgnored(userId: string): boolean;
|
|
||||||
getSince(userId: string): string;
|
|
||||||
|
|
||||||
getMutableRelationships(): Map<string, number>;
|
|
||||||
}
|
|
||||||
|
|
@ -1,14 +0,0 @@
|
||||||
import { FluxStore } from "..";
|
|
||||||
|
|
||||||
export class SelectedChannelStore extends FluxStore {
|
|
||||||
getChannelId(guildId?: string | null): string;
|
|
||||||
getVoiceChannelId(): string | undefined;
|
|
||||||
getCurrentlySelectedChannelId(guildId?: string): string | undefined;
|
|
||||||
getMostRecentSelectedTextChannelId(guildId: string): string | undefined;
|
|
||||||
getLastSelectedChannelId(guildId?: string): string;
|
|
||||||
// yes this returns a string
|
|
||||||
getLastSelectedChannels(guildId?: string): string;
|
|
||||||
|
|
||||||
/** If you follow an announcement channel, this will return whichever channel you chose as destination */
|
|
||||||
getLastChannelFollowingDestination(): { guildId?: string; channelId?: string; } | undefined;
|
|
||||||
}
|
|
||||||
|
|
@ -1,14 +0,0 @@
|
||||||
import { FluxStore } from "..";
|
|
||||||
|
|
||||||
export interface SelectedGuildState {
|
|
||||||
selectedGuildTimestampMillis: Record<string | number, number>;
|
|
||||||
selectedGuildId: string | null;
|
|
||||||
lastSelectedGuildId: string | null;
|
|
||||||
}
|
|
||||||
|
|
||||||
export class SelectedGuildStore extends FluxStore {
|
|
||||||
getGuildId(): string | null;
|
|
||||||
getLastSelectedGuildId(): string | null;
|
|
||||||
getLastSelectedTimestamp(guildId: string): number | null;
|
|
||||||
getState(): SelectedGuildState | undefined;
|
|
||||||
}
|
|
||||||
|
|
@ -1,15 +0,0 @@
|
||||||
import { FluxStore, GuildSticker, PremiumStickerPack, Sticker } from "..";
|
|
||||||
|
|
||||||
export type StickerGuildMap = Map<string, GuildSticker[]>;
|
|
||||||
|
|
||||||
export class StickersStore extends FluxStore {
|
|
||||||
getAllGuildStickers(): StickerGuildMap;
|
|
||||||
getRawStickersByGuild(): StickerGuildMap;
|
|
||||||
getPremiumPacks(): PremiumStickerPack[];
|
|
||||||
|
|
||||||
getStickerById(id: string): Sticker | undefined;
|
|
||||||
getStickerPack(id: string): PremiumStickerPack | undefined;
|
|
||||||
getStickersByGuildId(guildId: string): Sticker[] | undefined;
|
|
||||||
|
|
||||||
isPremiumPack(id: string): boolean;
|
|
||||||
}
|
|
||||||
|
|
@ -1,11 +0,0 @@
|
||||||
import { FluxStore } from "@vencord/discord-types";
|
|
||||||
|
|
||||||
export class StreamerModeStore extends FluxStore {
|
|
||||||
get autoToggle(): boolean;
|
|
||||||
get disableNotifications(): boolean;
|
|
||||||
get disableSounds(): boolean;
|
|
||||||
get enableContentProtection(): boolean;
|
|
||||||
get enabled(): boolean;
|
|
||||||
get hideInstantInvites(): boolean;
|
|
||||||
get hidePersonalInformation(): boolean;
|
|
||||||
}
|
|
||||||
|
|
@ -1,18 +0,0 @@
|
||||||
import { FluxStore } from "..";
|
|
||||||
|
|
||||||
export type ThemePreference = "dark" | "light" | "unknown";
|
|
||||||
export type SystemTheme = "dark" | "light";
|
|
||||||
export type Theme = "light" | "dark" | "darker" | "midnight";
|
|
||||||
|
|
||||||
export interface ThemeState {
|
|
||||||
theme: Theme;
|
|
||||||
status: 0 | 1;
|
|
||||||
preferences: Record<ThemePreference, Theme>;
|
|
||||||
}
|
|
||||||
export class ThemeStore extends FluxStore {
|
|
||||||
get theme(): Theme;
|
|
||||||
get darkSidebar(): boolean;
|
|
||||||
get systemTheme(): SystemTheme;
|
|
||||||
themePreferenceForSystemTheme(preference: ThemePreference): Theme;
|
|
||||||
getState(): ThemeState;
|
|
||||||
}
|
|
||||||
|
|
@ -1,9 +0,0 @@
|
||||||
import { FluxStore } from "..";
|
|
||||||
|
|
||||||
export class TypingStore extends FluxStore {
|
|
||||||
/**
|
|
||||||
* returns a map of user ids to timeout ids
|
|
||||||
*/
|
|
||||||
getTypingUsers(channelId: string): Record<string, number>;
|
|
||||||
isTyping(channelId: string, userId: string): boolean;
|
|
||||||
}
|
|
||||||
|
|
@ -1,151 +0,0 @@
|
||||||
import { FluxStore, Guild, User, Application, ApplicationInstallParams } from "..";
|
|
||||||
import { ApplicationIntegrationType } from "../../enums";
|
|
||||||
|
|
||||||
export interface MutualFriend {
|
|
||||||
/**
|
|
||||||
* the userid of the mutual friend
|
|
||||||
*/
|
|
||||||
key: string;
|
|
||||||
/**
|
|
||||||
* the status of the mutual friend
|
|
||||||
*/
|
|
||||||
status: "online" | "offline" | "idle" | "dnd";
|
|
||||||
/**
|
|
||||||
* the user object of the mutual friend
|
|
||||||
*/
|
|
||||||
user: User;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface MutualGuild {
|
|
||||||
/**
|
|
||||||
* the guild object of the mutual guild
|
|
||||||
*/
|
|
||||||
guild: Guild;
|
|
||||||
/**
|
|
||||||
* the user's nickname in the guild, if any
|
|
||||||
*/
|
|
||||||
nick: string | null;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ProfileBadge {
|
|
||||||
id: string;
|
|
||||||
description: string;
|
|
||||||
icon: string;
|
|
||||||
link?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ConnectedAccount {
|
|
||||||
type: "twitch" | "youtube" | "skype" | "steam" | "leagueoflegends" | "battlenet" | "bluesky" | "bungie" | "reddit" | "twitter" | "twitter_legacy" | "spotify" | "facebook" | "xbox" | "samsung" | "contacts" | "instagram" | "mastodon" | "soundcloud" | "github" | "playstation" | "playstation-stg" | "epicgames" | "riotgames" | "roblox" | "paypal" | "ebay" | "tiktok" | "crunchyroll" | "domain" | "amazon-music";
|
|
||||||
/**
|
|
||||||
* underlying id of connected account
|
|
||||||
* eg. account uuid
|
|
||||||
*/
|
|
||||||
id: string;
|
|
||||||
/**
|
|
||||||
* display name of connected account
|
|
||||||
*/
|
|
||||||
name: string;
|
|
||||||
verified: boolean;
|
|
||||||
metadata?: Record<string, string>;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ProfileApplication {
|
|
||||||
id: string;
|
|
||||||
customInstallUrl: string | undefined;
|
|
||||||
installParams: ApplicationInstallParams | undefined;
|
|
||||||
flags: number;
|
|
||||||
popularApplicationCommandIds?: string[];
|
|
||||||
integrationTypesConfig: Record<ApplicationIntegrationType, Partial<{
|
|
||||||
oauth2_install_params: ApplicationInstallParams;
|
|
||||||
}>>;
|
|
||||||
primarySkuId: string | undefined;
|
|
||||||
storefront_available: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface UserProfileBase extends Pick<User, "banner"> {
|
|
||||||
accentColor: number | null;
|
|
||||||
/**
|
|
||||||
* often empty for guild profiles, get the user profile for badges
|
|
||||||
*/
|
|
||||||
badges: ProfileBadge[];
|
|
||||||
bio: string | undefined;
|
|
||||||
popoutAnimationParticleType: string | null;
|
|
||||||
profileEffectExpiresAt: number | Date | undefined;
|
|
||||||
profileEffectId: undefined | string;
|
|
||||||
/**
|
|
||||||
* often an empty string when not set
|
|
||||||
*/
|
|
||||||
pronouns: string | "" | undefined;
|
|
||||||
themeColors: [number, number] | undefined;
|
|
||||||
userId: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ApplicationRoleConnection {
|
|
||||||
application: Application;
|
|
||||||
application_metadata: Record<string, any>;
|
|
||||||
metadata: Record<string, any>;
|
|
||||||
platform_name: string;
|
|
||||||
platform_username: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface UserProfile extends UserProfileBase, Pick<User, "premiumType"> {
|
|
||||||
/** If this is a bot user profile, this will be its application */
|
|
||||||
application: ProfileApplication | null;
|
|
||||||
applicationRoleConnections: ApplicationRoleConnection[] | undefined;
|
|
||||||
connectedAccounts: ConnectedAccount[] | undefined;
|
|
||||||
fetchStartedAt: number;
|
|
||||||
fetchEndedAt: number;
|
|
||||||
legacyUsername: string | undefined;
|
|
||||||
premiumGuildSince: Date | null;
|
|
||||||
premiumSince: Date | null;
|
|
||||||
}
|
|
||||||
|
|
||||||
export class UserProfileStore extends FluxStore {
|
|
||||||
/**
|
|
||||||
* @param userId the user ID of the profile being fetched.
|
|
||||||
* @param guildId the guild ID to of the profile being fetched.
|
|
||||||
* defaults to the internal symbol `NO GUILD ID` if nullish
|
|
||||||
*
|
|
||||||
* @returns true if the profile is being fetched, false otherwise.
|
|
||||||
*/
|
|
||||||
isFetchingProfile(userId: string, guildId?: string): boolean;
|
|
||||||
/**
|
|
||||||
* Check if mutual friends for {@link userId} are currently being fetched.
|
|
||||||
*
|
|
||||||
* @param userId the user ID of the mutual friends being fetched.
|
|
||||||
*
|
|
||||||
* @returns true if mutual friends are being fetched, false otherwise.
|
|
||||||
*/
|
|
||||||
isFetchingFriends(userId: string): boolean;
|
|
||||||
|
|
||||||
get isSubmitting(): boolean;
|
|
||||||
|
|
||||||
getUserProfile(userId: string): UserProfile | undefined;
|
|
||||||
|
|
||||||
getGuildMemberProfile(userId: string, guildId: string | undefined): UserProfileBase | null;
|
|
||||||
/**
|
|
||||||
* Get the mutual friends of a user.
|
|
||||||
*
|
|
||||||
* @param userId the user ID of the user to get the mutual friends of.
|
|
||||||
*
|
|
||||||
* @returns an array of mutual friends, or undefined if the user has no mutual friends
|
|
||||||
*/
|
|
||||||
getMutualFriends(userId: string): MutualFriend[] | undefined;
|
|
||||||
/**
|
|
||||||
* Get the count of mutual friends for a user.
|
|
||||||
*
|
|
||||||
* @param userId the user ID of the user to get the mutual friends count of.
|
|
||||||
*
|
|
||||||
* @returns the count of mutual friends, or undefined if the user has no mutual friends
|
|
||||||
*/
|
|
||||||
getMutualFriendsCount(userId: string): number | undefined;
|
|
||||||
/**
|
|
||||||
* Get the mutual guilds of a user.
|
|
||||||
*
|
|
||||||
* @param userId the user ID of the user to get the mutual guilds of.
|
|
||||||
*
|
|
||||||
* @returns an array of mutual guilds, or undefined if the user has no mutual guilds
|
|
||||||
*/
|
|
||||||
getMutualGuilds(userId: string): MutualGuild[] | undefined;
|
|
||||||
}
|
|
||||||
10
packages/discord-types/src/stores/UserStore.d.ts
vendored
10
packages/discord-types/src/stores/UserStore.d.ts
vendored
|
|
@ -1,10 +0,0 @@
|
||||||
import { FluxStore, User } from "..";
|
|
||||||
|
|
||||||
export class UserStore extends FluxStore {
|
|
||||||
filter(filter: (user: User) => boolean, sort?: boolean): Record<string, User>;
|
|
||||||
findByTag(username: string, discriminator: string): User;
|
|
||||||
forEach(action: (user: User) => void): void;
|
|
||||||
getCurrentUser(): User;
|
|
||||||
getUser(userId: string): User;
|
|
||||||
getUsers(): Record<string, User>;
|
|
||||||
}
|
|
||||||
|
|
@ -1,42 +0,0 @@
|
||||||
import { DiscordRecord } from "../common";
|
|
||||||
import { FluxStore } from "./FluxStore";
|
|
||||||
|
|
||||||
export type UserVoiceStateRecords = Record<string, VoiceState>;
|
|
||||||
export type VoiceStates = Record<string, UserVoiceStateRecords>;
|
|
||||||
|
|
||||||
export interface VoiceState extends DiscordRecord {
|
|
||||||
userId: string;
|
|
||||||
channelId: string | null | undefined;
|
|
||||||
sessionId: string | null | undefined;
|
|
||||||
mute: boolean;
|
|
||||||
deaf: boolean;
|
|
||||||
selfMute: boolean;
|
|
||||||
selfDeaf: boolean;
|
|
||||||
selfVideo: boolean;
|
|
||||||
selfStream: boolean | undefined;
|
|
||||||
suppress: boolean;
|
|
||||||
requestToSpeakTimestamp: string | null | undefined;
|
|
||||||
discoverable: boolean;
|
|
||||||
|
|
||||||
isVoiceMuted(): boolean;
|
|
||||||
isVoiceDeafened(): boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
export class VoiceStateStore extends FluxStore {
|
|
||||||
getAllVoiceStates(): VoiceStates;
|
|
||||||
|
|
||||||
getVoiceStates(guildId?: string | null): UserVoiceStateRecords;
|
|
||||||
getVoiceStatesForChannel(channelId: string): UserVoiceStateRecords;
|
|
||||||
getVideoVoiceStatesForChannel(channelId: string): UserVoiceStateRecords;
|
|
||||||
|
|
||||||
getVoiceState(guildId: string | null, userId: string): VoiceState | undefined;
|
|
||||||
getUserVoiceChannelId(guildId: string | null, userId: string): string | undefined;
|
|
||||||
getVoiceStateForChannel(channelId: string, userId?: string): VoiceState | undefined;
|
|
||||||
getVoiceStateForUser(userId: string): VoiceState | undefined;
|
|
||||||
|
|
||||||
getCurrentClientVoiceChannelId(guildId: string | null): string | undefined;
|
|
||||||
isCurrentClientInVoiceChannel(): boolean;
|
|
||||||
|
|
||||||
isInChannel(channelId: string, userId?: string): boolean;
|
|
||||||
hasVideo(channelId: string): boolean;
|
|
||||||
}
|
|
||||||
|
|
@ -1,7 +0,0 @@
|
||||||
import { FluxStore } from "..";
|
|
||||||
|
|
||||||
export class WindowStore extends FluxStore {
|
|
||||||
isElementFullScreen(): boolean;
|
|
||||||
isFocused(): boolean;
|
|
||||||
windowSize(): Record<"width" | "height", number>;
|
|
||||||
}
|
|
||||||
38
packages/discord-types/src/stores/index.d.ts
vendored
38
packages/discord-types/src/stores/index.d.ts
vendored
|
|
@ -1,38 +0,0 @@
|
||||||
// please keep in alphabetical order
|
|
||||||
export * from "./AuthenticationStore";
|
|
||||||
export * from "./ChannelStore";
|
|
||||||
export * from "./DraftStore";
|
|
||||||
export * from "./EmojiStore";
|
|
||||||
export * from "./FluxStore";
|
|
||||||
export * from "./GuildMemberStore";
|
|
||||||
export * from "./GuildRoleStore";
|
|
||||||
export * from "./GuildStore";
|
|
||||||
export * from "./MessageStore";
|
|
||||||
export * from "./RelationshipStore";
|
|
||||||
export * from "./SelectedChannelStore";
|
|
||||||
export * from "./SelectedGuildStore";
|
|
||||||
export * from "./StickersStore";
|
|
||||||
export * from "./StreamerModeStore";
|
|
||||||
export * from "./ThemeStore";
|
|
||||||
export * from "./TypingStore";
|
|
||||||
export * from "./UserProfileStore";
|
|
||||||
export * from "./UserStore";
|
|
||||||
export * from "./VoiceStateStore";
|
|
||||||
export * from "./WindowStore";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* React hook that returns stateful data for one or more stores
|
|
||||||
* You might need a custom comparator (4th argument) if your store data is an object
|
|
||||||
* @param stores The stores to listen to
|
|
||||||
* @param mapper A function that returns the data you need
|
|
||||||
* @param dependencies An array of reactive values which the hook depends on. Use this if your mapper or equality function depends on the value of another hook
|
|
||||||
* @param isEqual A custom comparator for the data returned by mapper
|
|
||||||
*
|
|
||||||
* @example const user = useStateFromStores([UserStore], () => UserStore.getCurrentUser(), null, (old, current) => old.id === current.id);
|
|
||||||
*/
|
|
||||||
export type useStateFromStores = <T>(
|
|
||||||
stores: any[],
|
|
||||||
mapper: () => T,
|
|
||||||
dependencies?: any,
|
|
||||||
isEqual?: (old: T, newer: T) => boolean
|
|
||||||
) => T;
|
|
||||||
|
|
@ -21,6 +21,7 @@
|
||||||
"@types/node": "^22.13.4",
|
"@types/node": "^22.13.4",
|
||||||
"@types/react": "18.3.1",
|
"@types/react": "18.3.1",
|
||||||
"@types/react-dom": "18.3.1",
|
"@types/react-dom": "18.3.1",
|
||||||
|
"discord-types": "^1.3.26",
|
||||||
"standalone-electron-types": "^34.2.0",
|
"standalone-electron-types": "^34.2.0",
|
||||||
"type-fest": "^4.35.0"
|
"type-fest": "^4.35.0"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
43
pnpm-lock.yaml
generated
43
pnpm-lock.yaml
generated
|
|
@ -65,12 +65,12 @@ importers:
|
||||||
'@types/yazl':
|
'@types/yazl':
|
||||||
specifier: ^2.4.5
|
specifier: ^2.4.5
|
||||||
version: 2.4.6
|
version: 2.4.6
|
||||||
'@vencord/discord-types':
|
|
||||||
specifier: link:packages/discord-types
|
|
||||||
version: link:packages/discord-types
|
|
||||||
diff:
|
diff:
|
||||||
specifier: ^7.0.0
|
specifier: ^7.0.0
|
||||||
version: 7.0.0
|
version: 7.0.0
|
||||||
|
discord-types:
|
||||||
|
specifier: ^1.3.26
|
||||||
|
version: 1.3.26
|
||||||
esbuild:
|
esbuild:
|
||||||
specifier: ^0.25.1
|
specifier: ^0.25.1
|
||||||
version: 0.25.1
|
version: 0.25.1
|
||||||
|
|
@ -141,18 +141,6 @@ importers:
|
||||||
specifier: ^0.3.5
|
specifier: ^0.3.5
|
||||||
version: 0.3.5
|
version: 0.3.5
|
||||||
|
|
||||||
packages/discord-types:
|
|
||||||
dependencies:
|
|
||||||
'@types/react':
|
|
||||||
specifier: ^19.0.10
|
|
||||||
version: 19.0.12
|
|
||||||
moment:
|
|
||||||
specifier: ^2.22.2
|
|
||||||
version: 2.30.1
|
|
||||||
type-fest:
|
|
||||||
specifier: ^4.41.0
|
|
||||||
version: 4.41.0
|
|
||||||
|
|
||||||
packages/vencord-types:
|
packages/vencord-types:
|
||||||
dependencies:
|
dependencies:
|
||||||
'@types/lodash':
|
'@types/lodash':
|
||||||
|
|
@ -167,6 +155,9 @@ importers:
|
||||||
'@types/react-dom':
|
'@types/react-dom':
|
||||||
specifier: 18.3.1
|
specifier: 18.3.1
|
||||||
version: 18.3.1
|
version: 18.3.1
|
||||||
|
discord-types:
|
||||||
|
specifier: ^1.3.26
|
||||||
|
version: 1.3.26
|
||||||
standalone-electron-types:
|
standalone-electron-types:
|
||||||
specifier: ^34.2.0
|
specifier: ^34.2.0
|
||||||
version: 34.2.0
|
version: 34.2.0
|
||||||
|
|
@ -531,6 +522,9 @@ packages:
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
'@types/react': ^19.0.0
|
'@types/react': ^19.0.0
|
||||||
|
|
||||||
|
'@types/react@17.0.2':
|
||||||
|
resolution: {integrity: sha512-Xt40xQsrkdvjn1EyWe1Bc0dJLcil/9x2vAuW7ya+PuQip4UYUaXyhzWmAbwRsdMgwOFHpfp7/FFZebDU6Y8VHA==}
|
||||||
|
|
||||||
'@types/react@18.3.1':
|
'@types/react@18.3.1':
|
||||||
resolution: {integrity: sha512-V0kuGBX3+prX+DQ/7r2qsv1NsdfnCLnTgnRJ1pYnxykBhGMz+qj+box5lq7XsO5mtZsBqpjwwTu/7wszPfMBcw==}
|
resolution: {integrity: sha512-V0kuGBX3+prX+DQ/7r2qsv1NsdfnCLnTgnRJ1pYnxykBhGMz+qj+box5lq7XsO5mtZsBqpjwwTu/7wszPfMBcw==}
|
||||||
|
|
||||||
|
|
@ -962,6 +956,9 @@ packages:
|
||||||
resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==}
|
resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==}
|
||||||
engines: {node: '>=8'}
|
engines: {node: '>=8'}
|
||||||
|
|
||||||
|
discord-types@1.3.26:
|
||||||
|
resolution: {integrity: sha512-ToG51AOCH+JTQf7b+8vuYQe5Iqwz7nZ7StpECAZ/VZcI1ZhQk13pvt9KkRTfRv1xNvwJ2qib4e3+RifQlo8VPQ==}
|
||||||
|
|
||||||
doctrine@2.1.0:
|
doctrine@2.1.0:
|
||||||
resolution: {integrity: sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==}
|
resolution: {integrity: sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==}
|
||||||
engines: {node: '>=0.10.0'}
|
engines: {node: '>=0.10.0'}
|
||||||
|
|
@ -2331,10 +2328,6 @@ packages:
|
||||||
resolution: {integrity: sha512-2dBz5D5ycHIoliLYLi0Q2V7KRaDlH0uWIvmk7TYlAg5slqwiPv1ezJdZm1QEM0xgk29oYWMCbIG7E6gHpvChlg==}
|
resolution: {integrity: sha512-2dBz5D5ycHIoliLYLi0Q2V7KRaDlH0uWIvmk7TYlAg5slqwiPv1ezJdZm1QEM0xgk29oYWMCbIG7E6gHpvChlg==}
|
||||||
engines: {node: '>=16'}
|
engines: {node: '>=16'}
|
||||||
|
|
||||||
type-fest@4.41.0:
|
|
||||||
resolution: {integrity: sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA==}
|
|
||||||
engines: {node: '>=16'}
|
|
||||||
|
|
||||||
typed-array-buffer@1.0.3:
|
typed-array-buffer@1.0.3:
|
||||||
resolution: {integrity: sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==}
|
resolution: {integrity: sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==}
|
||||||
engines: {node: '>= 0.4'}
|
engines: {node: '>= 0.4'}
|
||||||
|
|
@ -2771,6 +2764,11 @@ snapshots:
|
||||||
dependencies:
|
dependencies:
|
||||||
'@types/react': 19.0.12
|
'@types/react': 19.0.12
|
||||||
|
|
||||||
|
'@types/react@17.0.2':
|
||||||
|
dependencies:
|
||||||
|
'@types/prop-types': 15.7.14
|
||||||
|
csstype: 3.1.3
|
||||||
|
|
||||||
'@types/react@18.3.1':
|
'@types/react@18.3.1':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@types/prop-types': 15.7.14
|
'@types/prop-types': 15.7.14
|
||||||
|
|
@ -3257,6 +3255,11 @@ snapshots:
|
||||||
dependencies:
|
dependencies:
|
||||||
path-type: 4.0.0
|
path-type: 4.0.0
|
||||||
|
|
||||||
|
discord-types@1.3.26:
|
||||||
|
dependencies:
|
||||||
|
'@types/react': 17.0.2
|
||||||
|
moment: 2.30.1
|
||||||
|
|
||||||
doctrine@2.1.0:
|
doctrine@2.1.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
esutils: 2.0.3
|
esutils: 2.0.3
|
||||||
|
|
@ -4920,8 +4923,6 @@ snapshots:
|
||||||
|
|
||||||
type-fest@4.38.0: {}
|
type-fest@4.38.0: {}
|
||||||
|
|
||||||
type-fest@4.41.0: {}
|
|
||||||
|
|
||||||
typed-array-buffer@1.0.3:
|
typed-array-buffer@1.0.3:
|
||||||
dependencies:
|
dependencies:
|
||||||
call-bound: 1.0.4
|
call-bound: 1.0.4
|
||||||
|
|
|
||||||
|
|
@ -31,7 +31,6 @@ const defines = stringifyValues({
|
||||||
IS_UPDATER_DISABLED,
|
IS_UPDATER_DISABLED,
|
||||||
IS_WEB: false,
|
IS_WEB: false,
|
||||||
IS_EXTENSION: false,
|
IS_EXTENSION: false,
|
||||||
IS_USERSCRIPT: false,
|
|
||||||
VERSION,
|
VERSION,
|
||||||
BUILD_TIMESTAMP
|
BUILD_TIMESTAMP
|
||||||
});
|
});
|
||||||
|
|
@ -51,7 +50,7 @@ const nodeCommonOpts = {
|
||||||
format: "cjs",
|
format: "cjs",
|
||||||
platform: "node",
|
platform: "node",
|
||||||
target: ["esnext"],
|
target: ["esnext"],
|
||||||
// @ts-expect-error this is never undefined
|
// @ts-ignore this is never undefined
|
||||||
external: ["electron", "original-fs", "~pluginNatives", ...commonOpts.external]
|
external: ["electron", "original-fs", "~pluginNatives", ...commonOpts.external]
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -43,7 +43,6 @@ const commonOptions = {
|
||||||
define: stringifyValues({
|
define: stringifyValues({
|
||||||
IS_WEB: true,
|
IS_WEB: true,
|
||||||
IS_EXTENSION: false,
|
IS_EXTENSION: false,
|
||||||
IS_USERSCRIPT: false,
|
|
||||||
IS_STANDALONE: true,
|
IS_STANDALONE: true,
|
||||||
IS_DEV,
|
IS_DEV,
|
||||||
IS_REPORTER,
|
IS_REPORTER,
|
||||||
|
|
@ -99,7 +98,6 @@ const buildConfigs = [
|
||||||
inject: ["browser/GMPolyfill.js", ...(commonOptions?.inject || [])],
|
inject: ["browser/GMPolyfill.js", ...(commonOptions?.inject || [])],
|
||||||
define: {
|
define: {
|
||||||
...commonOptions.define,
|
...commonOptions.define,
|
||||||
IS_USERSCRIPT: "true",
|
|
||||||
window: "unsafeWindow",
|
window: "unsafeWindow",
|
||||||
},
|
},
|
||||||
outfile: "dist/Vencord.user.js",
|
outfile: "dist/Vencord.user.js",
|
||||||
|
|
|
||||||
|
|
@ -363,6 +363,6 @@ export const commonRendererPlugins = [
|
||||||
banImportPlugin(/^react$/, "Cannot import from react. React and hooks should be imported from @webpack/common"),
|
banImportPlugin(/^react$/, "Cannot import from react. React and hooks should be imported from @webpack/common"),
|
||||||
banImportPlugin(/^electron(\/.*)?$/, "Cannot import electron in browser code. You need to use a native.ts file"),
|
banImportPlugin(/^electron(\/.*)?$/, "Cannot import electron in browser code. You need to use a native.ts file"),
|
||||||
banImportPlugin(/^ts-pattern$/, "Cannot import from ts-pattern. match and P should be imported from @webpack/common"),
|
banImportPlugin(/^ts-pattern$/, "Cannot import from ts-pattern. match and P should be imported from @webpack/common"),
|
||||||
// @ts-expect-error this is never undefined
|
// @ts-ignore this is never undefined
|
||||||
...commonOpts.plugins
|
...commonOpts.plugins
|
||||||
];
|
];
|
||||||
|
|
|
||||||
|
|
@ -16,9 +16,6 @@
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// DO NOT REMOVE UNLESS YOU WISH TO FACE THE WRATH OF THE CIRCULAR DEPENDENCY DEMON!!!!!!!
|
|
||||||
import "~plugins";
|
|
||||||
|
|
||||||
export * as Api from "./api";
|
export * as Api from "./api";
|
||||||
export * as Components from "./components";
|
export * as Components from "./components";
|
||||||
export * as Plugins from "./plugins";
|
export * as Plugins from "./plugins";
|
||||||
|
|
@ -32,8 +29,7 @@ export { PlainSettings, Settings };
|
||||||
import "./utils/quickCss";
|
import "./utils/quickCss";
|
||||||
import "./webpack/patchWebpack";
|
import "./webpack/patchWebpack";
|
||||||
|
|
||||||
import { openUpdaterModal } from "@components/settings/tabs/updater";
|
import { openUpdaterModal } from "@components/VencordSettings/UpdaterTab";
|
||||||
import { IS_WINDOWS } from "@utils/constants";
|
|
||||||
import { StartAt } from "@utils/types";
|
import { StartAt } from "@utils/types";
|
||||||
|
|
||||||
import { get as dsGet } from "./api/DataStore";
|
import { get as dsGet } from "./api/DataStore";
|
||||||
|
|
@ -138,11 +134,7 @@ async function init() {
|
||||||
|
|
||||||
if (!IS_WEB && !IS_UPDATER_DISABLED) {
|
if (!IS_WEB && !IS_UPDATER_DISABLED) {
|
||||||
runUpdateCheck();
|
runUpdateCheck();
|
||||||
|
setInterval(runUpdateCheck, 1000 * 60 * 30); // 30 minutes
|
||||||
// this tends to get really annoying, so only do this if the user has auto-update without notification enabled
|
|
||||||
if (Settings.autoUpdate && !Settings.autoUpdateNotification) {
|
|
||||||
setInterval(runUpdateCheck, 1000 * 60 * 30); // 30 minutes
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (IS_DEV) {
|
if (IS_DEV) {
|
||||||
|
|
@ -165,7 +157,7 @@ init();
|
||||||
document.addEventListener("DOMContentLoaded", () => {
|
document.addEventListener("DOMContentLoaded", () => {
|
||||||
startAllPlugins(StartAt.DOMContentLoaded);
|
startAllPlugins(StartAt.DOMContentLoaded);
|
||||||
|
|
||||||
if (IS_DISCORD_DESKTOP && Settings.winNativeTitleBar && IS_WINDOWS) {
|
if (IS_DISCORD_DESKTOP && Settings.winNativeTitleBar && navigator.platform.toLowerCase().startsWith("win")) {
|
||||||
document.head.append(Object.assign(document.createElement("style"), {
|
document.head.append(Object.assign(document.createElement("style"), {
|
||||||
id: "vencord-native-titlebar-style",
|
id: "vencord-native-titlebar-style",
|
||||||
textContent: "[class*=titleBar]{display: none!important}"
|
textContent: "[class*=titleBar]{display: none!important}"
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,6 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import type { Settings } from "@api/Settings";
|
import type { Settings } from "@api/Settings";
|
||||||
import { CspRequestResult } from "@main/csp/manager";
|
|
||||||
import { PluginIpcMappings } from "@main/ipcPlugins";
|
import { PluginIpcMappings } from "@main/ipcPlugins";
|
||||||
import type { UserThemeHeader } from "@main/themes";
|
import type { UserThemeHeader } from "@main/themes";
|
||||||
import { IpcEvents } from "@shared/IpcEvents";
|
import { IpcEvents } from "@shared/IpcEvents";
|
||||||
|
|
@ -34,11 +33,10 @@ export default {
|
||||||
themes: {
|
themes: {
|
||||||
uploadTheme: (fileName: string, fileData: string) => invoke<void>(IpcEvents.UPLOAD_THEME, fileName, fileData),
|
uploadTheme: (fileName: string, fileData: string) => invoke<void>(IpcEvents.UPLOAD_THEME, fileName, fileData),
|
||||||
deleteTheme: (fileName: string) => invoke<void>(IpcEvents.DELETE_THEME, fileName),
|
deleteTheme: (fileName: string) => invoke<void>(IpcEvents.DELETE_THEME, fileName),
|
||||||
|
getThemesDir: () => invoke<string>(IpcEvents.GET_THEMES_DIR),
|
||||||
getThemesList: () => invoke<Array<UserThemeHeader>>(IpcEvents.GET_THEMES_LIST),
|
getThemesList: () => invoke<Array<UserThemeHeader>>(IpcEvents.GET_THEMES_LIST),
|
||||||
getThemeData: (fileName: string) => invoke<string | undefined>(IpcEvents.GET_THEME_DATA, fileName),
|
getThemeData: (fileName: string) => invoke<string | undefined>(IpcEvents.GET_THEME_DATA, fileName),
|
||||||
getSystemValues: () => invoke<Record<string, string>>(IpcEvents.GET_THEME_SYSTEM_VALUES),
|
getSystemValues: () => invoke<Record<string, string>>(IpcEvents.GET_THEME_SYSTEM_VALUES),
|
||||||
|
|
||||||
openFolder: () => invoke<void>(IpcEvents.OPEN_THEMES_FOLDER),
|
|
||||||
},
|
},
|
||||||
|
|
||||||
updater: {
|
updater: {
|
||||||
|
|
@ -51,8 +49,7 @@ export default {
|
||||||
settings: {
|
settings: {
|
||||||
get: () => sendSync<Settings>(IpcEvents.GET_SETTINGS),
|
get: () => sendSync<Settings>(IpcEvents.GET_SETTINGS),
|
||||||
set: (settings: Settings, pathToNotify?: string) => invoke<void>(IpcEvents.SET_SETTINGS, settings, pathToNotify),
|
set: (settings: Settings, pathToNotify?: string) => invoke<void>(IpcEvents.SET_SETTINGS, settings, pathToNotify),
|
||||||
|
getSettingsDir: () => invoke<string>(IpcEvents.GET_SETTINGS_DIR),
|
||||||
openFolder: () => invoke<void>(IpcEvents.OPEN_SETTINGS_FOLDER),
|
|
||||||
},
|
},
|
||||||
|
|
||||||
quickCss: {
|
quickCss: {
|
||||||
|
|
@ -76,17 +73,5 @@ export default {
|
||||||
openExternal: (url: string) => invoke<void>(IpcEvents.OPEN_EXTERNAL, url)
|
openExternal: (url: string) => invoke<void>(IpcEvents.OPEN_EXTERNAL, url)
|
||||||
},
|
},
|
||||||
|
|
||||||
csp: {
|
|
||||||
/**
|
|
||||||
* Note: Only supports full explicit matches, not wildcards.
|
|
||||||
*
|
|
||||||
* If `*.example.com` is allowed, `isDomainAllowed("https://sub.example.com")` will return false.
|
|
||||||
*/
|
|
||||||
isDomainAllowed: (url: string, directives: string[]) => invoke<boolean>(IpcEvents.CSP_IS_DOMAIN_ALLOWED, url, directives),
|
|
||||||
removeOverride: (url: string) => invoke<boolean>(IpcEvents.CSP_REMOVE_OVERRIDE, url),
|
|
||||||
requestAddOverride: (url: string, directives: string[], callerName: string) =>
|
|
||||||
invoke<CspRequestResult>(IpcEvents.CSP_REQUEST_ADD_OVERRIDE, url, directives, callerName),
|
|
||||||
},
|
|
||||||
|
|
||||||
pluginHelpers: PluginHelpers
|
pluginHelpers: PluginHelpers
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -17,9 +17,10 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import ErrorBoundary from "@components/ErrorBoundary";
|
import ErrorBoundary from "@components/ErrorBoundary";
|
||||||
import BadgeAPIPlugin from "plugins/_api/badges";
|
|
||||||
import { ComponentType, HTMLProps } from "react";
|
import { ComponentType, HTMLProps } from "react";
|
||||||
|
|
||||||
|
import Plugins from "~plugins";
|
||||||
|
|
||||||
export const enum BadgePosition {
|
export const enum BadgePosition {
|
||||||
START,
|
START,
|
||||||
END
|
END
|
||||||
|
|
@ -34,9 +35,7 @@ export interface ProfileBadge {
|
||||||
image?: string;
|
image?: string;
|
||||||
link?: string;
|
link?: string;
|
||||||
/** Action to perform when you click the badge */
|
/** Action to perform when you click the badge */
|
||||||
onClick?(event: React.MouseEvent, props: ProfileBadge & BadgeUserArgs): void;
|
onClick?(event: React.MouseEvent<HTMLButtonElement, MouseEvent>, props: BadgeUserArgs): void;
|
||||||
/** Action to perform when you right click the badge */
|
|
||||||
onContextMenu?(event: React.MouseEvent, props: BadgeUserArgs & BadgeUserArgs): void;
|
|
||||||
/** Should the user display this badge? */
|
/** Should the user display this badge? */
|
||||||
shouldShow?(userInfo: BadgeUserArgs): boolean;
|
shouldShow?(userInfo: BadgeUserArgs): boolean;
|
||||||
/** Optional props (e.g. style) for the badge, ignored for component badges */
|
/** Optional props (e.g. style) for the badge, ignored for component badges */
|
||||||
|
|
@ -78,34 +77,21 @@ export function removeProfileBadge(badge: ProfileBadge) {
|
||||||
export function _getBadges(args: BadgeUserArgs) {
|
export function _getBadges(args: BadgeUserArgs) {
|
||||||
const badges = [] as ProfileBadge[];
|
const badges = [] as ProfileBadge[];
|
||||||
for (const badge of Badges) {
|
for (const badge of Badges) {
|
||||||
if (badge.shouldShow && !badge.shouldShow(args)) {
|
if (!badge.shouldShow || badge.shouldShow(args)) {
|
||||||
continue;
|
const b = badge.getBadges
|
||||||
}
|
? badge.getBadges(args).map(b => {
|
||||||
|
b.component &&= ErrorBoundary.wrap(b.component, { noop: true });
|
||||||
|
return b;
|
||||||
|
})
|
||||||
|
: [{ ...badge, ...args }];
|
||||||
|
|
||||||
const b = badge.getBadges
|
badge.position === BadgePosition.START
|
||||||
? badge.getBadges(args).map(badge => ({
|
? badges.unshift(...b)
|
||||||
...args,
|
: badges.push(...b);
|
||||||
...badge,
|
|
||||||
component: badge.component && ErrorBoundary.wrap(badge.component, { noop: true })
|
|
||||||
}))
|
|
||||||
: [{ ...args, ...badge }];
|
|
||||||
|
|
||||||
if (badge.position === BadgePosition.START) {
|
|
||||||
badges.unshift(...b);
|
|
||||||
} else {
|
|
||||||
badges.push(...b);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
const donorBadges = (Plugins.BadgeAPI as unknown as typeof import("../plugins/_api/badges").default).getDonorBadges(args.userId);
|
||||||
const donorBadges = BadgeAPIPlugin.getDonorBadges(args.userId);
|
if (donorBadges) badges.unshift(...donorBadges);
|
||||||
if (donorBadges) {
|
|
||||||
badges.unshift(
|
|
||||||
...donorBadges.map(badge => ({
|
|
||||||
...args,
|
|
||||||
...badge,
|
|
||||||
}))
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return badges;
|
return badges;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,9 +8,9 @@ import "./ChatButton.css";
|
||||||
|
|
||||||
import ErrorBoundary from "@components/ErrorBoundary";
|
import ErrorBoundary from "@components/ErrorBoundary";
|
||||||
import { Logger } from "@utils/Logger";
|
import { Logger } from "@utils/Logger";
|
||||||
import { Channel } from "@vencord/discord-types";
|
|
||||||
import { waitFor } from "@webpack";
|
import { waitFor } from "@webpack";
|
||||||
import { Button, ButtonWrapperClasses, Tooltip } from "@webpack/common";
|
import { Button, ButtonWrapperClasses, Tooltip } from "@webpack/common";
|
||||||
|
import { Channel } from "discord-types/general";
|
||||||
import { HTMLProps, JSX, MouseEventHandler, ReactNode } from "react";
|
import { HTMLProps, JSX, MouseEventHandler, ReactNode } from "react";
|
||||||
|
|
||||||
let ChannelTextAreaClasses: Record<"button" | "buttonContainer", string>;
|
let ChannelTextAreaClasses: Record<"button" | "buttonContainer", string>;
|
||||||
|
|
|
||||||
|
|
@ -17,11 +17,13 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { mergeDefaults } from "@utils/mergeDefaults";
|
import { mergeDefaults } from "@utils/mergeDefaults";
|
||||||
import { CommandArgument, Message } from "@vencord/discord-types";
|
|
||||||
import { findByCodeLazy } from "@webpack";
|
import { findByCodeLazy } from "@webpack";
|
||||||
import { MessageActions, SnowflakeUtils } from "@webpack/common";
|
import { MessageActions, SnowflakeUtils } from "@webpack/common";
|
||||||
|
import { Message } from "discord-types/general";
|
||||||
import type { PartialDeep } from "type-fest";
|
import type { PartialDeep } from "type-fest";
|
||||||
|
|
||||||
|
import { Argument } from "./types";
|
||||||
|
|
||||||
const createBotMessage = findByCodeLazy('username:"Clyde"');
|
const createBotMessage = findByCodeLazy('username:"Clyde"');
|
||||||
|
|
||||||
export function generateId() {
|
export function generateId() {
|
||||||
|
|
@ -49,8 +51,8 @@ export function sendBotMessage(channelId: string, message: PartialDeep<Message>)
|
||||||
* @param fallbackValue Fallback value in case this option wasn't passed
|
* @param fallbackValue Fallback value in case this option wasn't passed
|
||||||
* @returns Value
|
* @returns Value
|
||||||
*/
|
*/
|
||||||
export function findOption<T>(args: CommandArgument[], name: string): T & {} | undefined;
|
export function findOption<T>(args: Argument[], name: string): T & {} | undefined;
|
||||||
export function findOption<T>(args: CommandArgument[], name: string, fallbackValue: T): T & {};
|
export function findOption<T>(args: Argument[], name: string, fallbackValue: T): T & {};
|
||||||
export function findOption(args: CommandArgument[], name: string, fallbackValue?: any) {
|
export function findOption(args: Argument[], name: string, fallbackValue?: any) {
|
||||||
return (args.find(a => a.name === name)?.value ?? fallbackValue) as any;
|
return (args.find(a => a.name === name)?.value ?? fallbackValue) as any;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -18,39 +18,38 @@
|
||||||
|
|
||||||
import { Logger } from "@utils/Logger";
|
import { Logger } from "@utils/Logger";
|
||||||
import { makeCodeblock } from "@utils/text";
|
import { makeCodeblock } from "@utils/text";
|
||||||
import { CommandArgument, CommandContext, CommandOption } from "@vencord/discord-types";
|
|
||||||
|
|
||||||
import { sendBotMessage } from "./commandHelpers";
|
import { sendBotMessage } from "./commandHelpers";
|
||||||
import { ApplicationCommandInputType, ApplicationCommandOptionType, ApplicationCommandType, VencordCommand } from "./types";
|
import { ApplicationCommandInputType, ApplicationCommandOptionType, ApplicationCommandType, Argument, Command, CommandContext, Option } from "./types";
|
||||||
|
|
||||||
export * from "./commandHelpers";
|
export * from "./commandHelpers";
|
||||||
export * from "./types";
|
export * from "./types";
|
||||||
|
|
||||||
export let BUILT_IN: VencordCommand[];
|
export let BUILT_IN: Command[];
|
||||||
export const commands = {} as Record<string, VencordCommand>;
|
export const commands = {} as Record<string, Command>;
|
||||||
|
|
||||||
// hack for plugins being evaluated before we can grab these from webpack
|
// hack for plugins being evaluated before we can grab these from webpack
|
||||||
const OptPlaceholder = Symbol("OptionalMessageOption") as any as CommandOption;
|
const OptPlaceholder = Symbol("OptionalMessageOption") as any as Option;
|
||||||
const ReqPlaceholder = Symbol("RequiredMessageOption") as any as CommandOption;
|
const ReqPlaceholder = Symbol("RequiredMessageOption") as any as Option;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Optional message option named "message" you can use in commands.
|
* Optional message option named "message" you can use in commands.
|
||||||
* Used in "tableflip" or "shrug"
|
* Used in "tableflip" or "shrug"
|
||||||
* @see {@link RequiredMessageOption}
|
* @see {@link RequiredMessageOption}
|
||||||
*/
|
*/
|
||||||
export let OptionalMessageOption: CommandOption = OptPlaceholder;
|
export let OptionalMessageOption: Option = OptPlaceholder;
|
||||||
/**
|
/**
|
||||||
* Required message option named "message" you can use in commands.
|
* Required message option named "message" you can use in commands.
|
||||||
* Used in "me"
|
* Used in "me"
|
||||||
* @see {@link OptionalMessageOption}
|
* @see {@link OptionalMessageOption}
|
||||||
*/
|
*/
|
||||||
export let RequiredMessageOption: CommandOption = ReqPlaceholder;
|
export let RequiredMessageOption: Option = ReqPlaceholder;
|
||||||
|
|
||||||
// Discord's command list has random gaps for some reason, which can cause issues while rendering the commands
|
// Discord's command list has random gaps for some reason, which can cause issues while rendering the commands
|
||||||
// Add this offset to every added command to keep them unique
|
// Add this offset to every added command to keep them unique
|
||||||
let commandIdOffset: number;
|
let commandIdOffset: number;
|
||||||
|
|
||||||
export const _init = function (cmds: VencordCommand[]) {
|
export const _init = function (cmds: Command[]) {
|
||||||
try {
|
try {
|
||||||
BUILT_IN = cmds;
|
BUILT_IN = cmds;
|
||||||
OptionalMessageOption = cmds.find(c => (c.untranslatedName || c.displayName) === "shrug")!.options![0];
|
OptionalMessageOption = cmds.find(c => (c.untranslatedName || c.displayName) === "shrug")!.options![0];
|
||||||
|
|
@ -62,7 +61,7 @@ export const _init = function (cmds: VencordCommand[]) {
|
||||||
return cmds;
|
return cmds;
|
||||||
} as never;
|
} as never;
|
||||||
|
|
||||||
export const _handleCommand = function (cmd: VencordCommand, args: CommandArgument[], ctx: CommandContext) {
|
export const _handleCommand = function (cmd: Command, args: Argument[], ctx: CommandContext) {
|
||||||
if (!cmd.isVencordCommand)
|
if (!cmd.isVencordCommand)
|
||||||
return cmd.execute(args, ctx);
|
return cmd.execute(args, ctx);
|
||||||
|
|
||||||
|
|
@ -93,7 +92,7 @@ export const _handleCommand = function (cmd: VencordCommand, args: CommandArgume
|
||||||
* Prepare a Command Option for Discord by filling missing fields
|
* Prepare a Command Option for Discord by filling missing fields
|
||||||
* @param opt
|
* @param opt
|
||||||
*/
|
*/
|
||||||
export function prepareOption<O extends CommandOption | VencordCommand>(opt: O): O {
|
export function prepareOption<O extends Option | Command>(opt: O): O {
|
||||||
opt.displayName ||= opt.name;
|
opt.displayName ||= opt.name;
|
||||||
opt.displayDescription ||= opt.description;
|
opt.displayDescription ||= opt.description;
|
||||||
opt.options?.forEach((opt, i, opts) => {
|
opt.options?.forEach((opt, i, opts) => {
|
||||||
|
|
@ -110,7 +109,7 @@ export function prepareOption<O extends CommandOption | VencordCommand>(opt: O):
|
||||||
// Yes, Discord registers individual commands for each subcommand
|
// Yes, Discord registers individual commands for each subcommand
|
||||||
// TODO: This probably doesn't support nested subcommands. If that is ever needed,
|
// TODO: This probably doesn't support nested subcommands. If that is ever needed,
|
||||||
// investigate
|
// investigate
|
||||||
function registerSubCommands(cmd: VencordCommand, plugin: string) {
|
function registerSubCommands(cmd: Command, plugin: string) {
|
||||||
cmd.options?.forEach(o => {
|
cmd.options?.forEach(o => {
|
||||||
if (o.type !== ApplicationCommandOptionType.SUB_COMMAND)
|
if (o.type !== ApplicationCommandOptionType.SUB_COMMAND)
|
||||||
throw new Error("When specifying sub-command options, all options must be sub-commands.");
|
throw new Error("When specifying sub-command options, all options must be sub-commands.");
|
||||||
|
|
@ -133,7 +132,7 @@ function registerSubCommands(cmd: VencordCommand, plugin: string) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export function registerCommand<C extends VencordCommand>(command: C, plugin: string) {
|
export function registerCommand<C extends Command>(command: C, plugin: string) {
|
||||||
if (!BUILT_IN) {
|
if (!BUILT_IN) {
|
||||||
console.warn(
|
console.warn(
|
||||||
"[CommandsAPI]",
|
"[CommandsAPI]",
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,106 @@
|
||||||
/*
|
/*
|
||||||
* Vencord, a Discord client mod
|
* Vencord, a modification for Discord's desktop app
|
||||||
* Copyright (c) 2025 Vendicated and contributors
|
* Copyright (c) 2022 Vendicated and contributors
|
||||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
*
|
||||||
*/
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
import { Command } from "@vencord/discord-types";
|
import { Channel, Guild } from "discord-types/general";
|
||||||
export { ApplicationCommandInputType, ApplicationCommandOptionType, ApplicationCommandType } from "@vencord/discord-types/enums";
|
import { Promisable } from "type-fest";
|
||||||
|
|
||||||
export interface VencordCommand extends Command {
|
export interface CommandContext {
|
||||||
isVencordCommand?: boolean;
|
channel: Channel;
|
||||||
|
guild?: Guild;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const enum ApplicationCommandOptionType {
|
||||||
|
SUB_COMMAND = 1,
|
||||||
|
SUB_COMMAND_GROUP = 2,
|
||||||
|
STRING = 3,
|
||||||
|
INTEGER = 4,
|
||||||
|
BOOLEAN = 5,
|
||||||
|
USER = 6,
|
||||||
|
CHANNEL = 7,
|
||||||
|
ROLE = 8,
|
||||||
|
MENTIONABLE = 9,
|
||||||
|
NUMBER = 10,
|
||||||
|
ATTACHMENT = 11,
|
||||||
|
}
|
||||||
|
|
||||||
|
export const enum ApplicationCommandInputType {
|
||||||
|
BUILT_IN = 0,
|
||||||
|
BUILT_IN_TEXT = 1,
|
||||||
|
BUILT_IN_INTEGRATION = 2,
|
||||||
|
BOT = 3,
|
||||||
|
PLACEHOLDER = 4,
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface Option {
|
||||||
|
name: string;
|
||||||
|
displayName?: string;
|
||||||
|
type: ApplicationCommandOptionType;
|
||||||
|
description: string;
|
||||||
|
displayDescription?: string;
|
||||||
|
required?: boolean;
|
||||||
|
options?: Option[];
|
||||||
|
choices?: Array<ChoicesOption>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ChoicesOption {
|
||||||
|
label: string;
|
||||||
|
value: string;
|
||||||
|
name: string;
|
||||||
|
displayName?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const enum ApplicationCommandType {
|
||||||
|
CHAT_INPUT = 1,
|
||||||
|
USER = 2,
|
||||||
|
MESSAGE = 3,
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface CommandReturnValue {
|
||||||
|
content: string;
|
||||||
|
/** TODO: implement */
|
||||||
|
cancel?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface Argument {
|
||||||
|
type: ApplicationCommandOptionType;
|
||||||
|
name: string;
|
||||||
|
value: string;
|
||||||
|
focused: undefined;
|
||||||
|
options: Argument[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface Command {
|
||||||
|
id?: string;
|
||||||
|
applicationId?: string;
|
||||||
|
type?: ApplicationCommandType;
|
||||||
|
inputType?: ApplicationCommandInputType;
|
||||||
|
plugin?: string;
|
||||||
|
isVencordCommand?: boolean;
|
||||||
|
|
||||||
|
name: string;
|
||||||
|
untranslatedName?: string;
|
||||||
|
displayName?: string;
|
||||||
|
description: string;
|
||||||
|
untranslatedDescription?: string;
|
||||||
|
displayDescription?: string;
|
||||||
|
|
||||||
|
options?: Option[];
|
||||||
|
predicate?(ctx: CommandContext): boolean;
|
||||||
|
|
||||||
|
execute(args: Argument[], ctx: CommandContext): Promisable<void | CommandReturnValue>;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -22,9 +22,9 @@ export function promisifyRequest<T = undefined>(
|
||||||
request: IDBRequest<T> | IDBTransaction,
|
request: IDBRequest<T> | IDBTransaction,
|
||||||
): Promise<T> {
|
): Promise<T> {
|
||||||
return new Promise<T>((resolve, reject) => {
|
return new Promise<T>((resolve, reject) => {
|
||||||
// @ts-expect-error - file size hacks
|
// @ts-ignore - file size hacks
|
||||||
request.oncomplete = request.onsuccess = () => resolve(request.result);
|
request.oncomplete = request.onsuccess = () => resolve(request.result);
|
||||||
// @ts-expect-error - file size hacks
|
// @ts-ignore - file size hacks
|
||||||
request.onabort = request.onerror = () => reject(request.error);
|
request.onabort = request.onerror = () => reject(request.error);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import ErrorBoundary from "@components/ErrorBoundary";
|
import ErrorBoundary from "@components/ErrorBoundary";
|
||||||
import { Channel, User } from "@vencord/discord-types";
|
import { Channel, User } from "discord-types/general/index.js";
|
||||||
import { JSX } from "react";
|
import { JSX } from "react";
|
||||||
|
|
||||||
interface DecoratorProps {
|
interface DecoratorProps {
|
||||||
|
|
|
||||||
|
|
@ -48,7 +48,7 @@ export function _modifyAccessories(
|
||||||
) {
|
) {
|
||||||
for (const [key, accessory] of accessories.entries()) {
|
for (const [key, accessory] of accessories.entries()) {
|
||||||
const res = (
|
const res = (
|
||||||
<ErrorBoundary noop message={`Failed to render ${key} Message Accessory`} key={key}>
|
<ErrorBoundary message={`Failed to render ${key} Message Accessory`} key={key}>
|
||||||
<accessory.render {...props} />
|
<accessory.render {...props} />
|
||||||
</ErrorBoundary>
|
</ErrorBoundary>
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import ErrorBoundary from "@components/ErrorBoundary";
|
import ErrorBoundary from "@components/ErrorBoundary";
|
||||||
import { Channel, Message } from "@vencord/discord-types";
|
import { Channel, Message } from "discord-types/general/index.js";
|
||||||
import { JSX } from "react";
|
import { JSX } from "react";
|
||||||
|
|
||||||
export interface MessageDecorationProps {
|
export interface MessageDecorationProps {
|
||||||
|
|
|
||||||
|
|
@ -17,8 +17,9 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { Logger } from "@utils/Logger";
|
import { Logger } from "@utils/Logger";
|
||||||
import type { Channel, CloudUpload, CustomEmoji, Message } from "@vencord/discord-types";
|
|
||||||
import { MessageStore } from "@webpack/common";
|
import { MessageStore } from "@webpack/common";
|
||||||
|
import { CustomEmoji } from "@webpack/types";
|
||||||
|
import type { Channel, Message } from "discord-types/general";
|
||||||
import type { Promisable } from "type-fest";
|
import type { Promisable } from "type-fest";
|
||||||
|
|
||||||
const MessageEventsLogger = new Logger("MessageEvents", "#e5c890");
|
const MessageEventsLogger = new Logger("MessageEvents", "#e5c890");
|
||||||
|
|
@ -30,6 +31,30 @@ export interface MessageObject {
|
||||||
tts: boolean;
|
tts: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface Upload {
|
||||||
|
classification: string;
|
||||||
|
currentSize: number;
|
||||||
|
description: string | null;
|
||||||
|
filename: string;
|
||||||
|
id: string;
|
||||||
|
isImage: boolean;
|
||||||
|
isVideo: boolean;
|
||||||
|
item: {
|
||||||
|
file: File;
|
||||||
|
platform: number;
|
||||||
|
};
|
||||||
|
loaded: number;
|
||||||
|
mimeType: string;
|
||||||
|
preCompressionSize: number;
|
||||||
|
responseUrl: string;
|
||||||
|
sensitive: boolean;
|
||||||
|
showLargeMessageDialog: boolean;
|
||||||
|
spoiler: boolean;
|
||||||
|
status: "NOT_STARTED" | "STARTED" | "UPLOADING" | "ERROR" | "COMPLETED" | "CANCELLED";
|
||||||
|
uniqueId: string;
|
||||||
|
uploadedFilename: string;
|
||||||
|
}
|
||||||
|
|
||||||
export interface MessageReplyOptions {
|
export interface MessageReplyOptions {
|
||||||
messageReference: Message["messageReference"];
|
messageReference: Message["messageReference"];
|
||||||
allowedMentions?: {
|
allowedMentions?: {
|
||||||
|
|
@ -38,9 +63,9 @@ export interface MessageReplyOptions {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface MessageOptions {
|
export interface MessageExtra {
|
||||||
stickers?: string[];
|
stickers?: string[];
|
||||||
uploads?: CloudUpload[];
|
uploads?: Upload[];
|
||||||
replyOptions: MessageReplyOptions;
|
replyOptions: MessageReplyOptions;
|
||||||
content: string;
|
content: string;
|
||||||
channel: Channel;
|
channel: Channel;
|
||||||
|
|
@ -48,17 +73,17 @@ export interface MessageOptions {
|
||||||
openWarningPopout: (props: any) => any;
|
openWarningPopout: (props: any) => any;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type MessageSendListener = (channelId: string, messageObj: MessageObject, options: MessageOptions) => Promisable<void | { cancel: boolean; }>;
|
export type MessageSendListener = (channelId: string, messageObj: MessageObject, extra: MessageExtra) => Promisable<void | { cancel: boolean; }>;
|
||||||
export type MessageEditListener = (channelId: string, messageId: string, messageObj: MessageObject) => Promisable<void | { cancel: boolean; }>;
|
export type MessageEditListener = (channelId: string, messageId: string, messageObj: MessageObject) => Promisable<void | { cancel: boolean; }>;
|
||||||
|
|
||||||
const sendListeners = new Set<MessageSendListener>();
|
const sendListeners = new Set<MessageSendListener>();
|
||||||
const editListeners = new Set<MessageEditListener>();
|
const editListeners = new Set<MessageEditListener>();
|
||||||
|
|
||||||
export async function _handlePreSend(channelId: string, messageObj: MessageObject, options: MessageOptions, replyOptions: MessageReplyOptions) {
|
export async function _handlePreSend(channelId: string, messageObj: MessageObject, extra: MessageExtra, replyOptions: MessageReplyOptions) {
|
||||||
options.replyOptions = replyOptions;
|
extra.replyOptions = replyOptions;
|
||||||
for (const listener of sendListeners) {
|
for (const listener of sendListeners) {
|
||||||
try {
|
try {
|
||||||
const result = await listener(channelId, messageObj, options);
|
const result = await listener(channelId, messageObj, extra);
|
||||||
if (result?.cancel) {
|
if (result?.cancel) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@
|
||||||
|
|
||||||
import ErrorBoundary from "@components/ErrorBoundary";
|
import ErrorBoundary from "@components/ErrorBoundary";
|
||||||
import { Logger } from "@utils/Logger";
|
import { Logger } from "@utils/Logger";
|
||||||
import { Channel, Message } from "@vencord/discord-types";
|
import { Channel, Message } from "discord-types/general";
|
||||||
import type { ComponentType, MouseEventHandler } from "react";
|
import type { ComponentType, MouseEventHandler } from "react";
|
||||||
|
|
||||||
const logger = new Logger("MessagePopover");
|
const logger = new Logger("MessagePopover");
|
||||||
|
|
|
||||||
|
|
@ -4,8 +4,9 @@
|
||||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { Message } from "@vencord/discord-types";
|
|
||||||
import { MessageCache, MessageStore } from "@webpack/common";
|
import { MessageCache, MessageStore } from "@webpack/common";
|
||||||
|
import { FluxStore } from "@webpack/types";
|
||||||
|
import { Message } from "discord-types/general";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update and re-render a message
|
* Update and re-render a message
|
||||||
|
|
@ -24,5 +25,5 @@ export function updateMessage(channelId: string, messageId: string, fields?: Par
|
||||||
});
|
});
|
||||||
|
|
||||||
MessageCache.commit(newChannelMessageCache);
|
MessageCache.commit(newChannelMessageCache);
|
||||||
MessageStore.emitChange();
|
(MessageStore as unknown as FluxStore).emitChange();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -16,10 +16,7 @@
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import ErrorBoundary from "@components/ErrorBoundary";
|
|
||||||
import { isPrimitiveReactNode } from "@utils/react";
|
|
||||||
import { waitFor } from "@webpack";
|
import { waitFor } from "@webpack";
|
||||||
import { ReactNode } from "react";
|
|
||||||
|
|
||||||
let NoticesModule: any;
|
let NoticesModule: any;
|
||||||
waitFor(m => m.show && m.dismiss && !m.suppressAll, m => NoticesModule = m);
|
waitFor(m => m.show && m.dismiss && !m.suppressAll, m => NoticesModule = m);
|
||||||
|
|
@ -39,11 +36,7 @@ export function nextNotice() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function showNotice(message: ReactNode, buttonText: string, onOkClick: () => void) {
|
export function showNotice(message: string, buttonText: string, onOkClick: () => void) {
|
||||||
const notice = isPrimitiveReactNode(message)
|
noticesQueue.push(["GENERIC", message, buttonText, onOkClick]);
|
||||||
? message
|
|
||||||
: <ErrorBoundary fallback={() => "Error Showing Notice"}>{message}</ErrorBoundary>;
|
|
||||||
|
|
||||||
noticesQueue.push(["GENERIC", notice, buttonText, onOkClick]);
|
|
||||||
if (!currentNotice) nextNotice();
|
if (!currentNotice) nextNotice();
|
||||||
}
|
}
|
||||||
|
|
@ -104,7 +104,9 @@ export default ErrorBoundary.wrap(function NotificationComponent({
|
||||||
</svg>
|
</svg>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
{richBody ?? <p className="vc-notification-p">{body}</p>}
|
<div>
|
||||||
|
{richBody ?? <p className="vc-notification-p">{body}</p>}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{image && <img className="vc-notification-img" src={image} alt="" />}
|
{image && <img className="vc-notification-img" src={image} alt="" />}
|
||||||
|
|
|
||||||
|
|
@ -20,10 +20,10 @@ import * as DataStore from "@api/DataStore";
|
||||||
import { Settings } from "@api/Settings";
|
import { Settings } from "@api/Settings";
|
||||||
import { classNameFactory } from "@api/Styles";
|
import { classNameFactory } from "@api/Styles";
|
||||||
import { Flex } from "@components/Flex";
|
import { Flex } from "@components/Flex";
|
||||||
import { openNotificationSettingsModal } from "@components/settings/tabs/vencord/NotificationSettings";
|
import { openNotificationSettingsModal } from "@components/VencordSettings/NotificationSettings";
|
||||||
import { closeModal, ModalCloseButton, ModalFooter, ModalHeader, ModalProps, ModalRoot, ModalSize, openModal } from "@utils/modal";
|
import { closeModal, ModalCloseButton, ModalContent, ModalFooter, ModalHeader, ModalProps, ModalRoot, ModalSize, openModal } from "@utils/modal";
|
||||||
import { useAwaiter } from "@utils/react";
|
import { useAwaiter } from "@utils/react";
|
||||||
import { Alerts, Button, Forms, ListScrollerThin, React, Text, Timestamp, useEffect, useReducer, useState } from "@webpack/common";
|
import { Alerts, Button, Forms, React, Text, Timestamp, useEffect, useReducer, useState } from "@webpack/common";
|
||||||
import { nanoid } from "nanoid";
|
import { nanoid } from "nanoid";
|
||||||
import type { DispatchWithoutAction } from "react";
|
import type { DispatchWithoutAction } from "react";
|
||||||
|
|
||||||
|
|
@ -103,9 +103,21 @@ export function useLogs() {
|
||||||
|
|
||||||
function NotificationEntry({ data }: { data: PersistentNotificationData; }) {
|
function NotificationEntry({ data }: { data: PersistentNotificationData; }) {
|
||||||
const [removing, setRemoving] = useState(false);
|
const [removing, setRemoving] = useState(false);
|
||||||
|
const ref = React.useRef<HTMLDivElement>(null);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const div = ref.current!;
|
||||||
|
|
||||||
|
const setHeight = () => {
|
||||||
|
if (div.clientHeight === 0) return requestAnimationFrame(setHeight);
|
||||||
|
div.style.height = `${div.clientHeight}px`;
|
||||||
|
};
|
||||||
|
|
||||||
|
setHeight();
|
||||||
|
}, []);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={cl("wrapper", { removing })}>
|
<div className={cl("wrapper", { removing })} ref={ref}>
|
||||||
<NotificationComponent
|
<NotificationComponent
|
||||||
{...data}
|
{...data}
|
||||||
permanent={true}
|
permanent={true}
|
||||||
|
|
@ -117,13 +129,13 @@ function NotificationEntry({ data }: { data: PersistentNotificationData; }) {
|
||||||
setTimeout(() => deleteNotification(data.timestamp), 200);
|
setTimeout(() => deleteNotification(data.timestamp), 200);
|
||||||
}}
|
}}
|
||||||
richBody={
|
richBody={
|
||||||
<div className={cl("body-wrapper")}>
|
<div className={cl("body")}>
|
||||||
<div className={cl("body")}>{data.body}</div>
|
{data.body}
|
||||||
<Timestamp timestamp={new Date(data.timestamp)} className={cl("timestamp")} />
|
<Timestamp timestamp={new Date(data.timestamp)} className={cl("timestamp")} />
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
</div >
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -139,14 +151,9 @@ export function NotificationLog({ log, pending }: { log: PersistentNotificationD
|
||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ListScrollerThin
|
<div className={cl("container")}>
|
||||||
className={cl("container")}
|
{log.map(n => <NotificationEntry data={n} key={n.id} />)}
|
||||||
sections={[log.length]}
|
</div>
|
||||||
sectionHeight={0}
|
|
||||||
rowHeight={120}
|
|
||||||
renderSection={() => null}
|
|
||||||
renderRow={item => <NotificationEntry data={log[item.row]} key={log[item.row].id} />}
|
|
||||||
/>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -154,15 +161,15 @@ function LogModal({ modalProps, close }: { modalProps: ModalProps; close(): void
|
||||||
const [log, pending] = useLogs();
|
const [log, pending] = useLogs();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ModalRoot {...modalProps} size={ModalSize.LARGE} className={cl("modal")}>
|
<ModalRoot {...modalProps} size={ModalSize.LARGE}>
|
||||||
<ModalHeader>
|
<ModalHeader>
|
||||||
<Text variant="heading-lg/semibold" style={{ flexGrow: 1 }}>Notification Log</Text>
|
<Text variant="heading-lg/semibold" style={{ flexGrow: 1 }}>Notification Log</Text>
|
||||||
<ModalCloseButton onClick={close} />
|
<ModalCloseButton onClick={close} />
|
||||||
</ModalHeader>
|
</ModalHeader>
|
||||||
|
|
||||||
<div style={{ width: "100%" }}>
|
<ModalContent>
|
||||||
<NotificationLog log={log} pending={pending} />
|
<NotificationLog log={log} pending={pending} />
|
||||||
</div>
|
</ModalContent>
|
||||||
|
|
||||||
<ModalFooter>
|
<ModalFooter>
|
||||||
<Flex>
|
<Flex>
|
||||||
|
|
|
||||||
|
|
@ -3,14 +3,18 @@
|
||||||
all: unset;
|
all: unset;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
color: var(--text-default);
|
color: var(--text-normal);
|
||||||
background-color: var(--background-base-low);
|
background-color: var(--background-secondary-alt);
|
||||||
border-radius: 6px;
|
border-radius: 6px;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.visual-refresh .vc-notification-root {
|
||||||
|
background-color: var(--bg-overlay-floating, var(--background-base-low));
|
||||||
|
}
|
||||||
|
|
||||||
.vc-notification-root:not(.vc-notification-log-wrapper > .vc-notification-root) {
|
.vc-notification-root:not(.vc-notification-log-wrapper > .vc-notification-root) {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
z-index: 2147483647;
|
z-index: 2147483647;
|
||||||
|
|
@ -28,7 +32,6 @@
|
||||||
|
|
||||||
.vc-notification-content {
|
.vc-notification-content {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
overflow: hidden;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.vc-notification-header {
|
.vc-notification-header {
|
||||||
|
|
@ -78,11 +81,6 @@
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.vc-notification-log-modal {
|
|
||||||
max-width: 962px;
|
|
||||||
width: clamp(var(--modal-width-large, 800px), 962px, 85vw);
|
|
||||||
}
|
|
||||||
|
|
||||||
.vc-notification-log-empty {
|
.vc-notification-log-empty {
|
||||||
height: 218px;
|
height: 218px;
|
||||||
background: url("/assets/b36de980b174d7b798c89f35c116e5c6.svg") center no-repeat;
|
background: url("/assets/b36de980b174d7b798c89f35c116e5c6.svg") center no-repeat;
|
||||||
|
|
@ -90,23 +88,19 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.vc-notification-log-container {
|
.vc-notification-log-container {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
padding: 1em;
|
padding: 1em;
|
||||||
max-height: min(750px, 75vh);
|
overflow: hidden;
|
||||||
width: 100%;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.vc-notification-log-wrapper {
|
.vc-notification-log-wrapper {
|
||||||
height: 120px;
|
|
||||||
width: 100%;
|
|
||||||
padding-bottom: 16px;
|
|
||||||
box-sizing: border-box;
|
|
||||||
transition: 200ms ease;
|
transition: 200ms ease;
|
||||||
transition-property: height, opacity;
|
transition-property: height, opacity;
|
||||||
|
}
|
||||||
|
|
||||||
/* stylelint-disable-next-line no-descending-specificity */
|
.vc-notification-log-wrapper:not(:last-child) {
|
||||||
.vc-notification-root {
|
margin-bottom: 1em;
|
||||||
height: 104px;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.vc-notification-log-removing {
|
.vc-notification-log-removing {
|
||||||
|
|
@ -115,18 +109,9 @@
|
||||||
margin-bottom: 1em;
|
margin-bottom: 1em;
|
||||||
}
|
}
|
||||||
|
|
||||||
.vc-notification-log-body-wrapper {
|
.vc-notification-log-body {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
width: 100%;
|
|
||||||
box-sizing: border-box;
|
|
||||||
}
|
|
||||||
|
|
||||||
.vc-notification-log-body {
|
|
||||||
white-space: nowrap;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
overflow: hidden;
|
|
||||||
line-height: 1.2em;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.vc-notification-log-timestamp {
|
.vc-notification-log-timestamp {
|
||||||
|
|
@ -138,4 +123,4 @@
|
||||||
.vc-notification-log-danger-btn {
|
.vc-notification-log-danger-btn {
|
||||||
color: var(--white-500);
|
color: var(--white-500);
|
||||||
background-color: var(--button-danger-background);
|
background-color: var(--button-danger-background);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -268,7 +268,7 @@ type ResolveUseSettings<T extends object> = {
|
||||||
[Key in keyof T]:
|
[Key in keyof T]:
|
||||||
Key extends string
|
Key extends string
|
||||||
? T[Key] extends Record<string, unknown>
|
? T[Key] extends Record<string, unknown>
|
||||||
// @ts-expect-error "Type instantiation is excessively deep and possibly infinite"
|
// @ts-ignore "Type instantiation is excessively deep and possibly infinite"
|
||||||
? UseSettings<T[Key]> extends string ? `${Key}.${UseSettings<T[Key]>}` : never
|
? UseSettings<T[Key]> extends string ? `${Key}.${UseSettings<T[Key]>}` : never
|
||||||
: Key
|
: Key
|
||||||
: never;
|
: never;
|
||||||
|
|
|
||||||
|
|
@ -16,9 +16,9 @@
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
export function AddonBadge({ text, color }) {
|
export function Badge({ text, color }) {
|
||||||
return (
|
return (
|
||||||
<div className="vc-addon-badge" style={{
|
<div className="vc-plugins-badge" style={{
|
||||||
backgroundColor: color,
|
backgroundColor: color,
|
||||||
justifySelf: "flex-end",
|
justifySelf: "flex-end",
|
||||||
marginLeft: "auto"
|
marginLeft: "auto"
|
||||||
|
|
@ -18,6 +18,7 @@
|
||||||
|
|
||||||
import { React, TextInput } from "@webpack/common";
|
import { React, TextInput } from "@webpack/common";
|
||||||
|
|
||||||
|
// TODO: Refactor settings to use this as well
|
||||||
interface TextInputProps {
|
interface TextInputProps {
|
||||||
/**
|
/**
|
||||||
* WARNING: Changing this between renders will have no effect!
|
* WARNING: Changing this between renders will have no effect!
|
||||||
|
|
|
||||||
|
|
@ -16,9 +16,10 @@
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { Heart } from "@components/Heart";
|
|
||||||
import { ButtonProps } from "@vencord/discord-types";
|
|
||||||
import { Button } from "@webpack/common";
|
import { Button } from "@webpack/common";
|
||||||
|
import { ButtonProps } from "@webpack/types";
|
||||||
|
|
||||||
|
import { Heart } from "./Heart";
|
||||||
|
|
||||||
export default function DonateButton({
|
export default function DonateButton({
|
||||||
look = Button.Looks.LINK,
|
look = Button.Looks.LINK,
|
||||||
|
|
@ -75,15 +75,10 @@ const ErrorBoundary = LazyComponent(() => {
|
||||||
logger.error(`${this.props.message || "A component threw an Error"}\n`, error, errorInfo.componentStack);
|
logger.error(`${this.props.message || "A component threw an Error"}\n`, error, errorInfo.componentStack);
|
||||||
}
|
}
|
||||||
|
|
||||||
get isNoop() {
|
|
||||||
if (IS_DEV) return false;
|
|
||||||
return this.props.noop;
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
if (this.state.error === NO_ERROR) return this.props.children;
|
if (this.state.error === NO_ERROR) return this.props.children;
|
||||||
|
|
||||||
if (this.isNoop) return null;
|
if (this.props.noop) return null;
|
||||||
|
|
||||||
if (this.props.fallback)
|
if (this.props.fallback)
|
||||||
return (
|
return (
|
||||||
|
|
|
||||||
|
|
@ -3,9 +3,5 @@
|
||||||
background-color: #e7828430;
|
background-color: #e7828430;
|
||||||
border: 1px solid #e78284;
|
border: 1px solid #e78284;
|
||||||
border-radius: 5px;
|
border-radius: 5px;
|
||||||
color: var(--text-default, white);
|
color: var(--text-normal, white);
|
||||||
|
|
||||||
& a:hover {
|
|
||||||
text-decoration: underline;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,7 @@ interface BaseIconProps extends IconProps {
|
||||||
}
|
}
|
||||||
|
|
||||||
type IconProps = JSX.IntrinsicElements["svg"];
|
type IconProps = JSX.IntrinsicElements["svg"];
|
||||||
|
type ImageProps = JSX.IntrinsicElements["img"];
|
||||||
|
|
||||||
function Icon({ height = 24, width = 24, className, children, viewBox, ...svgProps }: PropsWithChildren<BaseIconProps>) {
|
function Icon({ height = 24, width = 24, className, children, viewBox, ...svgProps }: PropsWithChildren<BaseIconProps>) {
|
||||||
return (
|
return (
|
||||||
|
|
|
||||||
|
|
@ -28,9 +28,6 @@ export function Link(props: React.PropsWithChildren<Props>) {
|
||||||
props.style.pointerEvents = "none";
|
props.style.pointerEvents = "none";
|
||||||
props["aria-disabled"] = true;
|
props["aria-disabled"] = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
props.rel ??= "noreferrer";
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<a role="link" target="_blank" {...props}>
|
<a role="link" target="_blank" {...props}>
|
||||||
{props.children}
|
{props.children}
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@
|
||||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import "./ContributorModal.css";
|
import "./contributorModal.css";
|
||||||
|
|
||||||
import { useSettings } from "@api/Settings";
|
import { useSettings } from "@api/Settings";
|
||||||
import { classNameFactory } from "@api/Styles";
|
import { classNameFactory } from "@api/Styles";
|
||||||
|
|
@ -14,13 +14,13 @@ import { DevsById } from "@utils/constants";
|
||||||
import { fetchUserProfile } from "@utils/discord";
|
import { fetchUserProfile } from "@utils/discord";
|
||||||
import { classes, pluralise } from "@utils/misc";
|
import { classes, pluralise } from "@utils/misc";
|
||||||
import { ModalContent, ModalRoot, openModal } from "@utils/modal";
|
import { ModalContent, ModalRoot, openModal } from "@utils/modal";
|
||||||
import { User } from "@vencord/discord-types";
|
|
||||||
import { Forms, showToast, useEffect, useMemo, UserProfileStore, useStateFromStores } from "@webpack/common";
|
import { Forms, showToast, useEffect, useMemo, UserProfileStore, useStateFromStores } from "@webpack/common";
|
||||||
|
import { User } from "discord-types/general";
|
||||||
|
|
||||||
import Plugins from "~plugins";
|
import Plugins from "~plugins";
|
||||||
|
|
||||||
|
import { PluginCard } from ".";
|
||||||
import { GithubButton, WebsiteButton } from "./LinkIconButton";
|
import { GithubButton, WebsiteButton } from "./LinkIconButton";
|
||||||
import { PluginCard } from "./PluginCard";
|
|
||||||
|
|
||||||
const cl = classNameFactory("vc-author-modal-");
|
const cl = classNameFactory("vc-author-modal-");
|
||||||
|
|
||||||
|
|
@ -2,11 +2,11 @@
|
||||||
height: 32px;
|
height: 32px;
|
||||||
width: 32px;
|
width: 32px;
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
border: 4px solid var(--background-base-lowest);
|
border: 4px solid var(--background-tertiary);
|
||||||
box-sizing: border-box
|
box-sizing: border-box
|
||||||
}
|
}
|
||||||
|
|
||||||
.vc-settings-modal-links {
|
.vc-settings-modal-links {
|
||||||
display: flex;
|
display: flex;
|
||||||
gap: 0.2em;
|
gap: 0.2em;
|
||||||
}
|
}
|
||||||
|
|
@ -6,10 +6,11 @@
|
||||||
|
|
||||||
import "./LinkIconButton.css";
|
import "./LinkIconButton.css";
|
||||||
|
|
||||||
import { GithubIcon, WebsiteIcon } from "@components/Icons";
|
|
||||||
import { getTheme, Theme } from "@utils/discord";
|
import { getTheme, Theme } from "@utils/discord";
|
||||||
import { MaskedLink, Tooltip } from "@webpack/common";
|
import { MaskedLink, Tooltip } from "@webpack/common";
|
||||||
|
|
||||||
|
import { GithubIcon, WebsiteIcon } from "..";
|
||||||
|
|
||||||
export function GithubLinkIcon() {
|
export function GithubLinkIcon() {
|
||||||
const theme = getTheme() === Theme.Light ? "#000000" : "#FFFFFF";
|
const theme = getTheme() === Theme.Light ? "#000000" : "#FFFFFF";
|
||||||
return <GithubIcon aria-hidden fill={theme} className={"vc-settings-modal-link-icon"} />;
|
return <GithubIcon aria-hidden fill={theme} className={"vc-settings-modal-link-icon"} />;
|
||||||
|
|
@ -23,32 +23,41 @@ import { useSettings } from "@api/Settings";
|
||||||
import { classNameFactory } from "@api/Styles";
|
import { classNameFactory } from "@api/Styles";
|
||||||
import ErrorBoundary from "@components/ErrorBoundary";
|
import ErrorBoundary from "@components/ErrorBoundary";
|
||||||
import { Flex } from "@components/Flex";
|
import { Flex } from "@components/Flex";
|
||||||
import { debounce } from "@shared/debounce";
|
|
||||||
import { gitRemote } from "@shared/vencordUserAgent";
|
import { gitRemote } from "@shared/vencordUserAgent";
|
||||||
import { proxyLazy } from "@utils/lazy";
|
import { proxyLazy } from "@utils/lazy";
|
||||||
import { Margins } from "@utils/margins";
|
import { Margins } from "@utils/margins";
|
||||||
import { classes, isObjectEmpty } from "@utils/misc";
|
import { classes, isObjectEmpty } from "@utils/misc";
|
||||||
import { ModalCloseButton, ModalContent, ModalHeader, ModalProps, ModalRoot, ModalSize, openModal } from "@utils/modal";
|
import { ModalCloseButton, ModalContent, ModalFooter, ModalHeader, ModalProps, ModalRoot, ModalSize, openModal } from "@utils/modal";
|
||||||
import { OptionType, Plugin } from "@utils/types";
|
import { OptionType, Plugin } from "@utils/types";
|
||||||
import { User } from "@vencord/discord-types";
|
import { findByPropsLazy, findComponentByCodeLazy } from "@webpack";
|
||||||
import { findByPropsLazy } from "@webpack";
|
import { Button, Clickable, FluxDispatcher, Forms, React, Text, Tooltip, UserStore, UserUtils } from "@webpack/common";
|
||||||
import { Clickable, FluxDispatcher, Forms, React, Text, Tooltip, useEffect, UserStore, UserSummaryItem, UserUtils, useState } from "@webpack/common";
|
import { User } from "discord-types/general";
|
||||||
import { Constructor } from "type-fest";
|
import { Constructor } from "type-fest";
|
||||||
|
|
||||||
import { PluginMeta } from "~plugins";
|
import { PluginMeta } from "~plugins";
|
||||||
|
|
||||||
import { OptionComponentMap } from "./components";
|
import {
|
||||||
|
ISettingCustomElementProps,
|
||||||
|
ISettingElementProps,
|
||||||
|
SettingBooleanComponent,
|
||||||
|
SettingCustomComponent,
|
||||||
|
SettingNumericComponent,
|
||||||
|
SettingSelectComponent,
|
||||||
|
SettingSliderComponent,
|
||||||
|
SettingTextComponent
|
||||||
|
} from "./components";
|
||||||
import { openContributorModal } from "./ContributorModal";
|
import { openContributorModal } from "./ContributorModal";
|
||||||
import { GithubButton, WebsiteButton } from "./LinkIconButton";
|
import { GithubButton, WebsiteButton } from "./LinkIconButton";
|
||||||
|
|
||||||
const cl = classNameFactory("vc-plugin-modal-");
|
const cl = classNameFactory("vc-plugin-modal-");
|
||||||
|
|
||||||
|
const UserSummaryItem = findComponentByCodeLazy("defaultRenderUser", "showDefaultAvatarsForNullUsers");
|
||||||
const AvatarStyles = findByPropsLazy("moreUsers", "emptyUser", "avatarContainer", "clickableAvatar");
|
const AvatarStyles = findByPropsLazy("moreUsers", "emptyUser", "avatarContainer", "clickableAvatar");
|
||||||
const UserRecord: Constructor<Partial<User>> = proxyLazy(() => UserStore.getCurrentUser().constructor) as any;
|
const UserRecord: Constructor<Partial<User>> = proxyLazy(() => UserStore.getCurrentUser().constructor) as any;
|
||||||
|
|
||||||
interface PluginModalProps extends ModalProps {
|
interface PluginModalProps extends ModalProps {
|
||||||
plugin: Plugin;
|
plugin: Plugin;
|
||||||
onRestartNeeded(key: string): void;
|
onRestartNeeded(): void;
|
||||||
}
|
}
|
||||||
|
|
||||||
function makeDummyUser(user: { username: string; id?: string; avatar?: string; }) {
|
function makeDummyUser(user: { username: string; id?: string; avatar?: string; }) {
|
||||||
|
|
@ -59,22 +68,39 @@ function makeDummyUser(user: { username: string; id?: string; avatar?: string; }
|
||||||
/** To stop discord making unwanted requests... */
|
/** To stop discord making unwanted requests... */
|
||||||
bot: true,
|
bot: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
FluxDispatcher.dispatch({
|
FluxDispatcher.dispatch({
|
||||||
type: "USER_UPDATE",
|
type: "USER_UPDATE",
|
||||||
user: newUser,
|
user: newUser,
|
||||||
});
|
});
|
||||||
|
|
||||||
return newUser;
|
return newUser;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const Components: Record<OptionType, React.ComponentType<ISettingElementProps<any> | ISettingCustomElementProps<any>>> = {
|
||||||
|
[OptionType.STRING]: SettingTextComponent,
|
||||||
|
[OptionType.NUMBER]: SettingNumericComponent,
|
||||||
|
[OptionType.BIGINT]: SettingNumericComponent,
|
||||||
|
[OptionType.BOOLEAN]: SettingBooleanComponent,
|
||||||
|
[OptionType.SELECT]: SettingSelectComponent,
|
||||||
|
[OptionType.SLIDER]: SettingSliderComponent,
|
||||||
|
[OptionType.COMPONENT]: SettingCustomComponent,
|
||||||
|
[OptionType.CUSTOM]: () => null,
|
||||||
|
};
|
||||||
|
|
||||||
export default function PluginModal({ plugin, onRestartNeeded, onClose, transitionState }: PluginModalProps) {
|
export default function PluginModal({ plugin, onRestartNeeded, onClose, transitionState }: PluginModalProps) {
|
||||||
|
const [authors, setAuthors] = React.useState<Partial<User>[]>([]);
|
||||||
|
|
||||||
const pluginSettings = useSettings().plugins[plugin.name];
|
const pluginSettings = useSettings().plugins[plugin.name];
|
||||||
|
|
||||||
|
const [tempSettings, setTempSettings] = React.useState<Record<string, any>>({});
|
||||||
|
|
||||||
|
const [errors, setErrors] = React.useState<Record<string, boolean>>({});
|
||||||
|
const [saveError, setSaveError] = React.useState<string | null>(null);
|
||||||
|
|
||||||
|
const canSubmit = () => Object.values(errors).every(e => !e);
|
||||||
|
|
||||||
const hasSettings = Boolean(pluginSettings && plugin.options && !isObjectEmpty(plugin.options));
|
const hasSettings = Boolean(pluginSettings && plugin.options && !isObjectEmpty(plugin.options));
|
||||||
|
|
||||||
const [authors, setAuthors] = useState<Partial<User>[]>([]);
|
React.useEffect(() => {
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
(async () => {
|
(async () => {
|
||||||
for (const user of plugin.authors.slice(0, 6)) {
|
for (const user of plugin.authors.slice(0, 6)) {
|
||||||
const author = user.id
|
const author = user.id
|
||||||
|
|
@ -87,40 +113,63 @@ export default function PluginModal({ plugin, onRestartNeeded, onClose, transiti
|
||||||
})();
|
})();
|
||||||
}, [plugin.authors]);
|
}, [plugin.authors]);
|
||||||
|
|
||||||
function renderSettings() {
|
async function saveAndClose() {
|
||||||
if (!hasSettings || !plugin.options)
|
if (!plugin.options) {
|
||||||
return <Forms.FormText>There are no settings for this plugin.</Forms.FormText>;
|
onClose();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const options = Object.entries(plugin.options).map(([key, setting]) => {
|
if (plugin.beforeSave) {
|
||||||
if (setting.type === OptionType.CUSTOM || setting.hidden) return null;
|
const result = await Promise.resolve(plugin.beforeSave(tempSettings));
|
||||||
|
if (result !== true) {
|
||||||
function onChange(newValue: any) {
|
setSaveError(result);
|
||||||
const option = plugin.options?.[key];
|
return;
|
||||||
if (!option || option.type === OptionType.CUSTOM) return;
|
|
||||||
|
|
||||||
pluginSettings[key] = newValue;
|
|
||||||
|
|
||||||
if (option.restartNeeded) onRestartNeeded(key);
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const Component = OptionComponentMap[setting.type];
|
let restartNeeded = false;
|
||||||
return (
|
for (const [key, value] of Object.entries(tempSettings)) {
|
||||||
<Component
|
const option = plugin.options[key];
|
||||||
id={key}
|
pluginSettings[key] = value;
|
||||||
key={key}
|
|
||||||
option={setting}
|
|
||||||
onChange={debounce(onChange)}
|
|
||||||
pluginSettings={pluginSettings}
|
|
||||||
definedSettings={plugin.settings}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
return (
|
if (option.type === OptionType.CUSTOM) continue;
|
||||||
<div className="vc-plugins-settings">
|
if (option?.restartNeeded) restartNeeded = true;
|
||||||
{options}
|
}
|
||||||
</div>
|
if (restartNeeded) onRestartNeeded();
|
||||||
);
|
onClose();
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderSettings() {
|
||||||
|
if (!hasSettings || !plugin.options) {
|
||||||
|
return <Forms.FormText>There are no settings for this plugin.</Forms.FormText>;
|
||||||
|
} else {
|
||||||
|
const options = Object.entries(plugin.options).map(([key, setting]) => {
|
||||||
|
if (setting.type === OptionType.CUSTOM || setting.hidden) return null;
|
||||||
|
|
||||||
|
function onChange(newValue: any) {
|
||||||
|
setTempSettings(s => ({ ...s, [key]: newValue }));
|
||||||
|
}
|
||||||
|
|
||||||
|
function onError(hasError: boolean) {
|
||||||
|
setErrors(e => ({ ...e, [key]: hasError }));
|
||||||
|
}
|
||||||
|
|
||||||
|
const Component = Components[setting.type];
|
||||||
|
return (
|
||||||
|
<Component
|
||||||
|
id={key}
|
||||||
|
key={key}
|
||||||
|
option={setting}
|
||||||
|
onChange={onChange}
|
||||||
|
onError={onError}
|
||||||
|
pluginSettings={pluginSettings}
|
||||||
|
definedSettings={plugin.settings}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
return <Flex flexDirection="column" style={{ gap: 12, marginBottom: 16 }}>{options}</Flex>;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function renderMoreUsers(_label: string, count: number) {
|
function renderMoreUsers(_label: string, count: number) {
|
||||||
|
|
@ -143,16 +192,38 @@ export default function PluginModal({ plugin, onRestartNeeded, onClose, transiti
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
function switchToPopout() {
|
||||||
|
onClose();
|
||||||
|
|
||||||
|
const PopoutKey = `DISCORD_VENCORD_PLUGIN_SETTINGS_MODAL_${plugin.name}`;
|
||||||
|
PopoutActions.open(
|
||||||
|
PopoutKey,
|
||||||
|
() => <PluginModal
|
||||||
|
transitionState={transitionState}
|
||||||
|
plugin={plugin}
|
||||||
|
onRestartNeeded={onRestartNeeded}
|
||||||
|
onClose={() => PopoutActions.close(PopoutKey)}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
const pluginMeta = PluginMeta[plugin.name];
|
const pluginMeta = PluginMeta[plugin.name];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ModalRoot transitionState={transitionState} size={ModalSize.MEDIUM}>
|
<ModalRoot transitionState={transitionState} size={ModalSize.MEDIUM} className="vc-text-selectable">
|
||||||
<ModalHeader separator={false} className={Margins.bottom8}>
|
<ModalHeader separator={false}>
|
||||||
<Text variant="heading-xl/bold" style={{ flexGrow: 1 }}>{plugin.name}</Text>
|
<Text variant="heading-lg/semibold" style={{ flexGrow: 1 }}>{plugin.name}</Text>
|
||||||
|
|
||||||
|
{/*
|
||||||
|
<Button look={Button.Looks.BLANK} onClick={switchToPopout}>
|
||||||
|
<OpenExternalIcon aria-label="Open in Popout" />
|
||||||
|
</Button>
|
||||||
|
*/}
|
||||||
<ModalCloseButton onClick={onClose} />
|
<ModalCloseButton onClick={onClose} />
|
||||||
</ModalHeader>
|
</ModalHeader>
|
||||||
|
<ModalContent>
|
||||||
<ModalContent className={Margins.bottom16}>
|
|
||||||
<Forms.FormSection>
|
<Forms.FormSection>
|
||||||
<Flex className={cl("info")}>
|
<Flex className={cl("info")}>
|
||||||
<Forms.FormText className={cl("description")}>{plugin.description}</Forms.FormText>
|
<Forms.FormText className={cl("description")}>{plugin.description}</Forms.FormText>
|
||||||
|
|
@ -169,14 +240,16 @@ export default function PluginModal({ plugin, onRestartNeeded, onClose, transiti
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</Flex>
|
</Flex>
|
||||||
<Text variant="heading-lg/semibold" className={classes(Margins.top8, Margins.bottom8)}>Authors</Text>
|
<Forms.FormTitle tag="h3" style={{ marginTop: 8, marginBottom: 0 }}>Authors</Forms.FormTitle>
|
||||||
<div style={{ width: "fit-content" }}>
|
<div style={{ width: "fit-content", marginBottom: 8 }}>
|
||||||
<UserSummaryItem
|
<UserSummaryItem
|
||||||
users={authors}
|
users={authors}
|
||||||
|
count={plugin.authors.length}
|
||||||
guildId={undefined}
|
guildId={undefined}
|
||||||
renderIcon={false}
|
renderIcon={false}
|
||||||
max={6}
|
max={6}
|
||||||
showDefaultAvatarsForNullUsers
|
showDefaultAvatarsForNullUsers
|
||||||
|
showUserPopout
|
||||||
renderMoreUsers={renderMoreUsers}
|
renderMoreUsers={renderMoreUsers}
|
||||||
renderUser={(user: User) => (
|
renderUser={(user: User) => (
|
||||||
<Clickable
|
<Clickable
|
||||||
|
|
@ -194,32 +267,59 @@ export default function PluginModal({ plugin, onRestartNeeded, onClose, transiti
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</Forms.FormSection>
|
</Forms.FormSection>
|
||||||
|
|
||||||
{!!plugin.settingsAboutComponent && (
|
{!!plugin.settingsAboutComponent && (
|
||||||
<div className={Margins.top16}>
|
<div className={classes(Margins.bottom8, "vc-text-selectable")}>
|
||||||
<Forms.FormSection>
|
<Forms.FormSection>
|
||||||
<ErrorBoundary message="An error occurred while rendering this plugin's custom Info Component">
|
<ErrorBoundary message="An error occurred while rendering this plugin's custom InfoComponent">
|
||||||
<plugin.settingsAboutComponent />
|
<plugin.settingsAboutComponent tempSettings={tempSettings} />
|
||||||
</ErrorBoundary>
|
</ErrorBoundary>
|
||||||
</Forms.FormSection>
|
</Forms.FormSection>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
<Forms.FormSection className={Margins.bottom16}>
|
||||||
<Forms.FormSection>
|
<Forms.FormTitle tag="h3">Settings</Forms.FormTitle>
|
||||||
<Text variant="heading-lg/semibold" className={classes(Margins.top16, Margins.bottom8)}>Settings</Text>
|
|
||||||
{renderSettings()}
|
{renderSettings()}
|
||||||
</Forms.FormSection>
|
</Forms.FormSection>
|
||||||
</ModalContent>
|
</ModalContent>
|
||||||
|
{hasSettings && <ModalFooter>
|
||||||
|
<Flex flexDirection="column" style={{ width: "100%" }}>
|
||||||
|
<Flex style={{ marginLeft: "auto" }}>
|
||||||
|
<Button
|
||||||
|
onClick={onClose}
|
||||||
|
size={Button.Sizes.SMALL}
|
||||||
|
color={Button.Colors.PRIMARY}
|
||||||
|
look={Button.Looks.LINK}
|
||||||
|
>
|
||||||
|
Cancel
|
||||||
|
</Button>
|
||||||
|
<Tooltip text="You must fix all errors before saving" shouldShow={!canSubmit()}>
|
||||||
|
{({ onMouseEnter, onMouseLeave }) => (
|
||||||
|
<Button
|
||||||
|
size={Button.Sizes.SMALL}
|
||||||
|
color={Button.Colors.BRAND}
|
||||||
|
onClick={saveAndClose}
|
||||||
|
onMouseEnter={onMouseEnter}
|
||||||
|
onMouseLeave={onMouseLeave}
|
||||||
|
disabled={!canSubmit()}
|
||||||
|
>
|
||||||
|
Save & Close
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
|
</Tooltip>
|
||||||
|
</Flex>
|
||||||
|
{saveError && <Text variant="text-md/semibold" style={{ color: "var(--text-danger)" }}>Error while saving: {saveError}</Text>}
|
||||||
|
</Flex>
|
||||||
|
</ModalFooter>}
|
||||||
</ModalRoot>
|
</ModalRoot>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function openPluginModal(plugin: Plugin, onRestartNeeded?: (pluginName: string, key: string) => void) {
|
export function openPluginModal(plugin: Plugin, onRestartNeeded?: (pluginName: string) => void) {
|
||||||
openModal(modalProps => (
|
openModal(modalProps => (
|
||||||
<PluginModal
|
<PluginModal
|
||||||
{...modalProps}
|
{...modalProps}
|
||||||
plugin={plugin}
|
plugin={plugin}
|
||||||
onRestartNeeded={(key: string) => onRestartNeeded?.(plugin.name, key)}
|
onRestartNeeded={() => onRestartNeeded?.(plugin.name)}
|
||||||
/>
|
/>
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
@ -0,0 +1,63 @@
|
||||||
|
/*
|
||||||
|
* Vencord, a modification for Discord's desktop app
|
||||||
|
* Copyright (c) 2022 Vendicated and contributors
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { wordsFromCamel, wordsToTitle } from "@utils/text";
|
||||||
|
import { PluginOptionBoolean } from "@utils/types";
|
||||||
|
import { Forms, React, Switch } from "@webpack/common";
|
||||||
|
|
||||||
|
import { ISettingElementProps } from ".";
|
||||||
|
|
||||||
|
export function SettingBooleanComponent({ option, pluginSettings, definedSettings, id, onChange, onError }: ISettingElementProps<PluginOptionBoolean>) {
|
||||||
|
const def = pluginSettings[id] ?? option.default;
|
||||||
|
|
||||||
|
const [state, setState] = React.useState(def ?? false);
|
||||||
|
const [error, setError] = React.useState<string | null>(null);
|
||||||
|
|
||||||
|
React.useEffect(() => {
|
||||||
|
onError(error !== null);
|
||||||
|
}, [error]);
|
||||||
|
|
||||||
|
function handleChange(newValue: boolean): void {
|
||||||
|
const isValid = option.isValid?.call(definedSettings, newValue) ?? true;
|
||||||
|
if (typeof isValid === "string") setError(isValid);
|
||||||
|
else if (!isValid) setError("Invalid input provided.");
|
||||||
|
else {
|
||||||
|
setError(null);
|
||||||
|
setState(newValue);
|
||||||
|
onChange(newValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Forms.FormSection>
|
||||||
|
<Switch
|
||||||
|
value={state}
|
||||||
|
onChange={handleChange}
|
||||||
|
note={option.description}
|
||||||
|
disabled={option.disabled?.call(definedSettings) ?? false}
|
||||||
|
{...option.componentProps}
|
||||||
|
hideBorder
|
||||||
|
style={{ marginBottom: "0.5em" }}
|
||||||
|
>
|
||||||
|
{wordsToTitle(wordsFromCamel(id))}
|
||||||
|
</Switch>
|
||||||
|
{error && <Forms.FormText style={{ color: "var(--text-danger)" }}>{error}</Forms.FormText>}
|
||||||
|
</Forms.FormSection>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -18,8 +18,8 @@
|
||||||
|
|
||||||
import { PluginOptionComponent } from "@utils/types";
|
import { PluginOptionComponent } from "@utils/types";
|
||||||
|
|
||||||
import { ComponentSettingProps } from "./Common";
|
import { ISettingCustomElementProps } from ".";
|
||||||
|
|
||||||
export function ComponentSetting({ option, onChange }: ComponentSettingProps<PluginOptionComponent>) {
|
export function SettingCustomComponent({ option, onChange, onError }: ISettingCustomElementProps<PluginOptionComponent>) {
|
||||||
return option.component({ setValue: onChange, option });
|
return option.component({ setValue: onChange, setError: onError, option });
|
||||||
}
|
}
|
||||||
|
|
@ -16,49 +16,58 @@
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import { Margins } from "@utils/margins";
|
||||||
|
import { wordsFromCamel, wordsToTitle } from "@utils/text";
|
||||||
import { OptionType, PluginOptionNumber } from "@utils/types";
|
import { OptionType, PluginOptionNumber } from "@utils/types";
|
||||||
import { React, TextInput, useState } from "@webpack/common";
|
import { Forms, React, TextInput } from "@webpack/common";
|
||||||
|
|
||||||
import { resolveError, SettingProps, SettingsSection } from "./Common";
|
import { ISettingElementProps } from ".";
|
||||||
|
|
||||||
const MAX_SAFE_NUMBER = BigInt(Number.MAX_SAFE_INTEGER);
|
const MAX_SAFE_NUMBER = BigInt(Number.MAX_SAFE_INTEGER);
|
||||||
|
|
||||||
export function NumberSetting({ option, pluginSettings, definedSettings, id, onChange }: SettingProps<PluginOptionNumber>) {
|
export function SettingNumericComponent({ option, pluginSettings, definedSettings, id, onChange, onError }: ISettingElementProps<PluginOptionNumber>) {
|
||||||
function serialize(value: any) {
|
function serialize(value: any) {
|
||||||
if (option.type === OptionType.BIGINT) return BigInt(value);
|
if (option.type === OptionType.BIGINT) return BigInt(value);
|
||||||
return Number(value);
|
return Number(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
const [state, setState] = useState<any>(`${pluginSettings[id] ?? option.default ?? 0}`);
|
const [state, setState] = React.useState<any>(`${pluginSettings[id] ?? option.default ?? 0}`);
|
||||||
const [error, setError] = useState<string | null>(null);
|
const [error, setError] = React.useState<string | null>(null);
|
||||||
|
|
||||||
function handleChange(newValue: any) {
|
React.useEffect(() => {
|
||||||
|
onError(error !== null);
|
||||||
|
}, [error]);
|
||||||
|
|
||||||
|
function handleChange(newValue) {
|
||||||
const isValid = option.isValid?.call(definedSettings, newValue) ?? true;
|
const isValid = option.isValid?.call(definedSettings, newValue) ?? true;
|
||||||
|
|
||||||
setError(resolveError(isValid));
|
setError(null);
|
||||||
|
if (typeof isValid === "string") setError(isValid);
|
||||||
if (isValid === true) {
|
else if (!isValid) setError("Invalid input provided.");
|
||||||
onChange(serialize(newValue));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (option.type === OptionType.NUMBER && BigInt(newValue) >= MAX_SAFE_NUMBER) {
|
if (option.type === OptionType.NUMBER && BigInt(newValue) >= MAX_SAFE_NUMBER) {
|
||||||
setState(`${Number.MAX_SAFE_INTEGER}`);
|
setState(`${Number.MAX_SAFE_INTEGER}`);
|
||||||
|
onChange(serialize(newValue));
|
||||||
} else {
|
} else {
|
||||||
setState(newValue);
|
setState(newValue);
|
||||||
|
onChange(serialize(newValue));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<SettingsSection name={id} description={option.description} error={error}>
|
<Forms.FormSection>
|
||||||
|
<Forms.FormTitle>{wordsToTitle(wordsFromCamel(id))}</Forms.FormTitle>
|
||||||
|
<Forms.FormText className={Margins.bottom20} type="description">{option.description}</Forms.FormText>
|
||||||
<TextInput
|
<TextInput
|
||||||
type="number"
|
type="number"
|
||||||
pattern="-?[0-9]+"
|
pattern="-?[0-9]+"
|
||||||
placeholder={option.placeholder ?? "Enter a number"}
|
|
||||||
value={state}
|
value={state}
|
||||||
onChange={handleChange}
|
onChange={handleChange}
|
||||||
|
placeholder={option.placeholder ?? "Enter a number"}
|
||||||
disabled={option.disabled?.call(definedSettings) ?? false}
|
disabled={option.disabled?.call(definedSettings) ?? false}
|
||||||
{...option.componentProps}
|
{...option.componentProps}
|
||||||
/>
|
/>
|
||||||
</SettingsSection>
|
{error && <Forms.FormText style={{ color: "var(--text-danger)" }}>{error}</Forms.FormText>}
|
||||||
|
</Forms.FormSection>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
@ -16,41 +16,50 @@
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import { Margins } from "@utils/margins";
|
||||||
|
import { wordsFromCamel, wordsToTitle } from "@utils/text";
|
||||||
import { PluginOptionSelect } from "@utils/types";
|
import { PluginOptionSelect } from "@utils/types";
|
||||||
import { React, Select, useState } from "@webpack/common";
|
import { Forms, React, Select } from "@webpack/common";
|
||||||
|
|
||||||
import { resolveError, SettingProps, SettingsSection } from "./Common";
|
import { ISettingElementProps } from ".";
|
||||||
|
|
||||||
export function SelectSetting({ option, pluginSettings, definedSettings, onChange, id }: SettingProps<PluginOptionSelect>) {
|
export function SettingSelectComponent({ option, pluginSettings, definedSettings, onChange, onError, id }: ISettingElementProps<PluginOptionSelect>) {
|
||||||
const def = pluginSettings[id] ?? option.options?.find(o => o.default)?.value;
|
const def = pluginSettings[id] ?? option.options?.find(o => o.default)?.value;
|
||||||
|
|
||||||
const [state, setState] = useState<any>(def ?? null);
|
const [state, setState] = React.useState<any>(def ?? null);
|
||||||
const [error, setError] = useState<string | null>(null);
|
const [error, setError] = React.useState<string | null>(null);
|
||||||
|
|
||||||
function handleChange(newValue: any) {
|
React.useEffect(() => {
|
||||||
|
onError(error !== null);
|
||||||
|
}, [error]);
|
||||||
|
|
||||||
|
function handleChange(newValue) {
|
||||||
const isValid = option.isValid?.call(definedSettings, newValue) ?? true;
|
const isValid = option.isValid?.call(definedSettings, newValue) ?? true;
|
||||||
|
if (typeof isValid === "string") setError(isValid);
|
||||||
setState(newValue);
|
else if (!isValid) setError("Invalid input provided.");
|
||||||
setError(resolveError(isValid));
|
else {
|
||||||
|
setError(null);
|
||||||
if (isValid === true) {
|
setState(newValue);
|
||||||
onChange(newValue);
|
onChange(newValue);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<SettingsSection name={id} description={option.description} error={error}>
|
<Forms.FormSection>
|
||||||
|
<Forms.FormTitle>{wordsToTitle(wordsFromCamel(id))}</Forms.FormTitle>
|
||||||
|
<Forms.FormText className={Margins.bottom16} type="description">{option.description}</Forms.FormText>
|
||||||
<Select
|
<Select
|
||||||
placeholder={option.placeholder ?? "Select an option"}
|
isDisabled={option.disabled?.call(definedSettings) ?? false}
|
||||||
options={option.options}
|
options={option.options}
|
||||||
|
placeholder={option.placeholder ?? "Select an option"}
|
||||||
maxVisibleItems={5}
|
maxVisibleItems={5}
|
||||||
closeOnSelect={true}
|
closeOnSelect={true}
|
||||||
select={handleChange}
|
select={handleChange}
|
||||||
isSelected={v => v === state}
|
isSelected={v => v === state}
|
||||||
serialize={v => String(v)}
|
serialize={v => String(v)}
|
||||||
isDisabled={option.disabled?.call(definedSettings) ?? false}
|
|
||||||
{...option.componentProps}
|
{...option.componentProps}
|
||||||
/>
|
/>
|
||||||
</SettingsSection>
|
{error && <Forms.FormText style={{ color: "var(--text-danger)" }}>{error}</Forms.FormText>}
|
||||||
|
</Forms.FormSection>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
@ -16,29 +16,46 @@
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import { Margins } from "@utils/margins";
|
||||||
|
import { wordsFromCamel, wordsToTitle } from "@utils/text";
|
||||||
import { PluginOptionSlider } from "@utils/types";
|
import { PluginOptionSlider } from "@utils/types";
|
||||||
import { React, Slider, useState } from "@webpack/common";
|
import { Forms, React, Slider } from "@webpack/common";
|
||||||
|
|
||||||
import { resolveError, SettingProps, SettingsSection } from "./Common";
|
import { ISettingElementProps } from ".";
|
||||||
|
|
||||||
export function SliderSetting({ option, pluginSettings, definedSettings, id, onChange }: SettingProps<PluginOptionSlider>) {
|
export function makeRange(start: number, end: number, step = 1) {
|
||||||
|
const ranges: number[] = [];
|
||||||
|
for (let value = start; value <= end; value += step) {
|
||||||
|
ranges.push(Math.round(value * 100) / 100);
|
||||||
|
}
|
||||||
|
return ranges;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function SettingSliderComponent({ option, pluginSettings, definedSettings, id, onChange, onError }: ISettingElementProps<PluginOptionSlider>) {
|
||||||
const def = pluginSettings[id] ?? option.default;
|
const def = pluginSettings[id] ?? option.default;
|
||||||
|
|
||||||
const [error, setError] = useState<string | null>(null);
|
const [error, setError] = React.useState<string | null>(null);
|
||||||
|
|
||||||
|
React.useEffect(() => {
|
||||||
|
onError(error !== null);
|
||||||
|
}, [error]);
|
||||||
|
|
||||||
function handleChange(newValue: number): void {
|
function handleChange(newValue: number): void {
|
||||||
const isValid = option.isValid?.call(definedSettings, newValue) ?? true;
|
const isValid = option.isValid?.call(definedSettings, newValue) ?? true;
|
||||||
|
if (typeof isValid === "string") setError(isValid);
|
||||||
setError(resolveError(isValid));
|
else if (!isValid) setError("Invalid input provided.");
|
||||||
|
else {
|
||||||
if (isValid === true) {
|
setError(null);
|
||||||
onChange(newValue);
|
onChange(newValue);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<SettingsSection name={id} description={option.description} error={error}>
|
<Forms.FormSection>
|
||||||
|
<Forms.FormTitle>{wordsToTitle(wordsFromCamel(id))}</Forms.FormTitle>
|
||||||
|
<Forms.FormText className={Margins.bottom20} type="description">{option.description}</Forms.FormText>
|
||||||
<Slider
|
<Slider
|
||||||
|
disabled={option.disabled?.call(definedSettings) ?? false}
|
||||||
markers={option.markers}
|
markers={option.markers}
|
||||||
minValue={option.markers[0]}
|
minValue={option.markers[0]}
|
||||||
maxValue={option.markers[option.markers.length - 1]}
|
maxValue={option.markers[option.markers.length - 1]}
|
||||||
|
|
@ -46,10 +63,9 @@ export function SliderSetting({ option, pluginSettings, definedSettings, id, onC
|
||||||
onValueChange={handleChange}
|
onValueChange={handleChange}
|
||||||
onValueRender={(v: number) => String(v.toFixed(2))}
|
onValueRender={(v: number) => String(v.toFixed(2))}
|
||||||
stickToMarkers={option.stickToMarkers ?? true}
|
stickToMarkers={option.stickToMarkers ?? true}
|
||||||
disabled={option.disabled?.call(definedSettings) ?? false}
|
|
||||||
{...option.componentProps}
|
{...option.componentProps}
|
||||||
/>
|
/>
|
||||||
</SettingsSection>
|
</Forms.FormSection>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -16,37 +16,45 @@
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import { Margins } from "@utils/margins";
|
||||||
|
import { wordsFromCamel, wordsToTitle } from "@utils/text";
|
||||||
import { PluginOptionString } from "@utils/types";
|
import { PluginOptionString } from "@utils/types";
|
||||||
import { React, TextInput, useState } from "@webpack/common";
|
import { Forms, React, TextInput } from "@webpack/common";
|
||||||
|
|
||||||
import { resolveError, SettingProps, SettingsSection } from "./Common";
|
import { ISettingElementProps } from ".";
|
||||||
|
|
||||||
export function TextSetting({ option, pluginSettings, definedSettings, id, onChange }: SettingProps<PluginOptionString>) {
|
export function SettingTextComponent({ option, pluginSettings, definedSettings, id, onChange, onError }: ISettingElementProps<PluginOptionString>) {
|
||||||
const [state, setState] = useState(pluginSettings[id] ?? option.default ?? null);
|
const [state, setState] = React.useState(pluginSettings[id] ?? option.default ?? null);
|
||||||
const [error, setError] = useState<string | null>(null);
|
const [error, setError] = React.useState<string | null>(null);
|
||||||
|
|
||||||
function handleChange(newValue: string) {
|
React.useEffect(() => {
|
||||||
|
onError(error !== null);
|
||||||
|
}, [error]);
|
||||||
|
|
||||||
|
function handleChange(newValue) {
|
||||||
const isValid = option.isValid?.call(definedSettings, newValue) ?? true;
|
const isValid = option.isValid?.call(definedSettings, newValue) ?? true;
|
||||||
|
if (typeof isValid === "string") setError(isValid);
|
||||||
|
else if (!isValid) setError("Invalid input provided.");
|
||||||
|
else setError(null);
|
||||||
|
|
||||||
setState(newValue);
|
setState(newValue);
|
||||||
setError(resolveError(isValid));
|
onChange(newValue);
|
||||||
|
|
||||||
if (isValid === true) {
|
|
||||||
onChange(newValue);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<SettingsSection name={id} description={option.description} error={error}>
|
<Forms.FormSection>
|
||||||
|
<Forms.FormTitle>{wordsToTitle(wordsFromCamel(id))}</Forms.FormTitle>
|
||||||
|
<Forms.FormText className={Margins.bottom20} type="description">{option.description}</Forms.FormText>
|
||||||
<TextInput
|
<TextInput
|
||||||
type="text"
|
type="text"
|
||||||
placeholder={option.placeholder ?? "Enter a value"}
|
|
||||||
value={state}
|
value={state}
|
||||||
onChange={handleChange}
|
onChange={handleChange}
|
||||||
maxLength={null}
|
placeholder={option.placeholder ?? "Enter a value"}
|
||||||
disabled={option.disabled?.call(definedSettings) ?? false}
|
disabled={option.disabled?.call(definedSettings) ?? false}
|
||||||
|
maxLength={null}
|
||||||
{...option.componentProps}
|
{...option.componentProps}
|
||||||
/>
|
/>
|
||||||
</SettingsSection>
|
{error && <Forms.FormText style={{ color: "var(--text-danger)" }}>{error}</Forms.FormText>}
|
||||||
|
</Forms.FormSection>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
43
src/components/PluginSettings/components/index.ts
Normal file
43
src/components/PluginSettings/components/index.ts
Normal file
|
|
@ -0,0 +1,43 @@
|
||||||
|
/*
|
||||||
|
* Vencord, a modification for Discord's desktop app
|
||||||
|
* Copyright (c) 2022 Vendicated and contributors
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { DefinedSettings, PluginOptionBase } from "@utils/types";
|
||||||
|
|
||||||
|
interface ISettingElementPropsBase<T> {
|
||||||
|
option: T;
|
||||||
|
onChange(newValue: any): void;
|
||||||
|
pluginSettings: {
|
||||||
|
[setting: string]: any;
|
||||||
|
enabled: boolean;
|
||||||
|
};
|
||||||
|
id: string;
|
||||||
|
onError(hasError: boolean): void;
|
||||||
|
definedSettings?: DefinedSettings;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type ISettingElementProps<T extends PluginOptionBase> = ISettingElementPropsBase<T>;
|
||||||
|
export type ISettingCustomElementProps<T extends Omit<PluginOptionBase, "description" | "placeholder">> = ISettingElementPropsBase<T>;
|
||||||
|
|
||||||
|
export * from "../../Badge";
|
||||||
|
export * from "./SettingBooleanComponent";
|
||||||
|
export * from "./SettingCustomComponent";
|
||||||
|
export * from "./SettingNumericComponent";
|
||||||
|
export * from "./SettingSelectComponent";
|
||||||
|
export * from "./SettingSliderComponent";
|
||||||
|
export * from "./SettingTextComponent";
|
||||||
|
|
||||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue