mirror of
https://github.com/Equicord/Equicord.git
synced 2025-01-31 03:33:36 -05:00
Merge remote-tracking branch 'upstream/dev' into dev
This commit is contained in:
commit
8222eb430e
42 changed files with 450 additions and 289 deletions
|
@ -9,7 +9,7 @@ import "./ChatButton.css";
|
||||||
import ErrorBoundary from "@components/ErrorBoundary";
|
import ErrorBoundary from "@components/ErrorBoundary";
|
||||||
import { Logger } from "@utils/Logger";
|
import { Logger } from "@utils/Logger";
|
||||||
import { waitFor } from "@webpack";
|
import { waitFor } from "@webpack";
|
||||||
import { Button, ButtonLooks, ButtonWrapperClasses, Tooltip } from "@webpack/common";
|
import { Button, ButtonWrapperClasses, Tooltip } from "@webpack/common";
|
||||||
import { Channel } from "discord-types/general";
|
import { Channel } from "discord-types/general";
|
||||||
import { HTMLProps, JSX, MouseEventHandler, ReactNode } from "react";
|
import { HTMLProps, JSX, MouseEventHandler, ReactNode } from "react";
|
||||||
|
|
||||||
|
@ -110,7 +110,7 @@ export const ChatBarButton = ErrorBoundary.wrap((props: ChatBarButtonProps) => {
|
||||||
<Button
|
<Button
|
||||||
aria-label={props.tooltip}
|
aria-label={props.tooltip}
|
||||||
size=""
|
size=""
|
||||||
look={ButtonLooks.BLANK}
|
look={Button.Looks.BLANK}
|
||||||
onMouseEnter={onMouseEnter}
|
onMouseEnter={onMouseEnter}
|
||||||
onMouseLeave={onMouseLeave}
|
onMouseLeave={onMouseLeave}
|
||||||
innerClassName={`${ButtonWrapperClasses.button} ${ChannelTextAreaClasses?.button}`}
|
innerClassName={`${ButtonWrapperClasses.button} ${ChannelTextAreaClasses?.button}`}
|
||||||
|
|
|
@ -122,7 +122,7 @@ export function findGroupChildrenByChildId(id: string | string[], children: Arra
|
||||||
}
|
}
|
||||||
|
|
||||||
interface ContextMenuProps {
|
interface ContextMenuProps {
|
||||||
contextMenuApiArguments?: Array<any>;
|
contextMenuAPIArguments?: Array<any>;
|
||||||
navId: string;
|
navId: string;
|
||||||
children: Array<ReactElement<any> | null>;
|
children: Array<ReactElement<any> | null>;
|
||||||
"aria-label": string;
|
"aria-label": string;
|
||||||
|
@ -136,7 +136,7 @@ export function _usePatchContextMenu(props: ContextMenuProps) {
|
||||||
children: cloneMenuChildren(props.children),
|
children: cloneMenuChildren(props.children),
|
||||||
};
|
};
|
||||||
|
|
||||||
props.contextMenuApiArguments ??= [];
|
props.contextMenuAPIArguments ??= [];
|
||||||
const contextMenuPatches = navPatches.get(props.navId);
|
const contextMenuPatches = navPatches.get(props.navId);
|
||||||
|
|
||||||
if (!Array.isArray(props.children)) props.children = [props.children];
|
if (!Array.isArray(props.children)) props.children = [props.children];
|
||||||
|
@ -144,7 +144,7 @@ export function _usePatchContextMenu(props: ContextMenuProps) {
|
||||||
if (contextMenuPatches) {
|
if (contextMenuPatches) {
|
||||||
for (const patch of contextMenuPatches) {
|
for (const patch of contextMenuPatches) {
|
||||||
try {
|
try {
|
||||||
patch(props.children, ...props.contextMenuApiArguments);
|
patch(props.children, ...props.contextMenuAPIArguments);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
ContextMenuLogger.error(`Patch for ${props.navId} errored,`, err);
|
ContextMenuLogger.error(`Patch for ${props.navId} errored,`, err);
|
||||||
}
|
}
|
||||||
|
@ -153,7 +153,7 @@ export function _usePatchContextMenu(props: ContextMenuProps) {
|
||||||
|
|
||||||
for (const patch of globalPatches) {
|
for (const patch of globalPatches) {
|
||||||
try {
|
try {
|
||||||
patch(props.navId, props.children, ...props.contextMenuApiArguments);
|
patch(props.navId, props.children, ...props.contextMenuAPIArguments);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
ContextMenuLogger.error("Global patch errored,", err);
|
ContextMenuLogger.error("Global patch errored,", err);
|
||||||
}
|
}
|
||||||
|
|
|
@ -237,15 +237,13 @@ export function migratePluginSettings(name: string, ...oldNames: string[]) {
|
||||||
}
|
}
|
||||||
|
|
||||||
export function migratePluginSetting(pluginName: string, oldSetting: string, newSetting: string) {
|
export function migratePluginSetting(pluginName: string, oldSetting: string, newSetting: string) {
|
||||||
const { plugins } = SettingsStore.plain;
|
const settings = SettingsStore.plain.plugins[pluginName];
|
||||||
|
if (!settings) return;
|
||||||
|
|
||||||
if (
|
if (!Object.hasOwn(settings, oldSetting) || Object.hasOwn(settings, newSetting)) return;
|
||||||
plugins[pluginName][newSetting] != null ||
|
|
||||||
plugins[pluginName][oldSetting] == null
|
|
||||||
) return;
|
|
||||||
|
|
||||||
plugins[pluginName][newSetting] = plugins[pluginName][oldSetting];
|
settings[newSetting] = settings[oldSetting];
|
||||||
delete plugins[pluginName][oldSetting];
|
delete settings[oldSetting];
|
||||||
SettingsStore.markAsChanged();
|
SettingsStore.markAsChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -66,14 +66,21 @@ async function runReporter() {
|
||||||
if (result == null || (result.$$vencordInternal != null && result.$$vencordInternal() == null)) throw new Error("Webpack Find Fail");
|
if (result == null || (result.$$vencordInternal != null && result.$$vencordInternal() == null)) throw new Error("Webpack Find Fail");
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
let logMessage = searchType;
|
let logMessage = searchType;
|
||||||
if (method === "find" || method === "proxyLazyWebpack" || method === "LazyComponentWebpack") logMessage += `(${args[0].toString().slice(0, 147)}...)`;
|
if (method === "find" || method === "proxyLazyWebpack" || method === "LazyComponentWebpack") {
|
||||||
else if (method === "extractAndLoadChunks") logMessage += `([${args[0].map(arg => `"${arg}"`).join(", ")}], ${args[1].toString()})`;
|
if (args[0].$$vencordProps != null) {
|
||||||
else if (method === "mapMangledModule") {
|
logMessage += `(${args[0].$$vencordProps.map(arg => `"${arg}"`).join(", ")})`;
|
||||||
|
} else {
|
||||||
|
logMessage += `(${args[0].toString().slice(0, 147)}...)`;
|
||||||
|
}
|
||||||
|
} else if (method === "extractAndLoadChunks") {
|
||||||
|
logMessage += `([${args[0].map(arg => `"${arg}"`).join(", ")}], ${args[1].toString()})`;
|
||||||
|
} else if (method === "mapMangledModule") {
|
||||||
const failedMappings = Object.keys(args[1]).filter(key => result?.[key] == null);
|
const failedMappings = Object.keys(args[1]).filter(key => result?.[key] == null);
|
||||||
|
|
||||||
logMessage += `("${args[0]}", {\n${failedMappings.map(mapping => `\t${mapping}: ${args[1][mapping].toString().slice(0, 147)}...`).join(",\n")}\n})`;
|
logMessage += `("${args[0]}", {\n${failedMappings.map(mapping => `\t${mapping}: ${args[1][mapping].toString().slice(0, 147)}...`).join(",\n")}\n})`;
|
||||||
|
} else {
|
||||||
|
logMessage += `(${args.map(arg => `"${arg}"`).join(", ")})`;
|
||||||
}
|
}
|
||||||
else logMessage += `(${args.map(arg => `"${arg}"`).join(", ")})`;
|
|
||||||
if (IS_COMPANION_TEST)
|
if (IS_COMPANION_TEST)
|
||||||
reporterData.failedWebpack[method].push(args.map(a => String(a)));
|
reporterData.failedWebpack[method].push(args.map(a => String(a)));
|
||||||
ReporterLogger.log("Webpack Find Fail:", logMessage);
|
ReporterLogger.log("Webpack Find Fail:", logMessage);
|
||||||
|
|
|
@ -28,7 +28,7 @@ import { Devs } from "@utils/constants";
|
||||||
import { Logger } from "@utils/Logger";
|
import { Logger } from "@utils/Logger";
|
||||||
import { Margins } from "@utils/margins";
|
import { Margins } from "@utils/margins";
|
||||||
import { isEquicordPluginDev, isPluginDev } from "@utils/misc";
|
import { isEquicordPluginDev, isPluginDev } from "@utils/misc";
|
||||||
import { closeModal, Modals, openModal } from "@utils/modal";
|
import { closeModal, ModalContent, ModalFooter, ModalHeader, ModalRoot, openModal } from "@utils/modal";
|
||||||
import definePlugin from "@utils/types";
|
import definePlugin from "@utils/types";
|
||||||
import { Forms, Toasts, UserStore } from "@webpack/common";
|
import { Forms, Toasts, UserStore } from "@webpack/common";
|
||||||
import { User } from "discord-types/general";
|
import { User } from "discord-types/general";
|
||||||
|
@ -159,8 +159,8 @@ export default definePlugin({
|
||||||
closeModal(modalKey);
|
closeModal(modalKey);
|
||||||
VencordNative.native.openExternal("https://github.com/sponsors/Vendicated");
|
VencordNative.native.openExternal("https://github.com/sponsors/Vendicated");
|
||||||
}}>
|
}}>
|
||||||
<Modals.ModalRoot {...props}>
|
<ModalRoot {...props}>
|
||||||
<Modals.ModalHeader>
|
<ModalHeader>
|
||||||
<Flex style={{ width: "100%", justifyContent: "center" }}>
|
<Flex style={{ width: "100%", justifyContent: "center" }}>
|
||||||
<Forms.FormTitle
|
<Forms.FormTitle
|
||||||
tag="h2"
|
tag="h2"
|
||||||
|
@ -174,8 +174,8 @@ export default definePlugin({
|
||||||
Vencord Donor
|
Vencord Donor
|
||||||
</Forms.FormTitle>
|
</Forms.FormTitle>
|
||||||
</Flex>
|
</Flex>
|
||||||
</Modals.ModalHeader>
|
</ModalHeader>
|
||||||
<Modals.ModalContent>
|
<ModalContent>
|
||||||
<Flex>
|
<Flex>
|
||||||
<img
|
<img
|
||||||
role="presentation"
|
role="presentation"
|
||||||
|
@ -198,13 +198,13 @@ export default definePlugin({
|
||||||
Please consider supporting the development of Vencord by becoming a donor. It would mean a lot!
|
Please consider supporting the development of Vencord by becoming a donor. It would mean a lot!
|
||||||
</Forms.FormText>
|
</Forms.FormText>
|
||||||
</div>
|
</div>
|
||||||
</Modals.ModalContent>
|
</ModalContent>
|
||||||
<Modals.ModalFooter>
|
<ModalFooter>
|
||||||
<Flex style={{ width: "100%", justifyContent: "center" }}>
|
<Flex style={{ width: "100%", justifyContent: "center" }}>
|
||||||
<DonateButton />
|
<DonateButton />
|
||||||
</Flex>
|
</Flex>
|
||||||
</Modals.ModalFooter>
|
</ModalFooter>
|
||||||
</Modals.ModalRoot>
|
</ModalRoot>
|
||||||
</ErrorBoundary>
|
</ErrorBoundary>
|
||||||
));
|
));
|
||||||
},
|
},
|
||||||
|
@ -229,8 +229,8 @@ export default definePlugin({
|
||||||
// Will get my own in the future
|
// Will get my own in the future
|
||||||
VencordNative.native.openExternal("https://github.com/sponsors/Vendicated");
|
VencordNative.native.openExternal("https://github.com/sponsors/Vendicated");
|
||||||
}}>
|
}}>
|
||||||
<Modals.ModalRoot {...props}>
|
<ModalRoot {...props}>
|
||||||
<Modals.ModalHeader>
|
<ModalHeader>
|
||||||
<Flex style={{ width: "100%", justifyContent: "center" }}>
|
<Flex style={{ width: "100%", justifyContent: "center" }}>
|
||||||
<Forms.FormTitle
|
<Forms.FormTitle
|
||||||
tag="h2"
|
tag="h2"
|
||||||
|
@ -244,8 +244,8 @@ export default definePlugin({
|
||||||
Equicord Donor
|
Equicord Donor
|
||||||
</Forms.FormTitle>
|
</Forms.FormTitle>
|
||||||
</Flex>
|
</Flex>
|
||||||
</Modals.ModalHeader>
|
</ModalHeader>
|
||||||
<Modals.ModalContent>
|
<ModalContent>
|
||||||
<Flex>
|
<Flex>
|
||||||
<img
|
<img
|
||||||
role="presentation"
|
role="presentation"
|
||||||
|
@ -268,13 +268,13 @@ export default definePlugin({
|
||||||
Please consider supporting the development of Equicord by becoming a donor. It would mean a lot! :3
|
Please consider supporting the development of Equicord by becoming a donor. It would mean a lot! :3
|
||||||
</Forms.FormText>
|
</Forms.FormText>
|
||||||
</div>
|
</div>
|
||||||
</Modals.ModalContent>
|
</ModalContent>
|
||||||
<Modals.ModalFooter>
|
<ModalFooter>
|
||||||
<Flex style={{ width: "100%", justifyContent: "center" }}>
|
<Flex style={{ width: "100%", justifyContent: "center" }}>
|
||||||
<DonateButton />
|
<DonateButton />
|
||||||
</Flex>
|
</Flex>
|
||||||
</Modals.ModalFooter>
|
</ModalFooter>
|
||||||
</Modals.ModalRoot>
|
</ModalRoot>
|
||||||
</ErrorBoundary>
|
</ErrorBoundary>
|
||||||
));
|
));
|
||||||
},
|
},
|
||||||
|
|
|
@ -12,11 +12,15 @@ export default definePlugin({
|
||||||
description: "API to add buttons to the chat input",
|
description: "API to add buttons to the chat input",
|
||||||
authors: [Devs.Ven],
|
authors: [Devs.Ven],
|
||||||
|
|
||||||
patches: [{
|
patches: [
|
||||||
find: '"gift")),(null',
|
{
|
||||||
replacement: {
|
find: '"sticker")',
|
||||||
match: /return\(!\i\.\i&&(?=\(\i\.isDM.+?(\i)\.push\(.{0,50}"gift")/,
|
replacement: {
|
||||||
replace: "$&(Vencord.Api.ChatButtons._injectButtons($1,arguments[0]),true)&&"
|
match: /return\((!)?\i\.\i(?:\|\||&&)(?=\(\i\.isDM.+?(\i)\.push)/,
|
||||||
|
replace: (m, not, children) => not
|
||||||
|
? `${m}(Vencord.Api.ChatButtons._injectButtons(${children},arguments[0]),true)&&`
|
||||||
|
: `${m}(Vencord.Api.ChatButtons._injectButtons(${children},arguments[0]),false)||`
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}]
|
]
|
||||||
});
|
});
|
||||||
|
|
|
@ -34,12 +34,22 @@ export default definePlugin({
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
find: ".Menu,{",
|
find: "navId:",
|
||||||
all: true,
|
all: true,
|
||||||
replacement: {
|
noWarn: true,
|
||||||
match: /Menu,{(?<=\.jsxs?\)\(\i\.Menu,{)/g,
|
replacement: [
|
||||||
replace: "$&contextMenuApiArguments:typeof arguments!=='undefined'?arguments:[],"
|
{
|
||||||
}
|
match: /navId:(?=.+?([,}].*?\)))/g,
|
||||||
|
replace: (m, rest) => {
|
||||||
|
// Check if this navId: match is a destructuring statement, ignore it if it is
|
||||||
|
const destructuringMatch = rest.match(/}=.+/);
|
||||||
|
if (destructuringMatch == null) {
|
||||||
|
return `contextMenuAPIArguments:typeof arguments!=='undefined'?arguments:[],${m}`;
|
||||||
|
}
|
||||||
|
return m;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
});
|
});
|
||||||
|
|
68
src/plugins/_api/menuItemDemangler.ts
Normal file
68
src/plugins/_api/menuItemDemangler.ts
Normal file
|
@ -0,0 +1,68 @@
|
||||||
|
/*
|
||||||
|
* Vencord, a Discord client mod
|
||||||
|
* Copyright (c) 2025 Vendicated and contributors
|
||||||
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { Devs } from "@utils/constants";
|
||||||
|
import { canonicalizeMatch } from "@utils/patches";
|
||||||
|
import definePlugin from "@utils/types";
|
||||||
|
|
||||||
|
// duplicate values have multiple branches with different types. Just include all to be safe
|
||||||
|
const nameMap = {
|
||||||
|
radio: "MenuRadioItem",
|
||||||
|
separator: "MenuSeparator",
|
||||||
|
checkbox: "MenuCheckboxItem",
|
||||||
|
groupstart: "MenuGroup",
|
||||||
|
|
||||||
|
control: "MenuControlItem",
|
||||||
|
compositecontrol: "MenuControlItem",
|
||||||
|
|
||||||
|
item: "MenuItem",
|
||||||
|
customitem: "MenuItem",
|
||||||
|
};
|
||||||
|
|
||||||
|
export default definePlugin({
|
||||||
|
name: "MenuItemDemanglerAPI",
|
||||||
|
description: "Demangles Discord's Menu Item module",
|
||||||
|
authors: [Devs.Ven],
|
||||||
|
required: true,
|
||||||
|
patches: [
|
||||||
|
{
|
||||||
|
find: '"Menu API',
|
||||||
|
replacement: {
|
||||||
|
match: /function.{0,80}type===(\i\.\i)\).{0,50}navigable:.+?Menu API/s,
|
||||||
|
replace: (m, mod) => {
|
||||||
|
const nameAssignments = [] as string[];
|
||||||
|
|
||||||
|
// if (t.type === m.MenuItem)
|
||||||
|
const typeCheckRe = canonicalizeMatch(/\(\i\.type===(\i\.\i)\)/g);
|
||||||
|
// push({type:"item"})
|
||||||
|
const pushTypeRe = /type:"(\w+)"/g;
|
||||||
|
|
||||||
|
let typeMatch: RegExpExecArray | null;
|
||||||
|
// for each if (t.type === ...)
|
||||||
|
while ((typeMatch = typeCheckRe.exec(m)) !== null) {
|
||||||
|
// extract the current menu item
|
||||||
|
const item = typeMatch[1];
|
||||||
|
// Set the starting index of the second regex to that of the first to start
|
||||||
|
// matching from after the if
|
||||||
|
pushTypeRe.lastIndex = typeCheckRe.lastIndex;
|
||||||
|
// extract the first type: "..."
|
||||||
|
const type = pushTypeRe.exec(m)?.[1];
|
||||||
|
if (type && type in nameMap) {
|
||||||
|
const name = nameMap[type];
|
||||||
|
nameAssignments.push(`Object.defineProperty(${item},"name",{value:"${name}"})`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (nameAssignments.length < 6) {
|
||||||
|
console.warn("[MenuItemDemanglerAPI] Expected to at least remap 6 items, only remapped", nameAssignments.length);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Merge all our redefines with the actual module
|
||||||
|
return `${nameAssignments.join(";")};${m}`;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
|
@ -64,7 +64,7 @@ export default definePlugin({
|
||||||
replace: (_, sectionTypes, commaOrSemi, elements, element) => `${commaOrSemi} $self.addSettings(${elements}, ${element}, ${sectionTypes}) ${commaOrSemi}`
|
replace: (_, sectionTypes, commaOrSemi, elements, element) => `${commaOrSemi} $self.addSettings(${elements}, ${element}, ${sectionTypes}) ${commaOrSemi}`
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
match: /({(?=.+?function (\i).{0,160}(\i)=\i\.useMemo.{0,140}return \i\.useMemo\(\(\)=>\i\(\3).+?function\(\){return )\2(?=})/,
|
match: /({(?=.+?function (\i).{0,160}(\i)=\i\.useMemo.{0,140}return \i\.useMemo\(\(\)=>\i\(\3).+?(?:function\(\){return |\(\)=>))\2/,
|
||||||
replace: (_, rest, settingsHook) => `${rest}$self.wrapSettingsHook(${settingsHook})`
|
replace: (_, rest, settingsHook) => `${rest}$self.wrapSettingsHook(${settingsHook})`
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
|
@ -173,8 +173,8 @@ export default definePlugin({
|
||||||
// Disable expanding and collapsing folders transition in the normal GuildsBar sidebar
|
// Disable expanding and collapsing folders transition in the normal GuildsBar sidebar
|
||||||
{
|
{
|
||||||
predicate: () => !settings.store.keepIcons,
|
predicate: () => !settings.store.keepIcons,
|
||||||
match: /(?<=#{intl::SERVER_FOLDER_PLACEHOLDER}.+?useTransition\)\()/,
|
match: /(?=,\{from:\{height)/,
|
||||||
replace: "$self.shouldShowTransition(arguments[0])&&"
|
replace: "&&$self.shouldShowTransition(arguments[0])"
|
||||||
},
|
},
|
||||||
// If we are rendering the normal GuildsBar sidebar, we avoid rendering guilds from folders that are expanded
|
// If we are rendering the normal GuildsBar sidebar, we avoid rendering guilds from folders that are expanded
|
||||||
{
|
{
|
||||||
|
|
|
@ -21,7 +21,7 @@ import { definePluginSettings } from "@api/Settings";
|
||||||
import ErrorBoundary from "@components/ErrorBoundary";
|
import ErrorBoundary from "@components/ErrorBoundary";
|
||||||
import { Devs } from "@utils/constants";
|
import { Devs } from "@utils/constants";
|
||||||
import definePlugin, { OptionType } from "@utils/types";
|
import definePlugin, { OptionType } from "@utils/types";
|
||||||
import { findByPropsLazy, findExportedComponentLazy, findStoreLazy } from "@webpack";
|
import { findByPropsLazy, findComponentByCodeLazy, findStoreLazy } from "@webpack";
|
||||||
import { Constants, React, RestAPI, Tooltip } from "@webpack/common";
|
import { Constants, React, RestAPI, Tooltip } from "@webpack/common";
|
||||||
|
|
||||||
import { RenameButton } from "./components/RenameButton";
|
import { RenameButton } from "./components/RenameButton";
|
||||||
|
@ -34,7 +34,7 @@ const UserSettingsModal = findByPropsLazy("saveAccountChanges", "open");
|
||||||
const TimestampClasses = findByPropsLazy("timestampTooltip", "blockquoteContainer");
|
const TimestampClasses = findByPropsLazy("timestampTooltip", "blockquoteContainer");
|
||||||
const SessionIconClasses = findByPropsLazy("sessionIcon");
|
const SessionIconClasses = findByPropsLazy("sessionIcon");
|
||||||
|
|
||||||
const BlobMask = findExportedComponentLazy("BlobMask");
|
const BlobMask = findComponentByCodeLazy("!1,lowerBadgeSize:");
|
||||||
|
|
||||||
const settings = definePluginSettings({
|
const settings = definePluginSettings({
|
||||||
backgroundCheck: {
|
backgroundCheck: {
|
||||||
|
|
|
@ -104,8 +104,8 @@ export default definePlugin({
|
||||||
find: 'minimal:"contentColumnMinimal"',
|
find: 'minimal:"contentColumnMinimal"',
|
||||||
replacement: [
|
replacement: [
|
||||||
{
|
{
|
||||||
match: /\(0,\i\.useTransition\)\((\i)/,
|
match: /(?=\(0,\i\.\i\)\((\i),\{from:\{position:"absolute")/,
|
||||||
replace: "(_cb=>_cb(void 0,$1))||$&"
|
replace: "(_cb=>_cb(void 0,$1))||"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
match: /\i\.animated\.div/,
|
match: /\i\.animated\.div/,
|
||||||
|
|
|
@ -69,8 +69,8 @@ export default definePlugin({
|
||||||
{
|
{
|
||||||
find: "https://github.com/highlightjs/highlight.js/issues/2277",
|
find: "https://github.com/highlightjs/highlight.js/issues/2277",
|
||||||
replacement: {
|
replacement: {
|
||||||
match: /(?<=&&\()console.log\(`Deprecated.+?`\),/,
|
match: /\(console.log\(`Deprecated.+?`\),/,
|
||||||
replace: ""
|
replace: "("
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
|
@ -63,7 +63,7 @@ function makeShortcuts() {
|
||||||
default:
|
default:
|
||||||
const uniqueMatches = [...new Set(matches)];
|
const uniqueMatches = [...new Set(matches)];
|
||||||
if (uniqueMatches.length > 1)
|
if (uniqueMatches.length > 1)
|
||||||
console.warn(`Warning: This filter matches ${matches.length} modules. Make it more specific!\n`, uniqueMatches);
|
console.warn(`Warning: This filter matches ${uniqueMatches.length} exports. Make it more specific!\n`, uniqueMatches);
|
||||||
|
|
||||||
return matches[0];
|
return matches[0];
|
||||||
}
|
}
|
||||||
|
@ -165,11 +165,38 @@ function loadAndCacheShortcut(key: string, val: any, forceLoad: boolean) {
|
||||||
const currentVal = val.getter();
|
const currentVal = val.getter();
|
||||||
if (!currentVal || val.preload === false) return currentVal;
|
if (!currentVal || val.preload === false) return currentVal;
|
||||||
|
|
||||||
const value = currentVal[SYM_LAZY_GET]
|
function unwrapProxy(value: any) {
|
||||||
? forceLoad ? currentVal[SYM_LAZY_GET]() : currentVal[SYM_LAZY_CACHED]
|
if (value[SYM_LAZY_GET]) {
|
||||||
: currentVal;
|
forceLoad ? currentVal[SYM_LAZY_GET]() : currentVal[SYM_LAZY_CACHED];
|
||||||
|
} else if (value.$$vencordInternal) {
|
||||||
|
return forceLoad ? value.$$vencordInternal() : value;
|
||||||
|
}
|
||||||
|
|
||||||
if (value) define(window.shortcutList, key, { value });
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
const value = unwrapProxy(currentVal);
|
||||||
|
if (typeof value === "object" && value !== null) {
|
||||||
|
const descriptors = Object.getOwnPropertyDescriptors(value);
|
||||||
|
|
||||||
|
for (const propKey in descriptors) {
|
||||||
|
if (value[propKey] == null) continue;
|
||||||
|
|
||||||
|
const descriptor = descriptors[propKey];
|
||||||
|
if (descriptor.writable === true || descriptor.set != null) {
|
||||||
|
const currentValue = value[propKey];
|
||||||
|
const newValue = unwrapProxy(currentValue);
|
||||||
|
if (newValue != null && currentValue !== newValue) {
|
||||||
|
value[propKey] = newValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (value != null) {
|
||||||
|
define(window.shortcutList, key, { value });
|
||||||
|
define(window, key, { value });
|
||||||
|
}
|
||||||
|
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
|
@ -42,10 +42,10 @@ export default definePlugin({
|
||||||
// Only one of the two patches will be at effect; Discord often updates to switch between them.
|
// Only one of the two patches will be at effect; Discord often updates to switch between them.
|
||||||
// See: https://discord.com/channels/1015060230222131221/1032770730703716362/1261398512017477673
|
// See: https://discord.com/channels/1015060230222131221/1032770730703716362/1261398512017477673
|
||||||
{
|
{
|
||||||
find: ".ENTER&&(!",
|
find: ".selectPreviousCommandOption(",
|
||||||
replacement: {
|
replacement: {
|
||||||
match: /(?<=(\i)\.which===\i\.\i.ENTER&&).{0,100}(\(0,\i\.\i\)\(\i\)).{0,100}(?=&&\(\i\.preventDefault)/,
|
match: /(?<=(\i)\.which(?:!==|===)\i\.\i.ENTER(\|\||&&)).{0,100}(\(0,\i\.\i\)\(\i\)).{0,100}(?=(?:\|\||&&)\(\i\.preventDefault)/,
|
||||||
replace: "$self.shouldSubmit($1, $2)"
|
replace: (_, event, condition, codeblock) => `${condition === "||" ? "!" : ""}$self.shouldSubmit(${event},${codeblock})`
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
|
@ -23,11 +23,11 @@ import { migratePluginSettings, Settings, useSettings } from "@api/Settings";
|
||||||
import ErrorBoundary from "@components/ErrorBoundary";
|
import ErrorBoundary from "@components/ErrorBoundary";
|
||||||
import { Devs } from "@utils/constants";
|
import { Devs } from "@utils/constants";
|
||||||
import definePlugin from "@utils/types";
|
import definePlugin from "@utils/types";
|
||||||
import { findExportedComponentLazy } from "@webpack";
|
import { findComponentByCodeLazy } from "@webpack";
|
||||||
import { Menu, Popout, useState } from "@webpack/common";
|
import { Menu, Popout, useState } from "@webpack/common";
|
||||||
import type { ReactNode } from "react";
|
import type { ReactNode } from "react";
|
||||||
|
|
||||||
const HeaderBarIcon = findExportedComponentLazy("Icon", "Divider");
|
const HeaderBarIcon = findComponentByCodeLazy(".HEADER_BAR_BADGE_TOP:", '.iconBadge,"top"');
|
||||||
|
|
||||||
function VencordPopout(onClose: () => void) {
|
function VencordPopout(onClose: () => void) {
|
||||||
const { useQuickCss } = useSettings(["useQuickCss"]);
|
const { useQuickCss } = useSettings(["useQuickCss"]);
|
||||||
|
|
|
@ -243,7 +243,7 @@ export default definePlugin({
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
find: ".PREMIUM_LOCKED;",
|
find: ".GUILD_SUBSCRIPTION_UNAVAILABLE;",
|
||||||
group: true,
|
group: true,
|
||||||
predicate: () => settings.store.enableEmojiBypass,
|
predicate: () => settings.store.enableEmojiBypass,
|
||||||
replacement: [
|
replacement: [
|
||||||
|
@ -264,8 +264,10 @@ export default definePlugin({
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
// Disallow the emoji for premium locked if the intention doesn't allow it
|
// Disallow the emoji for premium locked if the intention doesn't allow it
|
||||||
match: /!\i\.\i\.canUseEmojisEverywhere\(\i\)/,
|
match: /(!)?(\i\.\i\.canUseEmojisEverywhere\(\i\))/,
|
||||||
replace: m => `(${m}&&!${IS_BYPASSEABLE_INTENTION})`
|
replace: (m, not) => not
|
||||||
|
? `(${m}&&!${IS_BYPASSEABLE_INTENTION})`
|
||||||
|
: `(${m}||${IS_BYPASSEABLE_INTENTION})`
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
// Allow animated emojis to be used if the intention allows it
|
// Allow animated emojis to be used if the intention allows it
|
||||||
|
|
|
@ -22,11 +22,11 @@ import { Devs } from "@utils/constants";
|
||||||
import { getIntlMessage } from "@utils/discord";
|
import { getIntlMessage } from "@utils/discord";
|
||||||
import { NoopComponent } from "@utils/react";
|
import { NoopComponent } from "@utils/react";
|
||||||
import definePlugin from "@utils/types";
|
import definePlugin from "@utils/types";
|
||||||
import { filters, findByPropsLazy, waitFor } from "@webpack";
|
import { filters, findByCodeLazy, waitFor } from "@webpack";
|
||||||
import { ChannelStore, ContextMenuApi, UserStore } from "@webpack/common";
|
import { ChannelStore, ContextMenuApi, UserStore } from "@webpack/common";
|
||||||
import { Message } from "discord-types/general";
|
import { Message } from "discord-types/general";
|
||||||
|
|
||||||
const { useMessageMenu } = findByPropsLazy("useMessageMenu");
|
const useMessageMenu = findByCodeLazy(".MESSAGE,commandTargetId:");
|
||||||
|
|
||||||
interface CopyIdMenuItemProps {
|
interface CopyIdMenuItemProps {
|
||||||
id: string;
|
id: string;
|
||||||
|
|
|
@ -26,7 +26,7 @@ import { findComponentByCodeLazy } from "@webpack";
|
||||||
|
|
||||||
import style from "./style.css?managed";
|
import style from "./style.css?managed";
|
||||||
|
|
||||||
const Button = findComponentByCodeLazy("Button.Sizes.NONE,disabled:");
|
const Button = findComponentByCodeLazy(".NONE,disabled:", ".PANEL_BUTTON");
|
||||||
|
|
||||||
const ShowCurrentGame = getUserSettingLazy<boolean>("status", "showCurrentGame")!;
|
const ShowCurrentGame = getUserSettingLazy<boolean>("status", "showCurrentGame")!;
|
||||||
|
|
||||||
|
|
|
@ -29,7 +29,7 @@ export default definePlugin({
|
||||||
{
|
{
|
||||||
find: "hasFlag:{writable",
|
find: "hasFlag:{writable",
|
||||||
replacement: {
|
replacement: {
|
||||||
match: /if\((\i)<=(?:1<<30|1073741824)\)return/,
|
match: /if\((\i)<=(?:0x40000000|(?:1<<30|1073741824))\)return/,
|
||||||
replace: "if($1===(1<<20))return false;$&",
|
replace: "if($1===(1<<20))return false;$&",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
|
@ -243,7 +243,7 @@ export default definePlugin({
|
||||||
find: '"LocalActivityStore"',
|
find: '"LocalActivityStore"',
|
||||||
replacement: [
|
replacement: [
|
||||||
{
|
{
|
||||||
match: /HANG_STATUS.+?(?=!\i\(\)\(\i,\i\)&&)(?<=(\i)\.push.+?)/,
|
match: /HANG_STATUS.+?(?=!?\i\(\)\(\i,\i\))(?<=(\i)\.push.+?)/,
|
||||||
replace: (m, activities) => `${m}${activities}=${activities}.filter($self.isActivityNotIgnored);`
|
replace: (m, activities) => `${m}${activities}=${activities}.filter($self.isActivityNotIgnored);`
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
|
@ -50,7 +50,7 @@ export default definePlugin({
|
||||||
{
|
{
|
||||||
find: "#{intl::FRIENDS_SECTION_ONLINE}",
|
find: "#{intl::FRIENDS_SECTION_ONLINE}",
|
||||||
replacement: {
|
replacement: {
|
||||||
match: /(\(0,\i\.jsx\)\(\i\.TabBar\.Item,\{id:\i\.\i)\.BLOCKED,className:([^\s]+?)\.item,children:\i\.\i\.string\(\i\.\i#{intl::BLOCKED}\)\}\)/,
|
match: /(\(0,\i\.jsx\)\(\i\.\i\.Item,\{id:\i\.\i)\.BLOCKED,className:([^\s]+?)\.item,children:\i\.\i\.string\(\i\.\i#{intl::BLOCKED}\)\}\)/,
|
||||||
replace: "$1.IMPLICIT,className:$2.item,children:\"Implicit\"}),$&"
|
replace: "$1.IMPLICIT,className:$2.item,children:\"Implicit\"}),$&"
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
|
@ -56,7 +56,7 @@ export default definePlugin({
|
||||||
{
|
{
|
||||||
find: ".ROLE_MENTION)",
|
find: ".ROLE_MENTION)",
|
||||||
replacement: {
|
replacement: {
|
||||||
match: /children:\[\i&&.{0,50}\.RoleDot.{0,300},\i(?=\])/,
|
match: /children:\[\i&&.{0,100}className:\i.roleDot,.{0,200},\i(?=\])/,
|
||||||
replace: "$&,$self.renderRoleIcon(arguments[0])"
|
replace: "$&,$self.renderRoleIcon(arguments[0])"
|
||||||
}
|
}
|
||||||
}],
|
}],
|
||||||
|
|
|
@ -9,7 +9,7 @@ import ErrorBoundary from "@components/ErrorBoundary";
|
||||||
import { Devs } from "@utils/constants";
|
import { Devs } from "@utils/constants";
|
||||||
import { isNonNullish } from "@utils/guards";
|
import { isNonNullish } from "@utils/guards";
|
||||||
import definePlugin, { OptionType } from "@utils/types";
|
import definePlugin, { OptionType } from "@utils/types";
|
||||||
import { findExportedComponentLazy } from "@webpack";
|
import { findComponentByCodeLazy } from "@webpack";
|
||||||
import { SnowflakeUtils, Tooltip } from "@webpack/common";
|
import { SnowflakeUtils, Tooltip } from "@webpack/common";
|
||||||
import { Message } from "discord-types/general";
|
import { Message } from "discord-types/general";
|
||||||
|
|
||||||
|
@ -26,7 +26,7 @@ interface Diff {
|
||||||
}
|
}
|
||||||
|
|
||||||
const DISCORD_KT_DELAY = 1471228928;
|
const DISCORD_KT_DELAY = 1471228928;
|
||||||
const HiddenVisually = findExportedComponentLazy("HiddenVisually");
|
const HiddenVisually = findComponentByCodeLazy(".hiddenVisually]:");
|
||||||
|
|
||||||
export default definePlugin({
|
export default definePlugin({
|
||||||
name: "MessageLatency",
|
name: "MessageLatency",
|
||||||
|
|
|
@ -534,7 +534,7 @@ export default definePlugin({
|
||||||
|
|
||||||
{
|
{
|
||||||
// Message context base menu
|
// Message context base menu
|
||||||
find: "useMessageMenu:",
|
find: ".MESSAGE,commandTargetId:",
|
||||||
replacement: [
|
replacement: [
|
||||||
{
|
{
|
||||||
// Remove the first section if message is deleted
|
// Remove the first section if message is deleted
|
||||||
|
|
|
@ -16,7 +16,7 @@
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { definePluginSettings } from "@api/Settings";
|
import { definePluginSettings, migratePluginSetting } from "@api/Settings";
|
||||||
import { Devs } from "@utils/constants";
|
import { Devs } from "@utils/constants";
|
||||||
import { runtimeHashMessageKey } from "@utils/intlHash";
|
import { runtimeHashMessageKey } from "@utils/intlHash";
|
||||||
import { Logger } from "@utils/Logger";
|
import { Logger } from "@utils/Logger";
|
||||||
|
@ -27,12 +27,19 @@ import { Message } from "discord-types/general";
|
||||||
|
|
||||||
const RelationshipStore = findByPropsLazy("getRelationships", "isBlocked");
|
const RelationshipStore = findByPropsLazy("getRelationships", "isBlocked");
|
||||||
|
|
||||||
|
interface MessageDeleteProps {
|
||||||
|
// Internal intl message for BLOCKED_MESSAGE_COUNT
|
||||||
|
collapsedReason: () => any;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove this migration once enough time has passed
|
||||||
|
migratePluginSetting("NoBlockedMessages", "ignoreBlockedMessages", "ignoreMessages");
|
||||||
const settings = definePluginSettings({
|
const settings = definePluginSettings({
|
||||||
ignoreBlockedMessages: {
|
ignoreMessages: {
|
||||||
description: "Completely ignores (recent) incoming messages from blocked users (locally).",
|
description: "Completely ignores incoming messages from blocked and ignored (if enabled) users",
|
||||||
type: OptionType.BOOLEAN,
|
type: OptionType.BOOLEAN,
|
||||||
default: false,
|
default: false,
|
||||||
restartNeeded: true,
|
restartNeeded: true
|
||||||
},
|
},
|
||||||
hideRepliesToBlockedMessages: {
|
hideRepliesToBlockedMessages: {
|
||||||
description: "Hides replies to blocked messages.",
|
description: "Hides replies to blocked messages.",
|
||||||
|
@ -40,17 +47,18 @@ const settings = definePluginSettings({
|
||||||
default: false,
|
default: false,
|
||||||
restartNeeded: false,
|
restartNeeded: false,
|
||||||
},
|
},
|
||||||
|
applyToIgnoredUsers: {
|
||||||
|
description: "Additionally apply to 'ignored' users",
|
||||||
|
type: OptionType.BOOLEAN,
|
||||||
|
default: true,
|
||||||
|
restartNeeded: false
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
interface MessageDeleteProps {
|
|
||||||
// Internal intl message for BLOCKED_MESSAGE_COUNT
|
|
||||||
collapsedReason: () => any;
|
|
||||||
}
|
|
||||||
|
|
||||||
export default definePlugin({
|
export default definePlugin({
|
||||||
name: "NoBlockedMessages",
|
name: "NoBlockedMessages",
|
||||||
description: "Hides all blocked messages from chat completely.",
|
description: "Hides all blocked/ignored messages from chat completely",
|
||||||
authors: [Devs.rushii, Devs.Samu, Devs.Elvyra],
|
authors: [Devs.rushii, Devs.Samu, Devs.jamesbt365],
|
||||||
settings,
|
settings,
|
||||||
|
|
||||||
patches: [
|
patches: [
|
||||||
|
@ -68,11 +76,11 @@ export default definePlugin({
|
||||||
'"ReadStateStore"'
|
'"ReadStateStore"'
|
||||||
].map(find => ({
|
].map(find => ({
|
||||||
find,
|
find,
|
||||||
predicate: () => settings.store.ignoreBlockedMessages === true,
|
predicate: () => settings.store.ignoreMessages,
|
||||||
replacement: [
|
replacement: [
|
||||||
{
|
{
|
||||||
match: /(?<=function (\i)\((\i)\){)(?=.*MESSAGE_CREATE:\1)/,
|
match: /(?<=function (\i)\((\i)\){)(?=.*MESSAGE_CREATE:\1)/,
|
||||||
replace: (_, _funcName, props) => `if($self.isBlocked(${props}.message)||$self.isReplyToBlocked(${props}.message))return;`
|
replace: (_, _funcName, props) => `if($self.shouldIgnoreMessage(${props}.message)||$self.isReplyToBlocked(${props}.message))return;`
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
})),
|
})),
|
||||||
|
@ -87,6 +95,33 @@ export default definePlugin({
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
|
||||||
|
shouldIgnoreMessage(message: Message) {
|
||||||
|
try {
|
||||||
|
if (RelationshipStore.isBlocked(message.author.id)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return settings.store.applyToIgnoredUsers && RelationshipStore.isIgnored(message.author.id);
|
||||||
|
} catch (e) {
|
||||||
|
new Logger("NoBlockedMessages").error("Failed to check if user is blocked or ignored:", e);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
shouldHide(props: MessageDeleteProps): boolean {
|
||||||
|
try {
|
||||||
|
const collapsedReason = props.collapsedReason();
|
||||||
|
const blockedReason = i18n.t[runtimeHashMessageKey("BLOCKED_MESSAGE_COUNT")]();
|
||||||
|
const ignoredReason = settings.store.applyToIgnoredUsers
|
||||||
|
? i18n.t[runtimeHashMessageKey("IGNORED_MESSAGE_COUNT")]()
|
||||||
|
: null;
|
||||||
|
|
||||||
|
return collapsedReason === blockedReason || collapsedReason === ignoredReason;
|
||||||
|
} catch (e) {
|
||||||
|
console.error(e);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
isReplyToBlocked(message: Message) {
|
isReplyToBlocked(message: Message) {
|
||||||
if (!settings.store.hideRepliesToBlockedMessages) return false;
|
if (!settings.store.hideRepliesToBlockedMessages) return false;
|
||||||
try {
|
try {
|
||||||
|
@ -99,22 +134,5 @@ export default definePlugin({
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
new Logger("NoBlockedMessages").error("Failed to check if referenced message is blocked:", e);
|
new Logger("NoBlockedMessages").error("Failed to check if referenced message is blocked:", e);
|
||||||
}
|
}
|
||||||
},
|
|
||||||
|
|
||||||
isBlocked(message: Message) {
|
|
||||||
try {
|
|
||||||
return RelationshipStore.isBlocked(message.author.id);
|
|
||||||
} catch (e) {
|
|
||||||
new Logger("NoBlockedMessages").error("Failed to check if user is blocked:", e);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
shouldHide(props: MessageDeleteProps) {
|
|
||||||
try {
|
|
||||||
return props.collapsedReason() === i18n.t[runtimeHashMessageKey("BLOCKED_MESSAGE_COUNT")]();
|
|
||||||
} catch (e) {
|
|
||||||
new Logger("NoBlockedMessages").error("Failed to hide blocked message:", e);
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -100,8 +100,8 @@ export default definePlugin({
|
||||||
replace: "true"
|
replace: "true"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
match: /!\(0,\i\.isDesktop\)\(\)/,
|
match: /(!)?\(0,\i\.isDesktop\)\(\)/,
|
||||||
replace: "false"
|
replace: (_, not) => not ? "false" : "true"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
|
|
@ -46,8 +46,8 @@ export default definePlugin({
|
||||||
find: "#{intl::ONBOARDING_CHANNEL_THRESHOLD_WARNING}",
|
find: "#{intl::ONBOARDING_CHANNEL_THRESHOLD_WARNING}",
|
||||||
replacement: [
|
replacement: [
|
||||||
{
|
{
|
||||||
match: /{(\i:function\(\){return \i},?){2}}/,
|
match: /{(?:\i:(?:function\(\){return |\(\)=>)\i}?,?){2}}/,
|
||||||
replace: m => m.replaceAll(canonicalizeMatch(/return \i/g), "return ()=>Promise.resolve(true)")
|
replace: m => m.replaceAll(canonicalizeMatch(/(function\(\){return |\(\)=>)\i/g), "$1()=>Promise.resolve(true)")
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
predicate: () => settings.store.onboarding
|
predicate: () => settings.store.onboarding
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
|
|
||||||
import { classNameFactory } from "@api/Styles";
|
import { classNameFactory } from "@api/Styles";
|
||||||
import { ModalContent, ModalFooter, ModalHeader, ModalProps, ModalRoot, openModalLazy } from "@utils/modal";
|
import { ModalContent, ModalFooter, ModalHeader, ModalProps, ModalRoot, openModalLazy } from "@utils/modal";
|
||||||
import { extractAndLoadChunksLazy, findComponentByCodeLazy, findExportedComponentLazy } from "@webpack";
|
import { extractAndLoadChunksLazy, findComponentByCodeLazy } from "@webpack";
|
||||||
import { Button, Forms, Text, TextInput, Toasts, useMemo, useState } from "@webpack/common";
|
import { Button, Forms, Text, TextInput, Toasts, useMemo, useState } from "@webpack/common";
|
||||||
|
|
||||||
import { DEFAULT_COLOR, SWATCHES } from "../constants";
|
import { DEFAULT_COLOR, SWATCHES } from "../constants";
|
||||||
|
@ -30,7 +30,7 @@ interface ColorPickerWithSwatchesProps {
|
||||||
}
|
}
|
||||||
|
|
||||||
const ColorPicker = findComponentByCodeLazy<ColorPickerProps>("#{intl::USER_SETTINGS_PROFILE_COLOR_SELECT_COLOR}", ".BACKGROUND_PRIMARY)");
|
const ColorPicker = findComponentByCodeLazy<ColorPickerProps>("#{intl::USER_SETTINGS_PROFILE_COLOR_SELECT_COLOR}", ".BACKGROUND_PRIMARY)");
|
||||||
const ColorPickerWithSwatches = findExportedComponentLazy<ColorPickerWithSwatchesProps>("ColorPicker", "CustomColorPicker");
|
const ColorPickerWithSwatches = findComponentByCodeLazy<ColorPickerWithSwatchesProps>('id:"color-picker"');
|
||||||
|
|
||||||
export const requireSettingsMenu = extractAndLoadChunksLazy(['name:"UserSettings"'], /createPromise:.{0,20}(\i\.\i\("?.+?"?\).*?).then\(\i\.bind\(\i,"?(.+?)"?\)\).{0,50}"UserSettings"/);
|
export const requireSettingsMenu = extractAndLoadChunksLazy(['name:"UserSettings"'], /createPromise:.{0,20}(\i\.\i\("?.+?"?\).*?).then\(\i\.bind\(\i,"?(.+?)"?\)\).{0,50}"UserSettings"/);
|
||||||
|
|
||||||
|
|
|
@ -25,7 +25,7 @@ import { Settings } from "@api/Settings";
|
||||||
import ErrorBoundary from "@components/ErrorBoundary";
|
import ErrorBoundary from "@components/ErrorBoundary";
|
||||||
import { Devs } from "@utils/constants";
|
import { Devs } from "@utils/constants";
|
||||||
import definePlugin, { OptionType } from "@utils/types";
|
import definePlugin, { OptionType } from "@utils/types";
|
||||||
import { findByPropsLazy, findStoreLazy } from "@webpack";
|
import { filters, findStoreLazy, mapMangledModuleLazy } from "@webpack";
|
||||||
import { PresenceStore, Tooltip, UserStore } from "@webpack/common";
|
import { PresenceStore, Tooltip, UserStore } from "@webpack/common";
|
||||||
import { User } from "discord-types/general";
|
import { User } from "discord-types/general";
|
||||||
|
|
||||||
|
@ -71,7 +71,9 @@ const Icons = {
|
||||||
};
|
};
|
||||||
type Platform = keyof typeof Icons;
|
type Platform = keyof typeof Icons;
|
||||||
|
|
||||||
const StatusUtils = findByPropsLazy("useStatusFillColor", "StatusTypes");
|
const { useStatusFillColor } = mapMangledModuleLazy(".concat(.5625*", {
|
||||||
|
useStatusFillColor: filters.byCode(".hex")
|
||||||
|
});
|
||||||
|
|
||||||
const PlatformIcon = ({ platform, status, small }: { platform: Platform, status: string; small: boolean; }) => {
|
const PlatformIcon = ({ platform, status, small }: { platform: Platform, status: string; small: boolean; }) => {
|
||||||
const tooltip = platform === "embedded"
|
const tooltip = platform === "embedded"
|
||||||
|
@ -82,7 +84,7 @@ const PlatformIcon = ({ platform, status, small }: { platform: Platform, status:
|
||||||
Icon = Icons.embeddedvc;
|
Icon = Icons.embeddedvc;
|
||||||
}
|
}
|
||||||
|
|
||||||
return <Icon color={StatusUtils.useStatusFillColor(status)} tooltip={tooltip} small={small} />;
|
return <Icon color={useStatusFillColor(status)} tooltip={tooltip} small={small} />;
|
||||||
};
|
};
|
||||||
|
|
||||||
function ensureOwnStatus(user: User) {
|
function ensureOwnStatus(user: User) {
|
||||||
|
|
|
@ -122,8 +122,10 @@ export default definePlugin({
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
// Prevent Discord from trying to connect to hidden voice channels
|
// Prevent Discord from trying to connect to hidden voice channels
|
||||||
match: /(?=&&\i\.\i\.selectVoiceChannel\((\i)\.id\))/,
|
match: /(?=(\|\||&&)\i\.\i\.selectVoiceChannel\((\i)\.id\))/,
|
||||||
replace: (_, channel) => `&&!$self.isHiddenChannel(${channel})`
|
replace: (_, condition, channel) => condition === "||"
|
||||||
|
? `||$self.isHiddenChannel(${channel})`
|
||||||
|
: `&&!$self.isHiddenChannel(${channel})`
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
// Make Discord show inside the channel if clicking on a hidden or locked channel
|
// Make Discord show inside the channel if clicking on a hidden or locked channel
|
||||||
|
@ -136,8 +138,10 @@ export default definePlugin({
|
||||||
{
|
{
|
||||||
find: ".AUDIENCE),{isSubscriptionGated",
|
find: ".AUDIENCE),{isSubscriptionGated",
|
||||||
replacement: {
|
replacement: {
|
||||||
match: /!(\i)\.isRoleSubscriptionTemplatePreviewChannel\(\)/,
|
match: /(!)?(\i)\.isRoleSubscriptionTemplatePreviewChannel\(\)/,
|
||||||
replace: (m, channel) => `${m}&&!$self.isHiddenChannel(${channel})`
|
replace: (m, not, channel) => not
|
||||||
|
? `${m}&&!$self.isHiddenChannel(${channel})`
|
||||||
|
: `${m}||$self.isHiddenChannel(${channel})`
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -200,14 +204,10 @@ export default definePlugin({
|
||||||
},
|
},
|
||||||
// Make voice channels also appear as muted if they are muted
|
// Make voice channels also appear as muted if they are muted
|
||||||
{
|
{
|
||||||
match: /(?<=\.wrapper:\i\.notInteractive,)(.+?)if\((\i)\)return (\i\.MUTED);/,
|
match: /(?<=\.wrapper:\i\.notInteractive,)(.+?)(if\()?(\i)(?:\)return |\?)(\i\.MUTED)/,
|
||||||
replace: (_, otherClasses, isMuted, mutedClassExpression) => `${isMuted}?${mutedClassExpression}:"",${otherClasses}if(${isMuted})return "";`
|
replace: (_, otherClasses, isIf, isMuted, mutedClassExpression) => isIf
|
||||||
},
|
? `${isMuted}?${mutedClassExpression}:"",${otherClasses}if(${isMuted})return ""`
|
||||||
{
|
: `${isMuted}?${mutedClassExpression}:"",${otherClasses}${isMuted}?""`
|
||||||
// Make muted channels also appear as unread if hide unreads is false and the channel is hidden
|
|
||||||
predicate: () => settings.store.channelStyle === ChannelStyle.MutedUnread || settings.store.channelStyle === ChannelStyle.Unread,
|
|
||||||
match: /\.LOCKED;if\((?<={channel:(\i).+?)/,
|
|
||||||
replace: (m, channel) => `${m}!$self.isHiddenChannel(${channel})&&`
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
@ -215,6 +215,12 @@ export default definePlugin({
|
||||||
find: "UNREAD_IMPORTANT:",
|
find: "UNREAD_IMPORTANT:",
|
||||||
predicate: () => settings.store.channelStyle !== ChannelStyle.Unread && settings.store.channelStyle !== ChannelStyle.MutedUnread,
|
predicate: () => settings.store.channelStyle !== ChannelStyle.Unread && settings.store.channelStyle !== ChannelStyle.MutedUnread,
|
||||||
replacement: [
|
replacement: [
|
||||||
|
{
|
||||||
|
// Make muted channels also appear as unread if hide unreads is false, using the HiddenIconWithMutedStyle and the channel is hidden
|
||||||
|
predicate: () => settings.store.hideUnreads === false && settings.store.showMode === ShowMode.HiddenIconWithMutedStyle,
|
||||||
|
match: /(?<=\.LOCKED(?:;if\(|:))(?<={channel:(\i).+?)/,
|
||||||
|
replace: (_, channel) => `!$self.isHiddenChannel(${channel})&&`
|
||||||
|
},
|
||||||
{
|
{
|
||||||
// Hide unreads
|
// Hide unreads
|
||||||
match: /{channel:(\i),name:\i,.+?unread:(\i).+?;/,
|
match: /{channel:(\i),name:\i,.+?unread:(\i).+?;/,
|
||||||
|
|
|
@ -76,8 +76,8 @@ export default definePlugin({
|
||||||
find: "#{intl::GUILD_COMMUNICATION_DISABLED_ICON_TOOLTIP_BODY}",
|
find: "#{intl::GUILD_COMMUNICATION_DISABLED_ICON_TOOLTIP_BODY}",
|
||||||
replacement: [
|
replacement: [
|
||||||
{
|
{
|
||||||
match: /(\i)\.Tooltip,{(text:.{0,30}#{intl::GUILD_COMMUNICATION_DISABLED_ICON_TOOLTIP_BODY}\))/,
|
match: /\i\.\i,{(text:.{0,30}#{intl::GUILD_COMMUNICATION_DISABLED_ICON_TOOLTIP_BODY}\))/,
|
||||||
replace: "$self.TooltipWrapper,{message:arguments[0].message,$2"
|
replace: "$self.TooltipWrapper,{message:arguments[0].message,$1"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,12 +23,12 @@ import ErrorBoundary from "@components/ErrorBoundary";
|
||||||
import { Devs } from "@utils/constants";
|
import { Devs } from "@utils/constants";
|
||||||
import { getIntlMessage } from "@utils/discord";
|
import { getIntlMessage } from "@utils/discord";
|
||||||
import definePlugin, { OptionType } from "@utils/types";
|
import definePlugin, { OptionType } from "@utils/types";
|
||||||
import { findComponentByCodeLazy, findExportedComponentLazy, findStoreLazy } from "@webpack";
|
import { findComponentByCodeLazy, findStoreLazy } from "@webpack";
|
||||||
import { GuildMemberStore, RelationshipStore, SelectedChannelStore, Tooltip, UserStore, useStateFromStores } from "@webpack/common";
|
import { GuildMemberStore, RelationshipStore, SelectedChannelStore, Tooltip, UserStore, useStateFromStores } from "@webpack/common";
|
||||||
|
|
||||||
import { buildSeveralUsers } from "../typingTweaks";
|
import { buildSeveralUsers } from "../typingTweaks";
|
||||||
|
|
||||||
const ThreeDots = findExportedComponentLazy("Dots", "AnimatedDots");
|
const ThreeDots = findComponentByCodeLazy(".dots,", "dotRadius:");
|
||||||
const UserSummaryItem = findComponentByCodeLazy("defaultRenderUser", "showDefaultAvatarsForNullUsers");
|
const UserSummaryItem = findComponentByCodeLazy("defaultRenderUser", "showDefaultAvatarsForNullUsers");
|
||||||
const TypingStore = findStoreLazy("TypingStore");
|
const TypingStore = findStoreLazy("TypingStore");
|
||||||
const UserGuildSettingsStore = findStoreLazy("UserGuildSettingsStore");
|
const UserGuildSettingsStore = findStoreLazy("UserGuildSettingsStore");
|
||||||
|
|
|
@ -22,7 +22,7 @@ const VoiceStateStore = findStoreLazy("VoiceStateStore");
|
||||||
|
|
||||||
const UserSummaryItem = findComponentByCodeLazy("defaultRenderUser", "showDefaultAvatarsForNullUsers");
|
const UserSummaryItem = findComponentByCodeLazy("defaultRenderUser", "showDefaultAvatarsForNullUsers");
|
||||||
const Avatar = findComponentByCodeLazy(".status)/2):0");
|
const Avatar = findComponentByCodeLazy(".status)/2):0");
|
||||||
const GroupDMAvatars = findComponentByCodeLazy(".AvatarSizeSpecs[", "getAvatarURL");
|
const GroupDMAvatars = findComponentByCodeLazy("frontSrc:", "getAvatarURL");
|
||||||
|
|
||||||
const ActionButtonClasses = findByPropsLazy("actionButton", "highlight");
|
const ActionButtonClasses = findByPropsLazy("actionButton", "highlight");
|
||||||
|
|
||||||
|
|
|
@ -220,16 +220,16 @@ export default definePlugin({
|
||||||
{
|
{
|
||||||
find: ".cursorPointer:null,children",
|
find: ".cursorPointer:null,children",
|
||||||
replacement: {
|
replacement: {
|
||||||
match: /.Avatar,.+?src:(.+?\))(?=[,}])/,
|
match: /(?=,src:(\i.getAvatarURL\(.+?[)]))/,
|
||||||
replace: (m, avatarUrl) => `${m},onClick:()=>$self.openAvatar(${avatarUrl})`
|
replace: (_, avatarUrl) => `,onClick:()=>$self.openAvatar(${avatarUrl})`
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
// User Dms top large icon
|
// User Dms top large icon
|
||||||
{
|
{
|
||||||
find: 'experimentLocation:"empty_messages"',
|
find: 'experimentLocation:"empty_messages"',
|
||||||
replacement: {
|
replacement: {
|
||||||
match: /.Avatar,.+?src:(.+?\))(?=[,}])/,
|
match: /(?<=SIZE_80,)(?=src:(.+?\))[,}])/,
|
||||||
replace: (m, avatarUrl) => `${m},onClick:()=>$self.openAvatar(${avatarUrl})`
|
replace: (_, avatarUrl) => `onClick:()=>$self.openAvatar(${avatarUrl}),`
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
|
@ -16,7 +16,7 @@
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { findByPropsLazy, findModuleId, proxyLazyWebpack, wreq } from "@webpack";
|
import { filters, findModuleId, mapMangledModuleLazy, proxyLazyWebpack, wreq } from "@webpack";
|
||||||
import type { ComponentType, PropsWithChildren, ReactNode, Ref } from "react";
|
import type { ComponentType, PropsWithChildren, ReactNode, Ref } from "react";
|
||||||
|
|
||||||
import { LazyComponent } from "./react";
|
import { LazyComponent } from "./react";
|
||||||
|
@ -49,7 +49,7 @@ export interface ModalOptions {
|
||||||
|
|
||||||
type RenderFunction = (props: ModalProps) => ReactNode | Promise<ReactNode>;
|
type RenderFunction = (props: ModalProps) => ReactNode | Promise<ReactNode>;
|
||||||
|
|
||||||
export const Modals = findByPropsLazy("ModalRoot", "ModalCloseButton") as {
|
interface Modals {
|
||||||
ModalRoot: ComponentType<PropsWithChildren<{
|
ModalRoot: ComponentType<PropsWithChildren<{
|
||||||
transitionState: ModalTransitionState;
|
transitionState: ModalTransitionState;
|
||||||
size?: ModalSize;
|
size?: ModalSize;
|
||||||
|
@ -99,7 +99,21 @@ export const Modals = findByPropsLazy("ModalRoot", "ModalCloseButton") as {
|
||||||
hideOnFullscreen?: boolean;
|
hideOnFullscreen?: boolean;
|
||||||
className?: string;
|
className?: string;
|
||||||
}>;
|
}>;
|
||||||
};
|
}
|
||||||
|
|
||||||
|
const Modals: Modals = mapMangledModuleLazy(':"thin")', {
|
||||||
|
ModalRoot: filters.componentByCode('.MODAL,"aria-labelledby":'),
|
||||||
|
ModalHeader: filters.componentByCode(",id:"),
|
||||||
|
ModalContent: filters.componentByCode(".content,"),
|
||||||
|
ModalFooter: filters.componentByCode(".footer,"),
|
||||||
|
ModalCloseButton: filters.componentByCode(".close]:")
|
||||||
|
});
|
||||||
|
|
||||||
|
export const ModalRoot = LazyComponent(() => Modals.ModalRoot);
|
||||||
|
export const ModalHeader = LazyComponent(() => Modals.ModalHeader);
|
||||||
|
export const ModalContent = LazyComponent(() => Modals.ModalContent);
|
||||||
|
export const ModalFooter = LazyComponent(() => Modals.ModalFooter);
|
||||||
|
export const ModalCloseButton = LazyComponent(() => Modals.ModalCloseButton);
|
||||||
|
|
||||||
export type MediaModalItem = {
|
export type MediaModalItem = {
|
||||||
url: string;
|
url: string;
|
||||||
|
@ -135,38 +149,33 @@ export const openMediaModal: (props: MediaModalProps) => void = proxyLazyWebpack
|
||||||
return Object.values<any>(openMediaModalModule).find(v => String(v).includes("modalKey:"));
|
return Object.values<any>(openMediaModalModule).find(v => String(v).includes("modalKey:"));
|
||||||
});
|
});
|
||||||
|
|
||||||
export const ModalRoot = LazyComponent(() => Modals.ModalRoot);
|
interface ModalAPI {
|
||||||
export const ModalHeader = LazyComponent(() => Modals.ModalHeader);
|
/**
|
||||||
export const ModalContent = LazyComponent(() => Modals.ModalContent);
|
* Wait for the render promise to resolve, then open a modal with it.
|
||||||
export const ModalFooter = LazyComponent(() => Modals.ModalFooter);
|
* This is equivalent to render().then(openModal)
|
||||||
export const ModalCloseButton = LazyComponent(() => Modals.ModalCloseButton);
|
* You should use the Modal components exported by this file
|
||||||
|
*/
|
||||||
|
openModalLazy: (render: () => Promise<RenderFunction>, options?: ModalOptions & { contextKey?: string; }) => Promise<string>;
|
||||||
|
/**
|
||||||
|
* Open a Modal with the given render function.
|
||||||
|
* You should use the Modal components exported by this file
|
||||||
|
*/
|
||||||
|
openModal: (render: RenderFunction, options?: ModalOptions, contextKey?: string) => string;
|
||||||
|
/**
|
||||||
|
* Close a modal by its key
|
||||||
|
*/
|
||||||
|
closeModal: (modalKey: string, contextKey?: string) => void;
|
||||||
|
/**
|
||||||
|
* Close all open modals
|
||||||
|
*/
|
||||||
|
closeAllModals: () => void;
|
||||||
|
}
|
||||||
|
|
||||||
export const ModalAPI = findByPropsLazy("openModalLazy");
|
export const ModalAPI: ModalAPI = mapMangledModuleLazy(".modalKey?", {
|
||||||
|
openModalLazy: filters.byCode(".modalKey?"),
|
||||||
/**
|
openModal: filters.byCode(",instant:"),
|
||||||
* Wait for the render promise to resolve, then open a modal with it.
|
closeModal: filters.byCode(".onCloseCallback()"),
|
||||||
* This is equivalent to render().then(openModal)
|
closeAllModals: filters.byCode(".getState();for")
|
||||||
* You should use the Modal components exported by this file
|
});
|
||||||
*/
|
|
||||||
export const openModalLazy: (render: () => Promise<RenderFunction>, options?: ModalOptions & { contextKey?: string; }) => Promise<string>
|
|
||||||
= proxyLazyWebpack(() => ModalAPI.openModalLazy);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Open a Modal with the given render function.
|
|
||||||
* You should use the Modal components exported by this file
|
|
||||||
*/
|
|
||||||
export const openModal: (render: RenderFunction, options?: ModalOptions, contextKey?: string) => string
|
|
||||||
= proxyLazyWebpack(() => ModalAPI.openModal);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Close a modal by its key
|
|
||||||
*/
|
|
||||||
export const closeModal: (modalKey: string, contextKey?: string) => void
|
|
||||||
= proxyLazyWebpack(() => ModalAPI.closeModal);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Close all open modals
|
|
||||||
*/
|
|
||||||
export const closeAllModals: () => void
|
|
||||||
= proxyLazyWebpack(() => ModalAPI.closeAllModals);
|
|
||||||
|
|
||||||
|
export const { openModalLazy, openModal, closeModal, closeAllModals } = ModalAPI;
|
||||||
|
|
|
@ -16,78 +16,82 @@
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { filters, findByPropsLazy, waitFor } from "@webpack";
|
import { LazyComponent } from "@utils/lazyReact";
|
||||||
|
import { filters, mapMangledModuleLazy, waitFor } from "@webpack";
|
||||||
|
|
||||||
import { waitForComponent } from "./internal";
|
import { waitForComponent } from "./internal";
|
||||||
import * as t from "./types/components";
|
import * as t from "./types/components";
|
||||||
|
|
||||||
export let Forms = {} as {
|
|
||||||
FormTitle: t.FormTitle,
|
const FormTitle = waitForComponent<t.FormTitle>("FormTitle", filters.componentByCode('["defaultMargin".concat', '="h5"'));
|
||||||
FormSection: t.FormSection,
|
const FormText = waitForComponent<t.FormText>("FormText", filters.componentByCode(".SELECTABLE),", ".DISABLED:"));
|
||||||
FormDivider: t.FormDivider,
|
const FormSection = waitForComponent<t.FormSection>("FormSection", filters.componentByCode(".titleId)&&"));
|
||||||
FormText: t.FormText,
|
const FormDivider = waitForComponent<t.FormDivider>("FormDivider", filters.componentByCode(".divider,", ",style:", '"div"', /\.divider,\i\),style:/));
|
||||||
|
|
||||||
|
export const Forms = {
|
||||||
|
FormTitle,
|
||||||
|
FormText,
|
||||||
|
FormSection,
|
||||||
|
FormDivider
|
||||||
};
|
};
|
||||||
|
|
||||||
export let Icons = {} as t.Icons;
|
export const Card = waitForComponent<t.Card>("Card", filters.componentByCode(".editable),", ".outline:"));
|
||||||
|
export const Button = waitForComponent<t.Button>("Button", filters.componentByCode("#{intl::A11Y_LOADING_STARTED}))),!1"));
|
||||||
|
export const Switch = waitForComponent<t.Switch>("Switch", filters.componentByCode(".labelRow,ref:", ".disabledText"));
|
||||||
|
|
||||||
|
const Tooltips = mapMangledModuleLazy(".tooltipTop,bottom:", {
|
||||||
|
Tooltip: filters.componentByCode("this.renderTooltip()]"),
|
||||||
|
TooltipContainer: filters.componentByCode('="div",')
|
||||||
|
}) as {
|
||||||
|
Tooltip: t.Tooltip,
|
||||||
|
TooltipContainer: t.TooltipContainer;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const Tooltip = LazyComponent(() => Tooltips.Tooltip);
|
||||||
|
export const TooltipContainer = LazyComponent(() => Tooltips.TooltipContainer);
|
||||||
|
|
||||||
|
export const TextInput = waitForComponent<t.TextInput>("TextInput", filters.componentByCode(".error]:this.hasError()"));
|
||||||
|
export const TextArea = waitForComponent<t.TextArea>("TextArea", filters.componentByCode("this.getPaddingRight()},id:"));
|
||||||
|
export const Text = waitForComponent<t.Text>("Text", filters.componentByCode('case"always-white"'));
|
||||||
|
export const Heading = waitForComponent<t.Heading>("Heading", filters.componentByCode(">6?{", "variant:"));
|
||||||
|
export const Select = waitForComponent<t.Select>("Select", filters.componentByCode('.selectPositionTop]:"top"===', '"Escape"==='));
|
||||||
|
export const SearchableSelect = waitForComponent<t.SearchableSelect>("SearchableSelect", filters.componentByCode('.selectPositionTop]:"top"===', ".multi]:"));
|
||||||
|
export const Slider = waitForComponent<t.Slider>("Slider", filters.componentByCode('"markDash".concat('));
|
||||||
|
export const Popout = waitForComponent<t.Popout>("Popout", filters.componentByCode("ref:this.ref,preload:"));
|
||||||
|
export const Dialog = waitForComponent<t.Dialog>("Dialog", filters.componentByCode('role:"dialog",tabIndex:-1'));
|
||||||
|
export const TabBar = waitForComponent("TabBar", filters.componentByCode("ref:this.tabBarRef,className:"));
|
||||||
|
export const Paginator = waitForComponent<t.Paginator>("Paginator", filters.componentByCode('rel:"prev",children:'));
|
||||||
|
export const Clickable = waitForComponent<t.Clickable>("Clickable", filters.componentByCode("this.context?this.renderNonInteractive():"));
|
||||||
|
export const Avatar = waitForComponent<t.Avatar>("Avatar", filters.componentByCode(".size-1.375*"));
|
||||||
|
|
||||||
|
export let createScroller: (scrollbarClassName: string, fadeClassName: string, customThemeClassName: string) => t.ScrollerThin;
|
||||||
|
export let scrollerClasses: Record<string, string>;
|
||||||
|
waitFor(filters.byCode('="ltr",orientation:', "customTheme:", "forwardRef"), m => createScroller = m);
|
||||||
|
waitFor(["thin", "auto", "customTheme"], m => scrollerClasses = m);
|
||||||
|
|
||||||
|
export const ScrollerNone = LazyComponent(() => createScroller(scrollerClasses.none, scrollerClasses.fade, scrollerClasses.customTheme));
|
||||||
|
export const ScrollerThin = LazyComponent(() => createScroller(scrollerClasses.thin, scrollerClasses.fade, scrollerClasses.customTheme));
|
||||||
|
export const ScrollerAuto = LazyComponent(() => createScroller(scrollerClasses.auto, scrollerClasses.fade, scrollerClasses.customTheme));
|
||||||
|
|
||||||
|
const { FocusLock_ } = mapMangledModuleLazy("attachTo:null!==", {
|
||||||
|
FocusLock_: filters.componentByCode(".containerRef")
|
||||||
|
}) as {
|
||||||
|
FocusLock_: t.FocusLock;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const FocusLock = LazyComponent(() => FocusLock_);
|
||||||
|
|
||||||
export let Card: t.Card;
|
|
||||||
export let Button: t.Button;
|
|
||||||
export let Switch: t.Switch;
|
|
||||||
export let Tooltip: t.Tooltip;
|
|
||||||
export let TooltipContainer: t.TooltipContainer;
|
|
||||||
export let TextInput: t.TextInput;
|
|
||||||
export let TextArea: t.TextArea;
|
|
||||||
export let Text: t.Text;
|
|
||||||
export let Heading: t.Heading;
|
|
||||||
export let Select: t.Select;
|
|
||||||
export let SearchableSelect: t.SearchableSelect;
|
|
||||||
export let Slider: t.Slider;
|
|
||||||
export let ButtonLooks: t.ButtonLooks;
|
|
||||||
export let Popout: t.Popout;
|
|
||||||
export let Dialog: t.Dialog;
|
|
||||||
export let TabBar: any;
|
|
||||||
export let Paginator: t.Paginator;
|
|
||||||
export let ScrollerThin: t.ScrollerThin;
|
|
||||||
export let Clickable: t.Clickable;
|
|
||||||
export let Avatar: t.Avatar;
|
|
||||||
export let Dots: t.Dots;
|
|
||||||
export let FocusLock: t.FocusLock;
|
|
||||||
// token lagger real
|
|
||||||
/** css colour resolver stuff, no clue what exactly this does, just copied usage from Discord */
|
|
||||||
export let useToken: t.useToken;
|
export let useToken: t.useToken;
|
||||||
|
waitFor(m => {
|
||||||
|
if (typeof m !== "function") {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const str = String(m);
|
||||||
|
return str.includes(".resolve({theme:null") && !str.includes("useMemo");
|
||||||
|
}, m => useToken = m);
|
||||||
|
|
||||||
export const MaskedLink = waitForComponent<t.MaskedLink>("MaskedLink", filters.componentByCode("MASKED_LINK)"));
|
export const MaskedLink = waitForComponent<t.MaskedLink>("MaskedLink", filters.componentByCode("MASKED_LINK)"));
|
||||||
export const Timestamp = waitForComponent<t.Timestamp>("Timestamp", filters.byCode("#{intl::MESSAGE_EDITED_TIMESTAMP_A11Y_LABEL}"));
|
export const Timestamp = waitForComponent<t.Timestamp>("Timestamp", filters.componentByCode("#{intl::MESSAGE_EDITED_TIMESTAMP_A11Y_LABEL}"));
|
||||||
export const Flex = waitForComponent<t.Flex>("Flex", ["Justify", "Align", "Wrap"]);
|
export const Flex = waitForComponent<t.Flex>("Flex", ["Justify", "Align", "Wrap"]);
|
||||||
|
export const OAuth2AuthorizeModal = waitForComponent("OAuth2AuthorizeModal", filters.componentByCode(".authorize),children:", ".contentBackground"));
|
||||||
export const { OAuth2AuthorizeModal } = findByPropsLazy("OAuth2AuthorizeModal");
|
|
||||||
|
|
||||||
waitFor(["FormItem", "Button"], m => {
|
|
||||||
({
|
|
||||||
useToken,
|
|
||||||
Card,
|
|
||||||
Button,
|
|
||||||
FormSwitch: Switch,
|
|
||||||
Tooltip,
|
|
||||||
TooltipContainer,
|
|
||||||
TextInput,
|
|
||||||
TextArea,
|
|
||||||
Text,
|
|
||||||
Select,
|
|
||||||
SearchableSelect,
|
|
||||||
Slider,
|
|
||||||
ButtonLooks,
|
|
||||||
TabBar,
|
|
||||||
Popout,
|
|
||||||
Dialog,
|
|
||||||
Paginator,
|
|
||||||
ScrollerThin,
|
|
||||||
Clickable,
|
|
||||||
Avatar,
|
|
||||||
FocusLock,
|
|
||||||
Heading,
|
|
||||||
Dots
|
|
||||||
} = m);
|
|
||||||
Forms = m;
|
|
||||||
Icons = m;
|
|
||||||
});
|
|
||||||
|
|
|
@ -16,17 +16,29 @@
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { filters, mapMangledModuleLazy, waitFor } from "@webpack";
|
// eslint-disable-next-line path-alias/no-relative
|
||||||
|
import { filters, mapMangledModuleLazy, waitFor, wreq } from "../webpack";
|
||||||
import type * as t from "./types/menu";
|
import type * as t from "./types/menu";
|
||||||
|
|
||||||
export let Menu = {} as t.Menu;
|
export const Menu = {} as t.Menu;
|
||||||
|
|
||||||
waitFor(["MenuItem", "MenuSliderControl"], m => Menu = m);
|
// Relies on .name properties added by the MenuItemDemanglerAPI
|
||||||
|
waitFor(m => m.name === "MenuCheckboxItem", (_, id) => {
|
||||||
|
// we have to do this manual require by ID because m is in this case the MenuCheckBoxItem instead of the entire module
|
||||||
|
const module = wreq(id as any);
|
||||||
|
|
||||||
|
for (const e of Object.values(module)) {
|
||||||
|
if (typeof e === "function" && e.name.startsWith("Menu")) {
|
||||||
|
Menu[e.name] = e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
waitFor(filters.componentByCode('path:["empty"]'), m => Menu.Menu = m);
|
||||||
|
waitFor(filters.componentByCode("sliderContainer", "slider", "handleSize:16", "=100"), m => Menu.MenuSliderControl = m);
|
||||||
|
|
||||||
export const ContextMenuApi: t.ContextMenuApi = mapMangledModuleLazy('type:"CONTEXT_MENU_OPEN', {
|
export const ContextMenuApi: t.ContextMenuApi = mapMangledModuleLazy('type:"CONTEXT_MENU_OPEN', {
|
||||||
closeContextMenu: filters.byCode("CONTEXT_MENU_CLOSE"),
|
closeContextMenu: filters.byCode("CONTEXT_MENU_CLOSE"),
|
||||||
openContextMenu: filters.byCode("renderLazy:"),
|
openContextMenu: filters.byCode("renderLazy:"),
|
||||||
openContextMenuLazy: e => typeof e === "function" && e.toString().length < 100
|
openContextMenuLazy: e => typeof e === "function" && e.toString().length < 100
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
3
src/webpack/common/types/components.d.ts
vendored
3
src/webpack/common/types/components.d.ts
vendored
|
@ -18,14 +18,12 @@
|
||||||
|
|
||||||
import type { ComponentPropsWithRef, ComponentType, CSSProperties, FunctionComponent, HtmlHTMLAttributes, HTMLProps, JSX, KeyboardEvent, MouseEvent, PropsWithChildren, PropsWithRef, ReactNode, Ref } from "react";
|
import type { ComponentPropsWithRef, ComponentType, CSSProperties, FunctionComponent, HtmlHTMLAttributes, HTMLProps, JSX, KeyboardEvent, MouseEvent, PropsWithChildren, PropsWithRef, ReactNode, Ref } from "react";
|
||||||
|
|
||||||
import { IconNames } from "./iconNames";
|
|
||||||
|
|
||||||
export type TextVariant = "heading-sm/normal" | "heading-sm/medium" | "heading-sm/semibold" | "heading-sm/bold" | "heading-md/normal" | "heading-md/medium" | "heading-md/semibold" | "heading-md/bold" | "heading-lg/normal" | "heading-lg/medium" | "heading-lg/semibold" | "heading-lg/bold" | "heading-xl/normal" | "heading-xl/medium" | "heading-xl/bold" | "heading-xxl/normal" | "heading-xxl/medium" | "heading-xxl/bold" | "eyebrow" | "heading-deprecated-14/normal" | "heading-deprecated-14/medium" | "heading-deprecated-14/bold" | "text-xxs/normal" | "text-xxs/medium" | "text-xxs/semibold" | "text-xxs/bold" | "text-xs/normal" | "text-xs/medium" | "text-xs/semibold" | "text-xs/bold" | "text-sm/normal" | "text-sm/medium" | "text-sm/semibold" | "text-sm/bold" | "text-md/normal" | "text-md/medium" | "text-md/semibold" | "text-md/bold" | "text-lg/normal" | "text-lg/medium" | "text-lg/semibold" | "text-lg/bold" | "display-sm" | "display-md" | "display-lg" | "code";
|
export type TextVariant = "heading-sm/normal" | "heading-sm/medium" | "heading-sm/semibold" | "heading-sm/bold" | "heading-md/normal" | "heading-md/medium" | "heading-md/semibold" | "heading-md/bold" | "heading-lg/normal" | "heading-lg/medium" | "heading-lg/semibold" | "heading-lg/bold" | "heading-xl/normal" | "heading-xl/medium" | "heading-xl/bold" | "heading-xxl/normal" | "heading-xxl/medium" | "heading-xxl/bold" | "eyebrow" | "heading-deprecated-14/normal" | "heading-deprecated-14/medium" | "heading-deprecated-14/bold" | "text-xxs/normal" | "text-xxs/medium" | "text-xxs/semibold" | "text-xxs/bold" | "text-xs/normal" | "text-xs/medium" | "text-xs/semibold" | "text-xs/bold" | "text-sm/normal" | "text-sm/medium" | "text-sm/semibold" | "text-sm/bold" | "text-md/normal" | "text-md/medium" | "text-md/semibold" | "text-md/bold" | "text-lg/normal" | "text-lg/medium" | "text-lg/semibold" | "text-lg/bold" | "display-sm" | "display-md" | "display-lg" | "code";
|
||||||
export type FormTextTypes = Record<"DEFAULT" | "INPUT_PLACEHOLDER" | "DESCRIPTION" | "LABEL_BOLD" | "LABEL_SELECTED" | "LABEL_DESCRIPTOR" | "ERROR" | "SUCCESS", string>;
|
export type FormTextTypes = Record<"DEFAULT" | "INPUT_PLACEHOLDER" | "DESCRIPTION" | "LABEL_BOLD" | "LABEL_SELECTED" | "LABEL_DESCRIPTOR" | "ERROR" | "SUCCESS", string>;
|
||||||
export type HeadingTag = `h${1 | 2 | 3 | 4 | 5 | 6}`;
|
export type HeadingTag = `h${1 | 2 | 3 | 4 | 5 | 6}`;
|
||||||
|
|
||||||
export type Margins = Record<"marginTop16" | "marginTop8" | "marginBottom8" | "marginTop20" | "marginBottom20", string>;
|
export type Margins = Record<"marginTop16" | "marginTop8" | "marginBottom8" | "marginTop20" | "marginBottom20", string>;
|
||||||
export type ButtonLooks = Record<"FILLED" | "INVERTED" | "OUTLINED" | "LINK" | "BLANK", string>;
|
|
||||||
|
|
||||||
export type TextProps = PropsWithChildren<HtmlHTMLAttributes<HTMLDivElement> & {
|
export type TextProps = PropsWithChildren<HtmlHTMLAttributes<HTMLDivElement> & {
|
||||||
variant?: TextVariant;
|
variant?: TextVariant;
|
||||||
|
@ -511,4 +509,3 @@ export type Icon = ComponentType<JSX.IntrinsicElements["svg"] & {
|
||||||
colorClass?: string;
|
colorClass?: string;
|
||||||
} & Record<string, any>>;
|
} & Record<string, any>>;
|
||||||
|
|
||||||
export type Icons = Record<IconNames, Icon>;
|
|
||||||
|
|
14
src/webpack/common/types/iconNames.d.ts
vendored
14
src/webpack/common/types/iconNames.d.ts
vendored
File diff suppressed because one or more lines are too long
|
@ -173,26 +173,36 @@ function patchFactories(factories: Record<string, (module: any, exports: any, re
|
||||||
|
|
||||||
if (!exports) return;
|
if (!exports) return;
|
||||||
|
|
||||||
// There are (at the time of writing) 11 modules exporting the window
|
|
||||||
// Make these non enumerable to improve webpack search performance
|
|
||||||
if (require.c) {
|
if (require.c) {
|
||||||
let foundWindow = false;
|
let shouldMakeNonEnumerable = false;
|
||||||
|
|
||||||
if (exports === window) {
|
nonEnumerableChecking: {
|
||||||
foundWindow = true;
|
// There are (at the time of writing) 11 modules exporting the window,
|
||||||
} else if (typeof exports === "object") {
|
// and also modules exporting DOMTokenList, which breaks webpack finding
|
||||||
if (exports?.default === window) {
|
// Make these non enumerable to improve search performance and avoid erros
|
||||||
foundWindow = true;
|
if (exports === window || exports[Symbol.toStringTag] === "DOMTokenList") {
|
||||||
} else {
|
shouldMakeNonEnumerable = true;
|
||||||
for (const nested in exports) if (nested.length <= 3) {
|
break nonEnumerableChecking;
|
||||||
if (exports[nested] === window) {
|
}
|
||||||
foundWindow = true;
|
|
||||||
}
|
if (typeof exports !== "object") {
|
||||||
|
break nonEnumerableChecking;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (exports.default === window || exports.default?.[Symbol.toStringTag] === "DOMTokenList") {
|
||||||
|
shouldMakeNonEnumerable = true;
|
||||||
|
break nonEnumerableChecking;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const nested in exports) {
|
||||||
|
if (exports[nested] === window || exports[nested]?.[Symbol.toStringTag] === "DOMTokenList") {
|
||||||
|
shouldMakeNonEnumerable = true;
|
||||||
|
break nonEnumerableChecking;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (foundWindow) {
|
if (shouldMakeNonEnumerable) {
|
||||||
Object.defineProperty(require.c, id, {
|
Object.defineProperty(require.c, id, {
|
||||||
value: require.c[id],
|
value: require.c[id],
|
||||||
enumerable: false,
|
enumerable: false,
|
||||||
|
@ -222,7 +232,7 @@ function patchFactories(factories: Record<string, (module: any, exports: any, re
|
||||||
subscriptions.delete(filter);
|
subscriptions.delete(filter);
|
||||||
callback(exports.default, id);
|
callback(exports.default, id);
|
||||||
} else {
|
} else {
|
||||||
for (const nested in exports) if (nested.length <= 3) {
|
for (const nested in exports) {
|
||||||
if (exports[nested] && filter(exports[nested])) {
|
if (exports[nested] && filter(exports[nested])) {
|
||||||
subscriptions.delete(filter);
|
subscriptions.delete(filter);
|
||||||
callback(exports[nested], id);
|
callback(exports[nested], id);
|
||||||
|
|
|
@ -56,11 +56,14 @@ export const filters = {
|
||||||
: m => props.every(p => m[p] !== void 0),
|
: m => props.every(p => m[p] !== void 0),
|
||||||
|
|
||||||
byCode: (...code: CodeFilter): FilterFn => {
|
byCode: (...code: CodeFilter): FilterFn => {
|
||||||
code = code.map(canonicalizeMatch);
|
const parsedCode = code.map(canonicalizeMatch);
|
||||||
return m => {
|
const filter = m => {
|
||||||
if (typeof m !== "function") return false;
|
if (typeof m !== "function") return false;
|
||||||
return stringMatches(Function.prototype.toString.call(m), code);
|
return stringMatches(Function.prototype.toString.call(m), parsedCode);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
filter.$$vencordProps = [...code];
|
||||||
|
return filter;
|
||||||
},
|
},
|
||||||
byStoreName: (name: StoreNameFilter): FilterFn => m =>
|
byStoreName: (name: StoreNameFilter): FilterFn => m =>
|
||||||
m.constructor?.displayName === name,
|
m.constructor?.displayName === name,
|
||||||
|
@ -131,8 +134,7 @@ export const find = traceFunction("find", function find(filter: FilterFn, { isIn
|
||||||
return isWaitFor ? [found, key] : found;
|
return isWaitFor ? [found, key] : found;
|
||||||
}
|
}
|
||||||
|
|
||||||
// the length check makes search about 20% faster
|
for (const nestedMod in mod.exports) {
|
||||||
for (const nestedMod in mod.exports) if (nestedMod.length <= 3) {
|
|
||||||
const nested = mod.exports[nestedMod];
|
const nested = mod.exports[nestedMod];
|
||||||
if (nested && filter(nested)) {
|
if (nested && filter(nested)) {
|
||||||
return isWaitFor ? [nested, key] : nested;
|
return isWaitFor ? [nested, key] : nested;
|
||||||
|
@ -163,7 +165,7 @@ export function findAll(filter: FilterFn) {
|
||||||
|
|
||||||
if (mod.exports.default && filter(mod.exports.default))
|
if (mod.exports.default && filter(mod.exports.default))
|
||||||
ret.push(mod.exports.default);
|
ret.push(mod.exports.default);
|
||||||
else for (const nestedMod in mod.exports) if (nestedMod.length <= 3) {
|
else for (const nestedMod in mod.exports) {
|
||||||
const nested = mod.exports[nestedMod];
|
const nested = mod.exports[nestedMod];
|
||||||
if (nested && filter(nested)) ret.push(nested);
|
if (nested && filter(nested)) ret.push(nested);
|
||||||
}
|
}
|
||||||
|
@ -226,16 +228,15 @@ export const findBulk = traceFunction("findBulk", function findBulk(...filterFns
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const nestedMod in mod.exports)
|
for (const nestedMod in mod.exports) {
|
||||||
if (nestedMod.length <= 3) {
|
const nested = mod.exports[nestedMod];
|
||||||
const nested = mod.exports[nestedMod];
|
if (nested && filter(nested)) {
|
||||||
if (nested && filter(nested)) {
|
results[j] = nested;
|
||||||
results[j] = nested;
|
filters[j] = undefined;
|
||||||
filters[j] = undefined;
|
if (++found === length) break outer;
|
||||||
if (++found === length) break outer;
|
continue outer;
|
||||||
continue outer;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue