Compare commits
26 commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
35509f7412 | ||
|
|
3abb5fcda8 | ||
|
|
ec6fbb190f | ||
|
|
2a52efbd97 | ||
|
|
aa52e1a42b | ||
|
|
8411026c51 | ||
|
|
8ec5b0a8d8 | ||
|
|
4c315b6886 | ||
|
|
c2d7b68950 | ||
|
|
c2fbcec3bd | ||
|
|
619b0ef858 | ||
|
|
3bbf885146 | ||
|
|
34fa7cba20 | ||
|
|
2f6dfd9bee | ||
|
|
0e75d8a42f | ||
|
|
bef4b01382 | ||
| 09ed2c78ba | |||
| 82f668ab92 | |||
| a202904f7d | |||
| f4888f29f1 | |||
| 826e774af1 | |||
| 9051269657 | |||
| 2a87063176 | |||
| 741af9eb43 | |||
| acccc963ae | |||
| 77084203c6 |
186 changed files with 2207 additions and 1007 deletions
|
Before Width: | Height: | Size: 31 KiB After Width: | Height: | Size: 31 KiB |
|
|
@ -1,3 +1,12 @@
|
||||||
|
# A fork. A fork. We're a fork.
|
||||||
|
|
||||||
|
Installing is the same as the Vencord devs laid out: [(Install)](https://docs.vencord.dev/installing/)
|
||||||
|
* Beyond that, be sure to clone *this* repository instead of their upstream one.
|
||||||
|
* `git clone https://git.dorkbutt.lol/dorkbutt/vencord`
|
||||||
|
* After completing the steps, go to Settings > Vencord > Plugins and search for
|
||||||
|
"FORKED - usrbg" and enable it. Be sure to tweak its settings!
|
||||||
|
|
||||||
|
|
||||||
# Vencord
|
# Vencord
|
||||||
|
|
||||||

|

|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
"name": "vencord",
|
"name": "vencord",
|
||||||
"private": "true",
|
"private": "true",
|
||||||
"version": "1.12.5",
|
"version": "1.12.6",
|
||||||
"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",
|
||||||
|
|
|
||||||
165
packages/discord-types/LICENSE
Normal file
165
packages/discord-types/LICENSE
Normal file
|
|
@ -0,0 +1,165 @@
|
||||||
|
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.
|
||||||
42
packages/discord-types/README.md
Normal file
42
packages/discord-types/README.md
Normal file
|
|
@ -0,0 +1,42 @@
|
||||||
|
# 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.
|
||||||
32
packages/discord-types/enums/commands.ts
Normal file
32
packages/discord-types/enums/commands.ts
Normal file
|
|
@ -0,0 +1,32 @@
|
||||||
|
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
packages/discord-types/enums/index.ts
Normal file
1
packages/discord-types/enums/index.ts
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
export * from "./commands";
|
||||||
19
packages/discord-types/package.json
Normal file
19
packages/discord-types/package.json
Normal file
|
|
@ -0,0 +1,19 @@
|
||||||
|
{
|
||||||
|
"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"
|
||||||
|
}
|
||||||
|
}
|
||||||
21
packages/discord-types/src/classes.d.ts
vendored
Normal file
21
packages/discord-types/src/classes.d.ts
vendored
Normal file
|
|
@ -0,0 +1,21 @@
|
||||||
|
export interface ImageModalClasses {
|
||||||
|
image: string,
|
||||||
|
modal: string,
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
23
packages/discord-types/src/common/Application.d.ts
vendored
Normal file
23
packages/discord-types/src/common/Application.d.ts
vendored
Normal file
|
|
@ -0,0 +1,23 @@
|
||||||
|
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
Normal file
83
packages/discord-types/src/common/Channel.d.ts
vendored
Normal file
|
|
@ -0,0 +1,83 @@
|
||||||
|
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
Normal file
64
packages/discord-types/src/common/Guild.d.ts
vendored
Normal file
|
|
@ -0,0 +1,64 @@
|
||||||
|
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;
|
||||||
|
}
|
||||||
26
packages/discord-types/src/common/GuildMember.d.ts
vendored
Normal file
26
packages/discord-types/src/common/GuildMember.d.ts
vendored
Normal file
|
|
@ -0,0 +1,26 @@
|
||||||
|
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
Normal file
12
packages/discord-types/src/common/Record.d.ts
vendored
Normal file
|
|
@ -0,0 +1,12 @@
|
||||||
|
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
Normal file
33
packages/discord-types/src/common/Role.d.ts
vendored
Normal file
|
|
@ -0,0 +1,33 @@
|
||||||
|
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
Normal file
65
packages/discord-types/src/common/User.d.ts
vendored
Normal file
|
|
@ -0,0 +1,65 @@
|
||||||
|
// 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;
|
||||||
|
}
|
||||||
8
packages/discord-types/src/common/index.d.ts
vendored
Normal file
8
packages/discord-types/src/common/index.d.ts
vendored
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
export * from "./Application";
|
||||||
|
export * from "./Channel";
|
||||||
|
export * from "./Guild";
|
||||||
|
export * from "./GuildMember";
|
||||||
|
export * from "./messages";
|
||||||
|
export * from "./Role";
|
||||||
|
export * from "./User";
|
||||||
|
export * from "./Record";
|
||||||
61
packages/discord-types/src/common/messages/Commands.d.ts
vendored
Normal file
61
packages/discord-types/src/common/messages/Commands.d.ts
vendored
Normal file
|
|
@ -0,0 +1,61 @@
|
||||||
|
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>;
|
||||||
|
}
|
||||||
70
packages/discord-types/src/common/messages/Embed.d.ts
vendored
Normal file
70
packages/discord-types/src/common/messages/Embed.d.ts
vendored
Normal file
|
|
@ -0,0 +1,70 @@
|
||||||
|
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;
|
||||||
|
};
|
||||||
|
}
|
||||||
42
packages/discord-types/src/common/messages/Emoji.d.ts
vendored
Normal file
42
packages/discord-types/src/common/messages/Emoji.d.ts
vendored
Normal file
|
|
@ -0,0 +1,42 @@
|
||||||
|
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;
|
||||||
|
}
|
||||||
191
packages/discord-types/src/common/messages/Message.d.ts
vendored
Normal file
191
packages/discord-types/src/common/messages/Message.d.ts
vendored
Normal file
|
|
@ -0,0 +1,191 @@
|
||||||
|
import { CommandOption } from './Commands';
|
||||||
|
import { User, UserJSON } from '../User';
|
||||||
|
import { Embed, EmbedJSON } from './Embed';
|
||||||
|
import { DiscordRecord } from "../Record";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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: number;
|
||||||
|
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;
|
||||||
|
nick: unknown; // probably a string
|
||||||
|
nonce: string | undefined;
|
||||||
|
pinned: boolean;
|
||||||
|
reactions: MessageReaction[];
|
||||||
|
state: string;
|
||||||
|
stickerItems: {
|
||||||
|
format_type: number;
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
}[];
|
||||||
|
stickers: unknown[];
|
||||||
|
timestamp: moment.Moment;
|
||||||
|
tts: boolean;
|
||||||
|
type: number;
|
||||||
|
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: number): boolean;
|
||||||
|
isCommandType(): boolean;
|
||||||
|
isEdited(): boolean;
|
||||||
|
isSystemDM(): 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;
|
||||||
|
}
|
||||||
4
packages/discord-types/src/common/messages/index.d.ts
vendored
Normal file
4
packages/discord-types/src/common/messages/index.d.ts
vendored
Normal file
|
|
@ -0,0 +1,4 @@
|
||||||
|
export * from "./Commands";
|
||||||
|
export * from "./Message";
|
||||||
|
export * from "./Embed";
|
||||||
|
export * from "./Emoji";
|
||||||
|
|
@ -1,25 +1,7 @@
|
||||||
/*
|
|
||||||
* Vencord, a modification for Discord's desktop app
|
|
||||||
* Copyright (c) 2023 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 type { ComponentClass, ComponentPropsWithRef, ComponentType, CSSProperties, FunctionComponent, HtmlHTMLAttributes, HTMLProps, JSX, KeyboardEvent, MouseEvent, PointerEvent, PropsWithChildren, ReactNode, Ref, RefObject } from "react";
|
import type { ComponentClass, ComponentPropsWithRef, ComponentType, CSSProperties, FunctionComponent, HtmlHTMLAttributes, HTMLProps, JSX, KeyboardEvent, MouseEvent, PointerEvent, PropsWithChildren, ReactNode, Ref, RefObject } from "react";
|
||||||
|
|
||||||
|
// copy(find(m => Array.isArray(m) && m.includes("heading-sm/normal")).map(JSON.stringify).join("|"))
|
||||||
export type TextVariant = "heading-sm/normal" | "heading-sm/medium" | "heading-sm/semibold" | "heading-sm/bold" | "heading-md/normal" | "heading-md/medium" | "heading-md/semibold" | "heading-md/bold" | "heading-lg/normal" | "heading-lg/medium" | "heading-lg/semibold" | "heading-lg/bold" | "heading-xl/normal" | "heading-xl/medium" | "heading-xl/bold" | "heading-xxl/normal" | "heading-xxl/medium" | "heading-xxl/bold" | "eyebrow" | "heading-deprecated-14/normal" | "heading-deprecated-14/medium" | "heading-deprecated-14/bold" | "text-xxs/normal" | "text-xxs/medium" | "text-xxs/semibold" | "text-xxs/bold" | "text-xs/normal" | "text-xs/medium" | "text-xs/semibold" | "text-xs/bold" | "text-sm/normal" | "text-sm/medium" | "text-sm/semibold" | "text-sm/bold" | "text-md/normal" | "text-md/medium" | "text-md/semibold" | "text-md/bold" | "text-lg/normal" | "text-lg/medium" | "text-lg/semibold" | "text-lg/bold" | "display-sm" | "display-md" | "display-lg" | "code";
|
export type TextVariant = "heading-sm/normal" | "heading-sm/medium" | "heading-sm/semibold" | "heading-sm/bold" | "heading-sm/extrabold" | "heading-md/normal" | "heading-md/medium" | "heading-md/semibold" | "heading-md/bold" | "heading-md/extrabold" | "heading-lg/normal" | "heading-lg/medium" | "heading-lg/semibold" | "heading-lg/bold" | "heading-lg/extrabold" | "heading-xl/normal" | "heading-xl/medium" | "heading-xl/semibold" | "heading-xl/bold" | "heading-xl/extrabold" | "heading-xxl/normal" | "heading-xxl/medium" | "heading-xxl/semibold" | "heading-xxl/bold" | "heading-xxl/extrabold" | "eyebrow" | "heading-deprecated-12/normal" | "heading-deprecated-12/medium" | "heading-deprecated-12/semibold" | "heading-deprecated-12/bold" | "heading-deprecated-12/extrabold" | "redesign/heading-18/bold" | "text-xxs/normal" | "text-xxs/medium" | "text-xxs/semibold" | "text-xxs/bold" | "text-xs/normal" | "text-xs/medium" | "text-xs/semibold" | "text-xs/bold" | "text-sm/normal" | "text-sm/medium" | "text-sm/semibold" | "text-sm/bold" | "text-md/normal" | "text-md/medium" | "text-md/semibold" | "text-md/bold" | "text-lg/normal" | "text-lg/medium" | "text-lg/semibold" | "text-lg/bold" | "redesign/message-preview/normal" | "redesign/message-preview/medium" | "redesign/message-preview/semibold" | "redesign/message-preview/bold" | "redesign/channel-title/normal" | "redesign/channel-title/medium" | "redesign/channel-title/semibold" | "redesign/channel-title/bold" | "display-sm" | "display-md" | "display-lg" | "code";
|
||||||
export type FormTextTypes = Record<"DEFAULT" | "INPUT_PLACEHOLDER" | "DESCRIPTION" | "LABEL_BOLD" | "LABEL_SELECTED" | "LABEL_DESCRIPTOR" | "ERROR" | "SUCCESS", string>;
|
export type FormTextTypes = Record<"DEFAULT" | "INPUT_PLACEHOLDER" | "DESCRIPTION" | "LABEL_BOLD" | "LABEL_SELECTED" | "LABEL_DESCRIPTOR" | "ERROR" | "SUCCESS", string>;
|
||||||
export type HeadingTag = `h${1 | 2 | 3 | 4 | 5 | 6}`;
|
export type HeadingTag = `h${1 | 2 | 3 | 4 | 5 | 6}`;
|
||||||
|
|
||||||
30
packages/discord-types/src/flux.d.ts
vendored
Normal file
30
packages/discord-types/src/flux.d.ts
vendored
Normal file
|
|
@ -0,0 +1,30 @@
|
||||||
|
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
Normal file
22
packages/discord-types/src/fluxEvents.d.ts
vendored
Normal file
File diff suppressed because one or more lines are too long
9
packages/discord-types/src/index.d.ts
vendored
Normal file
9
packages/discord-types/src/index.d.ts
vendored
Normal file
|
|
@ -0,0 +1,9 @@
|
||||||
|
export * from "./common";
|
||||||
|
export * from "./classes";
|
||||||
|
export * from "./components";
|
||||||
|
export * from "./flux";
|
||||||
|
export * from "./fluxEvents";
|
||||||
|
export * from "./menu";
|
||||||
|
export * from "./stores";
|
||||||
|
export * from "./utils";
|
||||||
|
export * as Webpack from "../webpack";
|
||||||
|
|
@ -1,21 +1,3 @@
|
||||||
/*
|
|
||||||
* Vencord, a modification for Discord's desktop app
|
|
||||||
* Copyright (c) 2023 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 type { ComponentType, CSSProperties, MouseEvent, PropsWithChildren, ReactNode, UIEvent } from "react";
|
import type { ComponentType, CSSProperties, MouseEvent, PropsWithChildren, ReactNode, UIEvent } from "react";
|
||||||
|
|
||||||
type RC<C> = ComponentType<PropsWithChildren<C & Record<string, any>>>;
|
type RC<C> = ComponentType<PropsWithChildren<C & Record<string, any>>>;
|
||||||
|
|
@ -73,7 +55,7 @@ export interface Menu {
|
||||||
renderValue?(value: number): string,
|
renderValue?(value: number): string,
|
||||||
}>;
|
}>;
|
||||||
MenuSearchControl: RC<{
|
MenuSearchControl: RC<{
|
||||||
query: string
|
query: string;
|
||||||
onChange(query: string): void;
|
onChange(query: string): void;
|
||||||
placeholder?: string;
|
placeholder?: string;
|
||||||
}>;
|
}>;
|
||||||
24
packages/discord-types/src/stores/ChannelStore.d.ts
vendored
Normal file
24
packages/discord-types/src/stores/ChannelStore.d.ts
vendored
Normal file
|
|
@ -0,0 +1,24 @@
|
||||||
|
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>;
|
||||||
|
}
|
||||||
43
packages/discord-types/src/stores/DraftStore.d.ts
vendored
Normal file
43
packages/discord-types/src/stores/DraftStore.d.ts
vendored
Normal file
|
|
@ -0,0 +1,43 @@
|
||||||
|
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;
|
||||||
|
}
|
||||||
57
packages/discord-types/src/stores/EmojiStore.d.ts
vendored
Normal file
57
packages/discord-types/src/stores/EmojiStore.d.ts
vendored
Normal file
|
|
@ -0,0 +1,57 @@
|
||||||
|
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
Normal file
44
packages/discord-types/src/stores/FluxStore.d.ts
vendored
Normal file
|
|
@ -0,0 +1,44 @@
|
||||||
|
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[];
|
||||||
|
}
|
||||||
27
packages/discord-types/src/stores/GuildMemberStore.d.ts
vendored
Normal file
27
packages/discord-types/src/stores/GuildMemberStore.d.ts
vendored
Normal file
|
|
@ -0,0 +1,27 @@
|
||||||
|
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;
|
||||||
|
}
|
||||||
7
packages/discord-types/src/stores/GuildRoleStore.d.ts
vendored
Normal file
7
packages/discord-types/src/stores/GuildRoleStore.d.ts
vendored
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
import { FluxStore, Role } from "..";
|
||||||
|
|
||||||
|
export class GuildRoleStore extends FluxStore {
|
||||||
|
getRole(guildId: string, roleId: string): Role;
|
||||||
|
getRoles(guildId: string): Record<string, Role>;
|
||||||
|
getAllGuildRoles(): Record<string, Record<string, Role>>;
|
||||||
|
}
|
||||||
8
packages/discord-types/src/stores/GuildStore.d.ts
vendored
Normal file
8
packages/discord-types/src/stores/GuildStore.d.ts
vendored
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
import { Guild, FluxStore } from "..";
|
||||||
|
|
||||||
|
export class GuildStore extends FluxStore {
|
||||||
|
getGuild(guildId: string): Guild;
|
||||||
|
getGuildCount(): number;
|
||||||
|
getGuilds(): Record<string, Guild>;
|
||||||
|
getGuildIds(): string[];
|
||||||
|
}
|
||||||
13
packages/discord-types/src/stores/MessageStore.d.ts
vendored
Normal file
13
packages/discord-types/src/stores/MessageStore.d.ts
vendored
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
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;
|
||||||
|
}
|
||||||
21
packages/discord-types/src/stores/RelationshipStore.d.ts
vendored
Normal file
21
packages/discord-types/src/stores/RelationshipStore.d.ts
vendored
Normal file
|
|
@ -0,0 +1,21 @@
|
||||||
|
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;
|
||||||
|
getSince(userId: string): string;
|
||||||
|
|
||||||
|
getMutableRelationships(): Map<string, number>;
|
||||||
|
}
|
||||||
14
packages/discord-types/src/stores/SelectedChannelStore.d.ts
vendored
Normal file
14
packages/discord-types/src/stores/SelectedChannelStore.d.ts
vendored
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
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;
|
||||||
|
}
|
||||||
14
packages/discord-types/src/stores/SelectedGuildStore.d.ts
vendored
Normal file
14
packages/discord-types/src/stores/SelectedGuildStore.d.ts
vendored
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
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;
|
||||||
|
}
|
||||||
18
packages/discord-types/src/stores/ThemeStore.d.ts
vendored
Normal file
18
packages/discord-types/src/stores/ThemeStore.d.ts
vendored
Normal file
|
|
@ -0,0 +1,18 @@
|
||||||
|
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;
|
||||||
|
}
|
||||||
151
packages/discord-types/src/stores/UserProfileStore.d.ts
vendored
Normal file
151
packages/discord-types/src/stores/UserProfileStore.d.ts
vendored
Normal file
|
|
@ -0,0 +1,151 @@
|
||||||
|
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
Normal file
10
packages/discord-types/src/stores/UserStore.d.ts
vendored
Normal file
|
|
@ -0,0 +1,10 @@
|
||||||
|
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>;
|
||||||
|
}
|
||||||
7
packages/discord-types/src/stores/WindowStore.d.ts
vendored
Normal file
7
packages/discord-types/src/stores/WindowStore.d.ts
vendored
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
import { FluxStore } from "..";
|
||||||
|
|
||||||
|
export class WindowStore extends FluxStore {
|
||||||
|
isElementFullScreen(): boolean;
|
||||||
|
isFocused(): boolean;
|
||||||
|
windowSize(): Record<"width" | "height", number>;
|
||||||
|
}
|
||||||
33
packages/discord-types/src/stores/index.d.ts
vendored
Normal file
33
packages/discord-types/src/stores/index.d.ts
vendored
Normal file
|
|
@ -0,0 +1,33 @@
|
||||||
|
// please keep in alphabetical order
|
||||||
|
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 "./ThemeStore";
|
||||||
|
export * from "./UserProfileStore";
|
||||||
|
export * from "./UserStore";
|
||||||
|
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;
|
||||||
|
|
@ -1,22 +1,4 @@
|
||||||
/*
|
import { Channel, Guild, GuildMember, Message, User } from ".";
|
||||||
* Vencord, a modification for Discord's desktop app
|
|
||||||
* Copyright (c) 2023 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 { Channel, Guild, GuildMember, Message, User } from "discord-types/general";
|
|
||||||
import type { ReactNode } from "react";
|
import type { ReactNode } from "react";
|
||||||
import { LiteralUnion } from "type-fest";
|
import { LiteralUnion } from "type-fest";
|
||||||
|
|
||||||
|
|
@ -335,3 +317,19 @@ export interface DateUtils {
|
||||||
dateFormat(date: Date, format: string): string;
|
dateFormat(date: Date, format: string): string;
|
||||||
diffAsUnits(start: Date, end: Date, stopAtOneSecond?: boolean): Record<"days" | "hours" | "minutes" | "seconds", number>;
|
diffAsUnits(start: Date, end: Date, stopAtOneSecond?: boolean): Record<"days" | "hours" | "minutes" | "seconds", number>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface CommandOptions {
|
||||||
|
type: number;
|
||||||
|
name: string;
|
||||||
|
description: string;
|
||||||
|
required?: boolean;
|
||||||
|
choices?: {
|
||||||
|
name: string;
|
||||||
|
values: string | number;
|
||||||
|
}[];
|
||||||
|
options?: CommandOptions[];
|
||||||
|
channel_types?: number[];
|
||||||
|
min_value?: number;
|
||||||
|
max_value?: number;
|
||||||
|
autocomplete?: boolean;
|
||||||
|
}
|
||||||
|
|
@ -1,11 +1,9 @@
|
||||||
/*
|
/*
|
||||||
* Vencord, a Discord client mod
|
* @vencord/discord-types
|
||||||
* Copyright (c) 2024 Vendicated, Nuckyz and contributors
|
* Copyright (c) 2024 Vendicated, Nuckyz and contributors
|
||||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
* SPDX-License-Identifier: LGPL-3.0-or-later
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { SYM_ORIGINAL_FACTORY, SYM_PATCHED_BY, SYM_PATCHED_SOURCE } from "./patchWebpack";
|
|
||||||
|
|
||||||
export type ModuleExports = any;
|
export type ModuleExports = any;
|
||||||
|
|
||||||
export type Module = {
|
export type Module = {
|
||||||
|
|
@ -215,24 +213,3 @@ export type WebpackRequire = ((moduleId: PropertyKey) => ModuleExports) & {
|
||||||
/** rspack unique id */
|
/** rspack unique id */
|
||||||
ruid: string;
|
ruid: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Utility section for Vencord
|
|
||||||
|
|
||||||
export type AnyWebpackRequire = ((moduleId: PropertyKey) => ModuleExports) & Partial<Omit<WebpackRequire, "m">> & {
|
|
||||||
/** The module factories, where all modules that have been loaded are stored (pre-loaded or loaded by lazy chunks) */
|
|
||||||
m: Record<PropertyKey, AnyModuleFactory>;
|
|
||||||
};
|
|
||||||
|
|
||||||
/** exports can be anything, however initially it is always an empty object */
|
|
||||||
export type AnyModuleFactory = ((this: ModuleExports, module: Module, exports: ModuleExports, require: AnyWebpackRequire) => void) & {
|
|
||||||
[SYM_PATCHED_SOURCE]?: string;
|
|
||||||
[SYM_PATCHED_BY]?: Set<string>;
|
|
||||||
};
|
|
||||||
|
|
||||||
export type PatchedModuleFactory = AnyModuleFactory & {
|
|
||||||
[SYM_ORIGINAL_FACTORY]: AnyModuleFactory;
|
|
||||||
[SYM_PATCHED_SOURCE]?: string;
|
|
||||||
[SYM_PATCHED_BY]?: Set<string>;
|
|
||||||
};
|
|
||||||
|
|
||||||
export type MaybePatchedModuleFactory = PatchedModuleFactory | AnyModuleFactory;
|
|
||||||
|
|
@ -21,7 +21,6 @@
|
||||||
"@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,6 +141,18 @@ 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':
|
||||||
|
|
@ -155,9 +167,6 @@ 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
|
||||||
|
|
@ -522,9 +531,6 @@ 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==}
|
||||||
|
|
||||||
|
|
@ -956,9 +962,6 @@ 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'}
|
||||||
|
|
@ -2328,6 +2331,10 @@ 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'}
|
||||||
|
|
@ -2764,11 +2771,6 @@ 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
|
||||||
|
|
@ -3255,11 +3257,6 @@ 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
|
||||||
|
|
@ -4923,6 +4920,8 @@ 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
|
||||||
|
|
|
||||||
|
|
@ -51,7 +51,7 @@ const nodeCommonOpts = {
|
||||||
format: "cjs",
|
format: "cjs",
|
||||||
platform: "node",
|
platform: "node",
|
||||||
target: ["esnext"],
|
target: ["esnext"],
|
||||||
// @ts-ignore this is never undefined
|
// @ts-expect-error this is never undefined
|
||||||
external: ["electron", "original-fs", "~pluginNatives", ...commonOpts.external]
|
external: ["electron", "original-fs", "~pluginNatives", ...commonOpts.external]
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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-ignore this is never undefined
|
// @ts-expect-error this is never undefined
|
||||||
...commonOpts.plugins
|
...commonOpts.plugins
|
||||||
];
|
];
|
||||||
|
|
|
||||||
|
|
@ -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,13 +17,11 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
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() {
|
||||||
|
|
@ -51,8 +49,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: Argument[], name: string): T & {} | undefined;
|
export function findOption<T>(args: CommandArgument[], name: string): T & {} | undefined;
|
||||||
export function findOption<T>(args: Argument[], name: string, fallbackValue: T): T & {};
|
export function findOption<T>(args: CommandArgument[], name: string, fallbackValue: T): T & {};
|
||||||
export function findOption(args: Argument[], name: string, fallbackValue?: any) {
|
export function findOption(args: CommandArgument[], 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,38 +18,39 @@
|
||||||
|
|
||||||
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, Argument, Command, CommandContext, Option } from "./types";
|
import { ApplicationCommandInputType, ApplicationCommandOptionType, ApplicationCommandType, VencordCommand } from "./types";
|
||||||
|
|
||||||
export * from "./commandHelpers";
|
export * from "./commandHelpers";
|
||||||
export * from "./types";
|
export * from "./types";
|
||||||
|
|
||||||
export let BUILT_IN: Command[];
|
export let BUILT_IN: VencordCommand[];
|
||||||
export const commands = {} as Record<string, Command>;
|
export const commands = {} as Record<string, VencordCommand>;
|
||||||
|
|
||||||
// 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 Option;
|
const OptPlaceholder = Symbol("OptionalMessageOption") as any as CommandOption;
|
||||||
const ReqPlaceholder = Symbol("RequiredMessageOption") as any as Option;
|
const ReqPlaceholder = Symbol("RequiredMessageOption") as any as CommandOption;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 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: Option = OptPlaceholder;
|
export let OptionalMessageOption: CommandOption = 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: Option = ReqPlaceholder;
|
export let RequiredMessageOption: CommandOption = 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: Command[]) {
|
export const _init = function (cmds: VencordCommand[]) {
|
||||||
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];
|
||||||
|
|
@ -61,7 +62,7 @@ export const _init = function (cmds: Command[]) {
|
||||||
return cmds;
|
return cmds;
|
||||||
} as never;
|
} as never;
|
||||||
|
|
||||||
export const _handleCommand = function (cmd: Command, args: Argument[], ctx: CommandContext) {
|
export const _handleCommand = function (cmd: VencordCommand, args: CommandArgument[], ctx: CommandContext) {
|
||||||
if (!cmd.isVencordCommand)
|
if (!cmd.isVencordCommand)
|
||||||
return cmd.execute(args, ctx);
|
return cmd.execute(args, ctx);
|
||||||
|
|
||||||
|
|
@ -92,7 +93,7 @@ export const _handleCommand = function (cmd: Command, args: Argument[], ctx: Com
|
||||||
* 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 Option | Command>(opt: O): O {
|
export function prepareOption<O extends CommandOption | VencordCommand>(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) => {
|
||||||
|
|
@ -109,7 +110,7 @@ export function prepareOption<O extends Option | Command>(opt: O): 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: Command, plugin: string) {
|
function registerSubCommands(cmd: VencordCommand, 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.");
|
||||||
|
|
@ -132,7 +133,7 @@ function registerSubCommands(cmd: Command, plugin: string) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export function registerCommand<C extends Command>(command: C, plugin: string) {
|
export function registerCommand<C extends VencordCommand>(command: C, plugin: string) {
|
||||||
if (!BUILT_IN) {
|
if (!BUILT_IN) {
|
||||||
console.warn(
|
console.warn(
|
||||||
"[CommandsAPI]",
|
"[CommandsAPI]",
|
||||||
|
|
|
||||||
|
|
@ -1,106 +1,12 @@
|
||||||
/*
|
/*
|
||||||
* Vencord, a modification for Discord's desktop app
|
* Vencord, a Discord client mod
|
||||||
* Copyright (c) 2022 Vendicated and contributors
|
* Copyright (c) 2025 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 { Channel, Guild } from "discord-types/general";
|
import { Command } from "@vencord/discord-types";
|
||||||
import { Promisable } from "type-fest";
|
export { ApplicationCommandInputType, ApplicationCommandOptionType, ApplicationCommandType } from "@vencord/discord-types/enums";
|
||||||
|
|
||||||
export interface CommandContext {
|
export interface VencordCommand extends Command {
|
||||||
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;
|
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-ignore - file size hacks
|
// @ts-expect-error - file size hacks
|
||||||
request.oncomplete = request.onsuccess = () => resolve(request.result);
|
request.oncomplete = request.onsuccess = () => resolve(request.result);
|
||||||
// @ts-ignore - file size hacks
|
// @ts-expect-error - 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 "discord-types/general/index.js";
|
import { Channel, User } from "@vencord/discord-types";
|
||||||
import { JSX } from "react";
|
import { JSX } from "react";
|
||||||
|
|
||||||
interface DecoratorProps {
|
interface DecoratorProps {
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import ErrorBoundary from "@components/ErrorBoundary";
|
import ErrorBoundary from "@components/ErrorBoundary";
|
||||||
import { Channel, Message } from "discord-types/general/index.js";
|
import { Channel, Message } from "@vencord/discord-types";
|
||||||
import { JSX } from "react";
|
import { JSX } from "react";
|
||||||
|
|
||||||
export interface MessageDecorationProps {
|
export interface MessageDecorationProps {
|
||||||
|
|
|
||||||
|
|
@ -17,9 +17,8 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { Logger } from "@utils/Logger";
|
import { Logger } from "@utils/Logger";
|
||||||
|
import type { Channel, 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");
|
||||||
|
|
|
||||||
|
|
@ -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 "discord-types/general";
|
import { Channel, Message } from "@vencord/discord-types";
|
||||||
import type { ComponentType, MouseEventHandler } from "react";
|
import type { ComponentType, MouseEventHandler } from "react";
|
||||||
|
|
||||||
const logger = new Logger("MessagePopover");
|
const logger = new Logger("MessagePopover");
|
||||||
|
|
|
||||||
|
|
@ -4,9 +4,8 @@
|
||||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import { FluxStore, 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
|
||||||
|
|
|
||||||
|
|
@ -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-ignore "Type instantiation is excessively deep and possibly infinite"
|
// @ts-expect-error "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,8 +16,8 @@
|
||||||
* 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 { ButtonProps } from "@vencord/discord-types";
|
||||||
import { Button } from "@webpack/common";
|
import { Button } from "@webpack/common";
|
||||||
import { ButtonProps } from "@webpack/types";
|
|
||||||
|
|
||||||
import { Heart } from "./Heart";
|
import { Heart } from "./Heart";
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -14,8 +14,8 @@ 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";
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -26,12 +26,12 @@ import { Flex } from "@components/Flex";
|
||||||
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 { isObjectEmpty } from "@utils/misc";
|
||||||
import { ModalCloseButton, ModalContent, ModalFooter, 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, findComponentByCodeLazy } from "@webpack";
|
||||||
import { Button, Clickable, FluxDispatcher, Forms, React, Text, Tooltip, UserStore, UserUtils } from "@webpack/common";
|
import { Button, Clickable, FluxDispatcher, Forms, React, Text, Tooltip, UserStore, UserUtils } 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";
|
||||||
|
|
@ -212,7 +212,7 @@ export default function PluginModal({ plugin, onRestartNeeded, onClose, transiti
|
||||||
const pluginMeta = PluginMeta[plugin.name];
|
const pluginMeta = PluginMeta[plugin.name];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ModalRoot transitionState={transitionState} size={ModalSize.MEDIUM} className="vc-text-selectable">
|
<ModalRoot transitionState={transitionState} size={ModalSize.MEDIUM}>
|
||||||
<ModalHeader separator={false}>
|
<ModalHeader separator={false}>
|
||||||
<Text variant="heading-lg/semibold" style={{ flexGrow: 1 }}>{plugin.name}</Text>
|
<Text variant="heading-lg/semibold" style={{ flexGrow: 1 }}>{plugin.name}</Text>
|
||||||
|
|
||||||
|
|
@ -268,7 +268,7 @@ export default function PluginModal({ plugin, onRestartNeeded, onClose, transiti
|
||||||
</div>
|
</div>
|
||||||
</Forms.FormSection>
|
</Forms.FormSection>
|
||||||
{!!plugin.settingsAboutComponent && (
|
{!!plugin.settingsAboutComponent && (
|
||||||
<div className={classes(Margins.bottom8, "vc-text-selectable")}>
|
<div className={Margins.bottom8}>
|
||||||
<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 Info Component">
|
||||||
<plugin.settingsAboutComponent tempSettings={tempSettings} />
|
<plugin.settingsAboutComponent tempSettings={tempSettings} />
|
||||||
|
|
|
||||||
|
|
@ -45,7 +45,7 @@ const { startDependenciesRecursive, startPlugin, stopPlugin } = proxyLazy(() =>
|
||||||
const cl = classNameFactory("vc-plugins-");
|
const cl = classNameFactory("vc-plugins-");
|
||||||
const logger = new Logger("PluginSettings", "#a6d189");
|
const logger = new Logger("PluginSettings", "#a6d189");
|
||||||
|
|
||||||
const InputStyles = findByPropsLazy("inputWrapper", "inputDefault", "error");
|
const InputStyles = findByPropsLazy("inputWrapper", "inputError", "error");
|
||||||
const ButtonClasses = findByPropsLazy("button", "disabled", "enabled");
|
const ButtonClasses = findByPropsLazy("button", "disabled", "enabled");
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -62,7 +62,7 @@ function showErrorToast(message: string) {
|
||||||
|
|
||||||
function ReloadRequiredCard({ required }: { required: boolean; }) {
|
function ReloadRequiredCard({ required }: { required: boolean; }) {
|
||||||
return (
|
return (
|
||||||
<Card className={cl("info-card", { "restart-card": required })}>
|
<Card className={classes(cl("info-card"), required && "vc-warning-card")}>
|
||||||
{required ? (
|
{required ? (
|
||||||
<>
|
<>
|
||||||
<Forms.FormTitle tag="h5">Restart required!</Forms.FormTitle>
|
<Forms.FormTitle tag="h5">Restart required!</Forms.FormTitle>
|
||||||
|
|
@ -349,7 +349,7 @@ export default function PluginSettings() {
|
||||||
select={onStatusChange}
|
select={onStatusChange}
|
||||||
isSelected={v => v === searchValue.status}
|
isSelected={v => v === searchValue.status}
|
||||||
closeOnSelect={true}
|
closeOnSelect={true}
|
||||||
className={InputStyles.inputDefault}
|
className={InputStyles.input}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -66,13 +66,6 @@
|
||||||
gap: 0.25em;
|
gap: 0.25em;
|
||||||
}
|
}
|
||||||
|
|
||||||
.vc-plugins-restart-card {
|
|
||||||
padding: 1em;
|
|
||||||
background: var(--info-warning-background);
|
|
||||||
border: 1px solid var(--info-warning-foreground);
|
|
||||||
color: var(--info-warning-foreground);
|
|
||||||
}
|
|
||||||
|
|
||||||
.vc-plugins-restart-button {
|
.vc-plugins-restart-button {
|
||||||
margin-top: 0.5em;
|
margin-top: 0.5em;
|
||||||
background: var(--info-warning-foreground) !important;
|
background: var(--info-warning-foreground) !important;
|
||||||
|
|
|
||||||
|
|
@ -194,7 +194,7 @@ function ReplacementInput({ replacement, setReplacement, replacementError }) {
|
||||||
error={error ?? replacementError}
|
error={error ?? replacementError}
|
||||||
/>
|
/>
|
||||||
{!isFunc && (
|
{!isFunc && (
|
||||||
<div className="vc-text-selectable">
|
<div>
|
||||||
<Forms.FormTitle className={Margins.top8}>Cheat Sheet</Forms.FormTitle>
|
<Forms.FormTitle className={Margins.top8}>Cheat Sheet</Forms.FormTitle>
|
||||||
{Object.entries({
|
{Object.entries({
|
||||||
"\\i": "Special regex escape sequence that matches identifiers (varnames, classnames, etc.)",
|
"\\i": "Special regex escape sequence that matches identifiers (varnames, classnames, etc.)",
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,7 @@ import { openInviteModal } from "@utils/discord";
|
||||||
import { Margins } from "@utils/margins";
|
import { Margins } from "@utils/margins";
|
||||||
import { classes } from "@utils/misc";
|
import { classes } from "@utils/misc";
|
||||||
import { relaunch } from "@utils/native";
|
import { relaunch } from "@utils/native";
|
||||||
import { useAwaiter, useForceUpdater } from "@utils/react";
|
import { useForceUpdater } from "@utils/react";
|
||||||
import { getStylusWebStoreUrl } from "@utils/web";
|
import { getStylusWebStoreUrl } from "@utils/web";
|
||||||
import { findLazy } from "@webpack";
|
import { findLazy } from "@webpack";
|
||||||
import { Alerts, Button, Card, Forms, React, showToast, TabBar, TextArea, useEffect, useRef, useState } from "@webpack/common";
|
import { Alerts, Button, Card, Forms, React, showToast, TabBar, TextArea, useEffect, useRef, useState } from "@webpack/common";
|
||||||
|
|
@ -52,62 +52,6 @@ const FileInput: FileInput = findLazy(m => m.prototype?.activateUploadDialogue &
|
||||||
|
|
||||||
const cl = classNameFactory("vc-settings-theme-");
|
const cl = classNameFactory("vc-settings-theme-");
|
||||||
|
|
||||||
function Validator({ link }: { link: string; }) {
|
|
||||||
const [res, err, pending] = useAwaiter(() => fetch(link).then(res => {
|
|
||||||
if (res.status > 300) throw `${res.status} ${res.statusText}`;
|
|
||||||
const contentType = res.headers.get("Content-Type");
|
|
||||||
if (!contentType?.startsWith("text/css") && !contentType?.startsWith("text/plain"))
|
|
||||||
throw "Not a CSS file. Remember to use the raw link!";
|
|
||||||
|
|
||||||
return "Okay!";
|
|
||||||
}));
|
|
||||||
|
|
||||||
const text = pending
|
|
||||||
? "Checking..."
|
|
||||||
: err
|
|
||||||
? `Error: ${err instanceof Error ? err.message : String(err)}`
|
|
||||||
: "Valid!";
|
|
||||||
|
|
||||||
return <Forms.FormText style={{
|
|
||||||
color: pending ? "var(--text-muted)" : err ? "var(--text-danger)" : "var(--status-positive)"
|
|
||||||
}}>{text}</Forms.FormText>;
|
|
||||||
}
|
|
||||||
|
|
||||||
function Validators({ themeLinks }: { themeLinks: string[]; }) {
|
|
||||||
if (!themeLinks.length) return null;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<Forms.FormTitle className={Margins.top20} tag="h5">Validator</Forms.FormTitle>
|
|
||||||
<Forms.FormText>This section will tell you whether your themes can successfully be loaded</Forms.FormText>
|
|
||||||
<div>
|
|
||||||
{themeLinks.map(rawLink => {
|
|
||||||
const { label, link } = (() => {
|
|
||||||
const match = /^@(light|dark) (.*)/.exec(rawLink);
|
|
||||||
if (!match) return { label: rawLink, link: rawLink };
|
|
||||||
|
|
||||||
const [, mode, link] = match;
|
|
||||||
return { label: `[${mode} mode only] ${link}`, link };
|
|
||||||
})();
|
|
||||||
|
|
||||||
return <Card style={{
|
|
||||||
padding: ".5em",
|
|
||||||
marginBottom: ".5em",
|
|
||||||
marginTop: ".5em"
|
|
||||||
}} key={link}>
|
|
||||||
<Forms.FormTitle tag="h5" style={{
|
|
||||||
overflowWrap: "break-word"
|
|
||||||
}}>
|
|
||||||
{label}
|
|
||||||
</Forms.FormTitle>
|
|
||||||
<Validator link={link} />
|
|
||||||
</Card>;
|
|
||||||
})}
|
|
||||||
</div>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
interface ThemeCardProps {
|
interface ThemeCardProps {
|
||||||
theme: UserThemeHeader;
|
theme: UserThemeHeader;
|
||||||
enabled: boolean;
|
enabled: boolean;
|
||||||
|
|
@ -309,7 +253,13 @@ function ThemesTab() {
|
||||||
function renderOnlineThemes() {
|
function renderOnlineThemes() {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Card className="vc-settings-card vc-text-selectable">
|
<Card className={classes("vc-warning-card", Margins.bottom16)}>
|
||||||
|
<Forms.FormText>
|
||||||
|
This section is for advanced users. If you are having difficulties using it, use the
|
||||||
|
Local Themes tab instead.
|
||||||
|
</Forms.FormText>
|
||||||
|
</Card>
|
||||||
|
<Card className="vc-settings-card">
|
||||||
<Forms.FormTitle tag="h5">Paste links to css files here</Forms.FormTitle>
|
<Forms.FormTitle tag="h5">Paste links to css files here</Forms.FormTitle>
|
||||||
<Forms.FormText>One link per line</Forms.FormText>
|
<Forms.FormText>One link per line</Forms.FormText>
|
||||||
<Forms.FormText>You can prefix lines with @light or @dark to toggle them based on your Discord theme</Forms.FormText>
|
<Forms.FormText>You can prefix lines with @light or @dark to toggle them based on your Discord theme</Forms.FormText>
|
||||||
|
|
@ -321,12 +271,11 @@ function ThemesTab() {
|
||||||
value={themeText}
|
value={themeText}
|
||||||
onChange={setThemeText}
|
onChange={setThemeText}
|
||||||
className={"vc-settings-theme-links"}
|
className={"vc-settings-theme-links"}
|
||||||
placeholder="Theme Links"
|
placeholder="Enter Theme Links..."
|
||||||
spellCheck={false}
|
spellCheck={false}
|
||||||
onBlur={onBlur}
|
onBlur={onBlur}
|
||||||
rows={10}
|
rows={10}
|
||||||
/>
|
/>
|
||||||
<Validators themeLinks={settings.themeLinks} />
|
|
||||||
</Forms.FormSection>
|
</Forms.FormSection>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -225,7 +225,7 @@ function Updater() {
|
||||||
|
|
||||||
<Forms.FormTitle tag="h5">Repo</Forms.FormTitle>
|
<Forms.FormTitle tag="h5">Repo</Forms.FormTitle>
|
||||||
|
|
||||||
<Forms.FormText className="vc-text-selectable">
|
<Forms.FormText>
|
||||||
{repoPending
|
{repoPending
|
||||||
? repo
|
? repo
|
||||||
: err
|
: err
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
.vc-settings-tab-bar {
|
.vc-settings-tab-bar {
|
||||||
margin-top: 20px;
|
margin-top: 20px;
|
||||||
margin-bottom: 10px;
|
margin-bottom: 10px;
|
||||||
border-bottom: 2px solid var(--background-modifier-accent);
|
border-bottom: 1px solid var(--border-subtle);
|
||||||
}
|
}
|
||||||
|
|
||||||
.vc-settings-tab-bar-item {
|
.vc-settings-tab-bar-item {
|
||||||
|
|
@ -20,6 +20,13 @@
|
||||||
margin-bottom: 1em;
|
margin-bottom: 1em;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.vc-warning-card {
|
||||||
|
padding: 1em;
|
||||||
|
background: var(--info-warning-background);
|
||||||
|
border: 1px solid var(--info-warning-foreground);
|
||||||
|
color: var(--info-warning-foreground);
|
||||||
|
}
|
||||||
|
|
||||||
.vc-backup-restore-card {
|
.vc-backup-restore-card {
|
||||||
background-color: var(--info-warning-background);
|
background-color: var(--info-warning-background);
|
||||||
border-color: var(--info-warning-foreground);
|
border-color: var(--info-warning-foreground);
|
||||||
|
|
@ -30,19 +37,20 @@
|
||||||
/* Needed to fix bad themes that hide certain textarea elements for whatever eldritch reason */
|
/* Needed to fix bad themes that hide certain textarea elements for whatever eldritch reason */
|
||||||
display: inline-block !important;
|
display: inline-block !important;
|
||||||
color: var(--text-default) !important;
|
color: var(--text-default) !important;
|
||||||
padding: 0.5em;
|
padding: 0.5em 1em;
|
||||||
border: 1px solid var(--background-modifier-accent);
|
border: 1px solid var(--input-border);
|
||||||
max-height: unset;
|
max-height: unset;
|
||||||
background-color: transparent;
|
background-color: transparent;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
font-size: 12px;
|
|
||||||
line-height: 14px;
|
|
||||||
resize: none;
|
resize: none;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
font-size: 1em;
|
||||||
|
line-height: 2em;
|
||||||
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
.vc-settings-theme-links::placeholder {
|
.vc-settings-theme-links::placeholder {
|
||||||
color: var(--header-secondary);
|
color: var(--text-muted) !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.vc-settings-theme-links:focus {
|
.vc-settings-theme-links:focus {
|
||||||
|
|
@ -60,15 +68,6 @@
|
||||||
background-color: var(--button-danger-background);
|
background-color: var(--button-danger-background);
|
||||||
}
|
}
|
||||||
|
|
||||||
.vc-text-selectable,
|
|
||||||
.vc-text-selectable :where([class*="text" i], [class*="title" i]) {
|
|
||||||
/* make text selectable, silly discord makes the entirety of settings not selectable */
|
|
||||||
user-select: text;
|
|
||||||
|
|
||||||
/* discord also sets cursor: default which prevents the cursor from showing as text */
|
|
||||||
cursor: initial;
|
|
||||||
}
|
|
||||||
|
|
||||||
.vc-updater-modal {
|
.vc-updater-modal {
|
||||||
padding: 1.5em !important;
|
padding: 1.5em !important;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -12,11 +12,6 @@
|
||||||
position: relative;
|
position: relative;
|
||||||
}
|
}
|
||||||
|
|
||||||
.vc-settings-card {
|
|
||||||
padding: 1em;
|
|
||||||
margin-bottom: 1em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.vc-special-card-special {
|
.vc-special-card-special {
|
||||||
padding: 1em 1.5em;
|
padding: 1em 1.5em;
|
||||||
margin-bottom: 1em;
|
margin-bottom: 1em;
|
||||||
|
|
|
||||||
|
|
@ -6,9 +6,10 @@
|
||||||
|
|
||||||
import { Logger } from "@utils/Logger";
|
import { Logger } from "@utils/Logger";
|
||||||
import { canonicalizeMatch } from "@utils/patches";
|
import { canonicalizeMatch } from "@utils/patches";
|
||||||
|
import { ModuleFactory } from "@vencord/discord-types/webpack";
|
||||||
import * as Webpack from "@webpack";
|
import * as Webpack from "@webpack";
|
||||||
import { wreq } from "@webpack";
|
import { wreq } from "@webpack";
|
||||||
import { AnyModuleFactory, ModuleFactory } from "@webpack/wreq.d";
|
import { AnyModuleFactory } from "webpack";
|
||||||
|
|
||||||
export async function loadLazyChunks() {
|
export async function loadLazyChunks() {
|
||||||
const LazyChunkLoaderLogger = new Logger("LazyChunkLoader");
|
const LazyChunkLoaderLogger = new Logger("LazyChunkLoader");
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,7 @@ async function runReporter() {
|
||||||
}
|
}
|
||||||
}, "Vencord Reporter");
|
}, "Vencord Reporter");
|
||||||
|
|
||||||
// @ts-ignore
|
// @ts-expect-error
|
||||||
Vencord.Webpack._initReporter = function () {
|
Vencord.Webpack._initReporter = function () {
|
||||||
// initReporter is called in the patched entry point of Discord
|
// initReporter is called in the patched entry point of Discord
|
||||||
// setImmediate to only start searching for lazy chunks after Discord initialized the app
|
// setImmediate to only start searching for lazy chunks after Discord initialized the app
|
||||||
|
|
@ -83,7 +83,6 @@ async function runReporter() {
|
||||||
result = Webpack.mapMangledModule(code, mapper, includeBlacklistedExports);
|
result = Webpack.mapMangledModule(code, mapper, includeBlacklistedExports);
|
||||||
if (Object.keys(result).length !== Object.keys(mapper).length) throw new Error("Webpack Find Fail");
|
if (Object.keys(result).length !== Object.keys(mapper).length) throw new Error("Webpack Find Fail");
|
||||||
} else {
|
} else {
|
||||||
// @ts-ignore
|
|
||||||
result = Webpack[method](...args);
|
result = Webpack[method](...args);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -63,6 +63,9 @@ export const CspPolicies: PolicyMap = {
|
||||||
"dearrow-thumb.ajay.app": ImageSrc, // Dearrow Thumbnail CDN
|
"dearrow-thumb.ajay.app": ImageSrc, // Dearrow Thumbnail CDN
|
||||||
"usrbg.is-hardly.online": ImageSrc, // USRBG API
|
"usrbg.is-hardly.online": ImageSrc, // USRBG API
|
||||||
"icons.duckduckgo.com": ImageSrc, // DuckDuckGo Favicon API (Reverse Image Search)
|
"icons.duckduckgo.com": ImageSrc, // DuckDuckGo Favicon API (Reverse Image Search)
|
||||||
|
|
||||||
|
// forked addition
|
||||||
|
"*.dorkbutt.lol": ImageAndCssSrc,
|
||||||
};
|
};
|
||||||
|
|
||||||
const findHeader = (headers: PolicyMap, headerName: Lowercase<string>) => {
|
const findHeader = (headers: PolicyMap, headerName: Lowercase<string>) => {
|
||||||
|
|
|
||||||
|
|
@ -38,7 +38,7 @@ const asarPath = join(dirname(injectorPath), "..", asarName);
|
||||||
const discordPkg = require(join(asarPath, "package.json"));
|
const discordPkg = require(join(asarPath, "package.json"));
|
||||||
require.main!.filename = join(asarPath, discordPkg.main);
|
require.main!.filename = join(asarPath, discordPkg.main);
|
||||||
|
|
||||||
// @ts-ignore Untyped method? Dies from cringe
|
// @ts-expect-error Untyped method? Dies from cringe
|
||||||
app.setAppPath(asarPath);
|
app.setAppPath(asarPath);
|
||||||
|
|
||||||
if (!IS_VANILLA) {
|
if (!IS_VANILLA) {
|
||||||
|
|
|
||||||
|
|
@ -30,8 +30,8 @@ import { Margins } from "@utils/margins";
|
||||||
import { shouldShowContributorBadge } from "@utils/misc";
|
import { shouldShowContributorBadge } from "@utils/misc";
|
||||||
import { closeModal, ModalContent, ModalFooter, ModalHeader, ModalRoot, openModal } from "@utils/modal";
|
import { closeModal, ModalContent, ModalFooter, ModalHeader, ModalRoot, openModal } from "@utils/modal";
|
||||||
import definePlugin from "@utils/types";
|
import definePlugin from "@utils/types";
|
||||||
|
import { User } from "@vencord/discord-types";
|
||||||
import { Forms, Toasts, UserStore } from "@webpack/common";
|
import { Forms, Toasts, UserStore } from "@webpack/common";
|
||||||
import { User } from "discord-types/general";
|
|
||||||
|
|
||||||
const CONTRIBUTOR_BADGE = "https://cdn.discordapp.com/emojis/1092089799109775453.png?size=64";
|
const CONTRIBUTOR_BADGE = "https://cdn.discordapp.com/emojis/1092089799109775453.png?size=64";
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -27,7 +27,7 @@ export default definePlugin({
|
||||||
{
|
{
|
||||||
find: "#{intl::MESSAGE_UTILITIES_A11Y_LABEL}",
|
find: "#{intl::MESSAGE_UTILITIES_A11Y_LABEL}",
|
||||||
replacement: {
|
replacement: {
|
||||||
match: /(?<=:null),(.{0,40}togglePopout:.+?}\)),(.+?)\]}\):null,(?<=\((\i\.\i),{label:.+?children:\[(\i&&!\i)\?\(0,\i\.jsxs?\)\(\i\.Fragment.+?message:(\i).+?)/,
|
match: /(?<=:null),(.{0,40}togglePopout:.+?}\)),(.+?)\]}\):null,(?<=\((\i\.\i),{label:.+?:null,(\i)\?\(0,\i\.jsxs?\)\(\i\.Fragment.+?message:(\i).+?)/,
|
||||||
replace: (_, ReactButton, PotionButton, ButtonComponent, showReactButton, message) => "" +
|
replace: (_, ReactButton, PotionButton, ButtonComponent, showReactButton, message) => "" +
|
||||||
`]}):null,Vencord.Api.MessagePopover._buildPopoverElements(${ButtonComponent},${message}),${showReactButton}?${ReactButton}:null,${showReactButton}&&${PotionButton},`
|
`]}):null,Vencord.Api.MessagePopover._buildPopoverElements(${ButtonComponent},${message}),${showReactButton}?${ReactButton}:null,${showReactButton}&&${PotionButton},`
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,7 @@ import { definePluginSettings } from "@api/Settings";
|
||||||
import { Devs } from "@utils/constants";
|
import { Devs } from "@utils/constants";
|
||||||
import { Logger } from "@utils/Logger";
|
import { Logger } from "@utils/Logger";
|
||||||
import definePlugin, { OptionType, StartAt } from "@utils/types";
|
import definePlugin, { OptionType, StartAt } from "@utils/types";
|
||||||
import { WebpackRequire } from "@webpack/wreq.d";
|
import { WebpackRequire } from "@vencord/discord-types/webpack";
|
||||||
|
|
||||||
const settings = definePluginSettings({
|
const settings = definePluginSettings({
|
||||||
disableAnalytics: {
|
disableAnalytics: {
|
||||||
|
|
|
||||||
|
|
@ -213,7 +213,7 @@ export default definePlugin({
|
||||||
get chromiumVersion() {
|
get chromiumVersion() {
|
||||||
try {
|
try {
|
||||||
return VencordNative.native.getVersions().chrome
|
return VencordNative.native.getVersions().chrome
|
||||||
// @ts-ignore Typescript will add userAgentData IMMEDIATELY
|
// @ts-expect-error Typescript will add userAgentData IMMEDIATELY
|
||||||
|| navigator.userAgentData?.brands?.find(b => b.brand === "Chromium" || b.brand === "Google Chrome")?.version
|
|| navigator.userAgentData?.brands?.find(b => b.brand === "Chromium" || b.brand === "Google Chrome")?.version
|
||||||
|| null;
|
|| null;
|
||||||
} catch { // inb4 some stupid browser throws unsupported error for navigator.userAgentData, it's only in chromium
|
} catch { // inb4 some stupid browser throws unsupported error for navigator.userAgentData, it's only in chromium
|
||||||
|
|
|
||||||
|
|
@ -32,8 +32,8 @@ import { onlyOnce } from "@utils/onlyOnce";
|
||||||
import { makeCodeblock } from "@utils/text";
|
import { makeCodeblock } from "@utils/text";
|
||||||
import definePlugin from "@utils/types";
|
import definePlugin from "@utils/types";
|
||||||
import { checkForUpdates, isOutdated, update } from "@utils/updater";
|
import { checkForUpdates, isOutdated, update } from "@utils/updater";
|
||||||
|
import { Channel } from "@vencord/discord-types";
|
||||||
import { Alerts, Button, Card, ChannelStore, Forms, GuildMemberStore, Parser, PermissionsBits, PermissionStore, RelationshipStore, showToast, Text, Toasts, UserStore } from "@webpack/common";
|
import { Alerts, Button, Card, ChannelStore, Forms, GuildMemberStore, Parser, PermissionsBits, PermissionStore, RelationshipStore, showToast, Text, Toasts, UserStore } from "@webpack/common";
|
||||||
import { Channel } from "discord-types/general";
|
|
||||||
import { JSX } from "react";
|
import { JSX } from "react";
|
||||||
|
|
||||||
import gitHash from "~git-hash";
|
import gitHash from "~git-hash";
|
||||||
|
|
@ -196,7 +196,6 @@ export default definePlugin({
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// @ts-ignore outdated type
|
|
||||||
const roles = GuildMemberStore.getSelfMember(VENCORD_GUILD_ID)?.roles;
|
const roles = GuildMemberStore.getSelfMember(VENCORD_GUILD_ID)?.roles;
|
||||||
if (!roles || TrustedRolesIds.some(id => roles.includes(id))) return;
|
if (!roles || TrustedRolesIds.some(id => roles.includes(id))) return;
|
||||||
|
|
||||||
|
|
@ -319,7 +318,7 @@ export default definePlugin({
|
||||||
if (RelationshipStore.isFriend(userId) || isPluginDev(UserStore.getCurrentUser()?.id)) return null;
|
if (RelationshipStore.isFriend(userId) || isPluginDev(UserStore.getCurrentUser()?.id)) return null;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Card className={`vc-plugins-restart-card ${Margins.top8}`}>
|
<Card className={`vc-warning-card ${Margins.top8}`}>
|
||||||
Please do not private message Vencord plugin developers for support!
|
Please do not private message Vencord plugin developers for support!
|
||||||
<br />
|
<br />
|
||||||
Instead, use the Vencord support channel: {Parser.parse("https://discord.com/channels/1015060230222131221/1026515880080842772")}
|
Instead, use the Vencord support channel: {Parser.parse("https://discord.com/channels/1015060230222131221/1026515880080842772")}
|
||||||
|
|
|
||||||
|
|
@ -9,9 +9,9 @@ import ErrorBoundary from "@components/ErrorBoundary";
|
||||||
import { Devs } from "@utils/constants";
|
import { Devs } from "@utils/constants";
|
||||||
import { getCurrentChannel } from "@utils/discord";
|
import { getCurrentChannel } from "@utils/discord";
|
||||||
import definePlugin, { OptionType } from "@utils/types";
|
import definePlugin, { OptionType } from "@utils/types";
|
||||||
|
import { User } from "@vencord/discord-types";
|
||||||
import { findComponentByCodeLazy } from "@webpack";
|
import { findComponentByCodeLazy } from "@webpack";
|
||||||
import { ContextMenuApi, Menu, useEffect, useRef } from "@webpack/common";
|
import { ContextMenuApi, Menu, useEffect, useRef } from "@webpack/common";
|
||||||
import { User } from "discord-types/general";
|
|
||||||
|
|
||||||
interface UserProfileProps {
|
interface UserProfileProps {
|
||||||
popoutProps: Record<string, any>;
|
popoutProps: Record<string, any>;
|
||||||
|
|
|
||||||
|
|
@ -21,8 +21,8 @@ import { ScreenshareIcon } from "@components/Icons";
|
||||||
import { Devs } from "@utils/constants";
|
import { Devs } from "@utils/constants";
|
||||||
import { openImageModal } from "@utils/discord";
|
import { openImageModal } from "@utils/discord";
|
||||||
import definePlugin from "@utils/types";
|
import definePlugin from "@utils/types";
|
||||||
|
import { Channel, User } from "@vencord/discord-types";
|
||||||
import { Menu } from "@webpack/common";
|
import { Menu } from "@webpack/common";
|
||||||
import { Channel, User } from "discord-types/general";
|
|
||||||
|
|
||||||
import { ApplicationStreamingStore, ApplicationStreamPreviewStore } from "./webpack/stores";
|
import { ApplicationStreamingStore, ApplicationStreamPreviewStore } from "./webpack/stores";
|
||||||
import { ApplicationStream, Stream } from "./webpack/types/stores";
|
import { ApplicationStream, Stream } from "./webpack/types/stores";
|
||||||
|
|
|
||||||
|
|
@ -16,7 +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 { FluxStore } from "@webpack/types";
|
import { FluxStore } from "@vencord/discord-types";
|
||||||
|
|
||||||
export interface ApplicationStreamPreviewStore extends FluxStore {
|
export interface ApplicationStreamPreviewStore extends FluxStore {
|
||||||
getIsPreviewLoading: (guildId: string | bigint | null, channelId: string | bigint, ownerId: string | bigint) => boolean;
|
getIsPreviewLoading: (guildId: string | bigint | null, channelId: string | bigint, ownerId: string | bigint) => boolean;
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.vc-clientTheme-container [class^="swatch"] {
|
.vc-clientTheme-container [class^="swatch"] {
|
||||||
border: thin solid var(--background-modifier-accent) !important;
|
border: thin solid var(--input-border) !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.vc-clientTheme-buttons-container {
|
.vc-clientTheme-buttons-container {
|
||||||
|
|
|
||||||
|
|
@ -21,8 +21,8 @@ import { LinkIcon } from "@components/Icons";
|
||||||
import { copyToClipboard } from "@utils/clipboard";
|
import { copyToClipboard } from "@utils/clipboard";
|
||||||
import { Devs } from "@utils/constants";
|
import { Devs } from "@utils/constants";
|
||||||
import definePlugin from "@utils/types";
|
import definePlugin from "@utils/types";
|
||||||
|
import type { Channel, User } from "@vencord/discord-types";
|
||||||
import { Menu } from "@webpack/common";
|
import { Menu } from "@webpack/common";
|
||||||
import type { Channel, User } from "discord-types/general";
|
|
||||||
|
|
||||||
interface UserContextProps {
|
interface UserContextProps {
|
||||||
channel: Channel;
|
channel: Channel;
|
||||||
|
|
|
||||||
|
|
@ -6,8 +6,8 @@
|
||||||
|
|
||||||
import { debounce } from "@shared/debounce";
|
import { debounce } from "@shared/debounce";
|
||||||
import { proxyLazy } from "@utils/lazy";
|
import { proxyLazy } from "@utils/lazy";
|
||||||
|
import { User } from "@vencord/discord-types";
|
||||||
import { useEffect, useState, zustandCreate } from "@webpack/common";
|
import { useEffect, useState, zustandCreate } from "@webpack/common";
|
||||||
import { User } from "discord-types/general";
|
|
||||||
|
|
||||||
import { AvatarDecoration } from "../../";
|
import { AvatarDecoration } from "../../";
|
||||||
import { getUsersDecorations } from "../api";
|
import { getUsersDecorations } from "../api";
|
||||||
|
|
|
||||||
|
|
@ -11,9 +11,9 @@ import { Margins } from "@utils/margins";
|
||||||
import { classes, copyWithToast } from "@utils/misc";
|
import { classes, copyWithToast } from "@utils/misc";
|
||||||
import { closeAllModals, ModalCloseButton, ModalContent, ModalFooter, ModalHeader, ModalProps, ModalRoot, ModalSize, openModal } from "@utils/modal";
|
import { closeAllModals, ModalCloseButton, ModalContent, ModalFooter, ModalHeader, ModalProps, ModalRoot, ModalSize, openModal } from "@utils/modal";
|
||||||
import { Queue } from "@utils/Queue";
|
import { Queue } from "@utils/Queue";
|
||||||
|
import { User } from "@vencord/discord-types";
|
||||||
import { findComponentByCodeLazy } from "@webpack";
|
import { findComponentByCodeLazy } from "@webpack";
|
||||||
import { Alerts, Button, FluxDispatcher, Forms, GuildStore, NavigationRouter, Parser, Text, Tooltip, useEffect, UserStore, UserUtils, useState } from "@webpack/common";
|
import { Alerts, Button, FluxDispatcher, Forms, GuildStore, NavigationRouter, Parser, Text, Tooltip, useEffect, UserStore, UserUtils, useState } from "@webpack/common";
|
||||||
import { User } from "discord-types/general";
|
|
||||||
|
|
||||||
import { Decoration, getPresets, Preset } from "../../lib/api";
|
import { Decoration, getPresets, Preset } from "../../lib/api";
|
||||||
import { GUILD_ID, INVITE_KEY } from "../../lib/constants";
|
import { GUILD_ID, INVITE_KEY } from "../../lib/constants";
|
||||||
|
|
|
||||||
|
|
@ -68,8 +68,8 @@ export default definePlugin({
|
||||||
{
|
{
|
||||||
find: 'type:"user",revision',
|
find: 'type:"user",revision',
|
||||||
replacement: {
|
replacement: {
|
||||||
match: /!(\i)&&"CONNECTION_OPEN".+?;/g,
|
match: /!(\i)(?=&&"CONNECTION_OPEN")/,
|
||||||
replace: "$1=!0;"
|
replace: "!($1=true)"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -116,11 +116,19 @@ export default definePlugin({
|
||||||
},
|
},
|
||||||
// Fix some tricky experiments name causing a client crash
|
// Fix some tricky experiments name causing a client crash
|
||||||
{
|
{
|
||||||
match: /.getRegisteredExperiments\(\)(?<=(\i)=.+?).+?if\(null==(\i)(?=\)return null;)/,
|
match: /.getExperimentBucketName.+?if\(null==(\i)\|\|null==\i(?=\)return null;)/,
|
||||||
replace: "$&||!Object.hasOwn($1,$2)"
|
replace: "$&||({})[$1]!=null"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
// Fix another function which cases crashes with tricky experiment names and the experiment embed
|
||||||
|
{
|
||||||
|
find: "}getServerAssignment(",
|
||||||
|
replacement: {
|
||||||
|
match: /}getServerAssignment\((\i),\i,\i\){/,
|
||||||
|
replace: "$&if($1==null)return;"
|
||||||
|
}
|
||||||
|
}
|
||||||
],
|
],
|
||||||
|
|
||||||
start: () => !BugReporterExperiment.getCurrentConfig().hasBugReporterAccess && enableStyle(hideBugReport),
|
start: () => !BugReporterExperiment.getCurrentConfig().hasBugReporterAccess && enableStyle(hideBugReport),
|
||||||
|
|
|
||||||
|
|
@ -20,13 +20,14 @@ import { findGroupChildrenByChildId, NavContextMenuPatchCallback } from "@api/Co
|
||||||
import { migratePluginSettings } from "@api/Settings";
|
import { migratePluginSettings } from "@api/Settings";
|
||||||
import { CheckedTextInput } from "@components/CheckedTextInput";
|
import { CheckedTextInput } from "@components/CheckedTextInput";
|
||||||
import { Devs } from "@utils/constants";
|
import { Devs } from "@utils/constants";
|
||||||
|
import { getGuildAcronym } from "@utils/discord";
|
||||||
import { Logger } from "@utils/Logger";
|
import { Logger } from "@utils/Logger";
|
||||||
import { Margins } from "@utils/margins";
|
import { Margins } from "@utils/margins";
|
||||||
import { ModalContent, ModalHeader, ModalRoot, openModalLazy } from "@utils/modal";
|
import { ModalContent, ModalHeader, ModalRoot, openModalLazy } from "@utils/modal";
|
||||||
import definePlugin from "@utils/types";
|
import definePlugin from "@utils/types";
|
||||||
|
import { Guild } from "@vencord/discord-types";
|
||||||
import { findByCodeLazy, findStoreLazy } from "@webpack";
|
import { findByCodeLazy, findStoreLazy } from "@webpack";
|
||||||
import { Constants, EmojiStore, FluxDispatcher, Forms, GuildStore, Menu, PermissionsBits, PermissionStore, React, RestAPI, Toasts, Tooltip, UserStore } from "@webpack/common";
|
import { Constants, EmojiStore, FluxDispatcher, Forms, GuildStore, IconUtils, Menu, PermissionsBits, PermissionStore, React, RestAPI, Toasts, Tooltip, UserStore } from "@webpack/common";
|
||||||
import { Guild } from "discord-types/general";
|
|
||||||
import { Promisable } from "type-fest";
|
import { Promisable } from "type-fest";
|
||||||
|
|
||||||
const StickersStore = findStoreLazy("StickersStore");
|
const StickersStore = findStoreLazy("StickersStore");
|
||||||
|
|
@ -250,13 +251,18 @@ function CloneModal({ data }: { data: Sticker | Emoji; }) {
|
||||||
width: "100%",
|
width: "100%",
|
||||||
height: "100%",
|
height: "100%",
|
||||||
}}
|
}}
|
||||||
src={g.getIconURL(512, true)}
|
src={IconUtils.getGuildIconURL({
|
||||||
|
id: g.id,
|
||||||
|
icon: g.icon,
|
||||||
|
canAnimate: true,
|
||||||
|
size: 512
|
||||||
|
})}
|
||||||
alt={g.name}
|
alt={g.name}
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<Forms.FormText
|
<Forms.FormText
|
||||||
style={{
|
style={{
|
||||||
fontSize: getFontSize(g.acronym),
|
fontSize: getFontSize(getGuildAcronym(g)),
|
||||||
width: "100%",
|
width: "100%",
|
||||||
overflow: "hidden",
|
overflow: "hidden",
|
||||||
whiteSpace: "nowrap",
|
whiteSpace: "nowrap",
|
||||||
|
|
@ -264,7 +270,7 @@ function CloneModal({ data }: { data: Sticker | Emoji; }) {
|
||||||
cursor: isCloning ? "not-allowed" : "pointer",
|
cursor: isCloning ? "not-allowed" : "pointer",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{g.acronym}
|
{getGuildAcronym(g)}
|
||||||
</Forms.FormText>
|
</Forms.FormText>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -23,10 +23,9 @@ import { ApngBlendOp, ApngDisposeOp, importApngJs } from "@utils/dependencies";
|
||||||
import { getCurrentGuild, getEmojiURL } from "@utils/discord";
|
import { getCurrentGuild, getEmojiURL } from "@utils/discord";
|
||||||
import { Logger } from "@utils/Logger";
|
import { Logger } from "@utils/Logger";
|
||||||
import definePlugin, { OptionType, Patch } from "@utils/types";
|
import definePlugin, { OptionType, Patch } from "@utils/types";
|
||||||
|
import type { Emoji, Message } from "@vencord/discord-types";
|
||||||
import { findByCodeLazy, findByPropsLazy, findStoreLazy, proxyLazyWebpack } from "@webpack";
|
import { findByCodeLazy, findByPropsLazy, findStoreLazy, proxyLazyWebpack } from "@webpack";
|
||||||
import { Alerts, ChannelStore, DraftType, EmojiStore, FluxDispatcher, Forms, GuildMemberStore, lodash, Parser, PermissionsBits, PermissionStore, UploadHandler, UserSettingsActionCreators, UserStore } from "@webpack/common";
|
import { Alerts, ChannelStore, DraftType, EmojiStore, FluxDispatcher, Forms, GuildMemberStore, lodash, Parser, PermissionsBits, PermissionStore, UploadHandler, UserSettingsActionCreators, UserStore } from "@webpack/common";
|
||||||
import type { Emoji } from "@webpack/types";
|
|
||||||
import type { Message } from "discord-types/general";
|
|
||||||
import { applyPalette, GIFEncoder, quantize } from "gifenc";
|
import { applyPalette, GIFEncoder, quantize } from "gifenc";
|
||||||
import type { ReactElement, ReactNode } from "react";
|
import type { ReactElement, ReactNode } from "react";
|
||||||
|
|
||||||
|
|
@ -813,7 +812,6 @@ export default definePlugin({
|
||||||
|
|
||||||
let isUsableTwitchSubEmote = false;
|
let isUsableTwitchSubEmote = false;
|
||||||
if (e.managed && e.guildId) {
|
if (e.managed && e.guildId) {
|
||||||
// @ts-ignore outdated type
|
|
||||||
const myRoles = GuildMemberStore.getSelfMember(e.guildId)?.roles ?? [];
|
const myRoles = GuildMemberStore.getSelfMember(e.guildId)?.roles ?? [];
|
||||||
isUsableTwitchSubEmote = e.roles.some(r => myRoles.includes(r));
|
isUsableTwitchSubEmote = e.roles.some(r => myRoles.includes(r));
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -22,19 +22,16 @@ import "./index.css";
|
||||||
import { definePluginSettings } from "@api/Settings";
|
import { definePluginSettings } from "@api/Settings";
|
||||||
import ErrorBoundary from "@components/ErrorBoundary";
|
import ErrorBoundary from "@components/ErrorBoundary";
|
||||||
import { Devs } from "@utils/constants";
|
import { Devs } from "@utils/constants";
|
||||||
|
import { fetchUserProfile } from "@utils/discord";
|
||||||
import { Margins } from "@utils/margins";
|
import { Margins } from "@utils/margins";
|
||||||
import { classes, copyWithToast } from "@utils/misc";
|
import { classes, copyWithToast } from "@utils/misc";
|
||||||
|
import { useAwaiter } from "@utils/react";
|
||||||
import definePlugin, { OptionType } from "@utils/types";
|
import definePlugin, { OptionType } from "@utils/types";
|
||||||
|
import { User, UserProfile } from "@vencord/discord-types";
|
||||||
import { findComponentByCodeLazy } from "@webpack";
|
import { findComponentByCodeLazy } from "@webpack";
|
||||||
import { Button, ColorPicker, Flex, Forms, React, Text, UserProfileStore, UserStore, useState } from "@webpack/common";
|
import { Button, ColorPicker, Flex, Forms, React, Text, UserProfileStore, UserStore, useState } from "@webpack/common";
|
||||||
import { User } from "discord-types/general";
|
|
||||||
import { ReactElement } from "react";
|
|
||||||
import virtualMerge from "virtual-merge";
|
import virtualMerge from "virtual-merge";
|
||||||
|
|
||||||
interface UserProfile extends User {
|
|
||||||
themeColors?: Array<number>;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface Colors {
|
interface Colors {
|
||||||
primary: number;
|
primary: number;
|
||||||
accent: number;
|
accent: number;
|
||||||
|
|
@ -85,14 +82,6 @@ const settings = definePluginSettings({
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
interface ColorPickerProps {
|
|
||||||
color: number | null;
|
|
||||||
label: ReactElement<any>;
|
|
||||||
showEyeDropper?: boolean;
|
|
||||||
suggestedColors?: string[];
|
|
||||||
onChange(value: number | null): void;
|
|
||||||
}
|
|
||||||
|
|
||||||
// I can't be bothered to figure out the semantics of this component. The
|
// I can't be bothered to figure out the semantics of this component. The
|
||||||
// functions surely get some event argument sent to them and they likely aren't
|
// functions surely get some event argument sent to them and they likely aren't
|
||||||
// all required. If anyone who wants to use this component stumbles across this
|
// all required. If anyone who wants to use this component stumbles across this
|
||||||
|
|
@ -110,30 +99,15 @@ interface ProfileModalProps {
|
||||||
|
|
||||||
const ProfileModal = findComponentByCodeLazy<ProfileModalProps>("isTryItOutFlow:", "pendingThemeColors:", "pendingAvatarDecoration:", "EDIT_PROFILE_BANNER");
|
const ProfileModal = findComponentByCodeLazy<ProfileModalProps>("isTryItOutFlow:", "pendingThemeColors:", "pendingAvatarDecoration:", "EDIT_PROFILE_BANNER");
|
||||||
|
|
||||||
|
function SettingsAboutComponentWrapper() {
|
||||||
|
const [, , userProfileLoading] = useAwaiter(() => fetchUserProfile(UserStore.getCurrentUser().id));
|
||||||
|
|
||||||
export default definePlugin({
|
return !userProfileLoading && <SettingsAboutComponent />;
|
||||||
name: "FakeProfileThemes",
|
|
||||||
description: "Allows profile theming by hiding the colors in your bio thanks to invisible 3y3 encoding",
|
|
||||||
authors: [Devs.Alyxia, Devs.Remty],
|
|
||||||
patches: [
|
|
||||||
{
|
|
||||||
find: "UserProfileStore",
|
|
||||||
replacement: {
|
|
||||||
match: /(?<=getUserProfile\(\i\){return )(.+?)(?=})/,
|
|
||||||
replace: "$self.colorDecodeHook($1)"
|
|
||||||
}
|
}
|
||||||
},
|
|
||||||
{
|
function SettingsAboutComponent() {
|
||||||
find: "#{intl::USER_SETTINGS_RESET_PROFILE_THEME}",
|
|
||||||
replacement: {
|
|
||||||
match: /#{intl::USER_SETTINGS_RESET_PROFILE_THEME}\)}\)(?<=color:(\i),.{0,500}?color:(\i),.{0,500}?)/,
|
|
||||||
replace: "$&,$self.addCopy3y3Button({primary:$1,accent:$2})"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
settingsAboutComponent: () => {
|
|
||||||
const existingColors = decode(
|
const existingColors = decode(
|
||||||
UserProfileStore.getUserProfile(UserStore.getCurrentUser().id).bio
|
UserProfileStore.getUserProfile(UserStore.getCurrentUser().id)?.bio ?? ""
|
||||||
) ?? [0, 0];
|
) ?? [0, 0];
|
||||||
const [color1, setColor1] = useState(existingColors[0]);
|
const [color1, setColor1] = useState(existingColors[0]);
|
||||||
const [color2, setColor2] = useState(existingColors[1]);
|
const [color2, setColor2] = useState(existingColors[1]);
|
||||||
|
|
@ -218,10 +192,34 @@ export default definePlugin({
|
||||||
</div>
|
</div>
|
||||||
</Forms.FormText>
|
</Forms.FormText>
|
||||||
</Forms.FormSection>);
|
</Forms.FormSection>);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default definePlugin({
|
||||||
|
name: "FakeProfileThemes",
|
||||||
|
description: "Allows profile theming by hiding the colors in your bio thanks to invisible 3y3 encoding",
|
||||||
|
authors: [Devs.Alyxia, Devs.Remty],
|
||||||
|
patches: [
|
||||||
|
{
|
||||||
|
find: "UserProfileStore",
|
||||||
|
replacement: {
|
||||||
|
match: /(?<=getUserProfile\(\i\){return )(.+?)(?=})/,
|
||||||
|
replace: "$self.colorDecodeHook($1)"
|
||||||
},
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
find: "#{intl::USER_SETTINGS_RESET_PROFILE_THEME}",
|
||||||
|
replacement: {
|
||||||
|
match: /#{intl::USER_SETTINGS_RESET_PROFILE_THEME}\).+?}\)(?=\])(?<=color:(\i),.{0,500}?color:(\i),.{0,500}?)/,
|
||||||
|
replace: "$&,$self.addCopy3y3Button({primary:$1,accent:$2})"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
|
||||||
|
settingsAboutComponent: SettingsAboutComponentWrapper,
|
||||||
|
|
||||||
settings,
|
settings,
|
||||||
colorDecodeHook(user: UserProfile) {
|
colorDecodeHook(user: UserProfile) {
|
||||||
if (user) {
|
if (user?.bio) {
|
||||||
// don't replace colors if already set with nitro
|
// don't replace colors if already set with nitro
|
||||||
if (settings.store.nitroFirst && user.themeColors) return user;
|
if (settings.store.nitroFirst && user.themeColors) return user;
|
||||||
const colors = decode(user.bio);
|
const colors = decode(user.bio);
|
||||||
|
|
|
||||||
|
|
@ -18,8 +18,8 @@
|
||||||
|
|
||||||
import { Devs } from "@utils/constants";
|
import { Devs } from "@utils/constants";
|
||||||
import definePlugin from "@utils/types";
|
import definePlugin from "@utils/types";
|
||||||
|
import { Emoji } from "@vencord/discord-types";
|
||||||
import { EmojiStore } from "@webpack/common";
|
import { EmojiStore } from "@webpack/common";
|
||||||
import { Emoji } from "@webpack/types";
|
|
||||||
|
|
||||||
interface EmojiAutocompleteState {
|
interface EmojiAutocompleteState {
|
||||||
query?: {
|
query?: {
|
||||||
|
|
|
||||||
|
|
@ -18,8 +18,8 @@
|
||||||
|
|
||||||
import { Devs } from "@utils/constants";
|
import { Devs } from "@utils/constants";
|
||||||
import definePlugin from "@utils/types";
|
import definePlugin from "@utils/types";
|
||||||
|
import { Channel, User } from "@vencord/discord-types";
|
||||||
import { GuildStore } from "@webpack/common";
|
import { GuildStore } from "@webpack/common";
|
||||||
import { Channel, User } from "discord-types/general";
|
|
||||||
|
|
||||||
export default definePlugin({
|
export default definePlugin({
|
||||||
name: "ForceOwnerCrown",
|
name: "ForceOwnerCrown",
|
||||||
|
|
|
||||||
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