Compare commits
38 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
a8b6aea26f | ||
|
e50c2fafa5 | ||
|
6e3cafce42 | ||
|
4d0a064425 | ||
|
d1ad6c47a7 | ||
|
d5c35055f3 | ||
|
cb385d1b28 | ||
|
195f1a032f | ||
|
dfda9e7f84 | ||
|
0d5e2d0696 | ||
|
2834bed518 | ||
|
0b2c3c834a | ||
|
3a54a24c70 | ||
|
244d10dc9e | ||
|
c25bc0ff4b | ||
|
22334663cf | ||
|
8813f81bde | ||
|
84371ed456 | ||
|
8f61119b99 | ||
|
0a89d09727 | ||
|
474932161f | ||
|
bd95a25f4c | ||
|
6a57ecc22b | ||
|
0d665b7e0b | ||
|
d94b28fb8e | ||
|
bc1d8694d4 | ||
|
7bc1362cbd | ||
|
4dce836ff7 | ||
|
9f534c0685 | ||
|
c62d05e1b3 | ||
|
6a1cb133cd | ||
|
c6196dff81 | ||
|
acdb390302 | ||
|
08d88b326d | ||
|
a73858d131 | ||
|
b0caa6f4db | ||
|
168d4b4cd9 | ||
|
06cee75a56 |
@ -62,7 +62,7 @@
|
||||
"indent": ["error", 4, { "SwitchCase": 1 }],
|
||||
"arrow-parens": ["error", "as-needed"],
|
||||
"eol-last": ["error", "always"],
|
||||
"func-call-spacing": ["error", "never"],
|
||||
"@typescript-eslint/func-call-spacing": ["error", "never"],
|
||||
"no-multi-spaces": "error",
|
||||
"no-trailing-spaces": "error",
|
||||
"no-whitespace-before-property": "error",
|
||||
|
@ -16,51 +16,70 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/// <reference path="../src/modules.d.ts" />
|
||||
/// <reference path="../src/globals.d.ts" />
|
||||
|
||||
import monacoHtml from "~fileContent/../src/components/monacoWin.html";
|
||||
import * as DataStore from "../src/api/DataStore";
|
||||
import IpcEvents from "../src/utils/IpcEvents";
|
||||
import { debounce } from "../src/utils";
|
||||
import { getTheme, Theme } from "../src/utils/discord";
|
||||
|
||||
// Discord deletes this so need to store in variable
|
||||
const { localStorage } = window;
|
||||
|
||||
// listeners for ipc.on
|
||||
const listeners = {} as Record<string, Set<Function>>;
|
||||
const cssListeners = new Set<(css: string) => void>();
|
||||
const NOOP = () => { };
|
||||
const NOOP_ASYNC = async () => { };
|
||||
|
||||
const handlers = {
|
||||
[IpcEvents.GET_REPO]: () => "https://github.com/Vendicated/Vencord", // shrug
|
||||
[IpcEvents.GET_SETTINGS_DIR]: () => "LocalStorage",
|
||||
|
||||
[IpcEvents.GET_QUICK_CSS]: () => DataStore.get("VencordQuickCss").then(s => s ?? ""),
|
||||
[IpcEvents.SET_QUICK_CSS]: (css: string) => {
|
||||
DataStore.set("VencordQuickCss", css);
|
||||
listeners[IpcEvents.QUICK_CSS_UPDATE]?.forEach(l => l(null, css));
|
||||
},
|
||||
|
||||
[IpcEvents.GET_SETTINGS]: () => localStorage.getItem("VencordSettings") || "{}",
|
||||
[IpcEvents.SET_SETTINGS]: (s: string) => localStorage.setItem("VencordSettings", s),
|
||||
|
||||
[IpcEvents.GET_UPDATES]: () => ({ ok: true, value: [] }),
|
||||
|
||||
[IpcEvents.OPEN_EXTERNAL]: (url: string) => open(url, "_blank"),
|
||||
};
|
||||
|
||||
function onEvent(event: string, ...args: any[]) {
|
||||
const handler = handlers[event];
|
||||
if (!handler) throw new Error(`Event ${event} not implemented.`);
|
||||
return handler(...args);
|
||||
}
|
||||
const setCssDebounced = debounce((css: string) => VencordNative.quickCss.set(css));
|
||||
|
||||
// probably should make this less cursed at some point
|
||||
window.VencordNative = {
|
||||
getVersions: () => ({}),
|
||||
ipc: {
|
||||
send: (event: string, ...args: any[]) => void onEvent(event, ...args),
|
||||
sendSync: onEvent,
|
||||
on(event: string, listener: () => {}) {
|
||||
(listeners[event] ??= new Set()).add(listener);
|
||||
},
|
||||
off(event: string, listener: () => {}) {
|
||||
return listeners[event]?.delete(listener);
|
||||
},
|
||||
invoke: (event: string, ...args: any[]) => Promise.resolve(onEvent(event, ...args))
|
||||
native: {
|
||||
getVersions: () => ({}),
|
||||
openExternal: async (url) => void open(url, "_blank")
|
||||
},
|
||||
|
||||
updater: {
|
||||
getRepo: async () => ({ ok: true, value: "https://github.com/Vendicated/Vencord" }),
|
||||
getUpdates: async () => ({ ok: true, value: [] }),
|
||||
update: async () => ({ ok: true, value: false }),
|
||||
rebuild: async () => ({ ok: true, value: true }),
|
||||
},
|
||||
|
||||
quickCss: {
|
||||
get: () => DataStore.get("VencordQuickCss").then(s => s ?? ""),
|
||||
set: async (css: string) => {
|
||||
await DataStore.set("VencordQuickCss", css);
|
||||
cssListeners.forEach(l => l(css));
|
||||
},
|
||||
addChangeListener(cb) {
|
||||
cssListeners.add(cb);
|
||||
},
|
||||
openFile: NOOP_ASYNC,
|
||||
async openEditor() {
|
||||
const features = `popup,width=${Math.min(window.innerWidth, 1000)},height=${Math.min(window.innerHeight, 1000)}`;
|
||||
const win = open("about:blank", "VencordQuickCss", features);
|
||||
if (!win) {
|
||||
alert("Failed to open QuickCSS popup. Make sure to allow popups!");
|
||||
return;
|
||||
}
|
||||
|
||||
win.setCss = setCssDebounced;
|
||||
win.getCurrentCss = () => VencordNative.quickCss.get();
|
||||
win.getTheme = () =>
|
||||
getTheme() === Theme.Light
|
||||
? "vs-light"
|
||||
: "vs-dark";
|
||||
|
||||
win.document.write(monacoHtml);
|
||||
},
|
||||
},
|
||||
|
||||
settings: {
|
||||
get: () => localStorage.getItem("VencordSettings") || "{}",
|
||||
set: async (s: string) => localStorage.setItem("VencordSettings", s),
|
||||
getSettingsDir: async () => "LocalStorage"
|
||||
}
|
||||
};
|
||||
|
@ -26,10 +26,6 @@ export default definePlugin({
|
||||
name: "Your Name",
|
||||
},
|
||||
],
|
||||
// Delete `patches` if you are not using code patches, as it will make
|
||||
// your plugin require restarts, and your stop() method will not be
|
||||
// invoked at all. The presence of the key in the object alone is
|
||||
// enough to trigger this behavior, even if the value is an empty array.
|
||||
patches: [],
|
||||
// Delete these two below if you are only using code patches
|
||||
start() {},
|
||||
|
32
package.json
32
package.json
@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "vencord",
|
||||
"private": "true",
|
||||
"version": "1.2.0",
|
||||
"version": "1.2.1",
|
||||
"description": "The cutest Discord client mod",
|
||||
"homepage": "https://github.com/Vendicated/Vencord#readme",
|
||||
"bugs": {
|
||||
@ -32,20 +32,20 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@vap/core": "0.0.12",
|
||||
"@vap/shiki": "0.10.3",
|
||||
"@vap/shiki": "0.10.5",
|
||||
"fflate": "^0.7.4",
|
||||
"nanoid": "^4.0.2",
|
||||
"virtual-merge": "^1.0.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/diff": "^5.0.2",
|
||||
"@types/lodash": "^4.14.191",
|
||||
"@types/node": "^18.11.18",
|
||||
"@types/react": "^18.0.27",
|
||||
"@types/react-dom": "^18.0.10",
|
||||
"@types/diff": "^5.0.3",
|
||||
"@types/lodash": "^4.14.194",
|
||||
"@types/node": "^18.16.3",
|
||||
"@types/react": "^18.2.0",
|
||||
"@types/react-dom": "^18.2.1",
|
||||
"@types/yazl": "^2.4.2",
|
||||
"@typescript-eslint/eslint-plugin": "^5.49.0",
|
||||
"@typescript-eslint/parser": "^5.49.0",
|
||||
"@typescript-eslint/eslint-plugin": "^5.59.1",
|
||||
"@typescript-eslint/parser": "^5.59.1",
|
||||
"diff": "^5.1.0",
|
||||
"discord-types": "^1.3.26",
|
||||
"esbuild": "^0.15.18",
|
||||
@ -53,17 +53,17 @@
|
||||
"eslint-import-resolver-alias": "^1.1.2",
|
||||
"eslint-plugin-header": "^3.1.1",
|
||||
"eslint-plugin-path-alias": "^1.0.0",
|
||||
"eslint-plugin-simple-import-sort": "^8.0.0",
|
||||
"eslint-plugin-simple-import-sort": "^10.0.0",
|
||||
"eslint-plugin-unused-imports": "^2.0.0",
|
||||
"highlight.js": "10.6.0",
|
||||
"moment": "^2.29.4",
|
||||
"puppeteer-core": "^19.6.0",
|
||||
"puppeteer-core": "^19.11.1",
|
||||
"standalone-electron-types": "^1.0.0",
|
||||
"stylelint": "^14.16.1",
|
||||
"stylelint-config-standard": "^29.0.0",
|
||||
"tsx": "^3.12.6",
|
||||
"type-fest": "^3.5.3",
|
||||
"typescript": "^4.9.4"
|
||||
"stylelint": "^15.6.0",
|
||||
"stylelint-config-standard": "^33.0.0",
|
||||
"tsx": "^3.12.7",
|
||||
"type-fest": "^3.9.0",
|
||||
"typescript": "^5.0.4"
|
||||
},
|
||||
"packageManager": "pnpm@8.1.1",
|
||||
"pnpm": {
|
||||
|
734
pnpm-lock.yaml
generated
734
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
@ -130,7 +130,7 @@ async function printReport() {
|
||||
},
|
||||
{
|
||||
title: "Discord Errors",
|
||||
description: toCodeBlock(report.otherErrors.join("\n")),
|
||||
description: report.otherErrors.length ? toCodeBlock(report.otherErrors.join("\n")) : "None",
|
||||
color: report.otherErrors.length ? 0xff0000 : 0x00ff00
|
||||
}
|
||||
]
|
||||
@ -194,9 +194,10 @@ page.on("console", async e => {
|
||||
return a.toString();
|
||||
}
|
||||
})
|
||||
).then(a => a.join(" "));
|
||||
).then(a => a.join(" ").trim());
|
||||
|
||||
if (!text.startsWith("Failed to load resource: the server responded with a status of")) {
|
||||
|
||||
if (text.length && !text.startsWith("Failed to load resource: the server responded with a status of")) {
|
||||
console.error("Got unexpected error", text);
|
||||
report.otherErrors.push(text);
|
||||
}
|
||||
@ -233,7 +234,7 @@ function runTime(token: string) {
|
||||
// Needs native server to run
|
||||
if (p.name === "WebRichPresence (arRPC)") return;
|
||||
|
||||
p.required = true;
|
||||
Vencord.Settings.plugins[p.name].enabled = true;
|
||||
p.patches?.forEach(patch => {
|
||||
patch.plugin = p.name;
|
||||
delete patch.predicate;
|
||||
|
@ -28,12 +28,12 @@ import "./utils/quickCss";
|
||||
import "./webpack/patchWebpack";
|
||||
|
||||
import { showNotification } from "./api/Notifications";
|
||||
import { PlainSettings, Settings } from "./api/settings";
|
||||
import { PlainSettings, Settings } from "./api/Settings";
|
||||
import { patches, PMLogger, startAllPlugins } from "./plugins";
|
||||
import { localStorage } from "./utils/localStorage";
|
||||
import { relaunch } from "./utils/native";
|
||||
import { getCloudSettings, putCloudSettings } from "./utils/settingsSync";
|
||||
import { checkForUpdates, rebuild, update, UpdateLogger } from "./utils/updater";
|
||||
import { checkForUpdates, update, UpdateLogger } from "./utils/updater";
|
||||
import { onceReady } from "./webpack";
|
||||
import { SettingsRouter } from "./webpack/common";
|
||||
|
||||
@ -76,7 +76,6 @@ async function init() {
|
||||
|
||||
if (Settings.autoUpdate) {
|
||||
await update();
|
||||
await rebuild();
|
||||
if (Settings.autoUpdateNotification)
|
||||
setTimeout(() => showNotification({
|
||||
title: "Vencord has been updated!",
|
||||
|
@ -16,34 +16,46 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import IPC_EVENTS from "@utils/IpcEvents";
|
||||
import { IpcRenderer, ipcRenderer } from "electron";
|
||||
import { IpcEvents } from "@utils/IpcEvents";
|
||||
import { IpcRes } from "@utils/types";
|
||||
import { ipcRenderer } from "electron";
|
||||
|
||||
function assertEventAllowed(event: string) {
|
||||
if (!(event in IPC_EVENTS)) throw new Error(`Event ${event} not allowed.`);
|
||||
function invoke<T = any>(event: IpcEvents, ...args: any[]) {
|
||||
return ipcRenderer.invoke(event, ...args) as Promise<T>;
|
||||
}
|
||||
|
||||
export function sendSync<T = any>(event: IpcEvents, ...args: any[]) {
|
||||
return ipcRenderer.sendSync(event, ...args) as T;
|
||||
}
|
||||
|
||||
export default {
|
||||
getVersions: () => process.versions,
|
||||
ipc: {
|
||||
send(event: string, ...args: any[]) {
|
||||
assertEventAllowed(event);
|
||||
ipcRenderer.send(event, ...args);
|
||||
updater: {
|
||||
getUpdates: () => invoke<IpcRes<Record<"hash" | "author" | "message", string>[]>>(IpcEvents.GET_UPDATES),
|
||||
update: () => invoke<IpcRes<boolean>>(IpcEvents.UPDATE),
|
||||
rebuild: () => invoke<IpcRes<boolean>>(IpcEvents.BUILD),
|
||||
getRepo: () => invoke<IpcRes<string>>(IpcEvents.GET_REPO),
|
||||
},
|
||||
|
||||
settings: {
|
||||
get: () => sendSync<string>(IpcEvents.GET_SETTINGS),
|
||||
set: (settings: string) => invoke<void>(IpcEvents.SET_SETTINGS, settings),
|
||||
getSettingsDir: () => invoke<string>(IpcEvents.GET_SETTINGS_DIR),
|
||||
},
|
||||
|
||||
quickCss: {
|
||||
get: () => invoke<string>(IpcEvents.GET_QUICK_CSS),
|
||||
set: (css: string) => invoke<void>(IpcEvents.SET_QUICK_CSS, css),
|
||||
|
||||
addChangeListener(cb: (newCss: string) => void) {
|
||||
ipcRenderer.on(IpcEvents.QUICK_CSS_UPDATE, (_, css) => cb(css));
|
||||
},
|
||||
sendSync<T = any>(event: string, ...args: any[]): T {
|
||||
assertEventAllowed(event);
|
||||
return ipcRenderer.sendSync(event, ...args);
|
||||
},
|
||||
on(event: string, listener: Parameters<IpcRenderer["on"]>[1]) {
|
||||
assertEventAllowed(event);
|
||||
ipcRenderer.on(event, listener);
|
||||
},
|
||||
off(event: string, listener: Parameters<IpcRenderer["off"]>[1]) {
|
||||
assertEventAllowed(event);
|
||||
ipcRenderer.off(event, listener);
|
||||
},
|
||||
invoke<T = any>(event: string, ...args: any[]): Promise<T> {
|
||||
assertEventAllowed(event);
|
||||
return ipcRenderer.invoke(event, ...args);
|
||||
}
|
||||
}
|
||||
|
||||
openFile: () => invoke<void>(IpcEvents.OPEN_QUICKCSS),
|
||||
openEditor: () => invoke<void>(IpcEvents.OPEN_MONACO_EDITOR),
|
||||
},
|
||||
|
||||
native: {
|
||||
getVersions: () => process.versions as Partial<NodeJS.ProcessVersions>,
|
||||
openExternal: (url: string) => invoke<void>(IpcEvents.OPEN_EXTERNAL, url)
|
||||
},
|
||||
};
|
||||
|
@ -16,7 +16,7 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { makeCodeblock } from "@utils/misc";
|
||||
import { makeCodeblock } from "@utils/text";
|
||||
|
||||
import { sendBotMessage } from "./commandHelpers";
|
||||
import { ApplicationCommandInputType, ApplicationCommandOptionType, ApplicationCommandType, Argument, Command, CommandContext, Option } from "./types";
|
||||
|
@ -16,7 +16,7 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import Logger from "@utils/Logger";
|
||||
import { Logger } from "@utils/Logger";
|
||||
import type { ReactElement } from "react";
|
||||
|
||||
type ContextMenuPatchCallbackReturn = (() => void) | void;
|
||||
|
@ -16,7 +16,7 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import Logger from "@utils/Logger";
|
||||
import { Logger } from "@utils/Logger";
|
||||
import { MessageStore } from "@webpack/common";
|
||||
import type { Channel, Message } from "discord-types/general";
|
||||
import type { Promisable } from "type-fest";
|
||||
@ -36,10 +36,50 @@ export interface Emoji {
|
||||
export interface MessageObject {
|
||||
content: string,
|
||||
validNonShortcutEmojis: Emoji[];
|
||||
invalidEmojis: any[];
|
||||
tts: boolean;
|
||||
}
|
||||
|
||||
export interface Upload {
|
||||
classification: string;
|
||||
currentSize: number;
|
||||
description: string | null;
|
||||
filename: string;
|
||||
id: string;
|
||||
isImage: boolean;
|
||||
isVideo: boolean;
|
||||
item: {
|
||||
file: File;
|
||||
platform: number;
|
||||
};
|
||||
loaded: number;
|
||||
mimeType: string;
|
||||
preCompressionSize: number;
|
||||
responseUrl: string;
|
||||
sensitive: boolean;
|
||||
showLargeMessageDialog: boolean;
|
||||
spoiler: boolean;
|
||||
status: "NOT_STARTED" | "STARTED" | "UPLOADING" | "ERROR" | "COMPLETED" | "CANCELLED";
|
||||
uniqueId: string;
|
||||
uploadedFilename: string;
|
||||
}
|
||||
|
||||
export interface MessageReplyOptions {
|
||||
messageReference: Message["messageReference"];
|
||||
allowedMentions?: {
|
||||
parse: Array<string>;
|
||||
repliedUser: boolean;
|
||||
};
|
||||
}
|
||||
|
||||
export interface MessageExtra {
|
||||
stickerIds?: string[];
|
||||
stickers?: string[];
|
||||
uploads?: Upload[];
|
||||
replyOptions: MessageReplyOptions;
|
||||
content: string;
|
||||
channel: Channel;
|
||||
type?: any;
|
||||
openWarningPopout: (props: any) => any;
|
||||
}
|
||||
|
||||
export type SendListener = (channelId: string, messageObj: MessageObject, extra: MessageExtra) => Promisable<void | { cancel: boolean; }>;
|
||||
@ -48,7 +88,8 @@ export type EditListener = (channelId: string, messageId: string, messageObj: Me
|
||||
const sendListeners = new Set<SendListener>();
|
||||
const editListeners = new Set<EditListener>();
|
||||
|
||||
export async function _handlePreSend(channelId: string, messageObj: MessageObject, extra: MessageExtra) {
|
||||
export async function _handlePreSend(channelId: string, messageObj: MessageObject, extra: MessageExtra, replyOptions: MessageReplyOptions) {
|
||||
extra.replyOptions = replyOptions;
|
||||
for (const listener of sendListeners) {
|
||||
try {
|
||||
const result = await listener(channelId, messageObj, extra);
|
||||
|
@ -16,7 +16,7 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import Logger from "@utils/Logger";
|
||||
import { Logger } from "@utils/Logger";
|
||||
import { Channel, Message } from "discord-types/general";
|
||||
import type { MouseEventHandler } from "react";
|
||||
|
||||
|
@ -18,7 +18,7 @@
|
||||
|
||||
import "./styles.css";
|
||||
|
||||
import { useSettings } from "@api/settings";
|
||||
import { useSettings } from "@api/Settings";
|
||||
import ErrorBoundary from "@components/ErrorBoundary";
|
||||
import { classes } from "@utils/misc";
|
||||
import { React, useEffect, useMemo, useState, useStateFromStores, WindowStore } from "@webpack/common";
|
||||
|
@ -16,7 +16,7 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { Settings } from "@api/settings";
|
||||
import { Settings } from "@api/Settings";
|
||||
import { Queue } from "@utils/Queue";
|
||||
import { ReactDOM } from "@webpack/common";
|
||||
import type { ReactNode } from "react";
|
||||
|
@ -17,10 +17,10 @@
|
||||
*/
|
||||
|
||||
import * as DataStore from "@api/DataStore";
|
||||
import { Settings } from "@api/settings";
|
||||
import { Settings } from "@api/Settings";
|
||||
import { classNameFactory } from "@api/Styles";
|
||||
import { useAwaiter } from "@utils/misc";
|
||||
import { closeModal, ModalCloseButton, ModalContent, ModalFooter, ModalHeader, ModalProps, ModalRoot, ModalSize, openModal } from "@utils/modal";
|
||||
import { useAwaiter } from "@utils/react";
|
||||
import { Alerts, Button, Forms, moment, React, Text, Timestamp, useEffect, useReducer, useState } from "@webpack/common";
|
||||
import { nanoid } from "nanoid";
|
||||
import type { DispatchWithoutAction } from "react";
|
||||
|
@ -16,7 +16,7 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import Logger from "@utils/Logger";
|
||||
import { Logger } from "@utils/Logger";
|
||||
|
||||
const logger = new Logger("ServerListAPI");
|
||||
|
||||
|
@ -17,9 +17,8 @@
|
||||
*/
|
||||
|
||||
import { debounce } from "@utils/debounce";
|
||||
import IpcEvents from "@utils/IpcEvents";
|
||||
import { localStorage } from "@utils/localStorage";
|
||||
import Logger from "@utils/Logger";
|
||||
import { Logger } from "@utils/Logger";
|
||||
import { mergeDefaults } from "@utils/misc";
|
||||
import { putCloudSettings } from "@utils/settingsSync";
|
||||
import { DefinedSettings, OptionType, SettingsChecks, SettingsDefinition } from "@utils/types";
|
||||
@ -94,7 +93,7 @@ const DefaultSettings: Settings = {
|
||||
};
|
||||
|
||||
try {
|
||||
var settings = JSON.parse(VencordNative.ipc.sendSync(IpcEvents.GET_SETTINGS)) as Settings;
|
||||
var settings = JSON.parse(VencordNative.settings.get()) as Settings;
|
||||
mergeDefaults(settings, DefaultSettings);
|
||||
} catch (err) {
|
||||
var settings = mergeDefaults({} as Settings, DefaultSettings);
|
||||
@ -173,7 +172,7 @@ function makeProxy(settings: any, root = settings, path = ""): Settings {
|
||||
PlainSettings.cloud.settingsSyncVersion = Date.now();
|
||||
localStorage.Vencord_settingsDirty = true;
|
||||
saveSettingsOnFrequentAction();
|
||||
VencordNative.ipc.invoke(IpcEvents.SET_SETTINGS, JSON.stringify(root, null, 4));
|
||||
VencordNative.settings.set(JSON.stringify(root, null, 4));
|
||||
return true;
|
||||
}
|
||||
});
|
||||
@ -249,10 +248,7 @@ export function migratePluginSettings(name: string, ...oldNames: string[]) {
|
||||
logger.info(`Migrating settings from old name ${oldName} to ${name}`);
|
||||
plugins[name] = plugins[oldName];
|
||||
delete plugins[oldName];
|
||||
VencordNative.ipc.invoke(
|
||||
IpcEvents.SET_SETTINGS,
|
||||
JSON.stringify(settings, null, 4)
|
||||
);
|
||||
VencordNative.settings.set(JSON.stringify(settings, null, 4));
|
||||
break;
|
||||
}
|
||||
}
|
@ -16,11 +16,11 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import Logger from "@utils/Logger";
|
||||
import { proxyLazy } from "@utils/proxyLazy";
|
||||
import { proxyLazy } from "@utils/lazy";
|
||||
import { Logger } from "@utils/Logger";
|
||||
import { findModuleId, wreq } from "@webpack";
|
||||
|
||||
import { Settings } from "./settings";
|
||||
import { Settings } from "./Settings";
|
||||
|
||||
interface Setting<T> {
|
||||
/**
|
||||
|
@ -16,7 +16,6 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import IpcEvents from "@utils/IpcEvents";
|
||||
import { Button } from "@webpack/common";
|
||||
|
||||
import { Heart } from "./Heart";
|
||||
@ -27,9 +26,7 @@ export default function DonateButton(props: any) {
|
||||
{...props}
|
||||
look={Button.Looks.LINK}
|
||||
color={Button.Colors.TRANSPARENT}
|
||||
onClick={() =>
|
||||
VencordNative.ipc.invoke(IpcEvents.OPEN_EXTERNAL, "https://github.com/sponsors/Vendicated")
|
||||
}
|
||||
onClick={() => VencordNative.native.openExternal("https://github.com/sponsors/Vendicated")}
|
||||
>
|
||||
<Heart />
|
||||
Donate
|
||||
|
@ -16,9 +16,9 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import Logger from "@utils/Logger";
|
||||
import { Logger } from "@utils/Logger";
|
||||
import { Margins } from "@utils/margins";
|
||||
import { LazyComponent } from "@utils/misc";
|
||||
import { LazyComponent } from "@utils/react";
|
||||
import { React } from "@webpack/common";
|
||||
|
||||
import { ErrorCard } from "./ErrorCard";
|
||||
|
83
src/components/Icons.tsx
Normal file
83
src/components/Icons.tsx
Normal file
@ -0,0 +1,83 @@
|
||||
/*
|
||||
* 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 { classes } from "@utils/misc";
|
||||
import type { PropsWithChildren } from "react";
|
||||
|
||||
interface BaseIconProps extends IconProps {
|
||||
viewBox: string;
|
||||
}
|
||||
|
||||
interface IconProps {
|
||||
className?: string;
|
||||
height?: number;
|
||||
width?: number;
|
||||
}
|
||||
|
||||
function Icon({ height = 24, width = 24, className, children, viewBox }: PropsWithChildren<BaseIconProps>) {
|
||||
return (
|
||||
<svg
|
||||
className={classes(className, "vc-icon")}
|
||||
aria-hidden="true"
|
||||
role="img"
|
||||
width={width}
|
||||
height={height}
|
||||
viewBox={viewBox}
|
||||
>
|
||||
{children}
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Discord's link icon, as seen in the Message context menu "Copy Message Link" option
|
||||
*/
|
||||
export function LinkIcon({ height = 24, width = 24, className }: IconProps) {
|
||||
return (
|
||||
<Icon
|
||||
height={height}
|
||||
width={width}
|
||||
className={classes(className, "vc-link-icon")}
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<g fill="none" fill-rule="evenodd">
|
||||
<path fill="currentColor" d="M10.59 13.41c.41.39.41 1.03 0 1.42-.39.39-1.03.39-1.42 0a5.003 5.003 0 0 1 0-7.07l3.54-3.54a5.003 5.003 0 0 1 7.07 0 5.003 5.003 0 0 1 0 7.07l-1.49 1.49c.01-.82-.12-1.64-.4-2.42l.47-.48a2.982 2.982 0 0 0 0-4.24 2.982 2.982 0 0 0-4.24 0l-3.53 3.53a2.982 2.982 0 0 0 0 4.24zm2.82-4.24c.39-.39 1.03-.39 1.42 0a5.003 5.003 0 0 1 0 7.07l-3.54 3.54a5.003 5.003 0 0 1-7.07 0 5.003 5.003 0 0 1 0-7.07l1.49-1.49c-.01.82.12 1.64.4 2.43l-.47.47a2.982 2.982 0 0 0 0 4.24 2.982 2.982 0 0 0 4.24 0l3.53-3.53a2.982 2.982 0 0 0 0-4.24.973.973 0 0 1 0-1.42z" />
|
||||
<rect width={width} height={height} />
|
||||
</g>
|
||||
</Icon>
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Discord's copy icon, as seen in the user popout right of the username when clicking
|
||||
* your own username in the bottom left user panel
|
||||
*/
|
||||
export function CopyIcon(props: IconProps) {
|
||||
return (
|
||||
<Icon
|
||||
{...props}
|
||||
className={classes(props.className, "vc-copy-icon")}
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<g fill="currentColor">
|
||||
<path d="M16 1H4c-1.1 0-2 .9-2 2v14h2V3h12V1z" />
|
||||
<path d="M15 5H8c-1.1 0-1.99.9-1.99 2L6 21c0 1.1.89 2 1.99 2H19c1.1 0 2-.9 2-2V11l-6-6zM8 21V7h6v5h5v9H8z" />
|
||||
</g>
|
||||
</Icon>
|
||||
);
|
||||
}
|
@ -1,51 +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 { debounce } from "@utils/debounce";
|
||||
import IpcEvents from "@utils/IpcEvents";
|
||||
import { Queue } from "@utils/Queue";
|
||||
import { find } from "@webpack";
|
||||
|
||||
import monacoHtml from "~fileContent/monacoWin.html";
|
||||
|
||||
const queue = new Queue();
|
||||
const setCss = debounce((css: string) => {
|
||||
queue.push(() => VencordNative.ipc.invoke(IpcEvents.SET_QUICK_CSS, css));
|
||||
});
|
||||
|
||||
export async function launchMonacoEditor() {
|
||||
const features = `popup,width=${Math.min(window.innerWidth, 1000)},height=${Math.min(window.innerHeight, 1000)}`;
|
||||
const win = open("about:blank", "VencordQuickCss", features);
|
||||
if (!win) {
|
||||
alert("Failed to open QuickCSS popup. Make sure to allow popups!");
|
||||
return;
|
||||
}
|
||||
|
||||
win.setCss = setCss;
|
||||
win.getCurrentCss = () => VencordNative.ipc.invoke(IpcEvents.GET_QUICK_CSS);
|
||||
win.getTheme = () =>
|
||||
find(m =>
|
||||
m.ProtoClass?.typeName.endsWith("PreloadedUserSettings")
|
||||
)?.getCurrentValue()?.appearance?.theme === 2
|
||||
? "vs-light"
|
||||
: "vs-dark";
|
||||
|
||||
win.document.write(monacoHtml);
|
||||
|
||||
window.__VENCORD_MONACO_WIN__ = new WeakRef(win);
|
||||
}
|
@ -18,8 +18,8 @@
|
||||
|
||||
import { debounce } from "@utils/debounce";
|
||||
import { Margins } from "@utils/margins";
|
||||
import { makeCodeblock } from "@utils/misc";
|
||||
import { canonicalizeMatch, canonicalizeReplace } from "@utils/patches";
|
||||
import { makeCodeblock } from "@utils/text";
|
||||
import { ReplaceFn } from "@utils/types";
|
||||
import { search } from "@webpack";
|
||||
import { Button, Clipboard, Forms, Parser, React, Switch, Text, TextInput } from "@webpack/common";
|
||||
|
@ -17,13 +17,14 @@
|
||||
*/
|
||||
|
||||
import { generateId } from "@api/Commands";
|
||||
import { useSettings } from "@api/settings";
|
||||
import { useSettings } from "@api/Settings";
|
||||
import ErrorBoundary from "@components/ErrorBoundary";
|
||||
import { Flex } from "@components/Flex";
|
||||
import { proxyLazy } from "@utils/lazy";
|
||||
import { Margins } from "@utils/margins";
|
||||
import { classes, LazyComponent } from "@utils/misc";
|
||||
import { classes } from "@utils/misc";
|
||||
import { ModalCloseButton, ModalContent, ModalFooter, ModalHeader, ModalProps, ModalRoot, ModalSize } from "@utils/modal";
|
||||
import { proxyLazy } from "@utils/proxyLazy";
|
||||
import { LazyComponent } from "@utils/react";
|
||||
import { OptionType, Plugin } from "@utils/types";
|
||||
import { findByCode, findByPropsLazy } from "@webpack";
|
||||
import { Button, FluxDispatcher, Forms, React, Text, Tooltip, UserStore, UserUtils } from "@webpack/common";
|
||||
@ -128,6 +129,8 @@ export default function PluginModal({ plugin, onRestartNeeded, onClose, transiti
|
||||
return <Forms.FormText>There are no settings for this plugin.</Forms.FormText>;
|
||||
} else {
|
||||
const options = Object.entries(plugin.options).map(([key, setting]) => {
|
||||
if (setting.hidden) return null;
|
||||
|
||||
function onChange(newValue: any) {
|
||||
setTempSettings(s => ({ ...s, [key]: newValue }));
|
||||
}
|
||||
|
@ -20,7 +20,7 @@ import "./styles.css";
|
||||
|
||||
import * as DataStore from "@api/DataStore";
|
||||
import { showNotice } from "@api/Notices";
|
||||
import { useSettings } from "@api/settings";
|
||||
import { useSettings } from "@api/Settings";
|
||||
import { classNameFactory } from "@api/Styles";
|
||||
import ErrorBoundary from "@components/ErrorBoundary";
|
||||
import { Flex } from "@components/Flex";
|
||||
@ -29,10 +29,12 @@ import { Badge } from "@components/PluginSettings/components";
|
||||
import PluginModal from "@components/PluginSettings/PluginModal";
|
||||
import { Switch } from "@components/Switch";
|
||||
import { ChangeList } from "@utils/ChangeList";
|
||||
import Logger from "@utils/Logger";
|
||||
import { Logger } from "@utils/Logger";
|
||||
import { Margins } from "@utils/margins";
|
||||
import { classes, LazyComponent, useAwaiter } from "@utils/misc";
|
||||
import { classes } from "@utils/misc";
|
||||
import { openModalLazy } from "@utils/modal";
|
||||
import { onlyOnce } from "@utils/onlyOnce";
|
||||
import { LazyComponent, useAwaiter } from "@utils/react";
|
||||
import { Plugin } from "@utils/types";
|
||||
import { findByCode, findByPropsLazy } from "@webpack";
|
||||
import { Alerts, Button, Card, Forms, Parser, React, Select, Text, TextInput, Toasts, Tooltip } from "@webpack/common";
|
||||
@ -125,7 +127,7 @@ function PluginCard({ plugin, disabled, onRestartNeeded, onMouseEnter, onMouseLe
|
||||
}
|
||||
|
||||
// if the plugin has patches, dont use stopPlugin/startPlugin. Wait for restart to apply changes.
|
||||
if (plugin.patches) {
|
||||
if (plugin.patches?.length) {
|
||||
settings.enabled = !wasEnabled;
|
||||
onRestartNeeded(plugin.name);
|
||||
return;
|
||||
@ -258,6 +260,9 @@ export default ErrorBoundary.wrap(function PluginSettings() {
|
||||
requiredPlugins = [];
|
||||
|
||||
for (const p of sortedPlugins) {
|
||||
if (!p.options && p.name.endsWith("API") && searchValue.value !== "API")
|
||||
continue;
|
||||
|
||||
if (!pluginFilter(p)) continue;
|
||||
|
||||
const isRequired = p.required || depMap[p.name]?.some(d => settings.plugins[d].enabled);
|
||||
@ -341,7 +346,7 @@ export default ErrorBoundary.wrap(function PluginSettings() {
|
||||
);
|
||||
}, {
|
||||
message: "Failed to render the Plugin Settings. If this persists, try using the installer to reinstall!",
|
||||
onError: handleComponentFailed,
|
||||
onError: onlyOnce(handleComponentFailed),
|
||||
});
|
||||
|
||||
function makeDependencyList(deps: string[]) {
|
||||
|
@ -17,7 +17,7 @@
|
||||
*/
|
||||
|
||||
import { showNotification } from "@api/Notifications";
|
||||
import { Settings, useSettings } from "@api/settings";
|
||||
import { Settings, useSettings } from "@api/Settings";
|
||||
import { CheckedTextInput } from "@components/CheckedTextInput";
|
||||
import ErrorBoundary from "@components/ErrorBoundary";
|
||||
import { Link } from "@components/Link";
|
||||
|
@ -16,11 +16,11 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { useSettings } from "@api/settings";
|
||||
import { useSettings } from "@api/Settings";
|
||||
import ErrorBoundary from "@components/ErrorBoundary";
|
||||
import { Link } from "@components/Link";
|
||||
import { Margins } from "@utils/margins";
|
||||
import { useAwaiter } from "@utils/misc";
|
||||
import { useAwaiter } from "@utils/react";
|
||||
import { findLazy } from "@webpack";
|
||||
import { Card, Forms, React, TextArea } from "@webpack/common";
|
||||
|
||||
@ -93,7 +93,7 @@ export default ErrorBoundary.wrap(function () {
|
||||
<Card className="vc-settings-card vc-text-selectable">
|
||||
<Forms.FormTitle tag="h5">Paste links to .theme.css files here</Forms.FormTitle>
|
||||
<Forms.FormText>One link per line</Forms.FormText>
|
||||
<Forms.FormText>Make sure to use the raw links or github.io links!</Forms.FormText>
|
||||
<Forms.FormText><strong>Make sure to use the raw links or github.io links!</strong></Forms.FormText>
|
||||
<Forms.FormDivider className={Margins.top8 + " " + Margins.bottom8} />
|
||||
<Forms.FormTitle tag="h5">Find Themes:</Forms.FormTitle>
|
||||
<div style={{ marginBottom: ".5em" }}>
|
||||
|
@ -16,16 +16,18 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { useSettings } from "@api/settings";
|
||||
import { useSettings } from "@api/Settings";
|
||||
import ErrorBoundary from "@components/ErrorBoundary";
|
||||
import { ErrorCard } from "@components/ErrorCard";
|
||||
import { Flex } from "@components/Flex";
|
||||
import { handleComponentFailed } from "@components/handleComponentFailed";
|
||||
import { Link } from "@components/Link";
|
||||
import { Margins } from "@utils/margins";
|
||||
import { classes, useAwaiter } from "@utils/misc";
|
||||
import { classes } from "@utils/misc";
|
||||
import { relaunch } from "@utils/native";
|
||||
import { changes, checkForUpdates, getRepo, isNewer, rebuild, update, updateError, UpdateLogger } from "@utils/updater";
|
||||
import { onlyOnce } from "@utils/onlyOnce";
|
||||
import { useAwaiter } from "@utils/react";
|
||||
import { changes, checkForUpdates, getRepo, isNewer, update, updateError, UpdateLogger } from "@utils/updater";
|
||||
import { Alerts, Button, Card, Forms, Parser, React, Switch, Toasts } from "@webpack/common";
|
||||
|
||||
import gitHash from "~git-hash";
|
||||
@ -125,7 +127,6 @@ function Updatable(props: CommonProps) {
|
||||
onClick={withDispatcher(setIsUpdating, async () => {
|
||||
if (await update()) {
|
||||
setUpdates([]);
|
||||
await rebuild();
|
||||
await new Promise<void>(r => {
|
||||
Alerts.show({
|
||||
title: "Update Success!",
|
||||
@ -251,5 +252,5 @@ function Updater() {
|
||||
|
||||
export default IS_WEB ? null : ErrorBoundary.wrap(Updater, {
|
||||
message: "Failed to render the Updater. If this persists, try using the installer to reinstall!",
|
||||
onError: handleComponentFailed,
|
||||
onError: onlyOnce(handleComponentFailed),
|
||||
});
|
||||
|
@ -18,15 +18,15 @@
|
||||
|
||||
|
||||
import { openNotificationLogModal } from "@api/Notifications/notificationLog";
|
||||
import { Settings, useSettings } from "@api/settings";
|
||||
import { Settings, useSettings } from "@api/Settings";
|
||||
import { classNameFactory } from "@api/Styles";
|
||||
import DonateButton from "@components/DonateButton";
|
||||
import ErrorBoundary from "@components/ErrorBoundary";
|
||||
import { ErrorCard } from "@components/ErrorCard";
|
||||
import IpcEvents from "@utils/IpcEvents";
|
||||
import { Margins } from "@utils/margins";
|
||||
import { identity, useAwaiter } from "@utils/misc";
|
||||
import { identity } from "@utils/misc";
|
||||
import { relaunch, showItemInFolder } from "@utils/native";
|
||||
import { useAwaiter } from "@utils/react";
|
||||
import { Button, Card, Forms, React, Select, Slider, Switch } from "@webpack/common";
|
||||
|
||||
const cl = classNameFactory("vc-settings-");
|
||||
@ -39,7 +39,7 @@ type KeysOfType<Object, Type> = {
|
||||
}[keyof Object];
|
||||
|
||||
function VencordSettings() {
|
||||
const [settingsDir, , settingsDirPending] = useAwaiter(() => VencordNative.ipc.invoke<string>(IpcEvents.GET_SETTINGS_DIR), {
|
||||
const [settingsDir, , settingsDirPending] = useAwaiter(VencordNative.settings.getSettingsDir, {
|
||||
fallbackValue: "Loading..."
|
||||
});
|
||||
const settings = useSettings();
|
||||
@ -101,40 +101,35 @@ function VencordSettings() {
|
||||
<DonateCard image={donateImage} />
|
||||
<Forms.FormSection title="Quick Actions">
|
||||
<Card className={cl("quick-actions-card")}>
|
||||
{IS_WEB ? (
|
||||
<Button
|
||||
onClick={() => require("../Monaco").launchMonacoEditor()}
|
||||
size={Button.Sizes.SMALL}
|
||||
disabled={settingsDir === "Loading..."}>
|
||||
Open QuickCSS File
|
||||
</Button>
|
||||
) : (
|
||||
<React.Fragment>
|
||||
<React.Fragment>
|
||||
{!IS_WEB && (
|
||||
<Button
|
||||
onClick={relaunch}
|
||||
size={Button.Sizes.SMALL}>
|
||||
Restart Client
|
||||
</Button>
|
||||
<Button
|
||||
onClick={() => VencordNative.ipc.invoke(IpcEvents.OPEN_MONACO_EDITOR)}
|
||||
size={Button.Sizes.SMALL}
|
||||
disabled={settingsDir === "Loading..."}>
|
||||
Open QuickCSS File
|
||||
</Button>
|
||||
)}
|
||||
<Button
|
||||
onClick={() => VencordNative.quickCss.openEditor()}
|
||||
size={Button.Sizes.SMALL}
|
||||
disabled={settingsDir === "Loading..."}>
|
||||
Open QuickCSS File
|
||||
</Button>
|
||||
{!IS_WEB && (
|
||||
<Button
|
||||
onClick={() => showItemInFolder(settingsDir)}
|
||||
size={Button.Sizes.SMALL}
|
||||
disabled={settingsDirPending}>
|
||||
Open Settings Folder
|
||||
</Button>
|
||||
<Button
|
||||
onClick={() => VencordNative.ipc.invoke(IpcEvents.OPEN_EXTERNAL, "https://github.com/Vendicated/Vencord")}
|
||||
size={Button.Sizes.SMALL}
|
||||
disabled={settingsDirPending}>
|
||||
Open in GitHub
|
||||
</Button>
|
||||
</React.Fragment>
|
||||
)}
|
||||
)}
|
||||
<Button
|
||||
onClick={() => VencordNative.native.openExternal("https://github.com/Vendicated/Vencord")}
|
||||
size={Button.Sizes.SMALL}
|
||||
disabled={settingsDirPending}>
|
||||
Open in GitHub
|
||||
</Button>
|
||||
</React.Fragment>
|
||||
</Card>
|
||||
</Forms.FormSection>
|
||||
|
||||
|
@ -22,6 +22,7 @@ import { classNameFactory } from "@api/Styles";
|
||||
import ErrorBoundary from "@components/ErrorBoundary";
|
||||
import { handleComponentFailed } from "@components/handleComponentFailed";
|
||||
import { isMobile } from "@utils/misc";
|
||||
import { onlyOnce } from "@utils/onlyOnce";
|
||||
import { Forms, SettingsRouter, TabBar, Text } from "@webpack/common";
|
||||
|
||||
import BackupRestoreTab from "./BackupRestoreTab";
|
||||
@ -86,8 +87,10 @@ function Settings(props: SettingsProps) {
|
||||
</Forms.FormSection >;
|
||||
}
|
||||
|
||||
const onError = onlyOnce(handleComponentFailed);
|
||||
|
||||
export default function (props: SettingsProps) {
|
||||
return <ErrorBoundary onError={handleComponentFailed}>
|
||||
return <ErrorBoundary onError={onError}>
|
||||
<Settings tab={props.tab} />
|
||||
</ErrorBoundary>;
|
||||
}
|
||||
|
@ -15,7 +15,7 @@
|
||||
display: flex;
|
||||
gap: 1em;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
justify-content: space-evenly;
|
||||
flex-grow: 1;
|
||||
flex-flow: row wrap;
|
||||
margin-bottom: 1em;
|
||||
@ -59,7 +59,7 @@
|
||||
}
|
||||
|
||||
.vc-text-selectable,
|
||||
.vc-text-selectable :not(a, button) {
|
||||
.vc-text-selectable :not(a, button, a *, button *) {
|
||||
/* make text selectable, silly discord makes the entirety of settings not selectable */
|
||||
user-select: text;
|
||||
|
||||
|
@ -16,7 +16,7 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import Logger from "@utils/Logger";
|
||||
import { Logger } from "@utils/Logger";
|
||||
|
||||
if (IS_DEV) {
|
||||
var traces = {} as Record<string, [number, any[]]>;
|
||||
|
@ -19,7 +19,7 @@
|
||||
import "./updater";
|
||||
|
||||
import { debounce } from "@utils/debounce";
|
||||
import IpcEvents from "@utils/IpcEvents";
|
||||
import { IpcEvents } from "@utils/IpcEvents";
|
||||
import { Queue } from "@utils/Queue";
|
||||
import { BrowserWindow, ipcMain, shell } from "electron";
|
||||
import { mkdirSync, readFileSync, watch } from "fs";
|
||||
@ -44,7 +44,7 @@ export function readSettings() {
|
||||
}
|
||||
}
|
||||
|
||||
export function getSettings(): typeof import("@api/settings").Settings {
|
||||
export function getSettings(): typeof import("@api/Settings").Settings {
|
||||
try {
|
||||
return JSON.parse(readSettings());
|
||||
} catch {
|
||||
|
@ -16,7 +16,7 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import IpcEvents from "@utils/IpcEvents";
|
||||
import { IpcEvents } from "@utils/IpcEvents";
|
||||
import { execFile as cpExecFile } from "child_process";
|
||||
import { ipcMain } from "electron";
|
||||
import { join } from "path";
|
||||
|
@ -17,7 +17,7 @@
|
||||
*/
|
||||
|
||||
import { VENCORD_USER_AGENT } from "@utils/constants";
|
||||
import IpcEvents from "@utils/IpcEvents";
|
||||
import { IpcEvents } from "@utils/IpcEvents";
|
||||
import { ipcMain } from "electron";
|
||||
import { writeFile } from "fs/promises";
|
||||
import { join } from "path";
|
||||
|
@ -16,7 +16,7 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { Settings } from "@api/settings";
|
||||
import { Settings } from "@api/Settings";
|
||||
import { Devs } from "@utils/constants";
|
||||
import definePlugin, { OptionType } from "@utils/types";
|
||||
|
||||
|
@ -22,12 +22,11 @@ import ErrorBoundary from "@components/ErrorBoundary";
|
||||
import { Flex } from "@components/Flex";
|
||||
import { Heart } from "@components/Heart";
|
||||
import { Devs } from "@utils/constants";
|
||||
import IpcEvents from "@utils/IpcEvents";
|
||||
import Logger from "@utils/Logger";
|
||||
import { Logger } from "@utils/Logger";
|
||||
import { Margins } from "@utils/margins";
|
||||
import { closeModal, Modals, openModal } from "@utils/modal";
|
||||
import definePlugin from "@utils/types";
|
||||
import { Forms } from "@webpack/common";
|
||||
import { Forms, Toasts } from "@webpack/common";
|
||||
|
||||
const CONTRIBUTOR_BADGE = "https://cdn.discordapp.com/attachments/1033680203433660458/1092089947126780035/favicon.png";
|
||||
|
||||
@ -48,7 +47,29 @@ const ContributorBadge: ProfileBadge = {
|
||||
link: "https://github.com/Vendicated/Vencord"
|
||||
};
|
||||
|
||||
const DonorBadges = {} as Record<string, Pick<ProfileBadge, "image" | "description">[]>;
|
||||
let DonorBadges = {} as Record<string, Pick<ProfileBadge, "image" | "description">[]>;
|
||||
|
||||
async function loadBadges(noCache = false) {
|
||||
DonorBadges = {};
|
||||
|
||||
const init = {} as RequestInit;
|
||||
if (noCache)
|
||||
init.cache = "no-cache";
|
||||
|
||||
const badges = await fetch("https://gist.githubusercontent.com/Vendicated/51a3dd775f6920429ec6e9b735ca7f01/raw/badges.csv", init)
|
||||
.then(r => r.text());
|
||||
|
||||
const lines = badges.trim().split("\n");
|
||||
if (lines.shift() !== "id,tooltip,image") {
|
||||
new Logger("BadgeAPI").error("Invalid badges.csv file!");
|
||||
return;
|
||||
}
|
||||
|
||||
for (const line of lines) {
|
||||
const [id, description, image] = line.split(",");
|
||||
(DonorBadges[id] ??= []).push({ image, description });
|
||||
}
|
||||
}
|
||||
|
||||
export default definePlugin({
|
||||
name: "BadgeAPI",
|
||||
@ -82,24 +103,27 @@ export default definePlugin({
|
||||
}
|
||||
],
|
||||
|
||||
toolboxActions: {
|
||||
async "Refetch Badges"() {
|
||||
await loadBadges(true);
|
||||
Toasts.show({
|
||||
id: Toasts.genId(),
|
||||
message: "Successfully refetched badges!",
|
||||
type: Toasts.Type.SUCCESS
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
async start() {
|
||||
Vencord.Api.Badges.addBadge(ContributorBadge);
|
||||
await loadBadges();
|
||||
},
|
||||
|
||||
renderBadgeComponent: ErrorBoundary.wrap((badge: ProfileBadge & BadgeUserArgs) => {
|
||||
const Component = badge.component!;
|
||||
return <Component {...badge} />;
|
||||
}, { noop: true }),
|
||||
|
||||
async start() {
|
||||
Vencord.Api.Badges.addBadge(ContributorBadge);
|
||||
const badges = await fetch("https://gist.githubusercontent.com/Vendicated/51a3dd775f6920429ec6e9b735ca7f01/raw/badges.csv").then(r => r.text());
|
||||
const lines = badges.trim().split("\n");
|
||||
if (lines.shift() !== "id,tooltip,image") {
|
||||
new Logger("BadgeAPI").error("Invalid badges.csv file!");
|
||||
return;
|
||||
}
|
||||
for (const line of lines) {
|
||||
const [id, description, image] = line.split(",");
|
||||
(DonorBadges[id] ??= []).push({ image, description });
|
||||
}
|
||||
},
|
||||
|
||||
getDonorBadges(userId: string) {
|
||||
return DonorBadges[userId]?.map(badge => ({
|
||||
@ -115,7 +139,7 @@ export default definePlugin({
|
||||
const modalKey = openModal(props => (
|
||||
<ErrorBoundary noop onError={() => {
|
||||
closeModal(modalKey);
|
||||
VencordNative.ipc.invoke(IpcEvents.OPEN_EXTERNAL, "https://github.com/sponsors/Vendicated");
|
||||
VencordNative.native.openExternal("https://github.com/sponsors/Vendicated");
|
||||
}}>
|
||||
<Modals.ModalRoot {...props}>
|
||||
<Modals.ModalHeader>
|
||||
|
@ -22,17 +22,29 @@ import definePlugin from "@utils/types";
|
||||
export default definePlugin({
|
||||
name: "MessageEventsAPI",
|
||||
description: "Api required by anything using message events.",
|
||||
authors: [Devs.Arjix, Devs.hunt],
|
||||
authors: [Devs.Arjix, Devs.hunt, Devs.Ven],
|
||||
patches: [
|
||||
{
|
||||
find: '"MessageActionCreators"',
|
||||
replacement: [{
|
||||
match: /_sendMessage:(function\([^)]+\)){/,
|
||||
replace: "_sendMessage:async $1{if(await Vencord.Api.MessageEvents._handlePreSend(...arguments))return;"
|
||||
}, {
|
||||
match: /\beditMessage:(function\([^)]+\)){/,
|
||||
replacement: {
|
||||
// editMessage: function (...) {
|
||||
match: /\beditMessage:(function\(.+?\))\{/,
|
||||
// editMessage: async function (...) { await handlePreEdit(...); ...
|
||||
replace: "editMessage:async $1{await Vencord.Api.MessageEvents._handlePreEdit(...arguments);"
|
||||
}]
|
||||
}
|
||||
},
|
||||
{
|
||||
find: ".handleSendMessage=",
|
||||
replacement: {
|
||||
// props.chatInputType...then((function(isMessageValid)... var parsedMessage = b.c.parse(channel,... var replyOptions = f.g.getSendMessageOptionsForReply(pendingReply);
|
||||
// Lookbehind: validateMessage)({openWarningPopout:..., type: i.props.chatInputType, content: t, stickers: r, ...}).then((function(isMessageValid)
|
||||
match: /(props\.chatInputType.+?\.then\(\()(function.+?var (\i)=\i\.\i\.parse\((\i),.+?var (\i)=\i\.\i\.getSendMessageOptionsForReply\(\i\);)(?<=\)\(({.+?})\)\.then.+?)/,
|
||||
// props.chatInputType...then((async function(isMessageValid)... var replyOptions = f.g.getSendMessageOptionsForReply(pendingReply); if(await Vencord.api...) return { shoudClear:true, shouldRefocus:true };
|
||||
replace: (_, rest1, rest2, parsedMessage, channel, replyOptions, extra) => "" +
|
||||
`${rest1}async ${rest2}` +
|
||||
`if(await Vencord.Api.MessageEvents._handlePreSend(${channel}.id,${parsedMessage},${extra},${replyOptions}))` +
|
||||
"return{shoudClear:true,shouldRefocus:true};"
|
||||
}
|
||||
},
|
||||
{
|
||||
find: '("interactionUsernameProfile',
|
||||
|
@ -32,7 +32,7 @@ export default definePlugin({
|
||||
}
|
||||
},
|
||||
{
|
||||
find: "Messages.SERVERS",
|
||||
find: "Messages.SERVERS,children",
|
||||
replacement: {
|
||||
match: /(Messages\.SERVERS,children:)(.+?default:return null\}\}\)\))/,
|
||||
replace: "$1Vencord.Api.ServerList.renderAll(Vencord.Api.ServerList.ServerListRenderPosition.In).concat($2)"
|
||||
|
@ -16,7 +16,7 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { Settings } from "@api/settings";
|
||||
import { Settings } from "@api/Settings";
|
||||
import { classNameFactory } from "@api/Styles";
|
||||
import ErrorBoundary from "@components/ErrorBoundary";
|
||||
import { findByPropsLazy, findStoreLazy } from "@webpack";
|
||||
|
@ -18,7 +18,7 @@
|
||||
|
||||
import "./betterFolders.css";
|
||||
|
||||
import { definePluginSettings } from "@api/settings";
|
||||
import { definePluginSettings } from "@api/Settings";
|
||||
import { Devs } from "@utils/constants";
|
||||
import definePlugin, { OptionType } from "@utils/types";
|
||||
import { findByPropsLazy, findLazy, findStoreLazy } from "@webpack";
|
||||
|
@ -16,9 +16,8 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { Settings } from "@api/settings";
|
||||
import { Settings } from "@api/Settings";
|
||||
import { Devs } from "@utils/constants";
|
||||
import { makeLazy } from "@utils/misc";
|
||||
import definePlugin, { OptionType } from "@utils/types";
|
||||
|
||||
export default definePlugin({
|
||||
@ -30,7 +29,7 @@ export default definePlugin({
|
||||
{
|
||||
find: "hideNote:",
|
||||
all: true,
|
||||
predicate: makeLazy(() => Vencord.Settings.plugins.BetterNotesBox.hide),
|
||||
predicate: () => Vencord.Settings.plugins.BetterNotesBox.hide,
|
||||
replacement: {
|
||||
match: /hideNote:.+?(?=[,}])/g,
|
||||
replace: "hideNote:true",
|
||||
|
@ -16,7 +16,7 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { Settings } from "@api/settings";
|
||||
import { Settings } from "@api/Settings";
|
||||
import { Devs } from "@utils/constants";
|
||||
import definePlugin, { OptionType } from "@utils/types";
|
||||
import { Clipboard, Toasts } from "@webpack/common";
|
||||
|
@ -16,7 +16,7 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { Settings } from "@api/settings";
|
||||
import { Settings } from "@api/Settings";
|
||||
import { Devs } from "@utils/constants";
|
||||
import definePlugin, { OptionType } from "@utils/types";
|
||||
|
||||
|
@ -16,7 +16,7 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { Settings } from "@api/settings";
|
||||
import { Settings } from "@api/Settings";
|
||||
import ErrorBoundary from "@components/ErrorBoundary";
|
||||
import { Devs } from "@utils/constants";
|
||||
import definePlugin, { OptionType } from "@utils/types";
|
||||
|
@ -17,9 +17,9 @@
|
||||
*/
|
||||
|
||||
import { showNotification } from "@api/Notifications";
|
||||
import { definePluginSettings } from "@api/settings";
|
||||
import { definePluginSettings } from "@api/Settings";
|
||||
import { Devs } from "@utils/constants";
|
||||
import Logger from "@utils/Logger";
|
||||
import { Logger } from "@utils/Logger";
|
||||
import { closeAllModals } from "@utils/modal";
|
||||
import definePlugin, { OptionType } from "@utils/types";
|
||||
import { maybePromptToUpdate } from "@utils/updater";
|
||||
|
@ -16,11 +16,11 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { definePluginSettings } from "@api/settings";
|
||||
import { definePluginSettings } from "@api/Settings";
|
||||
import { Link } from "@components/Link";
|
||||
import { Devs } from "@utils/constants";
|
||||
import { isTruthy } from "@utils/guards";
|
||||
import { useAwaiter } from "@utils/misc";
|
||||
import { useAwaiter } from "@utils/react";
|
||||
import definePlugin, { OptionType } from "@utils/types";
|
||||
import { filters, findByCodeLazy, findByPropsLazy, mapMangledModuleLazy } from "@webpack";
|
||||
import {
|
||||
|
@ -16,15 +16,13 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { addContextMenuPatch, NavContextMenuPatchCallback, removeContextMenuPatch } from "@api/ContextMenu";
|
||||
import { showNotification } from "@api/Notifications";
|
||||
import { definePluginSettings } from "@api/settings";
|
||||
import { definePluginSettings } from "@api/Settings";
|
||||
import { Devs } from "@utils/constants";
|
||||
import Logger from "@utils/Logger";
|
||||
import { Logger } from "@utils/Logger";
|
||||
import { canonicalizeMatch, canonicalizeReplace } from "@utils/patches";
|
||||
import definePlugin, { OptionType } from "@utils/types";
|
||||
import { filters, findAll, search } from "@webpack";
|
||||
import { Menu } from "@webpack/common";
|
||||
|
||||
const PORT = 8485;
|
||||
const NAV_ID = "dev-companion-reconnect";
|
||||
@ -238,33 +236,25 @@ function initWs(isManual = false) {
|
||||
});
|
||||
}
|
||||
|
||||
const contextMenuPatch: NavContextMenuPatchCallback = children => () => {
|
||||
children.unshift(
|
||||
<Menu.MenuItem
|
||||
id={NAV_ID}
|
||||
label="Reconnect Dev Companion"
|
||||
action={() => {
|
||||
socket?.close(1000, "Reconnecting");
|
||||
initWs(true);
|
||||
}}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export default definePlugin({
|
||||
name: "DevCompanion",
|
||||
description: "Dev Companion Plugin",
|
||||
authors: [Devs.Ven],
|
||||
settings,
|
||||
|
||||
toolboxActions: {
|
||||
"Reconnect"() {
|
||||
socket?.close(1000, "Reconnecting");
|
||||
initWs(true);
|
||||
}
|
||||
},
|
||||
|
||||
start() {
|
||||
initWs();
|
||||
addContextMenuPatch("user-settings-cog", contextMenuPatch);
|
||||
},
|
||||
|
||||
stop() {
|
||||
socket?.close(1000, "Plugin Stopped");
|
||||
socket = void 0;
|
||||
removeContextMenuPatch("user-settings-cog", contextMenuPatch);
|
||||
}
|
||||
});
|
||||
|
@ -19,7 +19,7 @@
|
||||
import { addContextMenuPatch, findGroupChildrenByChildId, NavContextMenuPatchCallback, removeContextMenuPatch } from "@api/ContextMenu";
|
||||
import { CheckedTextInput } from "@components/CheckedTextInput";
|
||||
import { Devs } from "@utils/constants";
|
||||
import Logger from "@utils/Logger";
|
||||
import { Logger } from "@utils/Logger";
|
||||
import { Margins } from "@utils/margins";
|
||||
import { ModalContent, ModalHeader, ModalRoot, openModal } from "@utils/modal";
|
||||
import definePlugin from "@utils/types";
|
||||
|
@ -16,8 +16,11 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { definePluginSettings } from "@api/settings";
|
||||
import { definePluginSettings } from "@api/Settings";
|
||||
import ErrorBoundary from "@components/ErrorBoundary";
|
||||
import { ErrorCard } from "@components/ErrorCard";
|
||||
import { Devs } from "@utils/constants";
|
||||
import { Margins } from "@utils/margins";
|
||||
import definePlugin, { OptionType } from "@utils/types";
|
||||
import { findByPropsLazy } from "@webpack";
|
||||
import { Forms, React } from "@webpack/common";
|
||||
@ -87,6 +90,13 @@ export default definePlugin({
|
||||
match: /"staging"===window\.GLOBAL_ENV\.RELEASE_CHANNEL/,
|
||||
replace: "true"
|
||||
}
|
||||
},
|
||||
{
|
||||
find: 'H1,title:"Experiments"',
|
||||
replacement: {
|
||||
match: 'title:"Experiments",children:[',
|
||||
replace: "$&$self.WarningCard(),"
|
||||
}
|
||||
}
|
||||
],
|
||||
|
||||
@ -109,5 +119,19 @@ export default definePlugin({
|
||||
</Forms.FormText>
|
||||
</React.Fragment>
|
||||
);
|
||||
}
|
||||
},
|
||||
|
||||
WarningCard: ErrorBoundary.wrap(() => (
|
||||
<ErrorCard id="vc-experiments-warning-card" className={Margins.bottom16}>
|
||||
<Forms.FormTitle tag="h2">Hold on!!</Forms.FormTitle>
|
||||
|
||||
<Forms.FormText>
|
||||
Experiments are unreleased Discord features. They might not work, or even break your client or get your account disabled.
|
||||
</Forms.FormText>
|
||||
|
||||
<Forms.FormText className={Margins.top8}>
|
||||
Only use experiments if you know what you're doing. Vencord is not responsible for any damage caused by enabling experiments.
|
||||
</Forms.FormText>
|
||||
</ErrorCard>
|
||||
), { noop: true })
|
||||
});
|
||||
|
@ -17,11 +17,11 @@
|
||||
*/
|
||||
|
||||
import { addPreEditListener, addPreSendListener, removePreEditListener, removePreSendListener } from "@api/MessageEvents";
|
||||
import { definePluginSettings, Settings } from "@api/settings";
|
||||
import { definePluginSettings, Settings } from "@api/Settings";
|
||||
import { Devs } from "@utils/constants";
|
||||
import { ApngBlendOp, ApngDisposeOp, getGifEncoder, importApngJs } from "@utils/dependencies";
|
||||
import { getCurrentGuild } from "@utils/discord";
|
||||
import { proxyLazy } from "@utils/proxyLazy";
|
||||
import { proxyLazy } from "@utils/lazy";
|
||||
import definePlugin, { OptionType } from "@utils/types";
|
||||
import { findByCodeLazy, findByPropsLazy, findLazy, findStoreLazy } from "@webpack";
|
||||
import { ChannelStore, FluxDispatcher, Parser, PermissionStore, UserStore } from "@webpack/common";
|
||||
@ -641,7 +641,7 @@ export default definePlugin({
|
||||
if (!settings.enableStickerBypass)
|
||||
break stickerBypass;
|
||||
|
||||
const sticker = StickerStore.getStickerById(extra?.stickerIds?.[0]!);
|
||||
const sticker = StickerStore.getStickerById(extra.stickers?.[0]!);
|
||||
if (!sticker)
|
||||
break stickerBypass;
|
||||
|
||||
@ -663,7 +663,7 @@ export default definePlugin({
|
||||
link = `https://distok.top/stickers/${packId}/${sticker.id}.gif`;
|
||||
}
|
||||
|
||||
delete extra.stickerIds;
|
||||
extra.stickers!.length = 0;
|
||||
messageObj.content += " " + link + `&name=${encodeURIComponent(sticker.name)}`;
|
||||
}
|
||||
}
|
||||
|
@ -17,7 +17,7 @@
|
||||
*/
|
||||
|
||||
// This plugin is a port from Alyxia's Vendetta plugin
|
||||
import { definePluginSettings } from "@api/settings";
|
||||
import { definePluginSettings } from "@api/Settings";
|
||||
import ErrorBoundary from "@components/ErrorBoundary";
|
||||
import { Devs } from "@utils/constants";
|
||||
import { Margins } from "@utils/margins";
|
||||
|
@ -17,7 +17,7 @@
|
||||
*/
|
||||
|
||||
import { ApplicationCommandOptionType } from "@api/Commands";
|
||||
import { Settings } from "@api/settings";
|
||||
import { Settings } from "@api/Settings";
|
||||
import { makeRange } from "@components/PluginSettings/components";
|
||||
import { Devs } from "@utils/constants";
|
||||
import definePlugin, { OptionType } from "@utils/types";
|
||||
|
@ -19,7 +19,7 @@
|
||||
import * as DataStore from "@api/DataStore";
|
||||
import ErrorBoundary from "@components/ErrorBoundary";
|
||||
import { Devs } from "@utils/constants";
|
||||
import { useForceUpdater } from "@utils/misc";
|
||||
import { useForceUpdater } from "@utils/react";
|
||||
import definePlugin from "@utils/types";
|
||||
import { findByPropsLazy, findStoreLazy } from "@webpack";
|
||||
import { Tooltip } from "webpack/common";
|
||||
|
@ -17,7 +17,7 @@
|
||||
*/
|
||||
|
||||
import { addContextMenuPatch, NavContextMenuPatchCallback, removeContextMenuPatch } from "@api/ContextMenu";
|
||||
import { definePluginSettings } from "@api/settings";
|
||||
import { definePluginSettings } from "@api/Settings";
|
||||
import { disableStyle, enableStyle } from "@api/Styles";
|
||||
import { makeRange } from "@components/PluginSettings/components";
|
||||
import { Devs } from "@utils/constants";
|
||||
|
@ -17,8 +17,8 @@
|
||||
*/
|
||||
|
||||
import { registerCommand, unregisterCommand } from "@api/Commands";
|
||||
import { Settings } from "@api/settings";
|
||||
import Logger from "@utils/Logger";
|
||||
import { Settings } from "@api/Settings";
|
||||
import { Logger } from "@utils/Logger";
|
||||
import { Patch, Plugin } from "@utils/types";
|
||||
import { FluxDispatcher } from "@webpack/common";
|
||||
import { FluxEvents } from "@webpack/types";
|
||||
@ -99,9 +99,9 @@ export function startDependenciesRecursive(p: Plugin) {
|
||||
if (!Settings.plugins[dep].enabled) {
|
||||
startDependenciesRecursive(Plugins[dep]);
|
||||
// If the plugin has patches, don't start the plugin, just enable it.
|
||||
Settings.plugins[dep].enabled = true;
|
||||
if (Plugins[dep].patches) {
|
||||
logger.warn(`Enabling dependency ${dep} requires restart.`);
|
||||
Settings.plugins[dep].enabled = true;
|
||||
restartNeeded = true;
|
||||
return;
|
||||
}
|
||||
|
@ -17,7 +17,7 @@
|
||||
*/
|
||||
|
||||
import { addButton, removeButton } from "@api/MessagePopover";
|
||||
import { definePluginSettings } from "@api/settings";
|
||||
import { definePluginSettings } from "@api/Settings";
|
||||
import ErrorBoundary from "@components/ErrorBoundary";
|
||||
import { Devs } from "@utils/constants";
|
||||
import { getStegCloak } from "@utils/dependencies";
|
||||
@ -85,7 +85,7 @@ function ChatBarIcon() {
|
||||
onMouseLeave={onMouseLeave}
|
||||
innerClassName={ButtonWrapperClasses.button}
|
||||
onClick={() => buildEncModal()}
|
||||
style={{ padding: "0 4px" }}
|
||||
style={{ padding: "0 2px", scale: "0.9" }}
|
||||
>
|
||||
<div className={ButtonWrapperClasses.buttonWrapper}>
|
||||
<svg
|
||||
|
@ -16,10 +16,10 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { definePluginSettings } from "@api/settings";
|
||||
import { definePluginSettings } from "@api/Settings";
|
||||
import { Link } from "@components/Link";
|
||||
import { Devs } from "@utils/constants";
|
||||
import Logger from "@utils/Logger";
|
||||
import { Logger } from "@utils/Logger";
|
||||
import definePlugin, { OptionType } from "@utils/types";
|
||||
import { filters, findByPropsLazy, mapMangledModuleLazy } from "@webpack";
|
||||
import { FluxDispatcher, Forms } from "@webpack/common";
|
||||
|
@ -20,31 +20,34 @@ import ErrorBoundary from "@components/ErrorBoundary";
|
||||
import { Flex } from "@components/Flex";
|
||||
import { Devs } from "@utils/constants";
|
||||
import { getCurrentChannel } from "@utils/discord";
|
||||
import { useForceUpdater } from "@utils/misc";
|
||||
import definePlugin from "@utils/types";
|
||||
import { findStoreLazy } from "@webpack";
|
||||
import { Tooltip } from "@webpack/common";
|
||||
import { SelectedChannelStore, Tooltip, useStateFromStores } from "@webpack/common";
|
||||
import { FluxStore } from "@webpack/types";
|
||||
|
||||
const counts = {} as Record<string, [number, number]>;
|
||||
let forceUpdate: () => void;
|
||||
|
||||
const GuildMemberCountStore = findStoreLazy("GuildMemberCountStore");
|
||||
const GuildMemberCountStore = findStoreLazy("GuildMemberCountStore") as FluxStore & { getMemberCount(guildId: string): number | null; };
|
||||
const ChannelMemberStore = findStoreLazy("ChannelMemberStore") as FluxStore & {
|
||||
getProps(guildId: string, channelId: string): { groups: { count: number; id: string; }[]; };
|
||||
};
|
||||
|
||||
function MemberCount() {
|
||||
const guildId = getCurrentChannel().guild_id;
|
||||
const c = counts[guildId];
|
||||
const { id: channelId, guild_id: guildId } = useStateFromStores([SelectedChannelStore], () => getCurrentChannel());
|
||||
const { groups } = useStateFromStores(
|
||||
[ChannelMemberStore],
|
||||
() => ChannelMemberStore.getProps(guildId, channelId)
|
||||
);
|
||||
const total = useStateFromStores(
|
||||
[GuildMemberCountStore],
|
||||
() => GuildMemberCountStore.getMemberCount(guildId)
|
||||
);
|
||||
|
||||
forceUpdate = useForceUpdater();
|
||||
if (total == null)
|
||||
return null;
|
||||
|
||||
if (!c) return null;
|
||||
|
||||
let total = c[0].toLocaleString();
|
||||
if (total === "0" && c[1] > 0) {
|
||||
const approx = GuildMemberCountStore.getMemberCount(guildId);
|
||||
total = approx ? approx.toLocaleString() : "Loading...";
|
||||
}
|
||||
|
||||
const online = c[1].toLocaleString();
|
||||
const online =
|
||||
(groups.length === 1 && groups[0].id === "unknown")
|
||||
? 0
|
||||
: groups.reduce((count, curr) => count + (curr.id === "offline" ? 0 : curr.count), 0);
|
||||
|
||||
return (
|
||||
<Flex id="vc-membercount" style={{
|
||||
@ -55,7 +58,7 @@ function MemberCount() {
|
||||
alignContent: "center",
|
||||
gap: 0
|
||||
}}>
|
||||
<Tooltip text={`${online} Online`} position="bottom">
|
||||
<Tooltip text={`${online} Online in this Channel`} position="bottom">
|
||||
{props => (
|
||||
<div {...props}>
|
||||
<span
|
||||
@ -72,7 +75,7 @@ function MemberCount() {
|
||||
</div>
|
||||
)}
|
||||
</Tooltip>
|
||||
<Tooltip text={`${total} Total Members`} position="bottom">
|
||||
<Tooltip text={`${total} Total Server Members`} position="bottom">
|
||||
{props => (
|
||||
<div {...props}>
|
||||
<span
|
||||
@ -102,31 +105,10 @@ export default definePlugin({
|
||||
patches: [{
|
||||
find: ".isSidebarVisible,",
|
||||
replacement: {
|
||||
match: /(var (.)=.\.className.+?children):\[(.\.useMemo[^}]+"aria-multiselectable")/,
|
||||
match: /(var (\i)=\i\.className.+?children):\[(\i\.useMemo[^}]+"aria-multiselectable")/,
|
||||
replace: "$1:[$2.startsWith('members')?$self.render():null,$3"
|
||||
}
|
||||
}],
|
||||
|
||||
flux: {
|
||||
GUILD_MEMBER_LIST_UPDATE({ guildId, groups, memberCount, id }) {
|
||||
// eeeeeh - sometimes it has really wrong counts??? like 10 times less than actual
|
||||
// but if we only listen to everyone updates, sometimes we never get the count?
|
||||
// this seems to work but isn't optional
|
||||
if (id !== "everyone" && counts[guildId]) return;
|
||||
|
||||
let count = 0;
|
||||
for (const group of groups) {
|
||||
if (group.id !== "offline")
|
||||
count += group.count;
|
||||
}
|
||||
counts[guildId] = [memberCount, count];
|
||||
forceUpdate?.();
|
||||
}
|
||||
},
|
||||
|
||||
render: () => (
|
||||
<ErrorBoundary noop>
|
||||
<MemberCount />
|
||||
</ErrorBoundary>
|
||||
)
|
||||
render: ErrorBoundary.wrap(MemberCount, { noop: true })
|
||||
});
|
||||
|
@ -17,11 +17,12 @@
|
||||
*/
|
||||
|
||||
import { addAccessory } from "@api/MessageAccessories";
|
||||
import { definePluginSettings } from "@api/settings";
|
||||
import { definePluginSettings } from "@api/Settings";
|
||||
import ErrorBoundary from "@components/ErrorBoundary";
|
||||
import { Devs } from "@utils/constants.js";
|
||||
import { classes, LazyComponent } from "@utils/misc";
|
||||
import { classes } from "@utils/misc";
|
||||
import { Queue } from "@utils/Queue";
|
||||
import { LazyComponent } from "@utils/react";
|
||||
import definePlugin, { OptionType } from "@utils/types";
|
||||
import { find, findByCode, findByPropsLazy } from "@webpack";
|
||||
import {
|
||||
|
@ -19,11 +19,11 @@
|
||||
import "./messageLogger.css";
|
||||
|
||||
import { addContextMenuPatch, NavContextMenuPatchCallback, removeContextMenuPatch } from "@api/ContextMenu";
|
||||
import { Settings } from "@api/settings";
|
||||
import { Settings } from "@api/Settings";
|
||||
import { disableStyle, enableStyle } from "@api/Styles";
|
||||
import ErrorBoundary from "@components/ErrorBoundary";
|
||||
import { Devs } from "@utils/constants";
|
||||
import Logger from "@utils/Logger";
|
||||
import { Logger } from "@utils/Logger";
|
||||
import definePlugin, { OptionType } from "@utils/types";
|
||||
import { findByPropsLazy } from "@webpack";
|
||||
import { FluxDispatcher, i18n, Menu, moment, Parser, Timestamp, UserStore } from "@webpack/common";
|
||||
|
@ -18,7 +18,7 @@
|
||||
|
||||
import { ApplicationCommandInputType, ApplicationCommandOptionType, findOption, registerCommand, sendBotMessage, unregisterCommand } from "@api/Commands";
|
||||
import * as DataStore from "@api/DataStore";
|
||||
import { Settings } from "@api/settings";
|
||||
import { Settings } from "@api/Settings";
|
||||
import { Devs } from "@utils/constants";
|
||||
import definePlugin, { OptionType } from "@utils/types";
|
||||
|
||||
|
@ -16,9 +16,9 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { definePluginSettings } from "@api/settings";
|
||||
import { definePluginSettings } from "@api/Settings";
|
||||
import { Devs } from "@utils/constants";
|
||||
import { proxyLazy } from "@utils/proxyLazy.js";
|
||||
import { proxyLazy } from "@utils/lazy.js";
|
||||
import definePlugin, { OptionType } from "@utils/types";
|
||||
import { find, findByPropsLazy } from "@webpack";
|
||||
import { ChannelStore, GuildStore } from "@webpack/common";
|
||||
|
@ -16,7 +16,7 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { definePluginSettings } from "@api/settings";
|
||||
import { definePluginSettings } from "@api/Settings";
|
||||
import { makeRange } from "@components/PluginSettings/components/SettingSliderComponent";
|
||||
import { Devs } from "@utils/constants";
|
||||
import { sleep } from "@utils/misc";
|
||||
|
@ -16,7 +16,7 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { definePluginSettings } from "@api/settings";
|
||||
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";
|
||||
|
@ -16,7 +16,7 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { Settings } from "@api/settings";
|
||||
import { Settings } from "@api/Settings";
|
||||
import { Devs } from "@utils/constants";
|
||||
import definePlugin, { OptionType } from "@utils/types";
|
||||
import { findByPropsLazy } from "@webpack";
|
||||
|
@ -1,59 +0,0 @@
|
||||
/*
|
||||
* Vencord, a modification for Discord's desktop app
|
||||
* Copyright (c) 2022 Samu and Linnea Gräf
|
||||
*
|
||||
* 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 { addPreSendListener, MessageObject, removePreSendListener } from "@api/MessageEvents";
|
||||
import { Settings } from "@api/settings";
|
||||
import { Devs } from "@utils/constants";
|
||||
import definePlugin, { OptionType } from "@utils/types";
|
||||
|
||||
export default definePlugin({
|
||||
name: "NoCanaryMessageLinks",
|
||||
description: "Allows you to change/remove the subdomain of discord message and channel links",
|
||||
authors: [Devs.Samu, Devs.nea],
|
||||
options: {
|
||||
linkPrefix: {
|
||||
description: "The subdomain for your discord message links",
|
||||
type: OptionType.STRING,
|
||||
default: "",
|
||||
restartNeeded: false,
|
||||
},
|
||||
alwaysUseDiscordHost: {
|
||||
description: "Always use discord.com host (replace discordapp.com)",
|
||||
type: OptionType.BOOLEAN,
|
||||
default: false,
|
||||
restartNeeded: false,
|
||||
},
|
||||
},
|
||||
dependencies: ["MessageEventsAPI"],
|
||||
|
||||
removeBetas(msg: MessageObject) {
|
||||
const settings = Settings.plugins.NoCanaryMessageLinks;
|
||||
msg.content = msg.content.replace(
|
||||
/https:\/\/(?:canary\.|ptb\.)?(discord(?:app)?\.com)(\/channels\/(?:\d{17,20}|@me)\/\d{17,20}(?:\/\d{17,20})?)/g,
|
||||
(_, host, path) => "https://" + (settings.linkPrefix ? settings.linkPrefix + "." : "") + (settings.alwaysUseDiscordHost ? "discord.com" : host) + path
|
||||
);
|
||||
},
|
||||
|
||||
start() {
|
||||
this.preSend = addPreSendListener((_, msg) => this.removeBetas(msg));
|
||||
},
|
||||
|
||||
stop() {
|
||||
removePreSendListener(this.preSend);
|
||||
}
|
||||
});
|
@ -16,7 +16,7 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { definePluginSettings } from "@api/settings";
|
||||
import { definePluginSettings } from "@api/Settings";
|
||||
import { Devs } from "@utils/constants";
|
||||
import definePlugin, { OptionType } from "@utils/types";
|
||||
import type { Message } from "discord-types/general";
|
||||
|
@ -19,7 +19,7 @@
|
||||
import { ApplicationCommandInputType, ApplicationCommandOptionType, Argument, CommandContext, findOption, sendBotMessage } from "@api/Commands";
|
||||
import { Devs } from "@utils/constants";
|
||||
import { getGifEncoder } from "@utils/dependencies";
|
||||
import { makeLazy } from "@utils/misc";
|
||||
import { makeLazy } from "@utils/lazy";
|
||||
import definePlugin from "@utils/types";
|
||||
import { findByCodeLazy, findByPropsLazy } from "@webpack";
|
||||
|
||||
|
@ -16,7 +16,7 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { definePluginSettings, Settings, useSettings } from "@api/settings";
|
||||
import { definePluginSettings, Settings, useSettings } from "@api/Settings";
|
||||
import { OptionType } from "@utils/types";
|
||||
import { findStoreLazy } from "@webpack";
|
||||
|
||||
|
@ -19,7 +19,7 @@
|
||||
import { addBadge, BadgePosition, ProfileBadge, removeBadge } from "@api/Badges";
|
||||
import { addDecorator, removeDecorator } from "@api/MemberListDecorators";
|
||||
import { addDecoration, removeDecoration } from "@api/MessageDecorations";
|
||||
import { Settings } from "@api/settings";
|
||||
import { Settings } from "@api/Settings";
|
||||
import ErrorBoundary from "@components/ErrorBoundary";
|
||||
import { Devs } from "@utils/constants";
|
||||
import definePlugin, { OptionType } from "@utils/types";
|
||||
@ -30,7 +30,7 @@ import { User } from "discord-types/general";
|
||||
const SessionsStore = findStoreLazy("SessionsStore");
|
||||
|
||||
function Icon(path: string, viewBox = "0 0 24 24") {
|
||||
return ({ color, tooltip }: { color: string; tooltip: string; }) => (
|
||||
return ({ color, tooltip, wantMargin }: { color: string; tooltip: string; wantMargin: boolean; }) => (
|
||||
<Tooltip text={tooltip} >
|
||||
{(tooltipProps: any) => (
|
||||
<svg
|
||||
@ -39,6 +39,12 @@ function Icon(path: string, viewBox = "0 0 24 24") {
|
||||
width="20"
|
||||
viewBox={viewBox}
|
||||
fill={color}
|
||||
style={{
|
||||
marginLeft: wantMargin ? 4 : 0,
|
||||
verticalAlign: "top",
|
||||
position: "relative",
|
||||
top: wantMargin ? 1 : 0,
|
||||
}}
|
||||
>
|
||||
<path d={path} />
|
||||
</svg>
|
||||
@ -57,16 +63,16 @@ type Platform = keyof typeof Icons;
|
||||
|
||||
const getStatusColor = findByCodeLazy(".TWITCH", ".STREAMING", ".INVISIBLE");
|
||||
|
||||
const PlatformIcon = ({ platform, status }: { platform: Platform, status: string; }) => {
|
||||
const PlatformIcon = ({ platform, status, wantMargin }: { platform: Platform, status: string; wantMargin: boolean; }) => {
|
||||
const tooltip = platform[0].toUpperCase() + platform.slice(1);
|
||||
const Icon = Icons[platform] ?? Icons.desktop;
|
||||
|
||||
return <Icon color={`var(--${getStatusColor(status)}`} tooltip={tooltip} />;
|
||||
return <Icon color={`var(--${getStatusColor(status)}`} tooltip={tooltip} wantMargin={wantMargin} />;
|
||||
};
|
||||
|
||||
const getStatus = (id: string): Record<Platform, string> => PresenceStore.getState()?.clientStatuses?.[id];
|
||||
|
||||
const PlatformIndicator = ({ user, inline = false, marginLeft = "4px" }: { user: User; inline?: boolean; marginLeft?: string; }) => {
|
||||
const PlatformIndicator = ({ user, wantMargin = true }: { user: User; wantMargin?: boolean; }) => {
|
||||
if (!user || user.bot) return null;
|
||||
|
||||
if (user.id === UserStore.getCurrentUser().id) {
|
||||
@ -99,29 +105,21 @@ const PlatformIndicator = ({ user, inline = false, marginLeft = "4px" }: { user:
|
||||
key={platform}
|
||||
platform={platform as Platform}
|
||||
status={status}
|
||||
wantMargin={wantMargin}
|
||||
/>
|
||||
));
|
||||
|
||||
if (!icons.length) return null;
|
||||
|
||||
return (
|
||||
<div
|
||||
className="vc-platform-indicator"
|
||||
style={{
|
||||
marginLeft,
|
||||
gap: "4px",
|
||||
display: inline ? "inline-flex" : "flex",
|
||||
alignItems: "center",
|
||||
translate: inline ? "0 3px 0" : undefined
|
||||
}}
|
||||
>
|
||||
<span className="vc-platform-indicator">
|
||||
{icons}
|
||||
</div>
|
||||
</span>
|
||||
);
|
||||
};
|
||||
|
||||
const badge: ProfileBadge = {
|
||||
component: p => <PlatformIndicator {...p} marginLeft="" />,
|
||||
component: p => <PlatformIndicator {...p} wantMargin={false} />,
|
||||
position: BadgePosition.START,
|
||||
shouldShow: userInfo => !!Object.keys(getStatus(userInfo.user.id) ?? {}).length,
|
||||
key: "indicator"
|
||||
@ -146,7 +144,7 @@ const indicatorLocations = {
|
||||
description: "Inside messages",
|
||||
onEnable: () => addDecoration("platform-indicator", props =>
|
||||
<ErrorBoundary noop>
|
||||
<PlatformIndicator user={props.message?.author} inline />
|
||||
<PlatformIndicator user={props.message?.author} />
|
||||
</ErrorBoundary>
|
||||
),
|
||||
onDisable: () => removeDecoration("platform-indicator")
|
||||
|
@ -16,10 +16,10 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { Settings } from "@api/settings";
|
||||
import { Settings } from "@api/Settings";
|
||||
import { VENCORD_USER_AGENT } from "@utils/constants";
|
||||
import { debounce } from "@utils/debounce";
|
||||
import { useAwaiter } from "@utils/misc";
|
||||
import { useAwaiter } from "@utils/react";
|
||||
import { UserStore } from "@webpack/common";
|
||||
|
||||
import { settings } from "./settings";
|
||||
|
@ -16,7 +16,7 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { definePluginSettings } from "@api/settings";
|
||||
import { definePluginSettings } from "@api/Settings";
|
||||
import { OptionType } from "@utils/types";
|
||||
|
||||
import { PronounsFormat } from "./pronoundbUtils";
|
||||
|
@ -16,7 +16,7 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { definePluginSettings, Settings } from "@api/settings";
|
||||
import { definePluginSettings, Settings } from "@api/Settings";
|
||||
import { Devs } from "@utils/constants";
|
||||
import definePlugin, { OptionType } from "@utils/types";
|
||||
import { findByPropsLazy } from "@webpack";
|
||||
|
@ -16,7 +16,7 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { definePluginSettings } from "@api/settings";
|
||||
import { definePluginSettings } from "@api/Settings";
|
||||
import { OptionType } from "@utils/types";
|
||||
|
||||
export default definePluginSettings({
|
||||
|
@ -18,7 +18,7 @@
|
||||
|
||||
import { DataStore, Notices } from "@api/index";
|
||||
import { showNotification } from "@api/Notifications";
|
||||
import { ChannelStore, GuildStore, RelationshipStore, UserStore, UserUtils } from "@webpack/common";
|
||||
import { ChannelStore, GuildMemberStore, GuildStore, RelationshipStore, UserStore, UserUtils } from "@webpack/common";
|
||||
|
||||
import settings from "./settings";
|
||||
import { ChannelType, RelationshipType, SimpleGroupChannel, SimpleGuild } from "./types";
|
||||
@ -106,12 +106,16 @@ export function deleteGuild(id: string) {
|
||||
}
|
||||
|
||||
export async function syncGuilds() {
|
||||
guilds.clear();
|
||||
|
||||
const me = UserStore.getCurrentUser().id;
|
||||
for (const [id, { name, icon }] of Object.entries(GuildStore.getGuilds())) {
|
||||
guilds.set(id, {
|
||||
id,
|
||||
name,
|
||||
iconURL: icon && `https://cdn.discordapp.com/icons/${id}/${icon}.png`
|
||||
});
|
||||
if (GuildMemberStore.isMember(id, me))
|
||||
guilds.set(id, {
|
||||
id,
|
||||
name,
|
||||
iconURL: icon && `https://cdn.discordapp.com/icons/${id}/${icon}.png`
|
||||
});
|
||||
}
|
||||
await DataStore.set(guildsKey(), guilds);
|
||||
}
|
||||
@ -126,6 +130,8 @@ export function deleteGroup(id: string) {
|
||||
}
|
||||
|
||||
export async function syncGroups() {
|
||||
groups.clear();
|
||||
|
||||
for (const { type, id, name, rawRecipients, icon } of ChannelStore.getSortedPrivateChannels()) {
|
||||
if (type === ChannelType.GROUP_DM)
|
||||
groups.set(id, {
|
||||
|
@ -16,7 +16,7 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { Settings } from "@api/settings";
|
||||
import { Settings } from "@api/Settings";
|
||||
|
||||
import { Review } from "../entities/Review";
|
||||
import { ReviewDBUser } from "../entities/User";
|
||||
|
@ -16,8 +16,8 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { Settings } from "@api/settings";
|
||||
import Logger from "@utils/Logger";
|
||||
import { Settings } from "@api/Settings";
|
||||
import { Logger } from "@utils/Logger";
|
||||
import { openModal } from "@utils/modal";
|
||||
import { findByProps } from "@webpack";
|
||||
import { FluxDispatcher, React, SelectedChannelStore, Toasts, UserUtils } from "@webpack/common";
|
||||
|
@ -16,11 +16,12 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { classes, LazyComponent } from "@utils/misc";
|
||||
import { classes } from "@utils/misc";
|
||||
import { LazyComponent } from "@utils/react";
|
||||
import { findByProps } from "@webpack";
|
||||
|
||||
export default LazyComponent(() => {
|
||||
const { button, dangerous } = findByProps("button", "wrapper", "disabled","separator");
|
||||
const { button, dangerous } = findByProps("button", "wrapper", "disabled", "separator");
|
||||
|
||||
return function MessageButton(props) {
|
||||
return props.type === "delete"
|
||||
|
@ -16,8 +16,9 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { Settings } from "@api/settings";
|
||||
import { classes, LazyComponent } from "@utils/misc";
|
||||
import { Settings } from "@api/Settings";
|
||||
import { classes } from "@utils/misc";
|
||||
import { LazyComponent } from "@utils/react";
|
||||
import { filters, findBulk } from "@webpack";
|
||||
import { Alerts, moment, Timestamp, UserStore } from "@webpack/common";
|
||||
|
||||
|
@ -16,8 +16,9 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { Settings } from "@api/settings";
|
||||
import { classes, useAwaiter } from "@utils/misc";
|
||||
import { Settings } from "@api/Settings";
|
||||
import { classes } from "@utils/misc";
|
||||
import { useAwaiter } from "@utils/react";
|
||||
import { findLazy } from "@webpack";
|
||||
import { Forms, React, Text, UserStore } from "@webpack/common";
|
||||
import type { KeyboardEvent } from "react";
|
||||
|
@ -18,7 +18,7 @@
|
||||
|
||||
import "./style.css";
|
||||
|
||||
import { Settings } from "@api/settings";
|
||||
import { Settings } from "@api/Settings";
|
||||
import ErrorBoundary from "@components/ErrorBoundary";
|
||||
import { Devs } from "@utils/constants";
|
||||
import definePlugin, { OptionType } from "@utils/types";
|
||||
|
@ -16,7 +16,7 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { definePluginSettings } from "@api/settings";
|
||||
import { definePluginSettings } from "@api/Settings";
|
||||
import { Devs } from "@utils/constants";
|
||||
import definePlugin, { OptionType } from "@utils/types";
|
||||
import { ChannelStore, GuildMemberStore, GuildStore } from "@webpack/common";
|
||||
|
@ -18,7 +18,7 @@
|
||||
|
||||
import { addContextMenuPatch, findGroupChildrenByChildId, NavContextMenuPatchCallback, removeContextMenuPatch } from "@api/ContextMenu";
|
||||
import { Devs } from "@utils/constants";
|
||||
import { LazyComponent } from "@utils/misc";
|
||||
import { LazyComponent } from "@utils/react";
|
||||
import definePlugin from "@utils/types";
|
||||
import { findByCode, findByCodeLazy } from "@webpack";
|
||||
import { ChannelStore, i18n, Menu, SelectedChannelStore } from "@webpack/common";
|
||||
|
@ -43,7 +43,7 @@
|
||||
}
|
||||
|
||||
.vc-st-button {
|
||||
padding: 0 8px;
|
||||
padding: 0 6px;
|
||||
}
|
||||
|
||||
.vc-st-button svg {
|
||||
|
@ -17,10 +17,10 @@
|
||||
*/
|
||||
|
||||
import { addServerListElement, removeServerListElement, ServerListRenderPosition } from "@api/ServerList";
|
||||
import { Settings } from "@api/settings";
|
||||
import { Settings } from "@api/Settings";
|
||||
import ErrorBoundary from "@components/ErrorBoundary";
|
||||
import { Devs } from "@utils/constants";
|
||||
import { useForceUpdater } from "@utils/misc";
|
||||
import { useForceUpdater } from "@utils/react";
|
||||
import definePlugin, { OptionType } from "@utils/types";
|
||||
import { GuildStore, PresenceStore, RelationshipStore } from "@webpack/common";
|
||||
|
||||
|
@ -17,11 +17,11 @@
|
||||
*/
|
||||
|
||||
import { addContextMenuPatch } from "@api/ContextMenu";
|
||||
import { Settings } from "@api/settings";
|
||||
import { Settings } from "@api/Settings";
|
||||
import PatchHelper from "@components/PatchHelper";
|
||||
import { Devs } from "@utils/constants";
|
||||
import Logger from "@utils/Logger";
|
||||
import { LazyComponent } from "@utils/misc";
|
||||
import { Logger } from "@utils/Logger";
|
||||
import { LazyComponent } from "@utils/react";
|
||||
import definePlugin, { OptionType } from "@utils/types";
|
||||
import { SettingsRouter } from "@webpack/common";
|
||||
|
||||
@ -155,12 +155,12 @@ export default definePlugin({
|
||||
},
|
||||
|
||||
get electronVersion() {
|
||||
return VencordNative.getVersions().electron || window.armcord?.electron || null;
|
||||
return VencordNative.native.getVersions().electron || window.armcord?.electron || null;
|
||||
},
|
||||
|
||||
get chromiumVersion() {
|
||||
try {
|
||||
return VencordNative.getVersions().chrome
|
||||
return VencordNative.native.getVersions().chrome
|
||||
// @ts-ignore Typescript will add userAgentData IMMEDIATELY
|
||||
|| navigator.userAgentData?.brands?.find(b => b.brand === "Chromium" || b.brand === "Google Chrome")?.version
|
||||
|| null;
|
||||
|
@ -17,8 +17,7 @@
|
||||
*/
|
||||
|
||||
import ErrorBoundary from "@components/ErrorBoundary";
|
||||
import { useAwaiter } from "@utils/misc";
|
||||
import { useIntersection } from "@utils/react";
|
||||
import { useAwaiter, useIntersection } from "@utils/react";
|
||||
import { hljs, React } from "@webpack/common";
|
||||
|
||||
import { resolveLang } from "../api/languages";
|
||||
|
@ -16,7 +16,7 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { definePluginSettings } from "@api/settings";
|
||||
import { definePluginSettings } from "@api/Settings";
|
||||
import { disableStyle, enableStyle } from "@api/Styles";
|
||||
import { parseUrl } from "@utils/misc";
|
||||
import { wordsFromPascal, wordsToTitle } from "@utils/text";
|
||||
|
@ -61,10 +61,7 @@
|
||||
display: flex;
|
||||
position: absolute;
|
||||
justify-content: center;
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
inset: 0;
|
||||
}
|
||||
|
||||
.shiki-preview {
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Vencord, a modification for Discord's desktop app
|
||||
* Copyright (c) 2022 Samu
|
||||
* 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
|
||||
@ -16,27 +16,22 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { addPreSendListener, MessageObject, removePreSendListener } from "@api/MessageEvents";
|
||||
import { Devs } from "@utils/constants";
|
||||
import definePlugin from "@utils/types";
|
||||
|
||||
const re = /https?:\/\/twitter\.com(?=\/\w+?\/status\/)/g;
|
||||
|
||||
export default definePlugin({
|
||||
name: "FxTwitter",
|
||||
description: "Uses FxTwitter to improve embeds from twitter on send",
|
||||
authors: [Devs.Samu],
|
||||
dependencies: ["MessageEventsAPI"],
|
||||
name: "ShowAllMessageButtons",
|
||||
description: "Always show all message buttons no matter if you are holding the shift key or not.",
|
||||
authors: [Devs.Nuckyz],
|
||||
|
||||
addPrefix(msg: MessageObject) {
|
||||
msg.content = msg.content.replace(re, "https://fxtwitter.com");
|
||||
},
|
||||
|
||||
start() {
|
||||
this.preSend = addPreSendListener((_, msg) => this.addPrefix(msg));
|
||||
},
|
||||
|
||||
stop() {
|
||||
removePreSendListener(this.preSend);
|
||||
}
|
||||
patches: [
|
||||
{
|
||||
find: ".Messages.MESSAGE_UTILITIES_A11Y_LABEL",
|
||||
replacement: {
|
||||
// isExpanded: V, (?<=,V = shiftKeyDown && !H...;)
|
||||
match: /isExpanded:(\i),(?<=,\1=\i&&(!.+);.+?)/,
|
||||
replace: "isExpanded:$2,"
|
||||
}
|
||||
}
|
||||
]
|
||||
});
|
38
src/plugins/showConnections/VerifiedIcon.tsx
Normal file
38
src/plugins/showConnections/VerifiedIcon.tsx
Normal file
@ -0,0 +1,38 @@
|
||||
/*
|
||||
* 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 { LazyComponent } from "@utils/react";
|
||||
import { findByCode, findLazy } from "@webpack";
|
||||
import { i18n, useToken } from "@webpack/common";
|
||||
|
||||
const ColorMap = findLazy(m => m.colors?.INTERACTIVE_MUTED?.css);
|
||||
const VerifiedIconComponent = LazyComponent(() => findByCode(".CONNECTIONS_ROLE_OFFICIAL_ICON_TOOLTIP"));
|
||||
|
||||
export function VerifiedIcon() {
|
||||
const color = useToken(ColorMap.colors.INTERACTIVE_MUTED).hex();
|
||||
const forcedIconColor = useToken(ColorMap.colors.INTERACTIVE_ACTIVE).hex();
|
||||
|
||||
return (
|
||||
<VerifiedIconComponent
|
||||
color={color}
|
||||
forcedIconColor={forcedIconColor}
|
||||
size={16}
|
||||
tooltipText={i18n.Messages.CONNECTION_VERIFIED}
|
||||
/>
|
||||
);
|
||||
}
|
@ -18,15 +18,20 @@
|
||||
|
||||
import "./styles.css";
|
||||
|
||||
import { definePluginSettings } from "@api/settings";
|
||||
import { definePluginSettings } from "@api/Settings";
|
||||
import ErrorBoundary from "@components/ErrorBoundary";
|
||||
import { Flex } from "@components/Flex";
|
||||
import { CopyIcon, LinkIcon } from "@components/Icons";
|
||||
import { Devs } from "@utils/constants";
|
||||
import { copyWithToast, LazyComponent } from "@utils/misc";
|
||||
import { copyWithToast } from "@utils/misc";
|
||||
import { LazyComponent } from "@utils/react";
|
||||
import definePlugin, { OptionType } from "@utils/types";
|
||||
import { findByCode, findByCodeLazy, findByPropsLazy, findStoreLazy } from "@webpack";
|
||||
import { Text, Tooltip } from "@webpack/common";
|
||||
import { User } from "discord-types/general";
|
||||
|
||||
import { VerifiedIcon } from "./VerifiedIcon";
|
||||
|
||||
const Section = LazyComponent(() => findByCode("().lastSection"));
|
||||
const UserProfileStore = findStoreLazy("UserProfileStore");
|
||||
const ThemeStore = findStoreLazy("ThemeStore");
|
||||
@ -96,7 +101,13 @@ function ConnectionsComponent({ id, theme }: { id: string, theme: string; }) {
|
||||
>
|
||||
Connections
|
||||
</Text>
|
||||
{connections.map(connection => <CompactConnectionComponent connection={connection} theme={theme} />)}
|
||||
<Flex style={{
|
||||
marginTop: "8px",
|
||||
gap: getSpacingPx(settings.store.iconSpacing),
|
||||
flexWrap: "wrap"
|
||||
}}>
|
||||
{connections.map(connection => <CompactConnectionComponent connection={connection} theme={theme} />)}
|
||||
</Flex>
|
||||
</Section>
|
||||
);
|
||||
}
|
||||
@ -110,17 +121,23 @@ function CompactConnectionComponent({ connection, theme }: { connection: Connect
|
||||
aria-label={connection.name}
|
||||
src={theme === "light" ? platform.icon.lightSVG : platform.icon.darkSVG}
|
||||
style={{
|
||||
marginTop: getSpacingPx(settings.store.iconSpacing),
|
||||
marginRight: getSpacingPx(settings.store.iconSpacing),
|
||||
width: settings.store.iconSize,
|
||||
height: settings.store.iconSize
|
||||
}}
|
||||
/>
|
||||
);
|
||||
|
||||
const TooltipIcon = url ? LinkIcon : CopyIcon;
|
||||
|
||||
return (
|
||||
<Tooltip
|
||||
text={`${connection.name}${!connection.verified ? " (unverified)" : ""} (click to ${url ? "open" : "copy"})`}
|
||||
text={
|
||||
<span className="vc-sc-tooltip">
|
||||
{connection.name}
|
||||
{connection.verified && <VerifiedIcon />}
|
||||
<TooltipIcon height={16} width={16} />
|
||||
</span>
|
||||
}
|
||||
key={connection.id}
|
||||
>
|
||||
{tooltipProps =>
|
||||
|
@ -3,3 +3,9 @@
|
||||
display: inline-block;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.vc-sc-tooltip {
|
||||
display: inline-flex;
|
||||
gap: 0.25em;
|
||||
align-items: center;
|
||||
}
|
||||
|
@ -17,7 +17,7 @@
|
||||
*/
|
||||
|
||||
import ErrorBoundary from "@components/ErrorBoundary";
|
||||
import { LazyComponent } from "@utils/misc";
|
||||
import { LazyComponent } from "@utils/react";
|
||||
import { formatDuration } from "@utils/text";
|
||||
import { find, findByPropsLazy, findStoreLazy } from "@webpack";
|
||||
import { FluxDispatcher, GuildMemberStore, GuildStore, moment, Parser, PermissionStore, SnowflakeUtils, Text, Timestamp, Tooltip } from "@webpack/common";
|
||||
|
@ -18,7 +18,7 @@
|
||||
|
||||
import "./style.css";
|
||||
|
||||
import { definePluginSettings } from "@api/settings";
|
||||
import { definePluginSettings } from "@api/Settings";
|
||||
import ErrorBoundary from "@components/ErrorBoundary";
|
||||
import { Devs } from "@utils/constants";
|
||||
import { canonicalizeMatch } from "@utils/patches";
|
||||
|
@ -18,13 +18,13 @@
|
||||
|
||||
import "./styles.css";
|
||||
|
||||
import { definePluginSettings } from "@api/settings";
|
||||
import { definePluginSettings } from "@api/Settings";
|
||||
import { Devs } from "@utils/constants";
|
||||
import definePlugin, { OptionType } from "@utils/types";
|
||||
import { Message } from "discord-types/general";
|
||||
|
||||
interface UsernameProps {
|
||||
author: { nick: string };
|
||||
author: { nick: string; };
|
||||
message: Message;
|
||||
withMentionPrefix?: boolean;
|
||||
isRepliedMessage: boolean;
|
||||
|
@ -17,7 +17,7 @@
|
||||
*/
|
||||
|
||||
import { addPreSendListener, removePreSendListener, SendListener } from "@api/MessageEvents";
|
||||
import { definePluginSettings } from "@api/settings";
|
||||
import { definePluginSettings } from "@api/Settings";
|
||||
import ErrorBoundary from "@components/ErrorBoundary";
|
||||
import { Devs } from "@utils/constants";
|
||||
import definePlugin, { OptionType } from "@utils/types";
|
||||
@ -72,7 +72,7 @@ function SilentMessageToggle(chatBoxProps: {
|
||||
size=""
|
||||
look={ButtonLooks.BLANK}
|
||||
innerClassName={ButtonWrapperClasses.button}
|
||||
style={{ padding: "0 8px" }}
|
||||
style={{ padding: "0 6px" }}
|
||||
>
|
||||
<div className={ButtonWrapperClasses.buttonWrapper}>
|
||||
<svg
|
||||
|
@ -17,7 +17,7 @@
|
||||
*/
|
||||
|
||||
import { ApplicationCommandInputType, ApplicationCommandOptionType, findOption, sendBotMessage } from "@api/Commands";
|
||||
import { definePluginSettings } from "@api/settings";
|
||||
import { definePluginSettings } from "@api/Settings";
|
||||
import ErrorBoundary from "@components/ErrorBoundary";
|
||||
import { Devs } from "@utils/constants";
|
||||
import definePlugin, { OptionType } from "@utils/types";
|
||||
@ -57,7 +57,7 @@ function SilentTypingToggle(chatBoxProps: {
|
||||
size=""
|
||||
look={ButtonLooks.BLANK}
|
||||
innerClassName={ButtonWrapperClasses.button}
|
||||
style={{ padding: "0 8px" }}
|
||||
style={{ padding: "0 6px" }}
|
||||
>
|
||||
<div className={ButtonWrapperClasses.buttonWrapper}>
|
||||
<svg width="24" height="24" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 576 512">
|
||||
|
@ -16,9 +16,8 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { Settings } from "@api/settings";
|
||||
import IpcEvents from "@utils/IpcEvents";
|
||||
import { proxyLazy } from "@utils/proxyLazy";
|
||||
import { Settings } from "@api/Settings";
|
||||
import { proxyLazy } from "@utils/lazy";
|
||||
import { findByPropsLazy } from "@webpack";
|
||||
import { Flux, FluxDispatcher } from "@webpack/common";
|
||||
|
||||
@ -94,7 +93,7 @@ export const SpotifyStore = proxyLazy(() => {
|
||||
? "spotify:" + path.replaceAll("/", (_, idx) => idx === 0 ? "" : ":")
|
||||
: "https://open.spotify.com" + path;
|
||||
|
||||
VencordNative.ipc.invoke(IpcEvents.OPEN_EXTERNAL, url);
|
||||
VencordNative.native.openExternal(url);
|
||||
}
|
||||
|
||||
// Need to keep track of this manually
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user