diff --git a/package.json b/package.json index f251aeda7..32c3a3298 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "vencord", "private": "true", - "version": "1.11.5", + "version": "1.11.6", "description": "The cutest Discord client mod", "homepage": "https://github.com/Vendicated/Vencord#readme", "bugs": { diff --git a/src/plugins/_api/badges/index.tsx b/src/plugins/_api/badges/index.tsx index 9e94c6643..d22fb72d4 100644 --- a/src/plugins/_api/badges/index.tsx +++ b/src/plugins/_api/badges/index.tsx @@ -65,12 +65,12 @@ export default definePlugin({ { find: ".FULL_SIZE]:26", replacement: { - match: /(?<=(\i)=\(0,\i\.\i\)\(\i\);)return 0===\i.length\?/, - replace: "$1.unshift(...$self.getBadges(arguments[0].displayProfile));$&" + match: /(?=;return 0===(\i)\.length\?)(?<=(\i)\.useMemo.+?)/, + replace: ";$1=$2.useMemo(()=>[...$self.getBadges(arguments[0].displayProfile),...$1],[$1])" } }, { - find: ".description,delay:", + find: "#{intl::PROFILE_USER_BADGES}", replacement: [ { match: /(alt:" ","aria-hidden":!0,src:)(.{0,20}(\i)\.icon\))/, diff --git a/src/plugins/_api/chatButtons.ts b/src/plugins/_api/chatButtons.ts index 184b01584..d4e1ea8b0 100644 --- a/src/plugins/_api/chatButtons.ts +++ b/src/plugins/_api/chatButtons.ts @@ -17,7 +17,7 @@ export default definePlugin({ find: '"sticker")', replacement: { // FIXME(Bundler change related): Remove old compatiblity once enough time has passed - match: /return\((!)?\i\.\i(?:\|\||&&)(?=\(\i\.isDM.+?(\i)\.push)/, + match: /return\((!)?\i\.\i(?:\|\||&&)(?=\(.+?(\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)||` diff --git a/src/plugins/_api/dynamicImageModalApi.ts b/src/plugins/_api/dynamicImageModalApi.ts index 4d74cff24..759ef001b 100644 --- a/src/plugins/_api/dynamicImageModalApi.ts +++ b/src/plugins/_api/dynamicImageModalApi.ts @@ -14,11 +14,18 @@ export default definePlugin({ description: "Allows you to omit either width or height when opening an image modal", patches: [ { - find: "SCALE_DOWN:", + find: ".contain,SCALE_DOWN:", replacement: { match: /(?<="IMAGE"===\i\?)\i(?=\?)/, replace: "true" } + }, + { + find: ".dimensionlessImage,", + replacement: { + match: /(?<="IMAGE"===\i&&\(\i=)\i(?=\?)/, + replace: "true" + } } ] }); diff --git a/src/plugins/accountPanelServerProfile/index.tsx b/src/plugins/accountPanelServerProfile/index.tsx index c347cc982..d9fc9de16 100644 --- a/src/plugins/accountPanelServerProfile/index.tsx +++ b/src/plugins/accountPanelServerProfile/index.tsx @@ -73,7 +73,7 @@ export default definePlugin({ group: true, replacement: [ { - match: /(?<=\.AVATAR_SIZE\);)/, + match: /(?<=\.AVATAR_SIZE\).{0,100};)(?=return)/, replace: "$self.useAccountPanelRef();" }, { diff --git a/src/plugins/consoleJanitor/index.ts b/src/plugins/consoleJanitor/index.tsx similarity index 68% rename from src/plugins/consoleJanitor/index.ts rename to src/plugins/consoleJanitor/index.tsx index 34f5653c4..5a3b3cd1e 100644 --- a/src/plugins/consoleJanitor/index.ts +++ b/src/plugins/consoleJanitor/index.tsx @@ -5,8 +5,11 @@ */ import { definePluginSettings } from "@api/Settings"; +import { ErrorBoundary, Flex } from "@components/index"; import { Devs } from "@utils/constants"; -import definePlugin, { OptionType, StartAt } from "@utils/types"; +import { Margins } from "@utils/margins"; +import definePlugin, { defineDefault, OptionType, StartAt } from "@utils/types"; +import { Checkbox, Forms, Text } from "@webpack/common"; const Noop = () => { }; const NoopLogger = { @@ -24,6 +27,48 @@ const NoopLogger = { const logAllow = new Set(); +interface AllowLevels { + error: boolean; + warn: boolean; + trace: boolean; + log: boolean; + info: boolean; + debug: boolean; +} + +interface AllowLevelSettingProps { + settingKey: keyof AllowLevels; +} + +function AllowLevelSetting({ settingKey }: AllowLevelSettingProps) { + const { allowLevel } = settings.use(["allowLevel"]); + const value = allowLevel[settingKey]; + + return ( + settings.store.allowLevel[settingKey] = newValue} + size={20} + > + {settingKey[0].toUpperCase() + settingKey.slice(1)} + + ); +} + +const AllowLevelSettings = ErrorBoundary.wrap(() => { + return ( + + Filter List + Always allow loggers of these types + + {Object.keys(settings.store.allowLevel).map(key => ( + + ))} + + + ); +}); + const settings = definePluginSettings({ disableLoggers: { type: OptionType.BOOLEAN, @@ -45,6 +90,18 @@ const settings = definePluginSettings({ logAllow.clear(); newVal.split(";").map(x => x.trim()).forEach(logAllow.add.bind(logAllow)); } + }, + allowLevel: { + type: OptionType.COMPONENT, + component: AllowLevelSettings, + default: defineDefault({ + error: true, + warn: false, + trace: false, + log: false, + info: false, + debug: false + }) } }); @@ -61,8 +118,9 @@ export default definePlugin({ }, NoopLogger: () => NoopLogger, - shouldLog(logger: string) { - return logAllow.has(logger); + + shouldLog(logger: string, level: keyof AllowLevels) { + return logAllow.has(logger) || settings.store.allowLevel[level] === true; }, patches: [ @@ -136,13 +194,13 @@ export default definePlugin({ replace: "" } }, - // Patches discords generic logger function + // Patches Discord generic logger function { find: "Σ:", predicate: () => settings.store.disableLoggers, replacement: { match: /(?<=&&)(?=console)/, - replace: "$self.shouldLog(arguments[0])&&" + replace: "$self.shouldLog(arguments[0],arguments[1])&&" } }, { diff --git a/src/plugins/emoteCloner/index.tsx b/src/plugins/emoteCloner/index.tsx index 98bd46427..ffc2307e6 100644 --- a/src/plugins/emoteCloner/index.tsx +++ b/src/plugins/emoteCloner/index.tsx @@ -25,11 +25,14 @@ import { ModalContent, ModalHeader, ModalRoot, openModalLazy } from "@utils/moda import definePlugin from "@utils/types"; import { findByCodeLazy, findStoreLazy } from "@webpack"; import { Constants, EmojiStore, FluxDispatcher, Forms, GuildStore, Menu, PermissionsBits, PermissionStore, React, RestAPI, Toasts, Tooltip, UserStore } from "@webpack/common"; +import { Guild } from "discord-types/general"; import { Promisable } from "type-fest"; const StickersStore = findStoreLazy("StickersStore"); const uploadEmoji = findByCodeLazy(".GUILD_EMOJIS(", "EMOJI_UPLOAD_START"); +const getGuildMaxEmojiSlots = findByCodeLazy(".additionalEmojiSlots") as (guild: Guild) => number; + interface Sticker { t: "Sticker"; description: string; @@ -125,7 +128,7 @@ function getGuildCandidates(data: Data) { const { isAnimated } = data as Emoji; - const emojiSlots = g.getMaxEmojiSlots(); + const emojiSlots = getGuildMaxEmojiSlots(g); const { emojis } = EmojiStore.getGuilds()[g.id]; let count = 0; diff --git a/src/plugins/gameActivityToggle/index.tsx b/src/plugins/gameActivityToggle/index.tsx index 37d0ca4cd..c13014110 100644 --- a/src/plugins/gameActivityToggle/index.tsx +++ b/src/plugins/gameActivityToggle/index.tsx @@ -95,7 +95,7 @@ export default definePlugin({ { find: "#{intl::ACCOUNT_SPEAKING_WHILE_MUTED}", replacement: { - match: /this\.renderNameZone\(\).+?children:\[/, + match: /className:\i\.buttons,.{0,50}children:\[/, replace: "$&$self.GameActivityToggleButton()," } } diff --git a/src/plugins/imageZoom/index.tsx b/src/plugins/imageZoom/index.tsx index 934a5c775..1a17b6168 100644 --- a/src/plugins/imageZoom/index.tsx +++ b/src/plugins/imageZoom/index.tsx @@ -165,8 +165,35 @@ export default definePlugin({ { find: ".contain,SCALE_DOWN:", replacement: { - match: /\.slide,\i\),/g, - replace: `$&id:"${ELEMENT_ID}",` + match: /imageClassName:/, + replace: `id:"${ELEMENT_ID}",$&` + } + }, + + { + find: ".dimensionlessImage,", + replacement: [ + { + match: /className:\i\.media,/, + replace: `id:"${ELEMENT_ID}",$&` + }, + { + // This patch needs to be above the next one as it uses the zoomed class as an anchor + match: /\.zoomed]:.+?,(?=children:)/, + replace: "$&onClick:()=>{}," + }, + { + match: /className:\i\(\)\(\i\.wrapper,.+?}\),/, + replace: "" + }, + ] + }, + // Make media viewer options not hide when zoomed in with the default Discord feature + { + find: '="FOCUS_SENSITIVE",', + replacement: { + match: /(?<=\.hidden]:)\i/, + replace: "false" } }, diff --git a/src/plugins/shikiCodeblocks.desktop/shiki.css b/src/plugins/shikiCodeblocks.desktop/shiki.css index 32bf1c2e9..9d3a52c6f 100644 --- a/src/plugins/shikiCodeblocks.desktop/shiki.css +++ b/src/plugins/shikiCodeblocks.desktop/shiki.css @@ -96,6 +96,6 @@ .vc-shiki-root .vc-shiki-table-cell:last-child { padding-left: 8px; - overflow-wrap: break-word; + overflow-wrap: anywhere; width: 100%; } diff --git a/src/plugins/showMeYourName/index.tsx b/src/plugins/showMeYourName/index.tsx index bbafb58d3..bb22ee793 100644 --- a/src/plugins/showMeYourName/index.tsx +++ b/src/plugins/showMeYourName/index.tsx @@ -50,8 +50,8 @@ export default definePlugin({ { find: '?"@":""', replacement: { - match: /(?<=onContextMenu:\i,children:).*?\)}/, - replace: "$self.renderUsername(arguments[0])}" + match: /(?<=children:)\(\i\?"@":""\)\+\i(?=,|\})/, + replace: "$self.renderUsername(arguments[0])" } }, ], diff --git a/src/utils/types.ts b/src/utils/types.ts index 6a791c86e..3ad63ea1a 100644 --- a/src/utils/types.ts +++ b/src/utils/types.ts @@ -26,7 +26,7 @@ import { MessageDecorationFactory } from "@api/MessageDecorations"; import { MessageClickListener, MessageEditListener, MessageSendListener } from "@api/MessageEvents"; import { MessagePopoverButtonFactory } from "@api/MessagePopover"; import { FluxEvents } from "@webpack/types"; -import { JSX } from "react"; +import { ReactNode } from "react"; import { Promisable } from "type-fest"; // exists to export default definePlugin({...}) @@ -202,6 +202,10 @@ export const enum ReporterTestable { FluxEvents = 1 << 4 } +export function defineDefault(value: T) { + return value; +} + export const enum OptionType { STRING, NUMBER, @@ -334,7 +338,8 @@ export interface IPluginOptionComponentProps { export interface PluginSettingComponentDef { type: OptionType.COMPONENT; - component: (props: IPluginOptionComponentProps) => JSX.Element; + component: (props: IPluginOptionComponentProps) => ReactNode | Promise; + default?: any; } /** Maps a `PluginSettingDef` to its value type */ diff --git a/src/webpack/common/components.ts b/src/webpack/common/components.ts index 2681d51d3..d5249f2fa 100644 --- a/src/webpack/common/components.ts +++ b/src/webpack/common/components.ts @@ -38,6 +38,7 @@ export const Forms = { export const Card = waitForComponent("Card", filters.componentByCode(".editable),", ".outline:")); export const Button = waitForComponent("Button", filters.componentByCode("#{intl::A11Y_LOADING_STARTED}))),!1")); export const Switch = waitForComponent("Switch", filters.componentByCode(".labelRow,ref:", ".disabledText")); +export const Checkbox = waitForComponent("Checkbox", filters.componentByCode(".checkboxWrapperDisabled:")); const Tooltips = mapMangledModuleLazy(".tooltipTop,bottom:", { Tooltip: filters.componentByCode("this.renderTooltip()]"), @@ -94,7 +95,7 @@ waitFor(m => { export const MaskedLink = waitForComponent("MaskedLink", filters.componentByCode("MASKED_LINK)")); export const Timestamp = waitForComponent("Timestamp", filters.componentByCode("#{intl::MESSAGE_EDITED_TIMESTAMP_A11Y_LABEL}")); export const Flex = waitForComponent("Flex", ["Justify", "Align", "Wrap"]); -export const OAuth2AuthorizeModal = waitForComponent("OAuth2AuthorizeModal", filters.componentByCode(".authorize),children:", ".contentBackground")); +export const OAuth2AuthorizeModal = waitForComponent("OAuth2AuthorizeModal", filters.componentByCode(".authorize,children:", ".contentBackground")); export const Animations = mapMangledModuleLazy(".assign({colorNames:", { Transition: filters.componentByCode('["items","children"]', ",null,"), diff --git a/src/webpack/common/types/components.d.ts b/src/webpack/common/types/components.d.ts index 469cd4289..9f1bb3aaa 100644 --- a/src/webpack/common/types/components.d.ts +++ b/src/webpack/common/types/components.d.ts @@ -16,7 +16,7 @@ * along with this program. If not, see . */ -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, PointerEvent, PropsWithChildren, PropsWithRef, ReactNode, Ref } from "react"; 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"; @@ -197,6 +197,36 @@ export type Switch = ComponentType>; +export type CheckboxAligns = { + CENTER: "center"; + TOP: "top"; +}; + +export type CheckboxTypes = { + DEFAULT: "default"; + INVERTED: "inverted"; + GHOST: "ghost"; + ROW: "row"; +}; + +export type Checkbox = ComponentType> & { + Shapes: Record<"BOX" | "ROUND" | "SMALL_BOX", string>; + Aligns: CheckboxAligns; + Types: CheckboxTypes; +}; + export type Timestamp = ComponentType void }; -export const ApplicationAssetUtils = findByPropsLazy("fetchAssetIds", "getAssetImage") as { - fetchAssetIds: (applicationId: string, e: string[]) => Promise; -}; +export const ApplicationAssetUtils = mapMangledModuleLazy("getAssetImage: size must === [", { + fetchAssetIds: filters.byCode('.startsWith("http:")', ".dispatch({"), + getAssetFromImageURL: filters.byCode("].serialize(", ',":"'), + getAssetImage: filters.byCode("getAssetImage: size must === ["), + getAssets: filters.byCode(".assets") +}); export const Clipboard: t.Clipboard = mapMangledModuleLazy('queryCommandEnabled("copy")', { copy: filters.byCode(".copy("),