Compare commits
16 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
7e8397a4da | ||
|
555cf64080 | ||
|
2039e10fd5 | ||
|
e8d90d2b45 | ||
|
55af40ee74 | ||
|
a1fabcdf0a | ||
|
eaeb60308e | ||
|
662c0227eb | ||
|
543fdf4943 | ||
|
1225383723 | ||
|
07a9adbce2 | ||
|
42d8211871 | ||
|
ab3e993274 | ||
|
386dfe363a | ||
|
a4191c9f6c | ||
|
f1349a2787 |
3
.github/workflows/codeberg-mirror.yml
vendored
3
.github/workflows/codeberg-mirror.yml
vendored
@ -1,4 +1,7 @@
|
||||
name: Sync to Codeberg
|
||||
concurrency:
|
||||
group: ${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
on:
|
||||
push:
|
||||
workflow_dispatch:
|
||||
|
@ -41,12 +41,5 @@
|
||||
"path": "modifyResponseHeaders.json"
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
"browser_specific_settings": {
|
||||
"gecko": {
|
||||
"id": "vencord-firefox@vendicated.dev",
|
||||
"strict_min_version": "109.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "vencord",
|
||||
"private": "true",
|
||||
"version": "1.2.7",
|
||||
"version": "1.2.8",
|
||||
"description": "The cutest Discord client mod",
|
||||
"homepage": "https://github.com/Vendicated/Vencord#readme",
|
||||
"bugs": {
|
||||
@ -24,7 +24,7 @@
|
||||
"lint": "eslint . --ext .js,.jsx,.ts,.tsx --ignore-pattern src/userplugins",
|
||||
"lint-styles": "stylelint \"src/**/*.css\" --ignore-pattern src/userplugins",
|
||||
"lint:fix": "pnpm lint --fix",
|
||||
"test": "pnpm build && pnpm lint && pnpm lint-styles && pnpm testTsc",
|
||||
"test": "pnpm build && pnpm lint && pnpm lint-styles && pnpm testTsc && pnpm generatePluginJson",
|
||||
"testWeb": "pnpm lint && pnpm buildWeb && pnpm testTsc",
|
||||
"testTsc": "tsc --noEmit",
|
||||
"uninject": "node scripts/runInstaller.mjs",
|
||||
|
@ -19,11 +19,13 @@
|
||||
|
||||
import esbuild from "esbuild";
|
||||
|
||||
import { commonOpts, globPlugins, isStandalone, watch } from "./common.mjs";
|
||||
import { commonOpts, globPlugins, isStandalone, VERSION, watch } from "./common.mjs";
|
||||
|
||||
const defines = {
|
||||
IS_STANDALONE: isStandalone,
|
||||
IS_DEV: JSON.stringify(watch)
|
||||
IS_DEV: JSON.stringify(watch),
|
||||
VERSION: JSON.stringify(VERSION),
|
||||
BUILD_TIMESTAMP: Date.now(),
|
||||
};
|
||||
if (defines.IS_STANDALONE === "false")
|
||||
// If this is a local build (not standalone), optimise
|
||||
|
@ -24,9 +24,7 @@ import { readFileSync } from "fs";
|
||||
import { appendFile, mkdir, readFile, rm, writeFile } from "fs/promises";
|
||||
import { join } from "path";
|
||||
|
||||
// wtf is this assert syntax
|
||||
import PackageJSON from "../../package.json" assert { type: "json" };
|
||||
import { commonOpts, globPlugins, watch } from "./common.mjs";
|
||||
import { commonOpts, globPlugins, VERSION, watch } from "./common.mjs";
|
||||
|
||||
/**
|
||||
* @type {esbuild.BuildOptions}
|
||||
@ -47,7 +45,9 @@ const commonOptions = {
|
||||
IS_STANDALONE: "true",
|
||||
IS_DEV: JSON.stringify(watch),
|
||||
IS_DISCORD_DESKTOP: "false",
|
||||
IS_VENCORD_DESKTOP: "false"
|
||||
IS_VENCORD_DESKTOP: "false",
|
||||
VERSION: JSON.stringify(VERSION),
|
||||
BUILD_TIMESTAMP: Date.now(),
|
||||
}
|
||||
};
|
||||
|
||||
@ -67,7 +67,7 @@ await Promise.all(
|
||||
},
|
||||
outfile: "dist/Vencord.user.js",
|
||||
banner: {
|
||||
js: readFileSync("browser/userscript.meta.js", "utf-8").replace("%version%", `${PackageJSON.version}.${new Date().getTime()}`)
|
||||
js: readFileSync("browser/userscript.meta.js", "utf-8").replace("%version%", `${VERSION}.${new Date().getTime()}`)
|
||||
},
|
||||
footer: {
|
||||
// UserScripts get wrapped in an iife, so define Vencord prop on window that returns our local
|
||||
@ -88,7 +88,7 @@ async function buildPluginZip(target, files, shouldZip) {
|
||||
let content = await readFile(join("browser", f));
|
||||
if (f.startsWith("manifest")) {
|
||||
const json = JSON.parse(content.toString("utf-8"));
|
||||
json.version = PackageJSON.version;
|
||||
json.version = VERSION;
|
||||
content = new TextEncoder().encode(JSON.stringify(json));
|
||||
}
|
||||
|
||||
|
@ -16,6 +16,7 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import "../suppressExperimentalWarnings.js";
|
||||
import "../checkNodeVersion.js";
|
||||
|
||||
import { exec, execSync } from "child_process";
|
||||
@ -24,6 +25,11 @@ import { readdir, readFile } from "fs/promises";
|
||||
import { join, relative } from "path";
|
||||
import { promisify } from "util";
|
||||
|
||||
// wtf is this assert syntax
|
||||
import PackageJSON from "../../package.json" assert { type: "json" };
|
||||
|
||||
export const VERSION = PackageJSON.version;
|
||||
export const BUILD_TIMESTAMP = Date.now();
|
||||
export const watch = process.argv.includes("--watch");
|
||||
export const isStandalone = JSON.stringify(process.argv.includes("--standalone"));
|
||||
export const gitHash = execSync("git rev-parse --short HEAD", { encoding: "utf-8" }).trim();
|
||||
@ -64,7 +70,7 @@ export const globPlugins = kind => ({
|
||||
});
|
||||
|
||||
build.onLoad({ filter, namespace: "import-plugins" }, async () => {
|
||||
const pluginDirs = ["plugins", "userplugins"];
|
||||
const pluginDirs = ["plugins/_api", "plugins/_core", "plugins", "userplugins"];
|
||||
let code = "";
|
||||
let plugins = "\n";
|
||||
let i = 0;
|
||||
@ -72,8 +78,9 @@ export const globPlugins = kind => ({
|
||||
if (!existsSync(`./src/${dir}`)) continue;
|
||||
const files = await readdir(`./src/${dir}`);
|
||||
for (const file of files) {
|
||||
if (file.startsWith(".")) continue;
|
||||
if (file.startsWith("_") || file.startsWith(".")) continue;
|
||||
if (file === "index.ts") continue;
|
||||
|
||||
const fileBits = file.split(".");
|
||||
if (fileBits.length > 2 && ["ts", "tsx"].includes(fileBits.at(-1))) {
|
||||
const mod = fileBits.at(-2);
|
||||
|
@ -171,8 +171,8 @@ async function parseFile(fileName: string) {
|
||||
throw fail("no default export called 'definePlugin' found");
|
||||
}
|
||||
|
||||
async function getEntryPoint(dirent: Dirent) {
|
||||
const base = join("./src/plugins", dirent.name);
|
||||
async function getEntryPoint(dir: string, dirent: Dirent) {
|
||||
const base = join(dir, dirent.name);
|
||||
if (!dirent.isDirectory()) return base;
|
||||
|
||||
for (const name of ["index.ts", "index.tsx"]) {
|
||||
@ -186,13 +186,23 @@ async function getEntryPoint(dirent: Dirent) {
|
||||
throw new Error(`${dirent.name}: Couldn't find entry point`);
|
||||
}
|
||||
|
||||
function isPluginFile({ name }: { name: string; }) {
|
||||
if (name === "index.ts") return false;
|
||||
return !name.startsWith("_") && !name.startsWith(".");
|
||||
}
|
||||
|
||||
(async () => {
|
||||
parseDevs();
|
||||
const plugins = readdirSync("./src/plugins", { withFileTypes: true }).filter(d => d.name !== "index.ts");
|
||||
|
||||
const promises = plugins.map(async dirent => parseFile(await getEntryPoint(dirent)));
|
||||
const plugins = ["src/plugins", "src/plugins/_core"].flatMap(dir =>
|
||||
readdirSync(dir, { withFileTypes: true })
|
||||
.filter(isPluginFile)
|
||||
.map(async dirent =>
|
||||
parseFile(await getEntryPoint(dir, dirent))
|
||||
)
|
||||
);
|
||||
|
||||
const data = JSON.stringify(await Promise.all(promises));
|
||||
const data = JSON.stringify(await Promise.all(plugins));
|
||||
|
||||
if (process.argv.length > 2) {
|
||||
writeFileSync(process.argv[2], data);
|
||||
|
@ -22,7 +22,7 @@ import { ComponentType, HTMLProps } from "react";
|
||||
|
||||
import Plugins from "~plugins";
|
||||
|
||||
export enum BadgePosition {
|
||||
export const enum BadgePosition {
|
||||
START,
|
||||
END
|
||||
}
|
||||
@ -79,7 +79,7 @@ export function _getBadges(args: BadgeUserArgs) {
|
||||
: badges.push({ ...badge, ...args });
|
||||
}
|
||||
}
|
||||
const donorBadges = (Plugins.BadgeAPI as unknown as typeof import("../plugins/apiBadges").default).getDonorBadges(args.user.id);
|
||||
const donorBadges = (Plugins.BadgeAPI as unknown as typeof import("../plugins/_api/badges").default).getDonorBadges(args.user.id);
|
||||
if (donorBadges) badges.unshift(...donorBadges);
|
||||
|
||||
return badges;
|
||||
|
@ -24,7 +24,7 @@ export interface CommandContext {
|
||||
guild?: Guild;
|
||||
}
|
||||
|
||||
export enum ApplicationCommandOptionType {
|
||||
export const enum ApplicationCommandOptionType {
|
||||
SUB_COMMAND = 1,
|
||||
SUB_COMMAND_GROUP = 2,
|
||||
STRING = 3,
|
||||
@ -38,7 +38,7 @@ export enum ApplicationCommandOptionType {
|
||||
ATTACHMENT = 11,
|
||||
}
|
||||
|
||||
export enum ApplicationCommandInputType {
|
||||
export const enum ApplicationCommandInputType {
|
||||
BUILT_IN = 0,
|
||||
BUILT_IN_TEXT = 1,
|
||||
BUILT_IN_INTEGRATION = 2,
|
||||
@ -64,7 +64,7 @@ export interface ChoicesOption {
|
||||
displayName?: string;
|
||||
}
|
||||
|
||||
export enum ApplicationCommandType {
|
||||
export const enum ApplicationCommandType {
|
||||
CHAT_INPUT = 1,
|
||||
USER = 2,
|
||||
MESSAGE = 3,
|
||||
|
@ -20,7 +20,7 @@ import { Logger } from "@utils/Logger";
|
||||
|
||||
const logger = new Logger("ServerListAPI");
|
||||
|
||||
export enum ServerListRenderPosition {
|
||||
export const enum ServerListRenderPosition {
|
||||
Above,
|
||||
In,
|
||||
}
|
||||
|
@ -146,3 +146,47 @@ export function OwnerCrownIcon(props: IconProps) {
|
||||
</Icon>
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Discord's screenshare icon, as seen in the connection panel
|
||||
*/
|
||||
export function ScreenshareIcon(props: IconProps) {
|
||||
return (
|
||||
<Icon
|
||||
{...props}
|
||||
className={classes(props.className, "vc-screenshare-icon")}
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path
|
||||
fill="currentColor"
|
||||
fill-rule="evenodd"
|
||||
clip-rule="evenodd"
|
||||
d="M2 4.5C2 3.397 2.897 2.5 4 2.5H20C21.103 2.5 22 3.397 22 4.5V15.5C22 16.604 21.103 17.5 20 17.5H13V19.5H17V21.5H7V19.5H11V17.5H4C2.897 17.5 2 16.604 2 15.5V4.5ZM13.2 14.3375V11.6C9.864 11.6 7.668 12.6625 6 15C6.672 11.6625 8.532 8.3375 13.2 7.6625V5L18 9.6625L13.2 14.3375Z"
|
||||
/>
|
||||
</Icon>
|
||||
);
|
||||
}
|
||||
|
||||
export function ImageVisible(props: IconProps) {
|
||||
return (
|
||||
<Icon
|
||||
{...props}
|
||||
className={classes(props.className, "vc-image-visible")}
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path fill="currentColor" d="M5 21q-.825 0-1.413-.587Q3 19.825 3 19V5q0-.825.587-1.413Q4.175 3 5 3h14q.825 0 1.413.587Q21 4.175 21 5v14q0 .825-.587 1.413Q19.825 21 19 21Zm0-2h14V5H5v14Zm1-2h12l-3.75-5-3 4L9 13Zm-1 2V5v14Z" />
|
||||
</Icon>
|
||||
);
|
||||
}
|
||||
|
||||
export function ImageInvisible(props: IconProps) {
|
||||
return (
|
||||
<Icon
|
||||
{...props}
|
||||
className={classes(props.className, "vc-image-invisible")}
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path fill="currentColor" d="m21 18.15-2-2V5H7.85l-2-2H19q.825 0 1.413.587Q21 4.175 21 5Zm-1.2 4.45L18.2 21H5q-.825 0-1.413-.587Q3 19.825 3 19V5.8L1.4 4.2l1.4-1.4 18.4 18.4ZM6 17l3-4 2.25 3 .825-1.1L5 7.825V19h11.175l-2-2Zm7.425-6.425ZM10.6 13.4Z" />
|
||||
</Icon>
|
||||
);
|
||||
}
|
||||
|
@ -138,11 +138,13 @@ function PluginCard({ plugin, disabled, onRestartNeeded, onMouseEnter, onMouseLe
|
||||
}
|
||||
|
||||
const result = wasEnabled ? stopPlugin(plugin) : startPlugin(plugin);
|
||||
const action = wasEnabled ? "stop" : "start";
|
||||
|
||||
if (!result) {
|
||||
logger.error(`Failed to ${action} plugin ${plugin.name}`);
|
||||
showErrorToast(`Failed to ${action} plugin: ${plugin.name}`);
|
||||
settings.enabled = false;
|
||||
|
||||
const msg = `Error while ${wasEnabled ? "stopping" : "starting"} plugin ${plugin.name}`;
|
||||
logger.error(msg);
|
||||
showErrorToast(msg);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -171,7 +173,7 @@ function PluginCard({ plugin, disabled, onRestartNeeded, onMouseEnter, onMouseLe
|
||||
);
|
||||
}
|
||||
|
||||
enum SearchStatus {
|
||||
const enum SearchStatus {
|
||||
ALL,
|
||||
ENABLED,
|
||||
DISABLED
|
||||
|
2
src/globals.d.ts
vendored
2
src/globals.d.ts
vendored
@ -37,6 +37,8 @@ declare global {
|
||||
export var IS_STANDALONE: boolean;
|
||||
export var IS_DISCORD_DESKTOP: boolean;
|
||||
export var IS_VENCORD_DESKTOP: boolean;
|
||||
export var VERSION: string;
|
||||
export var BUILD_TIMESTAMP: number;
|
||||
|
||||
export var VencordNative: typeof import("./VencordNative").default;
|
||||
export var Vencord: typeof import("./Vencord");
|
||||
|
@ -82,6 +82,8 @@ export default definePlugin({
|
||||
}
|
||||
}],
|
||||
|
||||
customSections: [] as ((ID: Record<string, unknown>) => any)[],
|
||||
|
||||
makeSettingsCategories({ ID }: { ID: Record<string, unknown>; }) {
|
||||
return [
|
||||
{
|
||||
@ -123,11 +125,13 @@ export default definePlugin({
|
||||
label: "Patch Helper",
|
||||
element: require("@components/VencordSettings/PatchHelperTab").default,
|
||||
},
|
||||
// TODO: make this use customSections
|
||||
IS_VENCORD_DESKTOP && {
|
||||
section: "VencordDesktop",
|
||||
label: "Desktop Settings",
|
||||
element: VencordDesktop.Components.Settings,
|
||||
},
|
||||
...this.customSections.map(func => func(ID)),
|
||||
{
|
||||
section: ID.DIVIDER
|
||||
}
|
@ -20,7 +20,7 @@ import { Settings } from "@api/Settings";
|
||||
import { Devs } from "@utils/constants";
|
||||
import definePlugin, { OptionType } from "@utils/types";
|
||||
|
||||
enum Methods {
|
||||
const enum Methods {
|
||||
Random,
|
||||
Consistent,
|
||||
Timestamp,
|
||||
|
@ -104,6 +104,6 @@ export default definePlugin({
|
||||
|
||||
stop() {
|
||||
FluxDispatcher.dispatch({ type: "LOCAL_ACTIVITY_UPDATE", activity: null }); // clear status
|
||||
ws.close(); // close WebSocket
|
||||
ws?.close(); // close WebSocket
|
||||
}
|
||||
});
|
||||
|
100
src/plugins/biggerStreamPreview/index.tsx
Normal file
100
src/plugins/biggerStreamPreview/index.tsx
Normal file
@ -0,0 +1,100 @@
|
||||
/*
|
||||
* 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 { addContextMenuPatch, NavContextMenuPatchCallback, removeContextMenuPatch } from "@api/ContextMenu";
|
||||
import { ScreenshareIcon } from "@components/Icons";
|
||||
import { Devs } from "@utils/constants";
|
||||
import { openImageModal } from "@utils/discord";
|
||||
import definePlugin from "@utils/types";
|
||||
import { Menu } from "@webpack/common";
|
||||
import { Channel, User } from "discord-types/general";
|
||||
|
||||
import { ApplicationStreamingStore, ApplicationStreamPreviewStore } from "./webpack/stores";
|
||||
import { ApplicationStream, Stream } from "./webpack/types/stores";
|
||||
|
||||
export interface UserContextProps {
|
||||
channel: Channel,
|
||||
channelSelected: boolean,
|
||||
className: string,
|
||||
config: { context: string; };
|
||||
context: string,
|
||||
onHeightUpdate: Function,
|
||||
position: string,
|
||||
target: HTMLElement,
|
||||
theme: string,
|
||||
user: User;
|
||||
}
|
||||
|
||||
export interface StreamContextProps {
|
||||
appContext: string,
|
||||
className: string,
|
||||
config: { context: string; };
|
||||
context: string,
|
||||
exitFullscreen: Function,
|
||||
onHeightUpdate: Function,
|
||||
position: string,
|
||||
target: HTMLElement,
|
||||
stream: Stream,
|
||||
theme: string,
|
||||
}
|
||||
|
||||
export const handleViewPreview = async ({ guildId, channelId, ownerId }: ApplicationStream | Stream) => {
|
||||
const previewUrl = await ApplicationStreamPreviewStore.getPreviewURL(guildId, channelId, ownerId);
|
||||
if (!previewUrl) return;
|
||||
|
||||
openImageModal(previewUrl);
|
||||
};
|
||||
|
||||
export const addViewStreamContext: NavContextMenuPatchCallback = (children, { userId }: { userId: string | bigint; }) => () => {
|
||||
const stream = ApplicationStreamingStore.getAnyStreamForUser(userId);
|
||||
if (!stream) return;
|
||||
|
||||
const streamPreviewItem = (
|
||||
<Menu.MenuItem
|
||||
label="View Stream Preview"
|
||||
id="view-stream-preview"
|
||||
icon={ScreenshareIcon}
|
||||
action={() => stream && handleViewPreview(stream)}
|
||||
disabled={!stream}
|
||||
/>
|
||||
);
|
||||
|
||||
children.push(<Menu.MenuSeparator />, streamPreviewItem);
|
||||
};
|
||||
|
||||
export const streamContextPatch: NavContextMenuPatchCallback = (children, { stream }: StreamContextProps) => {
|
||||
return addViewStreamContext(children, { userId: stream.ownerId });
|
||||
};
|
||||
|
||||
export const userContextPatch: NavContextMenuPatchCallback = (children, { user }: UserContextProps) => {
|
||||
return addViewStreamContext(children, { userId: user.id });
|
||||
};
|
||||
|
||||
export default definePlugin({
|
||||
name: "BiggerStreamPreview",
|
||||
description: "This plugin allows you to enlarge stream previews",
|
||||
authors: [Devs.phil],
|
||||
start: () => {
|
||||
addContextMenuPatch("user-context", userContextPatch);
|
||||
addContextMenuPatch("stream-context", streamContextPatch);
|
||||
},
|
||||
stop: () => {
|
||||
removeContextMenuPatch("user-context", userContextPatch);
|
||||
removeContextMenuPatch("stream-context", streamContextPatch);
|
||||
}
|
||||
});
|
25
src/plugins/biggerStreamPreview/webpack/stores.ts
Normal file
25
src/plugins/biggerStreamPreview/webpack/stores.ts
Normal file
@ -0,0 +1,25 @@
|
||||
/*
|
||||
* 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 { findStoreLazy } from "@webpack";
|
||||
|
||||
import * as t from "./types/stores";
|
||||
|
||||
export const ApplicationStreamPreviewStore: t.ApplicationStreamPreviewStore = findStoreLazy("ApplicationStreamPreviewStore");
|
||||
export const ApplicationStreamingStore: t.ApplicationStreamingStore = findStoreLazy("ApplicationStreamingStore");
|
77
src/plugins/biggerStreamPreview/webpack/types/stores.ts
Normal file
77
src/plugins/biggerStreamPreview/webpack/types/stores.ts
Normal file
@ -0,0 +1,77 @@
|
||||
/*
|
||||
* 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 { FluxStore } from "@webpack/types";
|
||||
|
||||
export interface ApplicationStreamPreviewStore extends FluxStore {
|
||||
getIsPreviewLoading: (guildId: string | bigint | null, channelId: string | bigint, ownerId: string | bigint) => boolean;
|
||||
getPreviewURL: (guildId: string | bigint | null, channelId: string | bigint, ownerId: string | bigint) => Promise<string | null>;
|
||||
getPreviewURLForStreamKey: (streamKey: string) => ReturnType<ApplicationStreamPreviewStore["getPreviewURL"]>;
|
||||
}
|
||||
|
||||
export interface ApplicationStream {
|
||||
streamType: string;
|
||||
guildId: string | null;
|
||||
channelId: string;
|
||||
ownerId: string;
|
||||
}
|
||||
|
||||
export interface Stream extends ApplicationStream {
|
||||
state: string;
|
||||
}
|
||||
|
||||
export interface RTCStream {
|
||||
region: string,
|
||||
streamKey: string,
|
||||
viewerIds: string[];
|
||||
}
|
||||
|
||||
export interface StreamMetadata {
|
||||
id: string | null,
|
||||
pid: number | null,
|
||||
sourceName: string | null;
|
||||
}
|
||||
|
||||
export interface StreamingStoreState {
|
||||
activeStreams: [string, Stream][];
|
||||
rtcStreams: { [key: string]: RTCStream; };
|
||||
streamerActiveStreamMetadatas: { [key: string]: StreamMetadata | null; };
|
||||
streamsByUserAndGuild: { [key: string]: { [key: string]: ApplicationStream; }; };
|
||||
}
|
||||
|
||||
/**
|
||||
* example how a stream key could look like: `call(type of connection):1116549917987192913(channelId):305238513941667851(ownerId)`
|
||||
*/
|
||||
export interface ApplicationStreamingStore extends FluxStore {
|
||||
getActiveStreamForApplicationStream: (stream: ApplicationStream) => Stream | null;
|
||||
getActiveStreamForStreamKey: (streamKey: string) => Stream | null;
|
||||
getActiveStreamForUser: (userId: string | bigint, guildId?: string | bigint | null) => Stream | null;
|
||||
getAllActiveStreams: () => Stream[];
|
||||
getAllApplicationStreams: () => ApplicationStream[];
|
||||
getAllApplicationStreamsForChannel: (channelId: string | bigint) => ApplicationStream[];
|
||||
getAllActiveStreamsForChannel: (channelId: string | bigint) => Stream[];
|
||||
getAnyStreamForUser: (userId: string | bigint) => Stream | ApplicationStream | null;
|
||||
getStreamForUser: (userId: string | bigint, guildId?: string | bigint | null) => Stream | null;
|
||||
getCurrentUserActiveStream: () => Stream | null;
|
||||
getLastActiveStream: () => Stream | null;
|
||||
getState: () => StreamingStoreState;
|
||||
getRTCStream: (streamKey: string) => RTCStream | null;
|
||||
getStreamerActiveStreamMetadata: () => StreamMetadata;
|
||||
getViewerIds: (stream: ApplicationStream) => string[];
|
||||
isSelfStreamHidden: (channelId: string | bigint | null) => boolean;
|
||||
}
|
@ -74,7 +74,7 @@ interface Activity {
|
||||
flags: number;
|
||||
}
|
||||
|
||||
enum ActivityType {
|
||||
const enum ActivityType {
|
||||
PLAYING = 0,
|
||||
LISTENING = 2,
|
||||
WATCHING = 3,
|
||||
|
@ -1,61 +0,0 @@
|
||||
/*
|
||||
* Vencord, a modification for Discord's desktop app
|
||||
* Copyright (c) 2022 Vendicated and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { ApplicationCommandOptionType } from "@api/Commands";
|
||||
import { Settings } from "@api/Settings";
|
||||
import { makeRange } from "@components/PluginSettings/components";
|
||||
import { Devs } from "@utils/constants";
|
||||
import definePlugin, { OptionType } from "@utils/types";
|
||||
|
||||
export default definePlugin({
|
||||
name: "Fart2",
|
||||
authors: [Devs.Animal],
|
||||
description: "Enable farting v2, a slash command that allows you to perform or request that someone perform a little toot.",
|
||||
dependencies: ["CommandsAPI"],
|
||||
commands: [{
|
||||
name: "fart",
|
||||
description: "A simple command in which you may either request that a user do a little toot for you, or conduct one yourself.",
|
||||
options: [
|
||||
{
|
||||
type: ApplicationCommandOptionType.USER,
|
||||
name: "user",
|
||||
description: "A Discord™ user of which you would humbly request a toot from.",
|
||||
required: false
|
||||
}
|
||||
],
|
||||
|
||||
execute(args) {
|
||||
const fart = new Audio("https://raw.githubusercontent.com/ItzOnlyAnimal/AliuPlugins/main/fart.mp3");
|
||||
fart.volume = Settings.plugins.Fart2.volume;
|
||||
fart.play();
|
||||
|
||||
return {
|
||||
content: (args[0]) ? `<@${args[0].value}> fart` : "fart"
|
||||
};
|
||||
},
|
||||
}],
|
||||
options: {
|
||||
volume: {
|
||||
description: "how loud you wanna fart (aka volume)",
|
||||
type: OptionType.SLIDER,
|
||||
markers: makeRange(0, 1, 0.1),
|
||||
default: 0.5,
|
||||
stickToMarkers: false,
|
||||
}
|
||||
}
|
||||
});
|
@ -18,6 +18,7 @@
|
||||
|
||||
import { get, set } from "@api/DataStore";
|
||||
import { addButton, removeButton } from "@api/MessagePopover";
|
||||
import { ImageInvisible, ImageVisible } from "@components/Icons";
|
||||
import { Devs } from "@utils/constants";
|
||||
import definePlugin from "@utils/types";
|
||||
import { ChannelStore } from "@webpack/common";
|
||||
@ -26,17 +27,6 @@ let style: HTMLStyleElement;
|
||||
|
||||
const KEY = "HideAttachments_HiddenIds";
|
||||
|
||||
const ImageVisible = () => (
|
||||
<svg viewBox="0 0 24 24" fill="currentColor" aria-hidden="true">
|
||||
<path d="M5 21q-.825 0-1.413-.587Q3 19.825 3 19V5q0-.825.587-1.413Q4.175 3 5 3h14q.825 0 1.413.587Q21 4.175 21 5v14q0 .825-.587 1.413Q19.825 21 19 21Zm0-2h14V5H5v14Zm1-2h12l-3.75-5-3 4L9 13Zm-1 2V5v14Z" />
|
||||
</svg>
|
||||
);
|
||||
const ImageInvisible = () => (
|
||||
<svg viewBox="0 0 24 24" fill="currentColor" aria-hidden="true">
|
||||
<path d="m21 18.15-2-2V5H7.85l-2-2H19q.825 0 1.413.587Q21 4.175 21 5Zm-1.2 4.45L18.2 21H5q-.825 0-1.413-.587Q3 19.825 3 19V5.8L1.4 4.2l1.4-1.4 18.4 18.4ZM6 17l3-4 2.25 3 .825-1.1L5 7.825V19h11.175l-2-2Zm7.425-6.425ZM10.6 13.4Z" />
|
||||
</svg>
|
||||
);
|
||||
|
||||
let hiddenMessages: Set<string> = new Set();
|
||||
const getHiddenMessages = () => get(KEY).then(set => {
|
||||
hiddenMessages = set ?? new Set<string>();
|
||||
|
@ -24,7 +24,7 @@ import definePlugin from "@utils/types";
|
||||
import { findByPropsLazy, findStoreLazy } from "@webpack";
|
||||
import { Tooltip } from "webpack/common";
|
||||
|
||||
enum ActivitiesTypes {
|
||||
const enum ActivitiesTypes {
|
||||
Game,
|
||||
Embedded
|
||||
}
|
||||
|
@ -63,12 +63,12 @@ interface TrackData {
|
||||
}
|
||||
|
||||
// only relevant enum values
|
||||
enum ActivityType {
|
||||
const enum ActivityType {
|
||||
PLAYING = 0,
|
||||
LISTENING = 2,
|
||||
}
|
||||
|
||||
enum ActivityFlag {
|
||||
const enum ActivityFlag {
|
||||
INSTANCE = 1 << 0,
|
||||
}
|
||||
|
||||
|
@ -147,6 +147,11 @@ export default definePlugin({
|
||||
type: OptionType.BOOLEAN,
|
||||
description: "Whether to ignore messages by yourself",
|
||||
default: false
|
||||
},
|
||||
ignoreUsers: {
|
||||
type: OptionType.STRING,
|
||||
description: "Comma-separated list of user IDs to ignore",
|
||||
default: ""
|
||||
}
|
||||
},
|
||||
|
||||
@ -154,7 +159,7 @@ export default definePlugin({
|
||||
try {
|
||||
if (cache == null || (!isBulk && !cache.has(data.id))) return cache;
|
||||
|
||||
const { ignoreBots, ignoreSelf } = Settings.plugins.MessageLogger;
|
||||
const { ignoreBots, ignoreSelf, ignoreUsers } = Settings.plugins.MessageLogger;
|
||||
const myId = UserStore.getCurrentUser().id;
|
||||
|
||||
function mutate(id: string) {
|
||||
@ -165,7 +170,8 @@ export default definePlugin({
|
||||
const shouldIgnore = data.mlDeleted ||
|
||||
(msg.flags & EPHEMERAL) === EPHEMERAL ||
|
||||
ignoreBots && msg.author?.bot ||
|
||||
ignoreSelf && msg.author?.id === myId;
|
||||
ignoreSelf && msg.author?.id === myId ||
|
||||
ignoreUsers.includes(msg.author?.id);
|
||||
|
||||
if (shouldIgnore) {
|
||||
cache = cache.remove(id);
|
||||
|
@ -18,37 +18,8 @@
|
||||
|
||||
import { definePluginSettings } from "@api/Settings";
|
||||
import { Devs } from "@utils/constants";
|
||||
import { ModalContent, ModalFooter, ModalProps, ModalRoot, ModalSize, openModal } from "@utils/modal";
|
||||
import definePlugin, { OptionType } from "@utils/types";
|
||||
import { findByProps, findStoreLazy } from "@webpack";
|
||||
import { Button, Text } from "@webpack/common";
|
||||
|
||||
const UserGuildSettingsStore = findStoreLazy("UserGuildSettingsStore");
|
||||
|
||||
function NoDMNotificationsModal({ modalProps }: { modalProps: ModalProps; }) {
|
||||
return (
|
||||
<ModalRoot {...modalProps} size={ModalSize.MEDIUM}>
|
||||
<ModalContent>
|
||||
<div style={{ display: "flex", flexDirection: "column", justifyContent: "center", "alignItems": "center", textAlign: "center", height: "100%", padding: "8px 0", gap: "16px" }}>
|
||||
<Text variant="text-lg/semibold">You seem to have been affected by a bug that caused DM notifications to be muted and break if you used the MuteNewGuild plugin.</Text>
|
||||
<Text variant="text-lg/semibold">If you haven't received any notifications for private messages, this is why. This issue is now fixed, so they should work again. Please verify, and in case they are still broken, ask for help in the Vencord support channel!</Text>
|
||||
<Text variant="text-lg/semibold">We're very sorry for any inconvenience caused by this issue :(</Text>
|
||||
</div>
|
||||
</ModalContent>
|
||||
<ModalFooter>
|
||||
<div style={{ display: "flex", justifyContent: "center", width: "100%" }}>
|
||||
<Button
|
||||
onClick={modalProps.onClose}
|
||||
size={Button.Sizes.MEDIUM}
|
||||
color={Button.Colors.BRAND}
|
||||
>
|
||||
Understood!
|
||||
</Button>
|
||||
</div>
|
||||
</ModalFooter>
|
||||
</ModalRoot>
|
||||
);
|
||||
}
|
||||
import { findByProps } from "@webpack";
|
||||
|
||||
const settings = definePluginSettings({
|
||||
guild: {
|
||||
@ -92,15 +63,5 @@ export default definePlugin({
|
||||
suppress_roles: settings.store.role
|
||||
}
|
||||
);
|
||||
},
|
||||
|
||||
start() {
|
||||
const [isMuted, isEveryoneSupressed, isRolesSupressed] = [UserGuildSettingsStore.isMuted(null), UserGuildSettingsStore.isSuppressEveryoneEnabled(null), UserGuildSettingsStore.isSuppressRolesEnabled(null)];
|
||||
|
||||
if (isMuted || isEveryoneSupressed || isRolesSupressed) {
|
||||
findByProps("updateGuildNotificationSettings").updateGuildNotificationSettings(null, { muted: false, suppress_everyone: false, suppress_roles: false });
|
||||
|
||||
openModal(modalProps => <NoDMNotificationsModal modalProps={modalProps} />);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
104
src/plugins/mutualGroupDMs.tsx
Normal file
104
src/plugins/mutualGroupDMs.tsx
Normal file
@ -0,0 +1,104 @@
|
||||
/*
|
||||
* 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 { Devs } from "@utils/constants";
|
||||
import { isNonNullish } from "@utils/guards";
|
||||
import definePlugin from "@utils/types";
|
||||
import { findByPropsLazy } from "@webpack";
|
||||
import { Avatar, ChannelStore, Clickable, RelationshipStore, ScrollerThin, UserStore } from "@webpack/common";
|
||||
import { Channel, User } from "discord-types/general";
|
||||
|
||||
const SelectedChannelActionCreators = findByPropsLazy("selectPrivateChannel");
|
||||
const AvatarUtils = findByPropsLazy("getChannelIconURL");
|
||||
const UserUtils = findByPropsLazy("getGlobalName");
|
||||
|
||||
const ProfileListClasses = findByPropsLazy("emptyIconFriends", "emptyIconGuilds");
|
||||
const GuildLabelClasses = findByPropsLazy("guildNick", "guildAvatarWithoutIcon");
|
||||
|
||||
function getGroupDMName(channel: Channel) {
|
||||
return channel.name ||
|
||||
channel.recipients
|
||||
.map(UserStore.getUser)
|
||||
.filter(isNonNullish)
|
||||
.map(c => RelationshipStore.getNickname(c.id) || UserUtils.getName(c))
|
||||
.join(", ");
|
||||
}
|
||||
|
||||
export default definePlugin({
|
||||
name: "MutualGroupDMs",
|
||||
description: "Shows mutual group dms in profiles",
|
||||
authors: [Devs.amia],
|
||||
|
||||
patches: [
|
||||
{
|
||||
find: ".Messages.USER_PROFILE_MODAL", // Note: the module is lazy-loaded
|
||||
replacement: [
|
||||
{
|
||||
match: /(?<=\.MUTUAL_GUILDS\}\),)(?=(\i\.bot).{0,20}(\(0,\i\.jsx\)\(.{0,100}id:))/,
|
||||
replace: '$1?null:$2"MUTUAL_GDMS",children:"Mutual Groups"}),'
|
||||
},
|
||||
{
|
||||
match: /(?<={user:(\i),onClose:(\i)}\);)(?=case \i\.\i\.MUTUAL_FRIENDS)/,
|
||||
replace: "case \"MUTUAL_GDMS\":return $self.renderMutualGDMs($1,$2);"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
|
||||
renderMutualGDMs(user: User, onClose: () => void) {
|
||||
const entries = ChannelStore.getSortedPrivateChannels().filter(c => c.isGroupDM() && c.recipients.includes(user.id)).map(c => (
|
||||
<Clickable
|
||||
className={ProfileListClasses.listRow}
|
||||
onClick={() => {
|
||||
onClose();
|
||||
SelectedChannelActionCreators.selectPrivateChannel(c.id);
|
||||
}}
|
||||
>
|
||||
<Avatar
|
||||
src={AvatarUtils.getChannelIconURL({ id: c.id, icon: c.icon, size: 32 })}
|
||||
size="SIZE_40"
|
||||
className={ProfileListClasses.listAvatar}
|
||||
>
|
||||
</Avatar>
|
||||
<div className={ProfileListClasses.listRowContent}>
|
||||
<div className={ProfileListClasses.listName}>{getGroupDMName(c)}</div>
|
||||
<div className={GuildLabelClasses.guildNick}>{c.recipients.length} Members</div>
|
||||
</div>
|
||||
</Clickable>
|
||||
));
|
||||
|
||||
return (
|
||||
<ScrollerThin
|
||||
className={ProfileListClasses.listScroller}
|
||||
fade={true}
|
||||
onClose={onClose}
|
||||
>
|
||||
{entries.length > 0
|
||||
? entries
|
||||
: (
|
||||
<div className={ProfileListClasses.empty}>
|
||||
<div className={ProfileListClasses.emptyIconFriends}></div>
|
||||
<div className={ProfileListClasses.emptyText}>No group dms in common</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
</ScrollerThin>
|
||||
);
|
||||
}
|
||||
});
|
@ -24,7 +24,7 @@ import { useForceUpdater } from "@utils/react";
|
||||
import definePlugin, { OptionType } from "@utils/types";
|
||||
import { GuildStore, PresenceStore, RelationshipStore } from "@webpack/common";
|
||||
|
||||
enum IndicatorType {
|
||||
const enum IndicatorType {
|
||||
SERVER = 1 << 0,
|
||||
FRIEND = 1 << 1,
|
||||
BOTH = SERVER | FRIEND,
|
||||
|
@ -46,18 +46,18 @@ export type ShikiSpec = {
|
||||
}) => Promise<IThemedToken[][]>;
|
||||
};
|
||||
|
||||
export enum StyleSheets {
|
||||
export const enum StyleSheets {
|
||||
Main = "MAIN",
|
||||
DevIcons = "DEVICONS",
|
||||
}
|
||||
|
||||
export enum HljsSetting {
|
||||
export const enum HljsSetting {
|
||||
Never = "NEVER",
|
||||
Secondary = "SECONDARY",
|
||||
Primary = "PRIMARY",
|
||||
Always = "ALWAYS",
|
||||
}
|
||||
export enum DeviconSetting {
|
||||
export const enum DeviconSetting {
|
||||
Disabled = "DISABLED",
|
||||
Greyscale = "GREYSCALE",
|
||||
Color = "COLOR"
|
||||
|
@ -29,12 +29,12 @@ import openRolesAndUsersPermissionsModal, { PermissionType, RoleOrUserPermission
|
||||
import { sortPermissionOverwrites } from "../../permissionsViewer/utils";
|
||||
import { settings, VIEW_CHANNEL } from "..";
|
||||
|
||||
enum SortOrderTypes {
|
||||
const enum SortOrderTypes {
|
||||
LATEST_ACTIVITY = 0,
|
||||
CREATION_DATE = 1
|
||||
}
|
||||
|
||||
enum ForumLayoutTypes {
|
||||
const enum ForumLayoutTypes {
|
||||
DEFAULT = 0,
|
||||
LIST = 1,
|
||||
GRID = 2
|
||||
@ -61,7 +61,7 @@ interface ExtendedChannel extends Channel {
|
||||
availableTags?: Array<Tag>;
|
||||
}
|
||||
|
||||
enum ChannelTypes {
|
||||
const enum ChannelTypes {
|
||||
GUILD_TEXT = 0,
|
||||
GUILD_VOICE = 2,
|
||||
GUILD_ANNOUNCEMENT = 5,
|
||||
@ -69,12 +69,12 @@ enum ChannelTypes {
|
||||
GUILD_FORUM = 15
|
||||
}
|
||||
|
||||
enum VideoQualityModes {
|
||||
const enum VideoQualityModes {
|
||||
AUTO = 1,
|
||||
FULL = 2
|
||||
}
|
||||
|
||||
enum ChannelFlags {
|
||||
const enum ChannelFlags {
|
||||
PINNED = 1 << 1,
|
||||
REQUIRE_TAG = 1 << 4
|
||||
}
|
||||
|
@ -34,7 +34,7 @@ const ChannelListClasses = findByPropsLazy("channelName", "subtitle", "modeMuted
|
||||
export const VIEW_CHANNEL = 1n << 10n;
|
||||
const CONNECT = 1n << 20n;
|
||||
|
||||
enum ShowMode {
|
||||
const enum ShowMode {
|
||||
LockIcon,
|
||||
HiddenIconWithMutedStyle
|
||||
}
|
||||
@ -107,8 +107,8 @@ export default definePlugin({
|
||||
},
|
||||
{
|
||||
// Prevent Discord from trying to connect to hidden channels
|
||||
match: /if\(!\i&&!\i(?=.{0,50}?selectVoiceChannel\((\i)\.id\))/,
|
||||
replace: (m, channel) => `${m}&&!$self.isHiddenChannel(${channel})`
|
||||
match: /(?=\|\|\i\.default\.selectVoiceChannel\((\i)\.id\))/,
|
||||
replace: (_, channel) => `||$self.isHiddenChannel(${channel})`
|
||||
},
|
||||
{
|
||||
// Make Discord show inside the channel if clicking on a hidden or locked channel
|
||||
|
@ -27,7 +27,7 @@ import { Alerts, Forms, UserStore } from "@webpack/common";
|
||||
import gitHash from "~git-hash";
|
||||
import plugins from "~plugins";
|
||||
|
||||
import settings from "./settings";
|
||||
import settings from "./_core/settings";
|
||||
|
||||
const REMEMBER_DISMISS_KEY = "Vencord-SupportHelper-Dismiss";
|
||||
|
||||
@ -55,7 +55,10 @@ export default definePlugin({
|
||||
if (IS_DISCORD_DESKTOP) return `Discord Desktop v${DiscordNative.app.getVersion()}`;
|
||||
if (IS_VENCORD_DESKTOP) return `Vencord Desktop v${VencordDesktopNative.app.getVersion()}`;
|
||||
if ("armcord" in window) return `ArmCord v${window.armcord.version}`;
|
||||
return `Web (${navigator.userAgent})`;
|
||||
|
||||
// @ts-expect-error
|
||||
const name = typeof unsafeWindow !== "undefined" ? "UserScript" : "Web";
|
||||
return `${name} (${navigator.userAgent})`;
|
||||
})();
|
||||
|
||||
const isApiPlugin = (plugin: string) => plugin.endsWith("API") || plugins[plugin].required;
|
||||
@ -63,14 +66,18 @@ export default definePlugin({
|
||||
const enabledPlugins = Object.keys(plugins).filter(p => Vencord.Plugins.isPluginEnabled(p) && !isApiPlugin(p));
|
||||
const enabledApiPlugins = Object.keys(plugins).filter(p => Vencord.Plugins.isPluginEnabled(p) && isApiPlugin(p));
|
||||
|
||||
const info = {
|
||||
Vencord: `v${VERSION} • ${gitHash}${settings.additionalInfo} - ${Intl.DateTimeFormat("en-GB", { dateStyle: "medium" }).format(BUILD_TIMESTAMP)}`,
|
||||
"Discord Branch": RELEASE_CHANNEL,
|
||||
Client: client,
|
||||
Platform: window.navigator.platform,
|
||||
Outdated: isOutdated,
|
||||
OpenAsar: "openasar" in window,
|
||||
};
|
||||
|
||||
const debugInfo = `
|
||||
**Vencord Debug Info**
|
||||
>>> Discord Branch: ${RELEASE_CHANNEL}
|
||||
Client: ${client}
|
||||
Platform: ${window.navigator.platform}
|
||||
Vencord: ${gitHash}${settings.additionalInfo}
|
||||
Outdated: ${isOutdated}
|
||||
OpenAsar: ${"openasar" in window}
|
||||
>>> ${Object.entries(info).map(([k, v]) => `${k}: ${v}`).join("\n")}
|
||||
|
||||
Enabled Plugins (${enabledPlugins.length + enabledApiPlugins.length}):
|
||||
${makeCodeblock(enabledPlugins.join(", ") + "\n\n" + enabledApiPlugins.join(", "))}
|
||||
|
67
src/plugins/unsuppressEmbeds.tsx
Normal file
67
src/plugins/unsuppressEmbeds.tsx
Normal file
@ -0,0 +1,67 @@
|
||||
/*
|
||||
* Vencord, a modification for Discord's desktop app
|
||||
* Copyright (c) 2022 Vendicated and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { addContextMenuPatch, findGroupChildrenByChildId, NavContextMenuPatchCallback, removeContextMenuPatch } from "@api/ContextMenu";
|
||||
import { ImageInvisible, ImageVisible } from "@components/Icons";
|
||||
import { Devs } from "@utils/constants";
|
||||
import definePlugin from "@utils/types";
|
||||
import { Menu, PermissionsBits, PermissionStore, RestAPI, UserStore } from "@webpack/common";
|
||||
|
||||
const EMBED_SUPPRESSED = 1 << 2;
|
||||
|
||||
const messageContextMenuPatch: NavContextMenuPatchCallback = (children, { channel, message: { author, embeds, flags, id: messageId } }) => () => {
|
||||
const isEmbedSuppressed = (flags & EMBED_SUPPRESSED) !== 0;
|
||||
if (!isEmbedSuppressed && !embeds.length) return;
|
||||
|
||||
const hasEmbedPerms = channel.isPrivate() || !!(PermissionStore.getChannelPermissions({ id: channel.id }) & PermissionsBits.EMBED_LINKS);
|
||||
if (author.id === UserStore.getCurrentUser().id && !hasEmbedPerms) return;
|
||||
|
||||
const menuGroup = findGroupChildrenByChildId("delete", children);
|
||||
const deleteIndex = menuGroup?.findIndex(i => i?.props?.id === "delete");
|
||||
if (!deleteIndex || !menuGroup) return;
|
||||
|
||||
menuGroup.splice(deleteIndex - 1, 0, (
|
||||
<Menu.MenuItem
|
||||
id="unsuppress-embeds"
|
||||
key="unsuppress-embeds"
|
||||
label={isEmbedSuppressed ? "Unsuppress Embeds" : "Suppress Embeds"}
|
||||
color={isEmbedSuppressed ? undefined : "danger"}
|
||||
icon={isEmbedSuppressed ? ImageVisible : ImageInvisible}
|
||||
action={() =>
|
||||
RestAPI.patch({
|
||||
url: `/channels/${channel.id}/messages/${messageId}`,
|
||||
body: { flags: isEmbedSuppressed ? flags & ~EMBED_SUPPRESSED : flags | EMBED_SUPPRESSED }
|
||||
})
|
||||
}
|
||||
/>
|
||||
));
|
||||
};
|
||||
|
||||
export default definePlugin({
|
||||
name: "UnsuppressEmbeds",
|
||||
authors: [Devs.rad, Devs.HypedDomi],
|
||||
description: "Allows you to unsuppress embeds in messages",
|
||||
|
||||
start() {
|
||||
addContextMenuPatch("message", messageContextMenuPatch);
|
||||
},
|
||||
|
||||
stop() {
|
||||
removeContextMenuPatch("message", messageContextMenuPatch);
|
||||
},
|
||||
});
|
@ -20,15 +20,12 @@ import { addContextMenuPatch, NavContextMenuPatchCallback, removeContextMenuPatc
|
||||
import { definePluginSettings } from "@api/Settings";
|
||||
import { ImageIcon } from "@components/Icons";
|
||||
import { Devs } from "@utils/constants";
|
||||
import { ModalRoot, ModalSize, openModal } from "@utils/modal";
|
||||
import { LazyComponent } from "@utils/react";
|
||||
import { openImageModal } from "@utils/discord";
|
||||
import definePlugin, { OptionType } from "@utils/types";
|
||||
import { find, findByCode, findByPropsLazy } from "@webpack";
|
||||
import { findByPropsLazy } from "@webpack";
|
||||
import { GuildMemberStore, Menu } from "@webpack/common";
|
||||
import type { Channel, Guild, User } from "discord-types/general";
|
||||
|
||||
const ImageModal = LazyComponent(() => findByCode(".MEDIA_MODAL_CLOSE,"));
|
||||
const MaskedLink = LazyComponent(() => find(m => m.type?.toString().includes("MASKED_LINK)")));
|
||||
const BannerStore = findByPropsLazy("getGuildBannerURL");
|
||||
|
||||
interface UserContextProps {
|
||||
@ -60,26 +57,29 @@ const settings = definePluginSettings({
|
||||
value: "jpg",
|
||||
}
|
||||
]
|
||||
},
|
||||
imgSize: {
|
||||
type: OptionType.SELECT,
|
||||
description: "The image size to use",
|
||||
options: ["128", "256", "512", "1024", "2048", "4096"].map(n => ({ label: n, value: n, default: n === "1024" }))
|
||||
}
|
||||
});
|
||||
|
||||
function openImage(url: string) {
|
||||
const format = url.startsWith("/") ? "png" : settings.store.format;
|
||||
|
||||
const u = new URL(url, window.location.href);
|
||||
u.searchParams.set("size", "512");
|
||||
u.searchParams.set("size", settings.store.imgSize);
|
||||
u.pathname = u.pathname.replace(/\.(png|jpe?g|webp)$/, `.${format}`);
|
||||
url = u.toString();
|
||||
|
||||
openModal(modalProps => (
|
||||
<ModalRoot size={ModalSize.DYNAMIC} {...modalProps}>
|
||||
<ImageModal
|
||||
shouldAnimate={true}
|
||||
original={url}
|
||||
src={url}
|
||||
renderLinkComponent={MaskedLink}
|
||||
/>
|
||||
</ModalRoot>
|
||||
));
|
||||
u.searchParams.set("size", "4096");
|
||||
const originalUrl = u.toString();
|
||||
|
||||
openImageModal(url, {
|
||||
original: originalUrl,
|
||||
height: 256
|
||||
});
|
||||
}
|
||||
|
||||
const UserContext: NavContextMenuPatchCallback = (children, { user, guildId }: UserContextProps) => () => {
|
||||
@ -90,7 +90,7 @@ const UserContext: NavContextMenuPatchCallback = (children, { user, guildId }: U
|
||||
<Menu.MenuItem
|
||||
id="view-avatar"
|
||||
label="View Avatar"
|
||||
action={() => openImage(BannerStore.getUserAvatarURL(user, true, 512))}
|
||||
action={() => openImage(BannerStore.getUserAvatarURL(user, true))}
|
||||
icon={ImageIcon}
|
||||
/>
|
||||
{memberAvatar && (
|
||||
@ -122,7 +122,6 @@ const GuildContext: NavContextMenuPatchCallback = (children, { guild: { id, icon
|
||||
openImage(BannerStore.getGuildIconURL({
|
||||
id,
|
||||
icon,
|
||||
size: 512,
|
||||
canAnimate: true
|
||||
}))
|
||||
}
|
||||
|
@ -17,13 +17,14 @@
|
||||
*/
|
||||
|
||||
import { addButton, removeButton } from "@api/MessagePopover";
|
||||
import { definePluginSettings } from "@api/Settings";
|
||||
import ErrorBoundary from "@components/ErrorBoundary";
|
||||
import { Flex } from "@components/Flex";
|
||||
import { Devs } from "@utils/constants";
|
||||
import { Margins } from "@utils/margins";
|
||||
import { copyWithToast } from "@utils/misc";
|
||||
import { closeModal, ModalCloseButton, ModalContent, ModalFooter, ModalHeader, ModalRoot, ModalSize, openModal } from "@utils/modal";
|
||||
import definePlugin from "@utils/types";
|
||||
import definePlugin, { OptionType } from "@utils/types";
|
||||
import { Button, ChannelStore, Forms, Parser, Text } from "@webpack/common";
|
||||
import { Message } from "discord-types/general";
|
||||
|
||||
@ -41,22 +42,12 @@ function sortObject<T extends object>(obj: T): T {
|
||||
|
||||
function cleanMessage(msg: Message) {
|
||||
const clone = sortObject(JSON.parse(JSON.stringify(msg)));
|
||||
for (const key in clone.author) {
|
||||
switch (key) {
|
||||
case "id":
|
||||
case "username":
|
||||
case "usernameNormalized":
|
||||
case "discriminator":
|
||||
case "avatar":
|
||||
case "bot":
|
||||
case "system":
|
||||
case "publicFlags":
|
||||
break;
|
||||
default:
|
||||
// phone number, email, etc
|
||||
delete clone.author[key];
|
||||
}
|
||||
}
|
||||
for (const key of [
|
||||
"email",
|
||||
"phone",
|
||||
"mfaEnabled",
|
||||
"personalConnectionId"
|
||||
]) delete clone.author[key];
|
||||
|
||||
// message logger added properties
|
||||
const cloneAny = clone as any;
|
||||
@ -116,26 +107,58 @@ function openViewRawModal(msg: Message) {
|
||||
));
|
||||
}
|
||||
|
||||
const settings = definePluginSettings({
|
||||
clickMethod: {
|
||||
description: "Change the button to view the raw content/data of any message.",
|
||||
type: OptionType.SELECT,
|
||||
options: [
|
||||
{ label: "Left Click to view the raw content.", value: "Left", default: true },
|
||||
{ label: "Right click to view the raw content.", value: "Right" }
|
||||
]
|
||||
}
|
||||
});
|
||||
|
||||
export default definePlugin({
|
||||
name: "ViewRaw",
|
||||
description: "Copy and view the raw content/data of any message.",
|
||||
authors: [Devs.KingFish, Devs.Ven],
|
||||
authors: [Devs.KingFish, Devs.Ven, Devs.rad],
|
||||
dependencies: ["MessagePopoverAPI"],
|
||||
settings,
|
||||
|
||||
start() {
|
||||
addButton("ViewRaw", msg => {
|
||||
return {
|
||||
label: "View Raw (Left Click) / Copy Raw (Right Click)",
|
||||
icon: CopyIcon,
|
||||
message: msg,
|
||||
channel: ChannelStore.getChannel(msg.channel_id),
|
||||
onClick: () => openViewRawModal(msg),
|
||||
onContextMenu: e => {
|
||||
const handleClick = () => {
|
||||
if (settings.store.clickMethod === "Right") {
|
||||
copyWithToast(msg.content);
|
||||
} else {
|
||||
openViewRawModal(msg);
|
||||
}
|
||||
};
|
||||
|
||||
const handleContextMenu = e => {
|
||||
if (settings.store.clickMethod === "Left") {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
copyWithToast(msg.content);
|
||||
} else {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
openViewRawModal(msg);
|
||||
}
|
||||
};
|
||||
|
||||
const label = settings.store.clickMethod === "Right"
|
||||
? "Copy Raw (Left Click) / View Raw (Right Click)"
|
||||
: "View Raw (Left Click) / Copy Raw (Right Click)";
|
||||
|
||||
return {
|
||||
label,
|
||||
icon: CopyIcon,
|
||||
message: msg,
|
||||
channel: ChannelStore.getChannel(msg.channel_id),
|
||||
onClick: handleClick,
|
||||
onContextMenu: handleContextMenu
|
||||
};
|
||||
});
|
||||
},
|
||||
|
||||
|
@ -319,9 +319,21 @@ export const Devs = /* #__PURE__*/ Object.freeze({
|
||||
name: "amia",
|
||||
id: 142007603549962240n
|
||||
},
|
||||
phil: {
|
||||
name: "phil",
|
||||
id: 305288513941667851n
|
||||
},
|
||||
ImLvna: {
|
||||
name: "Luna <3",
|
||||
id: 174200708818665472n
|
||||
},
|
||||
rad: {
|
||||
name: "rad",
|
||||
id: 113027285765885952n
|
||||
},
|
||||
HypedDomi: {
|
||||
name: "HypedDomi",
|
||||
id: 354191516979429376n
|
||||
}
|
||||
} satisfies Record<string, Dev>);
|
||||
|
||||
|
@ -37,7 +37,7 @@ export const importApngJs = makeLazy(async () => {
|
||||
});
|
||||
|
||||
// https://wiki.mozilla.org/APNG_Specification#.60fcTL.60:_The_Frame_Control_Chunk
|
||||
export enum ApngDisposeOp {
|
||||
export const enum ApngDisposeOp {
|
||||
/**
|
||||
* no disposal is done on this frame before rendering the next; the contents of the output buffer are left as is.
|
||||
*/
|
||||
@ -53,7 +53,7 @@ export enum ApngDisposeOp {
|
||||
}
|
||||
|
||||
// TODO: Might need to somehow implement this
|
||||
export enum ApngBlendOp {
|
||||
export const enum ApngBlendOp {
|
||||
SOURCE,
|
||||
OVER
|
||||
}
|
||||
|
@ -18,9 +18,11 @@
|
||||
|
||||
import { MessageObject } from "@api/MessageEvents";
|
||||
import { findByPropsLazy, findLazy } from "@webpack";
|
||||
import { ChannelStore, ComponentDispatch, GuildStore, PrivateChannelsStore, SelectedChannelStore } from "@webpack/common";
|
||||
import { ChannelStore, ComponentDispatch, GuildStore, MaskedLink, ModalImageClasses, PrivateChannelsStore, SelectedChannelStore } from "@webpack/common";
|
||||
import { Guild, Message } from "discord-types/general";
|
||||
|
||||
import { ImageModal, ModalRoot, ModalSize, openModal } from "./modal";
|
||||
|
||||
const PreloadedUserSettings = findLazy(m => m.ProtoClass?.typeName.endsWith("PreloadedUserSettings"));
|
||||
const MessageActions = findByPropsLazy("editMessage", "sendMessage");
|
||||
|
||||
@ -77,3 +79,23 @@ export function sendMessage(
|
||||
|
||||
return MessageActions.sendMessage(channelId, messageData, waitForChannelReady, extra);
|
||||
}
|
||||
|
||||
export function openImageModal(url: string, props?: Partial<React.ComponentProps<ImageModal>>): string {
|
||||
return openModal(modalProps => (
|
||||
<ModalRoot
|
||||
{...modalProps}
|
||||
className={ModalImageClasses.modal}
|
||||
size={ModalSize.DYNAMIC}>
|
||||
<ImageModal
|
||||
className={ModalImageClasses.image}
|
||||
original={url}
|
||||
placeholder={url}
|
||||
src={url}
|
||||
renderLinkComponent={props => <MaskedLink {...props} />}
|
||||
shouldHideMediaOptions={false}
|
||||
shouldAnimate
|
||||
{...props}
|
||||
/>
|
||||
</ModalRoot>
|
||||
));
|
||||
}
|
@ -16,19 +16,19 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { filters, mapMangledModuleLazy } from "@webpack";
|
||||
import { filters, findByCode, mapMangledModuleLazy } from "@webpack";
|
||||
import type { ComponentType, PropsWithChildren, ReactNode, Ref } from "react";
|
||||
|
||||
import { LazyComponent } from "./react";
|
||||
|
||||
export enum ModalSize {
|
||||
export const enum ModalSize {
|
||||
SMALL = "small",
|
||||
MEDIUM = "medium",
|
||||
LARGE = "large",
|
||||
DYNAMIC = "dynamic",
|
||||
}
|
||||
|
||||
enum ModalTransitionState {
|
||||
const enum ModalTransitionState {
|
||||
ENTERING,
|
||||
ENTERED,
|
||||
EXITING,
|
||||
@ -107,6 +107,25 @@ export const Modals = mapMangledModuleLazy(".closeWithCircleBackground", {
|
||||
}>;
|
||||
};
|
||||
|
||||
export type ImageModal = ComponentType<{
|
||||
className?: string;
|
||||
src: string;
|
||||
placeholder: string;
|
||||
original: string;
|
||||
width?: number;
|
||||
height?: number;
|
||||
animated?: boolean;
|
||||
responsive?: boolean;
|
||||
renderLinkComponent(props: any): ReactNode;
|
||||
maxWidth?: number;
|
||||
maxHeight?: number;
|
||||
shouldAnimate?: boolean;
|
||||
onClose?(): void;
|
||||
shouldHideMediaOptions?: boolean;
|
||||
}>;
|
||||
|
||||
export const ImageModal = LazyComponent(() => findByCode(".renderLinkComponent", ".responsive") as ImageModal);
|
||||
|
||||
export const ModalRoot = LazyComponent(() => Modals.ModalRoot);
|
||||
export const ModalHeader = LazyComponent(() => Modals.ModalHeader);
|
||||
export const ModalContent = LazyComponent(() => Modals.ModalContent);
|
||||
|
@ -149,12 +149,6 @@ export async function putCloudSettings() {
|
||||
VencordNative.settings.set(JSON.stringify(PlainSettings, null, 4));
|
||||
|
||||
cloudSettingsLogger.info("Settings uploaded to cloud successfully");
|
||||
showNotification({
|
||||
title: "Cloud Settings",
|
||||
body: "Synchronized your settings to the cloud!",
|
||||
color: "var(--green-360)",
|
||||
noPersist: true
|
||||
});
|
||||
} catch (e: any) {
|
||||
cloudSettingsLogger.error("Failed to sync up", e);
|
||||
showNotification({
|
||||
|
@ -117,7 +117,7 @@ export interface PluginDef {
|
||||
tags?: string[];
|
||||
}
|
||||
|
||||
export enum OptionType {
|
||||
export const enum OptionType {
|
||||
STRING,
|
||||
NUMBER,
|
||||
BIGINT,
|
||||
|
24
src/webpack/common/classes.ts
Normal file
24
src/webpack/common/classes.ts
Normal file
@ -0,0 +1,24 @@
|
||||
/*
|
||||
* 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 { findByPropsLazy } from "@webpack";
|
||||
|
||||
import * as t from "./types/classes";
|
||||
|
||||
export const ModalImageClasses: t.ImageModalClasses = findByPropsLazy("image", "modal");
|
||||
export const ButtonWrapperClasses: t.ButtonWrapperClasses = findByPropsLazy("buttonWrapper", "buttonContent");
|
@ -17,7 +17,7 @@
|
||||
*/
|
||||
|
||||
// eslint-disable-next-line path-alias/no-relative
|
||||
import { filters, findByPropsLazy, waitFor } from "@webpack";
|
||||
import { filters, waitFor } from "@webpack";
|
||||
|
||||
import { waitForComponent } from "./internal";
|
||||
import * as t from "./types/components";
|
||||
@ -44,16 +44,18 @@ export let Popout: t.Popout;
|
||||
export let Dialog: t.Dialog;
|
||||
export let TabBar: any;
|
||||
export let Paginator: t.Paginator;
|
||||
export let ScrollerThin: t.ScrollerThin;
|
||||
export let Clickable: t.Clickable;
|
||||
export let Avatar: t.Avatar;
|
||||
// token lagger real
|
||||
/** css colour resolver stuff, no clue what exactly this does, just copied usage from Discord */
|
||||
export let useToken: t.useToken;
|
||||
|
||||
export const MaskedLink = waitForComponent<t.MaskedLink>("MaskedLink", m => m?.type?.toString().includes("MASKED_LINK)"));
|
||||
export const Timestamp = waitForComponent<t.Timestamp>("Timestamp", filters.byCode(".Messages.MESSAGE_EDITED_TIMESTAMP_A11Y_LABEL.format"));
|
||||
export const Flex = waitForComponent<t.Flex>("Flex", ["Justify", "Align", "Wrap"]);
|
||||
|
||||
export const ButtonWrapperClasses = findByPropsLazy("buttonWrapper", "buttonContent") as Record<string, string>;
|
||||
|
||||
waitFor("FormItem", m => {
|
||||
({ useToken, Card, Button, FormSwitch: Switch, Tooltip, TextInput, TextArea, Text, Select, SearchableSelect, Slider, ButtonLooks, TabBar, Popout, Dialog, Paginator } = m);
|
||||
({ useToken, Card, Button, FormSwitch: Switch, Tooltip, TextInput, TextArea, Text, Select, SearchableSelect, Slider, ButtonLooks, TabBar, Popout, Dialog, Paginator, ScrollerThin, Clickable, Avatar } = m);
|
||||
Forms = m;
|
||||
});
|
||||
|
@ -16,6 +16,7 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
export * from "./classes";
|
||||
export * from "./components";
|
||||
export * from "./menu";
|
||||
export * from "./react";
|
||||
@ -24,4 +25,3 @@ export * as ComponentTypes from "./types/components.d";
|
||||
export * as MenuTypes from "./types/menu.d";
|
||||
export * as UtilTypes from "./types/utils.d";
|
||||
export * from "./utils";
|
||||
|
||||
|
40
src/webpack/common/types/classes.d.ts
vendored
Normal file
40
src/webpack/common/types/classes.d.ts
vendored
Normal file
@ -0,0 +1,40 @@
|
||||
/*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
export interface ImageModalClasses {
|
||||
image: string,
|
||||
modal: string,
|
||||
responsiveWidthMobile: 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;
|
||||
}
|
50
src/webpack/common/types/components.d.ts
vendored
50
src/webpack/common/types/components.d.ts
vendored
@ -397,3 +397,53 @@ export type Paginator = ComponentType<{
|
||||
onPageChange?(page: number): void;
|
||||
hideMaxPage?: boolean;
|
||||
}>;
|
||||
|
||||
export type MaskedLink = ComponentType<{
|
||||
onClick(): void;
|
||||
trusted: boolean;
|
||||
title: string,
|
||||
href: string;
|
||||
}>;
|
||||
|
||||
export type ScrollerThin = ComponentType<PropsWithChildren<{
|
||||
className?: string;
|
||||
style?: CSSProperties;
|
||||
|
||||
dir?: "ltr";
|
||||
orientation?: "horizontal" | "vertical";
|
||||
paddingFix?: boolean;
|
||||
fade?: boolean;
|
||||
|
||||
onClose?(): void;
|
||||
onScroll?(): void;
|
||||
}>>;
|
||||
|
||||
export type Clickable = ComponentType<PropsWithChildren<{
|
||||
className?: string;
|
||||
|
||||
href?: string;
|
||||
ignoreKeyPress?: boolean;
|
||||
|
||||
onClick?(): void;
|
||||
onKeyPress?(): void;
|
||||
}>>;
|
||||
|
||||
export type Avatar = ComponentType<PropsWithChildren<{
|
||||
className?: string;
|
||||
|
||||
src?: string;
|
||||
size?: "SIZE_16" | "SIZE_20" | "SIZE_24" | "SIZE_32" | "SIZE_40" | "SIZE_48" | "SIZE_56" | "SIZE_80" | "SIZE_120";
|
||||
|
||||
statusColor?: string;
|
||||
statusTooltip?: string;
|
||||
statusBackdropColor?: string;
|
||||
|
||||
isMobile?: boolean;
|
||||
isTyping?: boolean;
|
||||
isSpeaking?: boolean;
|
||||
|
||||
typingIndicatorRef?: unknown;
|
||||
|
||||
"aria-hidden"?: boolean;
|
||||
"aria-label"?: string;
|
||||
}>>;
|
||||
|
1
src/webpack/common/types/menu.d.ts
vendored
1
src/webpack/common/types/menu.d.ts
vendored
@ -44,6 +44,7 @@ export interface Menu {
|
||||
onChildrenScroll?: Function;
|
||||
childRowHeight?: number;
|
||||
listClassName?: string;
|
||||
disabled?: boolean;
|
||||
}>;
|
||||
MenuCheckboxItem: RC<{
|
||||
id: string;
|
||||
|
Reference in New Issue
Block a user