fix everything (#3925)

Co-authored-by: prism <69634294+imjustprism@users.noreply.github.com>
Co-authored-by: sadan4 <117494111+sadan4@users.noreply.github.com>
Co-authored-by: Nuckyz <61953774+Nuckyz@users.noreply.github.com>
Co-authored-by: V <vendicated@riseup.net>
Co-authored-by: thororen1234 <78185467+thororen1234@users.noreply.github.com>
Co-authored-by: prism <snawalt420@proton.me>
Co-authored-by: wearrrrr <contact@wearr.dev>
Co-authored-by: Elvyra <88881326+EepyElvyra@users.noreply.github.com>
This commit is contained in:
sadan4 2026-01-23 19:59:53 -05:00 committed by GitHub
parent 702a71dee8
commit 575421f4d0
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
84 changed files with 272 additions and 350 deletions

View file

@ -1,16 +0,0 @@
export interface ButtonWrapperClasses {
hoverScale: string;
buttonWrapper: string;
button: string;
iconMask: string;
buttonContent: string;
icon: string;
pulseIcon: string;
pulseButton: string;
notificationDot: string;
sparkleContainer: string;
sparkleStar: string;
sparklePlus: string;
sparkle: string;
active: string;
}

View file

@ -1,5 +1,4 @@
export * from "./common";
export * from "./classes";
export * from "./components";
export * from "./flux";
export * from "./fluxEvents";

View file

@ -11,15 +11,15 @@ import { Logger } from "@utils/Logger";
import { classes } from "@utils/misc";
import { IconComponent } from "@utils/types";
import { Channel } from "@vencord/discord-types";
import { waitFor } from "@webpack";
import { ButtonWrapperClasses, Clickable, Menu, Tooltip } from "@webpack/common";
import { findCssClassesLazy } from "@webpack";
import { Clickable, Menu, Tooltip } from "@webpack/common";
import { HTMLProps, JSX, MouseEventHandler, ReactNode } from "react";
import { addContextMenuPatch, findGroupChildrenByChildId } from "./ContextMenu";
import { useSettings } from "./Settings";
let ChannelTextAreaClasses: Record<"button" | "buttonContainer", string>;
waitFor(["buttonContainer", "channelTextArea"], m => ChannelTextAreaClasses = m);
const ButtonWrapperClasses = findCssClassesLazy("button", "buttonWrapper", "notificationDot");
const ChannelTextAreaClasses = findCssClassesLazy("buttonContainer", "channelTextArea", "button");
export interface ChatBarProps {
channel: Channel;
@ -113,11 +113,9 @@ function VencordChatBarButtons(props: ChatBarProps) {
}
export function _injectButtons(buttons: ReactNode[], props: ChatBarProps) {
if (props.disabled) return;
if (props.disabled || buttons.length === 0) return;
buttons.unshift(<VencordChatBarButtons key="vencord-chat-buttons" {...props} />);
return buttons;
}
/**
@ -145,13 +143,13 @@ export const ChatBarButton = ErrorBoundary.wrap((props: ChatBarButtonProps) => {
aria-label={props.tooltip}
onMouseEnter={onMouseEnter}
onMouseLeave={onMouseLeave}
className={classes(ButtonWrapperClasses?.button, ChannelTextAreaClasses?.button)}
className={classes(ButtonWrapperClasses.button, ChannelTextAreaClasses?.button)}
onClick={props.onClick}
onContextMenu={props.onContextMenu}
onAuxClick={props.onAuxClick}
{...props.buttonProps}
>
<div className={ButtonWrapperClasses?.buttonWrapper}>
<div className={ButtonWrapperClasses.buttonWrapper}>
{props.children}
</div>
</Clickable>

View file

@ -4,10 +4,10 @@
* SPDX-License-Identifier: GPL-3.0-or-later
*/
import { findByPropsLazy } from "@webpack";
import { findCssClassesLazy } from "@webpack";
import { Parser } from "@webpack/common";
const CodeContainerClasses = findByPropsLazy("markup", "codeContainer");
const CodeContainerClasses = findCssClassesLazy("markup", "codeContainer");
/**
* Renders code in a Discord codeblock

View file

@ -16,8 +16,8 @@ export default definePlugin({
{
find: '"sticker")',
replacement: {
match: /(?<=className:.{0,20}\.buttons.{0,50}children:)(\i)/,
replace: "Vencord.Api.ChatButtons._injectButtons($1,arguments[0])"
match: /let (\i)=\(0,\i\.chain\).{0,150}?;(?=return 0===\1\.length)/,
replace: "$&Vencord.Api.ChatButtons._injectButtons($1,arguments[0]);"
}
}
]

View file

@ -50,10 +50,10 @@ export default definePlugin({
},
// Show plugin name instead of "Built-In"
{
find: ".source,children",
find: "#{intl::COMMANDS_OPTIONAL_COUNT}",
replacement: {
// ...children: p?.name
match: /(?<=:(.{1,3})\.displayDescription\}.{0,200}\.source,children:)[^}]+/,
match: /(?<=:(\i)\.displayDescription\}.{0,200}children:).{0,50}\.name(?=\}\))/,
replace: "$1.plugin||($&)"
}
}

View file

@ -14,7 +14,7 @@ export default definePlugin({
description: "Allows you to omit either width or height when opening an image modal",
patches: [
{
find: ".dimensionlessImage,",
find: ".renderLinkComponent)?",
replacement: {
// widthAndHeightPassed = w != null && w !== 0 && h == null || h === 0
match: /(?<=\i=)(null!=\i&&0!==\i)&&(null!=\i&&0!==\i)/,

View file

@ -30,7 +30,7 @@ export default definePlugin({
patches: [
{
find: ".lostPermission)",
find: "#{intl::GUILD_OWNER}),children:",
replacement: [
{
match: /children:\[(?=.{0,300},lostPermissionTooltipText:)/,

View file

@ -27,8 +27,8 @@ export default definePlugin({
{
find: "#{intl::REMOVE_ATTACHMENT_BODY}",
replacement: {
match: /(?<=.container\)?,children:)(\[.+?\])/,
replace: "Vencord.Api.MessageAccessories._modifyAccessories($1,this.props)",
match: /children:(\[[^\]]{0,100}?this.renderSuppressConfirmModal[^\]]{0,100}?\])/,
replace: "children:Vencord.Api.MessageAccessories._modifyAccessories($1,this.props)",
},
},
],

View file

@ -32,13 +32,6 @@ export default definePlugin({
match: /(?<=!1;)\i=null;(?=.{0,80}getPremiumSubscription\(\))/g,
replace: "if(Vencord.Api.Notices.currentNotice)return false;$&"
},
// FIXME(Bundler minifier change related): Remove the non used compability once enough time has passed
{
match: /(?<=,NOTICE_DISMISS:function\(\i\){)return null!=(\i)/,
replace: (m, notice) => `if(${notice}?.id=="VencordNotice")return(${notice}=null,Vencord.Api.Notices.nextNotice(),true);${m}`,
noWarn: true,
},
{
match: /(?<=function (\i)\(\i\){)return null!=(\i)(?=.+?NOTICE_DISMISS:\1)/,
replace: (m, _, notice) => `if(${notice}?.id=="VencordNotice")return(${notice}=null,Vencord.Api.Notices.nextNotice(),true);${m}`

View file

@ -27,7 +27,7 @@ export default definePlugin({
{
find: "#{intl::DISCODO_DISABLED}",
replacement: {
match: /(?<=#{intl::DISCODO_DISABLED}.+?return)(\(.{0,75}?tutorialContainer.+?}\))(?=}function)/,
match: /(?<=#{intl::DISCODO_DISABLED}.+?return)(\(.{0,150}?tutorialId:"friends-list".+?}\))(?=}function)/,
replace: "[$1].concat(Vencord.Api.ServerList.renderAll(Vencord.Api.ServerList.ServerListRenderPosition.Above))"
}
},

View file

@ -102,17 +102,17 @@ export default definePlugin({
patches: [
{
find: ".versionHash",
find: "#{intl::COPY_VERSION}",
replacement: [
{
match: /\.compactInfo.+?(?=null!=(\i)&&(.{0,20}\i\.Text.{0,200}?,children:).{0,15}?("span"),({className:\i\.versionHash,children:\["Build Override: ",\1\.id\]\})\)\}\))/,
match: /"text-xxs\/normal".{0,300}?(?=null!=(\i)&&(.{0,20}\i\.Text.{0,200}?,children:).{0,15}?("span"),({className:\i\.\i,children:\["Build Override: ",\1\.id\]\})\)\}\))/,
replace: (m, _buildOverride, makeRow, component, props) => {
props = props.replace(/children:\[.+\]/, "");
return `${m},$self.makeInfoElements(${component},${props}).map(e=>${makeRow}e})),`;
}
},
{
match: /\.info.+?\[\(0,\i\.jsxs?\)\((.{1,10}),(\{[^{}}]+\{.{0,20}.versionHash,.+?\})\)," "/,
match: /"text-xs\/normal".{0,300}?\[\(0,\i\.jsxs?\)\((.{1,10}),(\{[^{}}]+\{.{0,20}className:\i.\i,.+?\})\)," "/,
replace: (m, component, props) => {
props = props.replace(/children:\[.+\]/, "");
return `${m},$self.makeInfoElements(${component},${props})`;
@ -141,8 +141,8 @@ export default definePlugin({
find: "#{intl::USER_SETTINGS_ACTIONS_MENU_LABEL}",
replacement: {
// Skip the check Discord performs to make sure the section being selected in the user settings context menu is valid
match: /(?<=function\((\i),(\i),\i\)\{)(?=let \i=Object.values\(\i\.\i\).+?(\(0,\i\.openUserSettings\))\()/,
replace: (_, settingsPanel, section, openUserSettings) => `${openUserSettings}(${settingsPanel},{section:${section}});return;`
match: /null!=\(\i=Object.values\(\i\.\i\).{0,50}?&&(?=\(0,\i\.openUserSettings\)\(\i,\{section:\i)/,
replace: ""
}
},
{

View file

@ -49,9 +49,9 @@ export default definePlugin({
},
{
// Guild Banner
find: ".animatedBannerHoverLayer,onMouseEnter:",
find: "#{intl::DISCOVERABLE_GUILD_HEADER_PUBLIC_INFO}",
replacement: {
match: /(\.headerContent.+?guildBanner:\i,animate:)\i/,
match: /(guildBanner:\i,animate:)\i(?=}\):null)/,
replace: "$1!0"
}
},

View file

@ -24,7 +24,7 @@ import { CloudUpload } from "@vencord/discord-types";
import { findByCodeLazy } from "@webpack";
import { useState } from "@webpack/common";
const ActionBarIcon = findByCodeLazy(".actionBarIcon)");
const ActionBarIcon = findByCodeLazy("Children.map", "isValidElement", "dangerous:");
const enum Methods {
Random,

View file

@ -178,7 +178,7 @@ export default definePlugin({
},
// If we are rendering the Better Folders sidebar, we filter out everything but the Guild List from the Sidebar children
{
match: /unreadMentionsFixedFooter\].+?\}\)\]/,
match: /reverse:!0,.{0,150}?barClassName:.+?\}\)\]/,
replace: "$&.filter($self.makeGuildsBarSidebarFilter(!!arguments[0]?.isBetterFolders))"
}
]
@ -212,7 +212,7 @@ export default definePlugin({
// If we are rendering the normal GuildsBar sidebar, we make Discord think the folder is always collapsed to show better icons (the mini guild icons) and avoid transitions
{
predicate: () => settings.store.keepIcons,
match: /(?<=let{folderNode:\i,setNodeRef:\i,.+?expanded:(\i),.+?;)(?=let)/,
match: /(?<=let ?(?:\i,)*?{folderNode:\i,setNodeRef:\i,.+?expanded:(\i),.+?;)(?=let)/,
replace: (_, isExpanded) => `${isExpanded}=!!arguments[0]?.isBetterFolders&&${isExpanded};`
},
// Disable expanding and collapsing folders transition in the normal GuildsBar sidebar
@ -224,20 +224,20 @@ export default definePlugin({
// If we are rendering the normal GuildsBar sidebar, we avoid rendering guilds from folders that are expanded
{
predicate: () => !settings.store.keepIcons,
match: /folderGroupBackground.+?,(?=\i\(\(\i,\i,\i\)=>{let{key:.{0,70}"ul")(?<=selected:\i,expanded:(\i),.+?)/,
match: /"--custom-folder-color".+?(?=\i\(\(\i,\i,\i\)=>{let{key:.{0,70}"ul")(?<=selected:\i,expanded:(\i),.+?)/,
replace: (m, isExpanded) => `${m}$self.shouldRenderContents(arguments[0],${isExpanded})?null:`
},
// Decide if we should render the expanded folder background if we are rendering the Better Folders sidebar
{
predicate: () => settings.store.showFolderIcon !== FolderIconDisplay.Always,
match: /\.isExpanded\].{0,110}children:\[/,
match: /"--custom-folder-color".{0,110}?children:\[/,
replace: "$&$self.shouldShowFolderIconAndBackground(!!arguments[0]?.isBetterFolders,arguments[0]?.betterFoldersExpandedIds)&&"
},
// Decide if we should render the expanded folder icon if we are rendering the Better Folders sidebar
{
predicate: () => settings.store.showFolderIcon !== FolderIconDisplay.Always,
match: /(?<=\.folderGroupBackground.*?}\),)(?=\i,)/,
replace: "!$self.shouldShowFolderIconAndBackground(!!arguments[0]?.isBetterFolders,arguments[0]?.betterFoldersExpandedIds)?null:"
match: /"--custom-folder-color".+?className:\i\.\i}\),(?=\i,)/,
replace: "$&!$self.shouldShowFolderIconAndBackground(!!arguments[0]?.isBetterFolders,arguments[0]?.betterFoldersExpandedIds)?null:"
}
]
},
@ -252,12 +252,12 @@ export default definePlugin({
// One is for visual refresh, one is not,
// and each has a bunch of conditions &&ed in front of it.
// Add the betterFolders sidebar to both, keeping the conditions Discord uses.
match: /(?<=[[,])((?:!?\i&&)+)\(.{0,50}({className:\i\.guilds,themeOverride:\i})\)/g,
match: /(?<=[[,])((?:!?\i&&)+)\(.{0,50}({className:\i\.\i,themeOverride:\i})\)/g,
replace: (m, conditions, props) => `${m},${conditions}$self.FolderSideBar(${props})`
},
{
// Add grid styles to fix aligment with other visual refresh elements
match: /(?<=className:)\i\.base(?=,)/,
match: /(?<=className:)\i\.\i(?=,"data-fullscreen")/,
replace: `"${GRID_STYLE_NAME} "+$&`
}
]

View file

@ -29,7 +29,8 @@ export default definePlugin({
patches: [
{
find: ".dotBorderBase",
// Class used in this module is dotBorderBase
find: "M0 4C0 1.79086 1.79086 0 4 0H16C18.2091 0 20 1.79086 20 4V16C20 18.2091 18.2091 20 16 20H4C1.79086 20 0 18.2091 0 16V4Z",
replacement: {
match: /,viewBox:"0 0 20 20"/,
replace: "$&,onClick:()=>$self.copyToClipBoard(arguments[0].color),style:{cursor:'pointer'}",

View file

@ -23,7 +23,7 @@ import { definePluginSettings } from "@api/Settings";
import ErrorBoundary from "@components/ErrorBoundary";
import { Devs } from "@utils/constants";
import definePlugin, { OptionType } from "@utils/types";
import { findByPropsLazy, findComponentByCodeLazy, findStoreLazy } from "@webpack";
import { findByPropsLazy, findComponentByCodeLazy, findCssClassesLazy, findStoreLazy } from "@webpack";
import { Constants, React, RestAPI, Tooltip } from "@webpack/common";
import { RenameButton } from "./components/RenameButton";
@ -33,8 +33,8 @@ import { fetchNamesFromDataStore, getDefaultName, GetOsColor, GetPlatformIcon, s
const AuthSessionsStore = findStoreLazy("AuthSessionsStore");
const UserSettingsModal = findByPropsLazy("saveAccountChanges", "open");
const TimestampClasses = findByPropsLazy("timestamp", "blockquoteContainer");
const SessionIconClasses = findByPropsLazy("sessionIcon");
const TimestampClasses = findCssClassesLazy("timestamp", "blockquoteContainer");
const SessionIconClasses = findCssClassesLazy("sessionIcon");
const BlobMask = findComponentByCodeLazy("!1,lowerBadgeSize:");
@ -66,17 +66,17 @@ export default definePlugin({
replacement: [
// Replace children with a single label with state
{
match: /({variant:"eyebrow",className:\i\.sessionInfoRow,children:).{70,110}{children:"\\xb7"}\),\(0,\i\.\i\)\("span",{children:\i\[\d+\]}\)\]}\)\]/,
match: /({variant:"eyebrow",className:\i\.\i,children:).{70,110}{children:"\\xb7"}\),\(0,\i\.\i\)\("span",{children:\i\[\d+\]}\)\]}\)\]/,
replace: "$1$self.renderName(arguments[0])"
},
{
match: /({variant:"text-sm\/medium",className:\i\.sessionInfoRow,children:.{70,110}{children:"\\xb7"}\),\(0,\i\.\i\)\("span",{children:)(\i\[\d+\])}/,
replace: "$1$self.renderTimestamp({ ...arguments[0], timeLabel: $2 })}"
match: /({variant:"text-sm\/medium",className:\i\.\i,children:.{70,110}{children:"\\xb7"}\),\(0,\i\.\i\)\("span",{children:)(\i\[\d+\])}/,
replace: "$1$self.renderTimestamp({...arguments[0],timeLabel:$2})}"
},
// Replace the icon
{
match: /\.legacySession\),children:\[(?<=,icon:(\i)\}.+?)/,
replace: "$& $self.renderIcon({ ...arguments[0], DeviceIcon: $1 }), false &&"
match: /children:\[(?=.{0,125}?width:"32")(?<=,icon:(\i)\}.+?)/,
replace: "children:[$self.renderIcon({...arguments[0],DeviceIcon:$1}),false&&"
}
]
}

View file

@ -5,12 +5,13 @@
*/
import { definePluginSettings } from "@api/Settings";
import { classNameFactory, disableStyle, enableStyle } from "@api/Styles";
import { disableStyle, enableStyle } from "@api/Styles";
import { buildPluginMenuEntries, buildThemeMenuEntries } from "@plugins/vencordToolbox/menu";
import { Devs } from "@utils/constants";
import { classNameFactory } from "@utils/css";
import { Logger } from "@utils/Logger";
import definePlugin, { OptionType } from "@utils/types";
import { waitFor } from "@webpack";
import { findCssClassesLazy } from "@webpack";
import { ComponentDispatch, FocusLock, Menu, useEffect, useRef } from "@webpack/common";
import type { HTMLAttributes, ReactElement } from "react";
@ -19,8 +20,7 @@ import fullHeightStyle from "./fullHeightContext.css?managed";
type SettingsEntry = { section: string, label: string; };
const cl = classNameFactory("");
let Classes: Record<string, string>;
waitFor(["animating", "baseLayer", "bg", "layer", "layers"], m => Classes = m);
const Classes = findCssClassesLazy("animating", "baseLayer", "bg", "layer", "layers");
const settings = definePluginSettings({
disableFade: {
@ -139,8 +139,8 @@ export default definePlugin({
find: "#{intl::USER_SETTINGS_ACTIONS_MENU_LABEL}",
replacement: [
{
match: /=\[\];if\((\i)(?=\.forEach.{0,100}"logout"!==\i.{0,30}(\i)\.get\(\i\))/,
replace: "=$self.wrapMap([]);if($self.transformSettingsEntries($1,$2)",
match: /=\[\];(\i)(?=\.forEach.{0,100}"logout"!==\i.{0,30}(\i)\.get\(\i\))/,
replace: "=$self.wrapMap([]);$self.transformSettingsEntries($1,$2)",
predicate: () => settings.store.organizeMenu
},
{
@ -160,7 +160,7 @@ export default definePlugin({
// Thus, we sanity check webpack modules
Layer(props: LayerProps) {
try {
[FocusLock.$$vencordGetWrappedComponent(), ComponentDispatch, Classes].forEach(e => e.test);
[FocusLock.$$vencordGetWrappedComponent(), ComponentDispatch, Classes.layer].forEach(e => e.test);
} catch {
new Logger("BetterSettings").error("Failed to find some components");
return props.children;

View file

@ -46,10 +46,12 @@ export default definePlugin({
patches: [
{
find: "}renderEmbeds(",
replacement: [{
match: /\.container/,
replace: "$&+(this.props.channel.nsfw? ' vc-nsfw-img': '')"
}]
replacement: [
{
match: /(\.renderReactions\(\i\).+?className:)/,
replace: '$&(this.props?.channel?.nsfw?"vc-nsfw-img ":"")+'
}
]
}
],

View file

@ -56,14 +56,14 @@ const define: typeof Object.defineProperty =
};
function makeShortcuts() {
function newFindWrapper(filterFactory: (...props: any[]) => Webpack.FilterFn) {
function newFindWrapper(filterFactory: (...props: any[]) => Webpack.FilterFn, topLevelOnly = false) {
const cache = new Map<string, unknown>();
return function (...filterProps: unknown[]) {
const cacheKey = String(filterProps);
if (cache.has(cacheKey)) return cache.get(cacheKey);
const matches = findAll(filterFactory(...filterProps));
const matches = findAll(filterFactory(...filterProps), { topLevelOnly });
const result = (() => {
switch (matches.length) {
@ -118,6 +118,7 @@ function makeShortcuts() {
findByProps,
findAllByProps: (...props: string[]) => findAll(filters.byProps(...props)),
findByCode: newFindWrapper(filters.byCode),
findCssClasses: newFindWrapper(filters.byClassNames, true),
findAllByCode: (code: string) => findAll(filters.byCode(code)),
findComponentByCode: newFindWrapper(filters.componentByCode),
findAllComponentsByCode: (...code: string[]) => findAll(filters.componentByCode(...code)),

View file

@ -27,7 +27,7 @@ export default definePlugin({
{
find: "#{intl::PREVIEW_BYTES_LEFT}",
replacement: {
match: /\.footerGap.+?url:\i,fileName:\i,fileSize:\i}\),(?<=fileContents:(\i),bytesLeft:(\i).+?)/g,
match: /url:\i,fileName:\i,fileSize:\i}\),(?=.{0,25}setLanguage:)(?<=fileContents:(\i),bytesLeft:(\i).+?)/g,
replace: "$&$self.addCopyButton({fileContents:$1,bytesLeft:$2}),"
}
}

View file

@ -36,7 +36,7 @@ import { ApplicationAssetUtils, Button, FluxDispatcher, Forms, React, UserStore
import { RPCSettings } from "./RpcSettings";
const useProfileThemeStyle = findByCodeLazy("profileThemeStyle:", "--profile-gradient-primary-color");
const ActivityView = findComponentByCodeLazy(".party?(0", ".card");
const ActivityView = findComponentByCodeLazy(".party?(0", "USER_PROFILE_ACTIVITY");
const ShowCurrentGame = getUserSettingLazy<boolean>("status", "showCurrentGame")!;

View file

@ -47,14 +47,14 @@ export default definePlugin({
},
// Decoration modal module
{
find: ".decorationGridItem,",
find: "80,onlyAnimateOnHoverOrFocus:!",
replacement: [
{
match: /(?<==)\i=>{var{children.{20,200}decorationGridItem/,
match: /(?<==)\i=>{let{children.{20,200}isSelected:\i=!1\}=\i/,
replace: "$self.DecorationGridItem=$&",
},
{
match: /(?<==)\i=>{var{user:\i,avatarDecoration/,
match: /(?<==)\i=>{let{user:\i,avatarDecoration/,
replace: "$self.DecorationGridDecoration=$&",
},
// Remove NEW label from decor avatar decorations
@ -98,7 +98,7 @@ export default definePlugin({
},
...[
'"Message Username"', // Messages
".nameplatePreview,{", // Nameplate preview
"#{intl::COLLECTIBLES_NAMEPLATE_PREVIEW_A11Y}", // Nameplate preview
"#{intl::ayozFl::raw}", // Avatar preview
].map(find => ({
find,

View file

@ -13,7 +13,7 @@ import { openChangeDecorationModal } from "@plugins/decor/ui/modals/ChangeDecora
import { findComponentByCodeLazy } from "@webpack";
import { useEffect } from "@webpack/common";
const CustomizationSection = findComponentByCodeLazy(".customizationSectionBackground");
const CustomizationSection = findComponentByCodeLazy(".DESCRIPTION", "hasBackground:");
export interface DecorSectionProps {
hideTitle?: boolean;

View file

@ -6,13 +6,13 @@
import { cl } from "@plugins/decor/ui";
import { classes } from "@utils/misc";
import { findByPropsLazy } from "@webpack";
import { findCssClassesLazy } from "@webpack";
import { React } from "@webpack/common";
import { JSX } from "react";
import Grid, { GridProps } from "./Grid";
const ScrollerClasses = findByPropsLazy("managedReactiveScroller");
const ScrollerClasses = findCssClassesLazy("managedReactiveScroller", "thin");
type Section<SectionT, ItemT> = SectionT & {
items: Array<ItemT>;

View file

@ -5,10 +5,10 @@
*/
import { classNameFactory } from "@utils/css";
import { extractAndLoadChunksLazy, findByPropsLazy } from "@webpack";
import { extractAndLoadChunksLazy, findCssClassesLazy } from "@webpack";
export const cl = classNameFactory("vc-decor-");
export const DecorationModalStyles = findByPropsLazy("modalPreview", "modalCloseButton", "spinner", "modal");
export const DecorationModalClasses = findCssClassesLazy("modalPreview", "modalCloseButton", "spinner", "modal");
export const requireAvatarDecorationModal = extractAndLoadChunksLazy(["initialSelectedDecoration:", /initialSelectedDecoration:\i,.{0,300}\i\.e\(/]);
export const requireCreateStickerModal = extractAndLoadChunksLazy(["stickerInspected]:"]);
export const requireCreateStickerModal = extractAndLoadChunksLazy([".CREATE_STICKER_MODAL,", "isDisplayingIndividualStickers"]);

View file

@ -13,7 +13,7 @@ import { useAuthorizationStore } from "@plugins/decor/lib/stores/AuthorizationSt
import { useCurrentUserDecorationsStore } from "@plugins/decor/lib/stores/CurrentUserDecorationsStore";
import { decorationToAvatarDecoration } from "@plugins/decor/lib/utils/decoration";
import { settings } from "@plugins/decor/settings";
import { cl, DecorationModalStyles, requireAvatarDecorationModal } from "@plugins/decor/ui";
import { cl, DecorationModalClasses, requireAvatarDecorationModal } from "@plugins/decor/ui";
import { AvatarDecorationModalPreview } from "@plugins/decor/ui/components";
import DecorationGridCreate from "@plugins/decor/ui/components/DecorationGridCreate";
import DecorationGridNone from "@plugins/decor/ui/components/DecorationGridNone";
@ -139,7 +139,7 @@ function ChangeDecorationModal(props: ModalProps) {
return <ModalRoot
{...props}
size={ModalSize.DYNAMIC}
className={DecorationModalStyles.modal}
className={DecorationModalClasses.modal}
>
<ModalHeader separator={false} className={cl("modal-header")}>
<Text

View file

@ -8,7 +8,7 @@ import ErrorBoundary from "@components/ErrorBoundary";
import { Link } from "@components/Link";
import { GUILD_ID, INVITE_KEY, RAW_SKU_ID } from "@plugins/decor/lib/constants";
import { useCurrentUserDecorationsStore } from "@plugins/decor/lib/stores/CurrentUserDecorationsStore";
import { cl, DecorationModalStyles, requireAvatarDecorationModal, requireCreateStickerModal } from "@plugins/decor/ui";
import { cl, DecorationModalClasses, requireAvatarDecorationModal, requireCreateStickerModal } from "@plugins/decor/ui";
import { AvatarDecorationModalPreview } from "@plugins/decor/ui/components";
import { openInviteModal } from "@utils/discord";
import { Margins } from "@utils/margins";
@ -16,11 +16,11 @@ import { closeAllModals, ModalCloseButton, ModalContent, ModalFooter, ModalHeade
import { filters, findComponentByCodeLazy, mapMangledModuleLazy } from "@webpack";
import { Button, FluxDispatcher, Forms, GuildStore, NavigationRouter, Text, TextInput, useEffect, useMemo, UserStore, useState } from "@webpack/common";
const FileUpload = findComponentByCodeLazy(".fileUpload),");
const FileUpload = findComponentByCodeLazy(".currentTarget.files)", "lineClamp:1");
const { HelpMessage, HelpMessageTypes } = mapMangledModuleLazy('POSITIVE="positive', {
HelpMessageTypes: filters.byProps("POSITIVE", "WARNING", "INFO"),
HelpMessage: filters.byCode(".iconDiv")
HelpMessage: filters.byCode("messageType:")
});
function useObjectURL(object: Blob | MediaSource | null) {
@ -60,7 +60,7 @@ function CreateDecorationModal(props: ModalProps) {
return <ModalRoot
{...props}
size={ModalSize.MEDIUM}
className={DecorationModalStyles.modal}
className={DecorationModalClasses.modal}
>
<ModalHeader separator={false} className={cl("modal-header")}>
<Text

View file

@ -7,7 +7,7 @@
import { Flex } from "@components/Flex";
import { Link } from "@components/Link";
import { settings } from "@plugins/decor/settings";
import { cl, DecorationModalStyles, requireAvatarDecorationModal } from "@plugins/decor/ui";
import { cl, DecorationModalClasses, requireAvatarDecorationModal } from "@plugins/decor/ui";
import { ModalCloseButton, ModalContent, ModalFooter, ModalHeader, ModalProps, ModalRoot, ModalSize, openModal } from "@utils/modal";
import { Button, Forms, Text } from "@webpack/common";
@ -17,7 +17,7 @@ function GuidelinesModal(props: ModalProps) {
return <ModalRoot
{...props}
size={ModalSize.SMALL}
className={DecorationModalStyles.modal}
className={DecorationModalClasses.modal}
>
<ModalHeader separator={false} className={cl("modal-header")}>
<Text

View file

@ -25,7 +25,6 @@ import definePlugin, { OptionType, ReporterTestable } from "@utils/types";
import { filters, findAll, search } from "@webpack";
const PORT = 8485;
const NAV_ID = "dev-companion-reconnect";
const logger = new Logger("DevCompanion");
@ -164,6 +163,8 @@ function initWs(isManual = false) {
if (src.startsWith("function(")) {
src = "0," + src;
} else if (src.charCodeAt(0) >= 49 /* 1*/ && src.charCodeAt(0) <= 57 /* 9*/) {
src = "0,function" + src.substring(src.indexOf("("));
}
let i = 0;
@ -203,6 +204,9 @@ function initWs(isManual = false) {
case "":
results = findAll(parsedArgs[0]);
break;
case "CssClasses":
results = findAll(filters.byClassNames(...parsedArgs), { topLevelOnly: true });
break;
case "ByProps":
results = findAll(filters.byProps(...parsedArgs));
break;

View file

@ -106,7 +106,7 @@ export default definePlugin({
},
// Enable experiment embed on sent experiment links
{
find: ".experimentOverride,children:",
find: '"Clear Treatment "',
replacement: [
{
match: /\i\.isStaff\(\)/,

View file

@ -183,11 +183,11 @@ export default definePlugin({
makeBypassPatches(),
// Patch the emoji picker in voice calls to not be bypassed by fake nitro
{
find: "emojiItemDisabled]",
find: '.getByName("fork_and_knife")',
predicate: () => settings.store.enableEmojiBypass,
replacement: {
match: /CHAT/,
replace: "STATUS"
match: ".CHAT",
replace: ".STATUS"
}
},
{

View file

@ -10,14 +10,14 @@ import ErrorBoundary from "@components/ErrorBoundary";
import { Devs } from "@utils/constants";
import { getCurrentChannel } from "@utils/discord";
import definePlugin from "@utils/types";
import { findByCodeLazy, findByPropsLazy, findComponentByCodeLazy } from "@webpack";
import { findByCodeLazy, findByPropsLazy, findComponentByCodeLazy, findCssClassesLazy } from "@webpack";
import { RelationshipStore, Text } from "@webpack/common";
const containerWrapper = findByPropsLazy("memberSinceWrapper");
const container = findByPropsLazy("memberSince");
const WrapperClasses = findCssClassesLazy("memberSinceWrapper");
const ContainerClasses = findCssClassesLazy("memberSince");
const getCreatedAtDate = findByCodeLazy('month:"short",day:"numeric"');
const locale = findByPropsLazy("getLocale");
const Section = findComponentByCodeLazy("headingVariant:", ".section", ".header");
const Section = findComponentByCodeLazy("headingVariant:", '"section"', "headingIcon:");
export default definePlugin({
name: "FriendsSince",
@ -34,7 +34,7 @@ export default definePlugin({
},
// User Profile Modal
{
find: ".connections,userId:",
find: ",applicationRoleConnection:",
replacement: {
match: /#{intl::USER_PROFILE_MEMBER_SINCE}\),.{0,100}userId:(\i\.id),.{0,100}}\)}\),/,
replace: "$&,$self.FriendsSinceComponent({userId:$1,isSidebar:false}),"
@ -77,8 +77,8 @@ export default definePlugin({
headingColor="text-default"
className="vc-friendsSince-profile-section"
>
<div className={containerWrapper.memberSinceWrapper}>
<div className={container.memberSince}>
<div className={WrapperClasses.memberSinceWrapper}>
<div className={ContainerClasses.memberSince}>
{!!getCurrentChannel()?.guild_id && (
<svg
aria-hidden="true"

View file

@ -27,6 +27,7 @@ export default definePlugin({
patches: [
{
// Same find as RoleColorEverywhere chatbox mentions
find: ':"text":',
replacement: {
match: /(hidePersonalInformation\).+?)(if\(null!=\i\){.+?return \i)(?=})/,

View file

@ -28,7 +28,7 @@ import { Menu } from "@webpack/common";
import managedStyle from "./style.css?managed";
const Button = findComponentByCodeLazy(".greenTooltip,", ".greenTooltipContent");
const Button = findComponentByCodeLazy(".GREEN,positionKeyStemOverride:");
const ShowCurrentGame = getUserSettingLazy<boolean>("status", "showCurrentGame")!;
@ -114,8 +114,8 @@ export default definePlugin({
{
find: "#{intl::ACCOUNT_SPEAKING_WHILE_MUTED}",
replacement: {
match: /className:\i\.buttons,.{0,50}children:\[/,
replace: "$&$self.GameActivityToggleButton(arguments[0]),"
match: /children:\[(?=.{0,25}?accountContainerRef)/,
replace: "children:[$self.GameActivityToggleButton(arguments[0]),"
}
}
],

View file

@ -161,7 +161,7 @@ export default definePlugin({
{
find: "#{intl::WELCOME_CTA_LABEL}",
replacement: {
match: /className:\i\.welcomeCTA,(?<={channel:\i,message:\i}=(\i).+?)/,
match: /className:\i\.\i,(?=.{0,40}?"sticker")(?<={channel:\i,message:\i}=(\i).+?)/,
replace: "$&onContextMenu:(vcEvent)=>$self.pickSticker(vcEvent, $1),"
}
}

View file

@ -250,35 +250,20 @@ export default definePlugin({
replace: (m, runningGames) => `${m}${runningGames}=${runningGames}.filter(({id,name})=>$self.isActivityNotIgnored({type:0,application_id:id,name}));`
}
},
// FIXME(Bundler minifier change related): Remove the non used compability once enough time has passed
{
find: "#{intl::SETTINGS_GAMES_TOGGLE_OVERLAY}",
replacement: {
// let { ... nowPlaying: a = !1 ...
// let { overlay: b ... } = Props
match: /#{intl::SETTINGS_GAMES_TOGGLE_OVERLAY}.+?}\(\),(?<=nowPlaying:(\i)=!1,.+?overlay:\i,[^}]+?\}=(\i).+?)/,
replace: (m, nowPlaying, props) => `${m}$self.renderToggleGameActivityButton(${props},${nowPlaying}),`,
noWarn: true,
}
},
{
find: "#{intl::SETTINGS_GAMES_TOGGLE_OVERLAY}",
replacement: {
// let { ... nowPlaying: a = !1 ...
// let { overlay: b ... } = Props ...
// ToggleOverLayButton(), nowPlaying && ... RemoveGameButton()
match: /\.gameNameLastPlayed.+?,\i\(\),(?<=nowPlaying:(\i)=!1,.+?overlay:\i,[^}]+?\}=(\i).+?)(?=\1&&)/,
replace: (m, nowPlaying, props) => `${m}$self.renderToggleGameActivityButton(${props},${nowPlaying}),`,
match: /(\i)&&!\i\|\|\i\?null(?<=return (\i)\.verified.+?)/,
replace: "$self.renderToggleGameActivityButton($2,$1),$&"
}
},
// Activities from the apps launcher in the bottom right of the chat bar
{
find: ".promotedLabelWrapperNonBanner,children",
find: "#{intl::EMBEDDED_ACTIVITIES_DEVELOPER_ACTIVITY}",
replacement: {
match: /\.appDetailsHeaderContainer.+?children:\i.*?}\),(?<=application:(\i).+?)/,
replace: (m, props) => `${m}$self.renderToggleActivityButton(${props}),`
match: /lineClamp:1.{0,50}?(?=!\i&&\i\?.+?application:(\i))/,
replace: "$&$self.renderToggleActivityButton($1),"
}
}
],

View file

@ -27,10 +27,10 @@ export default definePlugin({
patches: [
{
find: ".clickableWrapper",
find: ".RESPONSIVE?",
replacement: {
match: /\.originalLink,href:(\i)/,
replace: "$&,title:$self.getTitle($1)"
match: /(?="data-role":"img","data-safe-src":)(?<=href:(\i).+?)/,
replace: "title:$self.getTitle($1),"
}
},
],

View file

@ -104,21 +104,19 @@ export const Magnifier = ErrorBoundary.wrap<MagnifierProps>(({ instance, size: i
const onMouseUp = () => {
setOpacity(0);
if (settings.store.saveZoomValues) {
settings.store.zoom = zoom.current;
settings.store.size = size.current;
}
};
const onWheel = async (e: WheelEvent) => {
if (instance.state.mouseOver && instance.state.mouseDown && !isShiftDown.current) {
const val = zoom.current + ((e.deltaY / 100) * (settings.store.invertScroll ? -1 : 1)) * settings.store.zoomSpeed;
zoom.current = val <= 1 ? 1 : val;
if (settings.store.saveZoomValues) settings.store.zoom = zoom.current;
updateMousePosition(e);
}
if (instance.state.mouseOver && instance.state.mouseDown && isShiftDown.current) {
const val = size.current + (e.deltaY * (settings.store.invertScroll ? -1 : 1)) * settings.store.zoomSpeed;
size.current = val <= 50 ? 50 : val;
if (settings.store.saveZoomValues) settings.store.size = size.current;
updateMousePosition(e);
}
};
@ -152,13 +150,6 @@ export const Magnifier = ErrorBoundary.wrap<MagnifierProps>(({ instance, size: i
};
}, []);
useLayoutEffect(() => () => {
if (settings.store.saveZoomValues) {
settings.store.zoom = zoom.current;
settings.store.size = size.current;
}
});
const imageSrc = useMemo(() => {
try {
const imageUrl = new URL(instance.props.src);

View file

@ -163,10 +163,10 @@ export default definePlugin({
patches: [
{
find: ".dimensionlessImage,",
find: ".renderLinkComponent)?",
replacement: [
{
match: /className:\i\.media,/,
match: /useFullWidth:!0,shouldLink:/,
replace: `id:"${ELEMENT_ID}",$&`
},
{
@ -179,7 +179,7 @@ export default definePlugin({
{
find: '="FOCUS_SENSITIVE",',
replacement: {
match: /(?<=\.hidden]:)\i/,
match: /(?<=\[\i\.\i]:)\i&&!\i&&"PINNED"!==\i/,
replace: "false"
}
},

View file

@ -51,7 +51,7 @@ export default definePlugin({
{
find: "#{intl::FRIENDS_SECTION_ONLINE}),className:",
replacement: {
match: /,{id:(\i\.\i)\.PENDING,show:.+?className:(\i\.item)/,
match: /,{id:(\i\.\i)\.PENDING,show:.+?className:(\i\.\i)(?=\},\{id:)/,
replace: (rest, relationShipTypes, className) => `,{id:${relationShipTypes}.IMPLICIT,show:true,className:${className},content:"Implicit"}${rest}`
}
},

View file

@ -70,14 +70,14 @@ export default definePlugin({
find: "{isSidebarVisible:",
replacement: [
{
match: /(?<=var\{className:(\i),.+?children):\[(\i\.useMemo[^}]+"aria-multiselectable")/,
replace: ":[$1?.includes('members')?$self.render():null,$2",
match: /children:\[(\i\.useMemo[^}]+"aria-multiselectable")(?<=className:(\i),.+?)/,
replace: "children:[$2?.includes('members')?$self.render():null,$1",
},
],
predicate: () => settings.store.memberList
},
{
find: ".invitesDisabledTooltip",
find: "GuildTooltip - ",
replacement: {
match: /#{intl::VIEW_AS_ROLES_MENTIONS_WARNING}.{0,100}(?=])/,
replace: "$&,$self.renderTooltip(arguments[0].guild)"

View file

@ -57,7 +57,7 @@ export default definePlugin({
{
find: ".ROLE_MENTION)",
replacement: {
match: /children:\[\i&&.{0,100}className:\i.roleDot,.{0,200},\i(?=\])/,
match: /children:\[\i&&.{0,100}className:\i.\i,background:!1,.{0,50}?,\i(?=\])/,
replace: "$&,$self.renderRoleIcon(arguments[0])"
}
}],

View file

@ -10,7 +10,6 @@ import { Devs } from "@utils/constants";
import { isNonNullish } from "@utils/guards";
import definePlugin, { OptionType } from "@utils/types";
import { Message } from "@vencord/discord-types";
import { findComponentByCodeLazy } from "@webpack";
import { AuthenticationStore, SnowflakeUtils, Tooltip } from "@webpack/common";
type FillValue = ("status-danger" | "status-warning" | "status-positive" | "text-muted");
@ -26,7 +25,6 @@ interface Diff {
}
const DISCORD_KT_DELAY = 1471228928;
const HiddenVisually = findComponentByCodeLazy(".hiddenVisually]:");
export default definePlugin({
name: "MessageLatency",
@ -161,13 +159,7 @@ export default definePlugin({
text={text}
position="top"
>
{
props => <>
{<this.Icon delta={d.delta} fill={d.fill} props={props} />}
{/* Time Out indicator uses this, I think this is for a11y */}
<HiddenVisually>Delayed Message</HiddenVisually>
</>
}
{props => <this.Icon delta={d.delta} fill={d.fill} props={props} />}
</Tooltip>;
}, { noop: true });
},

View file

@ -25,7 +25,7 @@ import { classes } from "@utils/misc";
import { Queue } from "@utils/Queue";
import definePlugin, { OptionType } from "@utils/types";
import { Channel, Message } from "@vencord/discord-types";
import { findByPropsLazy, findComponentByCodeLazy } from "@webpack";
import { findComponentByCodeLazy, findComponentLazy, findCssClassesLazy } from "@webpack";
import {
Button,
ChannelStore,
@ -47,12 +47,12 @@ const messageCache = new Map<string, {
fetched: boolean;
}>();
const Embed = findComponentByCodeLazy(".inlineMediaEmbed");
const AutoModEmbed = findComponentByCodeLazy(".withFooter]:", "childrenMessageContent:");
const Embed = findComponentLazy(m => m.prototype?.renderSuppressButton);
const AutoModEmbed = findComponentByCodeLazy("withFooter", "childrenMessageContent:");
const ChannelMessage = findComponentByCodeLazy("childrenExecutedCommand:", ".hideAccessories");
const SearchResultClasses = findByPropsLazy("message", "searchResult");
const EmbedClasses = findByPropsLazy("embedAuthorIcon", "embedAuthor", "embedAuthor");
const SearchResultClasses = findCssClassesLazy("message", "searchResult");
const EmbedClasses = findCssClassesLazy("embedAuthorIcon", "embedAuthor", "embedAuthor", "embedMargin");
const MessageDisplayCompact = getUserSettingLazy("textAndImages", "messageDisplayCompact")!;

View file

@ -10,13 +10,13 @@ import { classNameFactory } from "@utils/css";
import { Margins } from "@utils/margins";
import { classes } from "@utils/misc";
import { ModalCloseButton, ModalContent, ModalHeader, ModalProps, ModalRoot, ModalSize, openModal } from "@utils/modal";
import { findByPropsLazy } from "@webpack";
import { findCssClassesLazy } from "@webpack";
import { TabBar, Text, Timestamp, useState } from "@webpack/common";
import { parseEditContent } from ".";
const CodeContainerClasses = findByPropsLazy("markup", "codeContainer");
const MiscClasses = findByPropsLazy("messageContent", "markupRtl");
const CodeContainerClasses = findCssClassesLazy("markup", "codeContainer");
const MiscClasses = findCssClassesLazy("messageContent", "markupRtl");
const cl = classNameFactory("vc-ml-modal-");

View file

@ -29,7 +29,7 @@ import { Logger } from "@utils/Logger";
import { classes } from "@utils/misc";
import definePlugin, { OptionType } from "@utils/types";
import { Message } from "@vencord/discord-types";
import { findByPropsLazy } from "@webpack";
import { findCssClassesLazy } from "@webpack";
import { ChannelStore, FluxDispatcher, Menu, MessageStore, Parser, SelectedChannelStore, Timestamp, UserStore, useStateFromStores } from "@webpack/common";
import overlayStyle from "./deleteStyleOverlay.css?managed";
@ -42,7 +42,7 @@ interface MLMessage extends Message {
firstEditTimestamp?: Date;
}
const styles = findByPropsLazy("edited", "communicationDisabled", "isSystemMessage");
const MessageClasses = findCssClassesLazy("edited", "communicationDisabled", "isSystemMessage");
function addDeleteStyle() {
if (Settings.plugins.MessageLogger.deleteStyle === "text") {
@ -177,7 +177,7 @@ export default definePlugin({
isEdited={true}
isInline={false}
>
<span className={styles.edited}>{" "}({getIntlMessage("MESSAGE_EDITED")})</span>
<span className={MessageClasses.edited}>{" "}({getIntlMessage("MESSAGE_EDITED")})</span>
</Timestamp>
</div>
))}
@ -445,11 +445,11 @@ export default definePlugin({
{
// Attachment renderer
find: ".removeMosaicItemHoverButton",
find: "#{intl::REMOVE_ATTACHMENT_TOOLTIP_TEXT}",
replacement: [
{
match: /\[\i\.obscured\]:.+?,(?<=item:(\i).+?)/,
replace: '$&"messagelogger-deleted-attachment":$1.originalItem?.deleted,'
match: /\.SPOILER,(?=\[\i\.\i\]:)/,
replace: '$&"messagelogger-deleted-attachment":arguments[0]?.item?.originalItem?.deleted,'
}
]
},
@ -471,7 +471,7 @@ export default definePlugin({
find: ".SEND_FAILED,",
replacement: {
// Render editHistory behind the message content
match: /\.isFailed]:.+?children:\[/,
match: /\]:\i.isUnsupported.{0,20}?,children:\[/,
replace: "$&arguments[0]?.message?.editHistory?.length>0&&$self.renderEdits(arguments[0]),"
}
},
@ -480,8 +480,8 @@ export default definePlugin({
find: "#{intl::MESSAGE_EDITED}",
replacement: {
// Make edit marker clickable
match: /"span",\{(?=className:\i\.edited,)/,
replace: "$self.EditMarker,{message:arguments[0].message,"
match: /(isInline:!1,children:.{0,50}?)"span",\{(?=className:)/,
replace: "$1$self.EditMarker,{message:arguments[0].message,"
}
},

View file

@ -18,22 +18,24 @@
import "./style.css";
import { BaseText } from "@components/BaseText";
import ErrorBoundary from "@components/ErrorBoundary";
import { Devs } from "@utils/constants";
import { isNonNullish } from "@utils/guards";
import { Logger } from "@utils/Logger";
import definePlugin from "@utils/types";
import { Channel, User } from "@vencord/discord-types";
import { findByPropsLazy, findComponentByCodeLazy } from "@webpack";
import { findByPropsLazy, findComponentByCodeLazy, findCssClassesLazy } from "@webpack";
import { Avatar, ChannelStore, Clickable, IconUtils, RelationshipStore, ScrollerThin, Text, useMemo, UserStore } from "@webpack/common";
import { JSX } from "react";
const SelectedChannelActionCreators = findByPropsLazy("selectPrivateChannel");
const UserUtils = findByPropsLazy("getGlobalName");
const ProfileListClasses = findByPropsLazy("emptyIconFriends", "emptyIconGuilds");
const MutualsListClasses = findByPropsLazy("row", "icon", "name", "nick");
const ExpandableList = findComponentByCodeLazy('"PRESS_SECTION"', ".header");
const ProfileListClasses = findCssClassesLazy("empty", "textContainer", "connectionIcon");
const TabBarClasses = findCssClassesLazy("tabPanelScroller", "tabBarPanel");
const MutualsListClasses = findCssClassesLazy("row", "icon", "name", "details");
const ExpandableList = findComponentByCodeLazy('action:"PRESS_SECTION"', "section");
function getGroupDMName(channel: Channel) {
return channel.name ||
@ -102,7 +104,7 @@ export default definePlugin({
// Discord adds spacing between each item which pushes our tab off screen.
// set the gap to zero to ensure ours stays on screen
{
match: /className:\i\.tabBar/,
match: /className:\i\.\i(?=,type:"top")/,
replace: '$& + " vc-mutual-gdms-modal-tab-bar"'
}
]
@ -116,7 +118,7 @@ export default definePlugin({
replace: "$&$self.pushSection($1,arguments[0].user);"
},
{
match: /\.tabBarPanel,.*?children:(?=.+?section:(\i))/,
match: /children:(?=.{0,100}?component:.+?section:(\i))/,
replace: "$&$1==='MUTUAL_GDMS'?$self.renderMutualGDMs(arguments[0]):"
},
// Make the gap between each item smaller so our tab can fit.
@ -134,7 +136,7 @@ export default definePlugin({
replace: "$&||$self.getMutualGroupDms(arguments[0].user.id).length>0"
},
{
match: /\.openUserProfileModal.+?\)}\)}\)(?<=,(\i)&&(\i)&&(\(0,\i\.jsxs?\)\(\i\.\i,{className:(\i)\.divider}\)).+?)/,
match: /\.openUserProfileModal.+?\)}\)}\)(?<=,(\i)&&(\i)&&(\(0,\i\.jsxs?\)\(\i\.\i,{className:(\i)\.\i}\)).{0,50}?"MUTUAL_FRIENDS".+?)/,
replace: (m, hasMutualGuilds, hasMutualFriends, Divider, classes) => "" +
`${m},$self.renderDMPageList({user:arguments[0].user,hasDivider:${hasMutualGuilds}||${hasMutualFriends},Divider:${Divider},listStyle:${classes}.list})`
}
@ -172,7 +174,7 @@ export default definePlugin({
return (
<ScrollerThin
className={ProfileListClasses.listScroller}
className={TabBarClasses.tabPanelScroller}
fade={true}
onClose={onClose}
>
@ -180,8 +182,9 @@ export default definePlugin({
? entries
: (
<div className={ProfileListClasses.empty}>
<div className={ProfileListClasses.emptyIconFriends}></div>
<div className={ProfileListClasses.emptyText}>No group dms in common</div>
<div className={ProfileListClasses.textContainer}>
<BaseText tag="h3" size="md" weight="medium" style={{ color: "var(--text-strong)" }}>You don't have any group chats in common</BaseText>
</div>
</div>
)
}

View file

@ -22,7 +22,7 @@ import { cl, getGuildPermissionSpecMap, getSortedRolesForMember, sortUserRoles }
import { getIntlMessage } from "@utils/discord";
import { classes } from "@utils/misc";
import type { Guild, GuildMember } from "@vencord/discord-types";
import { filters, findBulk, proxyLazyWebpack } from "@webpack";
import { findCssClassesLazy } from "@webpack";
import { PermissionsBits, Text, Tooltip, useMemo, UserStore } from "@webpack/common";
import { PermissionsSortOrder, settings } from "..";
@ -37,14 +37,8 @@ interface UserPermission {
type UserPermissions = Array<UserPermission>;
const { RoleClasses, RoleBorderClasses } = proxyLazyWebpack(() => {
const [RoleClasses, RoleBorderClasses] = findBulk(
filters.byProps("role", "roleCircle", "roleName"),
filters.byProps("roleCircle", "dot", "dotBorderColor")
) as Record<string, string>[];
return { RoleClasses, RoleBorderClasses };
});
const RoleClasses = findCssClassesLazy("role", "roleName", "roleRemoveButton", "roleNameOverflow", "root");
const RoleBorderClasses = findCssClassesLazy("roleCircle", "dot", "dotBorderColor");
interface FakeRoleProps extends React.HTMLAttributes<HTMLDivElement> {
text: string;
@ -56,7 +50,7 @@ function FakeRole({ text, color, ...props }: FakeRoleProps) {
<div {...props} className={classes(RoleClasses.role)}>
<div className={RoleClasses.roleRemoveButton}>
<span
className={classes(RoleBorderClasses.roleCircle, RoleClasses.roleCircle)}
className={RoleBorderClasses.roleCircle}
style={{ backgroundColor: color }}
/>
</div>

View file

@ -27,15 +27,14 @@ import { Devs } from "@utils/constants";
import { classes } from "@utils/misc";
import definePlugin, { OptionType } from "@utils/types";
import type { Guild } from "@vencord/discord-types";
import { findByPropsLazy } from "@webpack";
import { findCssClassesLazy } from "@webpack";
import { Button, ChannelStore, Dialog, GuildMemberStore, GuildRoleStore, GuildStore, match, Menu, PermissionsBits, Popout, useRef, UserStore } from "@webpack/common";
import openRolesAndUsersPermissionsModal, { PermissionType, RoleOrUserPermission } from "./components/RolesAndUsersPermissions";
import UserPermissions from "./components/UserPermissions";
import { getSortedRolesForMember, sortPermissionOverwrites } from "./utils";
const PopoutClasses = findByPropsLazy("container", "scroller", "list");
const RoleButtonClasses = findByPropsLazy("button", "icon");
const PopoutClasses = findCssClassesLazy("container", "scroller", "list");
export const enum PermissionsSortOrder {
HighestRole,

View file

@ -28,9 +28,9 @@ export default definePlugin({
settings,
patches: [
{
find: ".removeMosaicItemHoverButton),",
find: '["VIDEO","CLIP","AUDIO"]',
replacement: {
match: /(\.nonMediaMosaicItem\]:.{0,40}children:)(\i.slice\(\i\))(?<=showDownload:(\i).+?isVisualMediaType:(\i).+?)/,
match: /(\[\i>0&&\i\.length>0.{0,150}?children:)(\i.slice\(\i\))(?<=showDownload:(\i).+?isVisualMediaType:(\i).+?)/,
replace: (_, rest, origChildren, showDownload, isVisualMediaType) => `${rest}[${showDownload}&&${isVisualMediaType}&&$self.PictureInPictureButton(),...${origChildren}]`
}
}

View file

@ -12,7 +12,7 @@ import { Devs } from "@utils/constants";
import { classes } from "@utils/misc";
import definePlugin, { OptionType, StartAt } from "@utils/types";
import { Channel } from "@vencord/discord-types";
import { findByPropsLazy, findStoreLazy } from "@webpack";
import { findCssClassesLazy, findStoreLazy } from "@webpack";
import { Clickable, ContextMenuApi, FluxDispatcher, Menu, React } from "@webpack/common";
import { contextMenus } from "./components/contextMenu";
@ -26,7 +26,7 @@ interface ChannelComponentProps {
selected: boolean;
}
const headerClasses = findByPropsLazy("privateChannelsHeaderContainer");
const headerClasses = findCssClassesLazy("privateChannelsHeaderContainer", "headerText");
export const PrivateChannelSortStore = findStoreLazy("PrivateChannelSortStore") as { getPrivateChannelIds: () => string[]; };
@ -72,7 +72,7 @@ export default definePlugin({
patches: [
{
find: ".privateChannelsHeaderContainer,",
find: '"private-channels-".concat(',
replacement: [
{
// Filter out pinned channels from the private channel list
@ -95,8 +95,8 @@ export default definePlugin({
replace: "$&if($self.isCategoryIndex($1.section))return $self.renderCategory($1);"
},
{
match: /(?<=span",{)className:\i\.headerText,/,
replace: "...$self.makeSpanProps(),$&"
match: /"renderSection".{0,300}?"span",{/,
replace: "$&...$self.makeSpanProps(),"
},
// Fix Row Height

View file

@ -28,12 +28,12 @@ export default definePlugin({
patches: [
{
find: ".folderPreviewGuildIconError",
find: "#{intl::GUILD_FOLDER_TOOLTIP_A11Y_LABEL}",
replacement: [
{
// Discord always renders both plain and guild icons folders and uses a css transtion to switch between them
match: /(?<=.folderButtonContent]:(!\i))/,
replace: (_, hasFolderButtonContentClass) => `,"vc-plainFolderIcon-plain":${hasFolderButtonContentClass}`
match: /\.slice\(0,4\).+?\]:(\i),\[\i\.\i\]:!\1/,
replace: (m, hasFolderButtonContent) => `${m},"vc-plainFolderIcon-plain":!${hasFolderButtonContent}`
}
]

View file

@ -10,11 +10,11 @@ import ErrorBoundary from "@components/ErrorBoundary";
import { Devs } from "@utils/constants";
import definePlugin from "@utils/types";
import type { Message } from "@vencord/discord-types";
import { findByPropsLazy } from "@webpack";
import { findCssClassesLazy } from "@webpack";
import { DateUtils, Timestamp } from "@webpack/common";
import type { HTMLAttributes } from "react";
const MessageClasses = findByPropsLazy("separator", "latin24CompactTimeStamp");
const MessageClasses = findCssClassesLazy("separator", "latin24CompactTimeStamp");
function Sep(props: HTMLAttributes<HTMLElement>) {
return <i className={MessageClasses.separator} aria-hidden={true} {...props} />;

View file

@ -18,10 +18,10 @@
import { Devs, IS_MAC } from "@utils/constants";
import definePlugin from "@utils/types";
import { findByPropsLazy } from "@webpack";
import { findCssClassesLazy } from "@webpack";
const SpoilerClasses = findByPropsLazy("spoilerContent");
const MessagesClasses = findByPropsLazy("messagesWrapper", "navigationDescription");
const SpoilerClasses = findCssClassesLazy("spoilerContent", "hidden");
const MessagesClasses = findCssClassesLazy("messagesWrapper", "navigationDescription");
export default definePlugin({
name: "RevealAllSpoilers",

View file

@ -18,10 +18,10 @@
import { DeleteIcon } from "@components/Icons";
import { classes } from "@utils/misc";
import { findByPropsLazy } from "@webpack";
import { findCssClassesLazy } from "@webpack";
import { Tooltip } from "@webpack/common";
const iconClasses = findByPropsLazy("button", "wrapper", "disabled", "separator");
const iconClasses = findCssClassesLazy("button", "wrapper", "disabled", "separator", "dangerous");
export function DeleteButton({ onClick }: { onClick(): void; }) {
return (

View file

@ -23,10 +23,9 @@ import ErrorBoundary from "@components/ErrorBoundary";
import { NotesIcon, OpenExternalIcon } from "@components/Icons";
import { TooltipContainer } from "@components/TooltipContainer";
import { Devs } from "@utils/constants";
import { classes } from "@utils/misc";
import definePlugin from "@utils/types";
import { Guild, User } from "@vencord/discord-types";
import { findByPropsLazy } from "@webpack";
import { findCssClassesLazy } from "@webpack";
import { Alerts, Clickable, Menu, Parser } from "@webpack/common";
import { Auth, initAuth, updateAuth } from "./auth";
@ -36,7 +35,7 @@ import { getCurrentUserInfo, readNotification } from "./reviewDbApi";
import { settings } from "./settings";
import { showToast } from "./utils";
const BannerButtonClasses = findByPropsLazy("bannerButton");
const BannerButtonClasses = findCssClassesLazy("bannerButton");
const guildPopoutPatch: NavContextMenuPatchCallback = (children, { guild }: { guild: Guild, onClose(): void; }) => {
if (!guild) return;
@ -152,7 +151,7 @@ export default definePlugin({
<TooltipContainer text="View Reviews">
<Clickable
onClick={() => openReviewsModal(user.id, user.username, ReviewType.User)}
className={classes(BannerButtonClasses.bannerButton)}
className={BannerButtonClasses.bannerButton}
>
<NotesIcon height={16} width={16} />
</Clickable>

View file

@ -130,4 +130,4 @@
.vc-rdb-block-modal-unblock {
cursor: pointer;
}
}

View file

@ -91,7 +91,8 @@ export default definePlugin({
},
// Slate
{
find: ".userTooltip,children",
// Same find as FullUserInChatbox
find: ':"text":',
replacement: [
{
match: /let\{id:(\i),guildId:\i,channelId:(\i)[^}]*\}.*?\.\i,{(?=children)/,
@ -105,8 +106,8 @@ export default definePlugin({
find: 'tutorialId:"whos-online',
replacement: [
{
match: /(?<=\.roleIcon.{0,15}:null,).{0,150}— ",\i\]\}\)\]/,
replace: "$self.RoleGroupColor(arguments[0])]"
match: /(#{intl::CHANNEL_MEMBERS_A11Y_LABEL}.+}\):null,).{0,100}?— ",\i\]\}\)\]/,
replace: (_, rest) => `${rest}$self.RoleGroupColor(arguments[0])]`
},
],
predicate: () => settings.store.memberList
@ -123,20 +124,21 @@ export default definePlugin({
},
// Voice Users
{
find: ".usernameSpeaking]:",
find: "#{intl::GUEST_NAME_SUFFIX})]",
replacement: [
{
match: /\.usernameSpeaking\]:.+?,(?=children)(?<=guildId:(\i),.+?user:(\i).+?)/,
replace: "$&style:$self.getColorStyle($2.id,$1),"
match: /#{intl::GUEST_NAME_SUFFIX}.{0,50}?""\](?<=guildId:(\i),.{0,50}?user:(\i).+?)/,
replace: "$&,style:$self.getColorStyle($2.id,$1),"
}
],
predicate: () => settings.store.voiceUsers
},
// Reaction List
{
find: ".reactionDefault",
find: "MessageReactions.render:",
replacement: {
match: /tag:"strong"(?=.{0,50}\i\.name)(?<=onContextMenu:.{0,15}\((\i),(\i),\i\).+?)/,
// FIXME: (?:medium|normal) is for stable compat
match: /tag:"strong",variant:"text-md\/(?:medium|normal)"(?<=onContextMenu:.{0,15}\((\i),(\i),\i\).+?)/,
replace: "$&,style:$self.getColorStyle($2?.id,$1?.channel?.id)"
},
predicate: () => settings.store.reactorsList,
@ -145,7 +147,7 @@ export default definePlugin({
{
find: ",reactionVoteCounts",
replacement: {
match: /\.name,(?="aria-label)/,
match: /\.SIZE_32.+?variant:"text-md\/normal",className:\i\.\i,(?="aria-label":)/,
replace: "$&style:$self.getColorStyle(arguments[0]?.user?.id,arguments[0]?.channel?.id),"
},
predicate: () => settings.store.pollResults
@ -154,7 +156,7 @@ export default definePlugin({
{
find: ".SEND_FAILED,",
replacement: {
match: /(?<=isUnsupported\]:(\i)\.isUnsupported\}\),)(?=children:\[)/,
match: /(?<=\]:(\i)\.isUnsupported.{0,50}?,)(?=children:\[)/,
replace: "style:$self.useMessageColorsStyle($1),"
},
predicate: () => settings.store.colorChatMessages

View file

@ -12,10 +12,10 @@ import { classes } from "@utils/misc";
import { ModalRoot, ModalSize, openModal } from "@utils/modal";
import { useAwaiter } from "@utils/react";
import { Guild, User } from "@vencord/discord-types";
import { findByPropsLazy, findComponentByCodeLazy } from "@webpack";
import { findComponentByCodeLazy, findCssClassesLazy } from "@webpack";
import { FluxDispatcher, Forms, GuildChannelStore, GuildMemberStore, GuildRoleStore, IconUtils, Parser, PresenceStore, RelationshipStore, ScrollerThin, SnowflakeUtils, TabBar, Timestamp, useEffect, UserStore, UserUtils, useState, useStateFromStores } from "@webpack/common";
const IconClasses = findByPropsLazy("icon", "acronym", "childWrapper");
const IconClasses = findCssClassesLazy("icon", "acronym", "childWrapper");
const FriendRow = findComponentByCodeLazy("discriminatorClass:", ".isMobileOnline", "getAvatarURL");
const cl = classNameFactory("vc-gp-");

View file

@ -25,7 +25,7 @@ import { sortPermissionOverwrites } from "@plugins/permissionsViewer/utils";
import { classes } from "@utils/misc";
import { formatDuration } from "@utils/text";
import type { Channel } from "@vencord/discord-types";
import { findByPropsLazy, findComponentByCodeLazy } from "@webpack";
import { findByPropsLazy, findComponentByCodeLazy, findCssClassesLazy } from "@webpack";
import { EmojiStore, FluxDispatcher, GuildMemberStore, GuildStore, Parser, PermissionsBits, PermissionStore, SnowflakeUtils, Text, Timestamp, Tooltip, useEffect, useState } from "@webpack/common";
import { cl, settings } from "..";
@ -81,8 +81,7 @@ const enum ChannelFlags {
}
const ChatScrollClasses = findByPropsLazy("auto", "managedReactiveScroller");
const ChatClasses = findByPropsLazy("chat", "content", "noChat", "chatContent");
const ChatScrollClasses = findCssClassesLazy("auto", "managedReactiveScroller", "customTheme");
const ChannelBeginHeader = findComponentByCodeLazy("#{intl::ROLE_REQUIRED_SINGLE_USER_MESSAGE}");
const TagComponent = findComponentByCodeLazy("#{intl::FORUM_TAG_A11Y_FILTER_BY_TAG}");

View file

@ -25,15 +25,15 @@ import { classNameFactory } from "@utils/css";
import { classes } from "@utils/misc";
import definePlugin, { OptionType } from "@utils/types";
import type { Channel, Role } from "@vencord/discord-types";
import { findByPropsLazy } from "@webpack";
import { findCssClassesLazy } from "@webpack";
import { ChannelStore, PermissionsBits, PermissionStore, Tooltip } from "@webpack/common";
import HiddenChannelLockScreen from "./components/HiddenChannelLockScreen";
const ChannelListClasses = findByPropsLazy("modeMuted", "modeSelected", "unread", "icon");
export const cl = classNameFactory("vc-shc-");
const ChannelListClasses = findCssClassesLazy("modeSelected", "modeMuted", "unread", "icon");
const enum ShowMode {
LockIcon,
HiddenIconWithMutedStyle
@ -106,7 +106,7 @@ export default definePlugin({
replacement: [
{
// Do not show confirmation to join a voice channel when already connected to another if clicking on a hidden voice channel
match: /(?<=getIgnoredUsersForVoiceChannel\((\i)\.id\);return\()/,
match: /(?<=getIgnoredUsersForVoiceChannel\((\i)\.id\)[^;]+?;return\()/,
replace: (_, channel) => `!$self.isHiddenChannel(${channel})&&`
},
{
@ -166,7 +166,7 @@ export default definePlugin({
replacement: [
// Make the channel appear as muted if it's hidden
{
match: /\.subtitle,.+?;(?=return\(0,\i\.jsxs?\))(?<={channel:(\i),name:\i,muted:(\i).+?;)/,
match: /Children\.count.+?;(?=return\(0,\i\.jsxs?\)\(\i\.\i,{focusTarget:)(?<={channel:(\i),name:\i,muted:(\i).+?;)/,
replace: (m, channel, muted) => `${m}${muted}=$self.isHiddenChannel(${channel})?true:${muted};`
},
// Add the hidden eye icon if the channel is hidden
@ -176,7 +176,7 @@ export default definePlugin({
},
// Make voice channels also appear as muted if they are muted
{
match: /(?<=\.wrapper:\i\.notInteractive,)(.+?)if\((\i)(?:\)return |\?)(\i\.MUTED)/,
match: /(?<=\?\i\.\i:\i\.\i,)(.{0,150}?)if\((\i)(?:\)return |\?)(\i\.MUTED)/,
replace: (_, otherClasses, isMuted, mutedClassExpression) => `${isMuted}?${mutedClassExpression}:"",${otherClasses}if(${isMuted})return ""`
}
]
@ -193,7 +193,7 @@ export default definePlugin({
{
// Hide unreads
predicate: () => settings.store.hideUnreads === true,
match: /\.subtitle,.+?;(?=return\(0,\i\.jsxs?\))(?<={channel:(\i),name:\i,.+?unread:(\i).+?)/,
match: /Children\.count.+?;(?=return\(0,\i\.jsxs?\)\(\i\.\i,{focusTarget:)(?<={channel:(\i),name:\i,.+?unread:(\i).+?)/,
replace: (m, channel, unread) => `${m}${unread}=$self.isHiddenChannel(${channel})?false:${unread};`
}
]
@ -301,7 +301,7 @@ export default definePlugin({
},
{
// Patch the header to only return allowed users and roles if it's a hidden channel or locked channel (Like when it's used on the HiddenChannelLockScreen)
match: /return\(0,\i\.jsxs?\)\(\i\.\i,{channelId:(\i)\.id(?=.+?(\(0,\i\.jsxs?\)\("div",{className:\i\.members.+?\]}\)),)/,
match: /return\(0,\i\.jsxs?\)\(\i\.\i,{channelId:(\i)\.id(?=.+?(\(0,\i\.jsxs?\)\("div",{className:\i\.\i,children:\[.{0,100}\i\.length>0.+?\]}\)),)/,
replace: (m, channel, allowedUsersAndRolesComponent) => `if($self.isHiddenChannel(${channel},true)){return${allowedUsersAndRolesComponent};}${m}`
},
{
@ -368,7 +368,7 @@ export default definePlugin({
},
{
// Disable bad CSS class which mess up hidden voice channels styling
match: /callContainer,(?<=\i\.callContainer,)/,
match: /(?=\i\|\|\i!==\i\.\i\.FULL_SCREEN.{0,100}?this\._callContainerRef)/,
replace: '$&!this.props.inCall&&$self.isHiddenChannel(this.props.channel,true)?"":'
}
]
@ -408,7 +408,7 @@ export default definePlugin({
},
{
// Remove the open chat button for the HiddenChannelLockScreen
match: /(?<=&&)\(0,\i\.jsxs?\).{0,180}\.buttonIcon/,
match: /(?<="participants-list-button"\),!\i&&)\(0,\i\.jsxs?\).{0,280}?iconClassName:/,
replace: "!$self.isHiddenChannel(arguments[0]?.channel,true)&&$&"
}
]
@ -438,10 +438,10 @@ export default definePlugin({
},
},
{
find: 'className:"channelMention",children',
find: 'className:"channelMention",children:',
replacement: {
// Show inside voice channel instead of trying to join them when clicking on a channel mention
match: /(?<=getChannel\(\i\);if\(null!=(\i))(?=.{0,100}?selectVoiceChannel)/,
match: /(?<=getChannel\(\i\);null!=(\i))(?=.{0,100}?selectVoiceChannel)/,
replace: (_, channel) => `&&!$self.isHiddenChannel(${channel})`
}
},
@ -461,7 +461,7 @@ export default definePlugin({
]
},
{
find: ".invitesDisabledTooltip",
find: "GuildTooltip - ",
replacement: {
// Make GuildChannelStore.getChannels return hidden channels
match: /(?<=getChannels\(\i)(?=\))/,

View file

@ -104,4 +104,4 @@
cursor: not-allowed;
margin-left: 6px;
z-index: 0;
}
}

View file

@ -72,8 +72,8 @@ export default definePlugin({
find: "#{intl::GUILD_MEMBER_MOD_VIEW_HIGHEST_ROLE}),children:",
predicate: () => settings.store.showModView,
replacement: {
match: /(?<=\.highestRole\),)role:\i(?<=\[\i\.roles,\i\.highestRoleId,(\i)\].+)/,
replace: "role:$self.getHighestRole(arguments[0],$1)",
match: /(#{intl::GUILD_MEMBER_MOD_VIEW_HIGHEST_ROLE}.{0,80})role:\i(?<=\[\i\.roles,\i\.highestRoleId,(\i)\].+?)/,
replace: (_, rest, roles) => `${rest}role:$self.getHighestRole(arguments[0],${roles})`,
}
},
// allows you to open mod view on yourself

View file

@ -65,7 +65,7 @@ export default definePlugin({
find: "#{intl::FRIEND_REQUEST_CANCEL}",
replacement: {
predicate: () => settings.store.showDates,
match: /(?<=\.listItemContents,children:\[)\(0,.+?(?=,\(0)(?<=user:(\i).+?)/,
match: /(?<=children:\[)\(0,.{0,100}user:\i,hovered:\i.+?(?=,\(0)(?<=user:(\i).+?)/,
replace: (children, user) => `$self.WrapperDateComponent({user:${user},children:${children}})`
}
}],

View file

@ -53,7 +53,7 @@ export default definePlugin({
},
patches: [
{
find: "this.isCopiedStreakGodlike",
find: "#{intl::ACCOUNT_SPEAKING_WHILE_MUTED}",
replacement: {
// react.jsx)(AccountPanel, { ..., showTaglessAccountPanel: blah })
match: /(?<=\i\.jsxs?\)\()(\i),{(?=[^}]*?userTag:\i,hidePrivateData:)/,

View file

@ -42,13 +42,6 @@ export default definePlugin({
{
find: ",BURST_REACTION_EFFECT_PLAY",
replacement: [
// FIXME(Bundler minifier change related): Remove the non used compability once enough time has passed
{
// if (inlinedCalculatePlayingCount(a,b) >= limit) return;
match: /(BURST_REACTION_EFFECT_PLAY:\i=>{.+?if\()(\(\(\i,\i\)=>.+?\(\i,\i\))>=5+?(?=\))/,
replace: (_, rest, playingCount) => `${rest}!$self.shouldPlayBurstReaction(${playingCount})`,
noWarn: true,
},
{
/*
* var limit = 5

View file

@ -29,10 +29,10 @@ export default definePlugin({
// Add data-author-id and data-is-self to all messages
{
find: ".messageListItem",
find: "Message must not be a thread starter message",
replacement: {
match: /\.messageListItem(?=,"aria)/,
replace: "$&,...$self.getMessageProps(arguments[0])"
match: /"aria-setsize":-1,(?=.{0,150}?#{intl::MESSAGE_A11Y_ROLE_DESCRIPTION})/,
replace: "...$self.getMessageProps(arguments[0]),$&"
}
},

View file

@ -27,7 +27,7 @@ import definePlugin, { OptionType } from "@utils/types";
import { findComponentByCodeLazy } from "@webpack";
import { GuildMemberStore, RelationshipStore, SelectedChannelStore, Tooltip, TypingStore, UserGuildSettingsStore, UserStore, UserSummaryItem, useStateFromStores } from "@webpack/common";
const ThreeDots = findComponentByCodeLazy(".dots,", "dotRadius:");
const ThreeDots = findComponentByCodeLazy("Math.min(1,Math.max(", "dotRadius:");
const enum IndicatorMode {
Dots = 1 << 0,

View file

@ -21,13 +21,13 @@ import ErrorBoundary from "@components/ErrorBoundary";
import { getIntlMessage } from "@utils/discord";
import { classes } from "@utils/misc";
import { Message } from "@vencord/discord-types";
import { findByPropsLazy } from "@webpack";
import { findCssClassesLazy } from "@webpack";
import { Tooltip, UserStore } from "@webpack/common";
import { settings } from "./settings";
import { useFormattedPronouns } from "./utils";
const styles: Record<string, string> = findByPropsLazy("timestampInline");
const TimestampClasses = findCssClassesLazy("timestampInline", "timestamp");
const MessageDisplayCompact = getUserSettingLazy("textAndImages", "messageDisplayCompact")!;
const AUTO_MODERATION_ACTION = 24;
@ -49,7 +49,7 @@ function PronounsChatComponent({ message }: { message: Message; }) {
{tooltipProps => (
<span
{...tooltipProps}
className={classes(styles.timestampInline, styles.timestamp)}
className={classes(TimestampClasses.timestampInline, TimestampClasses.timestamp)}
> {pronouns}</span>
)}
</Tooltip>

View file

@ -10,18 +10,15 @@ import ShowHiddenChannelsPlugin from "@plugins/showHiddenChannels";
import { classNameFactory } from "@utils/css";
import { classes } from "@utils/misc";
import { Channel } from "@vencord/discord-types";
import { filters, findByPropsLazy, mapMangledModuleLazy } from "@webpack";
import { findByPropsLazy, findCssClassesLazy } from "@webpack";
import { ChannelRouter, ChannelStore, Parser, PermissionsBits, PermissionStore, React, showToast, Text, Toasts, Tooltip, useMemo, UserStore, UserSummaryItem, useStateFromStores, VoiceStateStore } from "@webpack/common";
import { PropsWithChildren } from "react";
const cl = classNameFactory("vc-uvs-");
const { selectVoiceChannel } = findByPropsLazy("selectVoiceChannel", "selectChannel");
const { useChannelName } = mapMangledModuleLazy("#{intl::GROUP_DM_ALONE}", {
useChannelName: filters.byCode("()=>null==")
});
const ActionButtonClasses = findByPropsLazy("actionButton", "highlight");
const ActionButtonClasses = findCssClassesLazy("actionButton", "highlight");
type IconProps = Omit<React.ComponentPropsWithoutRef<"div">, "children"> & {
size?: number;

View file

@ -87,7 +87,7 @@ export default definePlugin({
{
find: "null!=this.peopleListItemRef.current",
replacement: {
match: /\.actions,children:\[(?<=isFocused:(\i).+?)/,
match: /\.isProvisional.{0,50}?className:\i\.\i,children:\[(?<=isFocused:(\i).+?)/,
replace: "$&$self.VoiceChannelIndicator({userId:this?.props?.user?.id,isActionButton:true,shouldHighlight:$1}),"
},
predicate: () => settings.store.showInMemberList

View file

@ -28,7 +28,7 @@ import type { PropsWithChildren } from "react";
import { renderPopout } from "./menu";
const HeaderBarIcon = findComponentByCodeLazy(".HEADER_BAR_BADGE_TOP:", '.iconBadge,"top"');
const HeaderBarIcon = findComponentByCodeLazy(".HEADER_BAR_BADGE_TOP:", '"aria-haspopup":');
export const settings = definePluginSettings({
showPluginMenu: {

View file

@ -197,21 +197,18 @@ export default definePlugin({
patches: [
// Avatar component used in User DMs "User Profile" popup in the right and User Profile Modal pfp
{
find: ".overlay:void 0,status:",
replacement: [
{
match: /avatarSrc:(\i),eventHandlers:(\i).+?"div",.{0,100}className:\i,/,
replace: "$&style:{cursor:\"pointer\"},onClick:()=>{$self.openAvatar($1)},",
}
],
all: true
find: "imageClassName:null!=",
replacement: {
match: /avatarSrc:(\i),eventHandlers:(\i).+?"div",.{0,100}className:\i,/,
replace: "$&style:{cursor:\"pointer\"},onClick:()=>{$self.openAvatar($1)},",
}
},
// Banners
{
find: 'backgroundColor:"COMPLETE"',
replacement: {
match: /(\.banner,.+?),style:{(?=.+?backgroundImage:null!=(\i)\?"url\("\.concat\(\2,)/,
replace: (_, rest, bannerSrc) => `${rest},onClick:()=>${bannerSrc}!=null&&$self.openBanner(${bannerSrc}),style:{cursor:${bannerSrc}!=null?"pointer":void 0,`
match: /(overflow:"visible",.{0,125}?!1\),)style:{(?=.+?backgroundImage:null!=(\i)\?"url\("\.concat\(\2,)/,
replace: (_, rest, bannerSrc) => `${rest}onClick:()=>${bannerSrc}!=null&&$self.openBanner(${bannerSrc}),style:{cursor:${bannerSrc}!=null?"pointer":void 0,`
}
},
// Group DMs top small & large icon
@ -225,7 +222,7 @@ export default definePlugin({
},
// User DMs top small icon
{
find: ".cursorPointer:null,children",
find: ".channel.getRecipientId(),",
replacement: {
match: /(?=,src:(\i.getAvatarURL\(.+?[)]))/,
replace: (_, avatarUrl) => `,onClick:()=>$self.openAvatar(${avatarUrl})`

View file

@ -15,10 +15,10 @@ export default definePlugin({
authors: [Devs.puv],
patches: [
{
find: "rippleContainer,children",
find: "#{intl::LgCPMt::raw}",
replacement: {
match: /\(0,\i\.jsx\).{0,150},children:.{0,50}\("source",{src:(\i)}\)}\)/,
replace: "[$&, $self.renderDownload($1)]"
match: /(?<=onVolumeHide:\i\}\))/,
replace: ",$self.renderDownload(arguments[0].src)"
}
}
],

View file

@ -2,11 +2,10 @@
width: 24px;
height: 24px;
color: var(--interactive-icon-default);
margin-left: 12px;
cursor: pointer;
position: relative;
}
.vc-voice-download:hover {
color: var(--interactive-icon-active);
}
}

View file

@ -32,7 +32,7 @@ import definePlugin from "@utils/types";
import { chooseFile } from "@utils/web";
import { CloudUpload as TCloudUpload } from "@vencord/discord-types";
import { CloudUploadPlatform } from "@vencord/discord-types/enums";
import { findByPropsLazy, findLazy, findStoreLazy } from "@webpack";
import { findCssClassesLazy, findLazy, findStoreLazy } from "@webpack";
import { Button, Constants, FluxDispatcher, Forms, lodash, Menu, MessageActions, PermissionsBits, PermissionStore, RestAPI, SelectedChannelStore, showToast, SnowflakeUtils, Toasts, useEffect, useState } from "@webpack/common";
import { ComponentType } from "react";
@ -43,7 +43,7 @@ import { VoiceRecorderWeb } from "./WebRecorder";
const CloudUpload: typeof TCloudUpload = findLazy(m => m.prototype?.trackUploadFinished);
const PendingReplyStore = findStoreLazy("PendingReplyStore");
const OptionClasses = findByPropsLazy("optionName", "optionIcon", "optionLabel");
const OptionClasses = findCssClassesLazy("optionName", "optionIcon", "optionLabel");
export const cl = classNameFactory("vc-vmsg-");
export type VoiceRecorder = ComponentType<{

View file

@ -23,10 +23,8 @@ import { Queue } from "@utils/Queue";
import { useForceUpdater } from "@utils/react";
import definePlugin from "@utils/types";
import { CustomEmoji, Message, ReactionEmoji, User } from "@vencord/discord-types";
import { findByPropsLazy } from "@webpack";
import { ChannelStore, Constants, FluxDispatcher, React, RestAPI, useEffect, useLayoutEffect, UserStore, UserSummaryItem } from "@webpack/common";
const AvatarStyles = findByPropsLazy("moreUsers", "emptyUser", "avatarContainer", "clickableAvatar");
let Scroll: any = null;
const queue = new Queue();
let reactions: Record<string, ReactionCacheEntry>;

View file

@ -1,22 +0,0 @@
/*
* 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 * as t from "@vencord/discord-types";
import { findByPropsLazy } from "@webpack";
export const ButtonWrapperClasses: t.ButtonWrapperClasses = findByPropsLazy("buttonWrapper", "buttonContent");

View file

@ -26,7 +26,7 @@ import { TooltipContainer as TooltipContainerComponent } from "@components/Toolt
import { TooltipFallback } from "@components/TooltipFallback";
import { LazyComponent } from "@utils/lazyReact";
import * as t from "@vencord/discord-types";
import { filters, mapMangledModuleLazy, waitFor } from "@webpack";
import { filters, find, findCssClassesLazy, mapMangledCssClasses, mapMangledModuleLazy, proxyLazyWebpack, waitFor } from "@webpack";
import { waitForComponent } from "./internal";
@ -50,9 +50,7 @@ export const Button = ButtonCompat;
/** @deprecated Use FormSwitch from Vencord */
export const Switch = FormSwitchCompat as never;
/** @deprecated Use Card from Vencord */
export const Card = waitForComponent<never>("Card", filters.componentByCode(".editable),", ".outline:"));
export const Checkbox = waitForComponent<t.Checkbox>("Checkbox", filters.componentByCode(".checkboxWrapperDisabled:"));
export const Checkbox = waitForComponent<t.Checkbox>("Checkbox", filters.componentByCode('"data-toggleable-component":"checkbox'));
export const Tooltip = waitForComponent<t.Tooltip>("Tooltip", m => m.prototype?.shouldShowTooltip && m.prototype.render, TooltipFallback);
/** @deprecated import from @vencord/components */
@ -77,19 +75,26 @@ export const UserSummaryItem = waitForComponent("UserSummaryItem", filters.compo
export let createScroller: (scrollbarClassName: string, fadeClassName: string, customThemeClassName: string) => t.ScrollerThin;
export let createListScroller: (scrollBarClassName: string, fadeClassName: string, someOtherClassIdkMan: string, resizeObserverClass: typeof ResizeObserver) => t.ListScrollerThin;
export let scrollerClasses: Record<string, string>;
export let listScrollerClasses: Record<string, string>;
const listScrollerClassnames = ["thin", "auto", "fade"] as const;
export const scrollerClasses = findCssClassesLazy("thin", "auto", "fade", "customTheme", "none");
const isListScroller = filters.byClassNames(...listScrollerClassnames);
const isNotNormalScroller = filters.byClassNames("customTheme");
export const listScrollerClasses = proxyLazyWebpack(() => {
const mod = find(m => isListScroller(m) && !isNotNormalScroller(m), { topLevelOnly: true });
if (!mod) return {} as Record<typeof listScrollerClassnames[number], string>;
return mapMangledCssClasses(mod, listScrollerClassnames);
});
waitFor(filters.byCode('="ltr",orientation:', "customTheme:", "forwardRef"), m => createScroller = m);
waitFor(filters.byCode("getScrollerNode:", "resizeObserver:", "sectionHeight:"), m => createListScroller = m);
waitFor(["thin", "auto", "customTheme"], m => scrollerClasses = m);
waitFor(m => m.thin && m.auto && !m.customTheme, m => listScrollerClasses = 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));
export const ListScrollerNone = LazyComponent(() => createListScroller(listScrollerClasses.none, listScrollerClasses.fade, "", ResizeObserver));
export const ListScrollerThin = LazyComponent(() => createListScroller(listScrollerClasses.thin, listScrollerClasses.fade, "", ResizeObserver));
export const ListScrollerAuto = LazyComponent(() => createListScroller(listScrollerClasses.auto, listScrollerClasses.fade, "", ResizeObserver));
@ -107,7 +112,7 @@ waitFor(m => {
export const MaskedLink = waitForComponent<t.MaskedLink>("MaskedLink", filters.componentByCode("MASKED_LINK)"));
export const Timestamp = waitForComponent<t.Timestamp>("Timestamp", filters.componentByCode("#{intl::MESSAGE_EDITED_TIMESTAMP_A11Y_LABEL}"));
export const OAuth2AuthorizeModal = waitForComponent("OAuth2AuthorizeModal", filters.componentByCode(".authorize,children:", ".contentBackground"));
export const OAuth2AuthorizeModal = waitForComponent("OAuth2AuthorizeModal", filters.componentByCode("hasContentBackground", "oauth2_authorize"));
export const Animations = mapMangledModuleLazy(".assign({colorNames:", {
Transition: filters.componentByCode('["items","children"]', ",null,"),

View file

@ -16,7 +16,6 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
export * from "./classes";
export * from "./components";
export * from "./menu";
export * from "./react";

View file

@ -41,7 +41,7 @@ waitFor(m => m.name === "MenuCheckboxItem", (_, id) => {
});
waitFor(filters.componentByCode('path:["empty"]'), m => Menu.Menu = m);
waitFor(filters.componentByCode("sliderContainer", "slider", "handleSize:16", "=100"), m => Menu.MenuSliderControl = m);
waitFor(filters.componentByCode("SLIDER)", "handleSize:16"), m => Menu.MenuSliderControl = m);
waitFor(filters.componentByCode(".SEARCH)", ".focus()", "query:"), m => Menu.MenuSearchControl = m);
export const ContextMenuApi: t.ContextMenuApi = mapMangledModuleLazy('type:"CONTEXT_MENU_OPEN', {

View file

@ -148,7 +148,7 @@ export const ApplicationAssetUtils = mapMangledModuleLazy("getAssetImage: size m
getAssets: filters.byCode(".assets")
});
export const NavigationRouter: t.NavigationRouter = mapMangledModuleLazy("Transitioning to ", {
export const NavigationRouter: t.NavigationRouter = mapMangledModuleLazy("transitionTo - Transitioning to", {
transitionTo: filters.byCode("transitionTo -"),
transitionToGuild: filters.byCode("transitionToGuild -"),
back: filters.byCode("goBack()"),

View file

@ -256,7 +256,7 @@ export const find = traceFunction("find", function find(filter: FilterFn, { isIn
return isWaitFor ? [null, null] : null;
});
export function findAll(filter: FilterFn) {
export function findAll(filter: FilterFn, { topLevelOnly = false }: { topLevelOnly?: boolean; } = {}) {
if (typeof filter !== "function")
throw new Error("Invalid filter. Expected a function got " + typeof filter);
@ -268,7 +268,7 @@ export function findAll(filter: FilterFn) {
if (filter(mod.exports))
ret.push(mod.exports);
if (typeof mod.exports !== "object")
if (typeof mod.exports !== "object" || topLevelOnly)
continue;
for (const nestedMod in mod.exports) {
@ -389,7 +389,7 @@ export function findModuleFactory(...code: CodeFilter) {
return wreq.m[id];
}
export const lazyWebpackSearchHistory = [] as Array<["find" | "findByProps" | "findByCode" | "findStore" | "findComponent" | "findComponentByCode" | "findExportedComponent" | "waitFor" | "waitForComponent" | "waitForStore" | "proxyLazyWebpack" | "LazyComponentWebpack" | "extractAndLoadChunks" | "mapMangledModule", any[]]>;
export const lazyWebpackSearchHistory = [] as Array<["find" | "findByProps" | "findByCode" | "findCssClasses" | "findStore" | "findComponent" | "findComponentByCode" | "findExportedComponent" | "waitFor" | "waitForComponent" | "waitForStore" | "proxyLazyWebpack" | "LazyComponentWebpack" | "extractAndLoadChunks" | "mapMangledModule", any[]]>;
/**
* This is just a wrapper around {@link proxyLazy} to make our reporter test for your webpack finds.
@ -578,23 +578,32 @@ export function findExportedComponentLazy<T extends object = any>(...props: Prop
});
}
export function findCssClasses<S extends string>(...classes: S[]): Record<S, string> {
const res = find(filters.byClassNames(...classes), { isIndirect: true, topLevelOnly: true });
if (!res)
handleModuleNotFound("findCssClasses", ...classes);
const values = Object.values(res);
export function mapMangledCssClasses<S extends string>(mappedModule: object, classes: S[] | ReadonlyArray<S>): Record<S, string> {
const values = Object.values(mappedModule);
const mapped = {} as Record<S, string>;
for (const cls of classes) {
const re = makeClassNameRegex(cls);
mapped[cls] = values.find(v => typeof v === "string" && re.test(v)) as string;
if (!mapped[cls]) // this should never happen unless this is used manually with invalid input
throw new Error(`mapMangledCssClasses: Invalid input. ${cls} not found in module`);
}
return mapped;
}
export function findCssClasses<S extends string>(...classes: S[]): Record<S, string> {
const res = find(filters.byClassNames(...classes), { isIndirect: true, topLevelOnly: true });
if (!res) {
handleModuleNotFound("findCssClasses", ...classes);
return {} as Record<S, string>;
}
return mapMangledCssClasses(res, classes);
}
export function findCssClassesLazy<S extends string>(...classes: S[]) {
if (IS_REPORTER) lazyWebpackSearchHistory.push(["findCssClasses", classes]);