From d766db1002f5646c69bf336f9934ff99a5130128 Mon Sep 17 00:00:00 2001 From: Sqaaakoi Date: Thu, 6 Feb 2025 08:11:55 +1300 Subject: [PATCH] Merge branch 'dev' into managed-styles-rewrite (Rename style to managedStyle in PluginDef) --- src/api/MemberListDecorators.tsx | 19 +++++++++++++------ src/api/MessageDecorations.tsx | 18 ++++++++++++------ .../index.tsx} | 11 ++++++++--- .../_api/memberListDecorators/style.css | 11 +++++++++++ .../index.tsx} | 9 +++++++-- src/plugins/_api/messageDecorations/style.css | 18 ++++++++++++++++++ src/plugins/blurNsfw/index.ts | 11 +++++------ src/plugins/copyEmojiMarkdown/index.tsx | 10 +++++----- src/plugins/gameActivityToggle/index.tsx | 5 +++-- src/plugins/imageZoom/index.tsx | 8 ++++---- src/plugins/index.ts | 8 ++++---- src/plugins/platformIndicators/index.tsx | 10 +++------- src/plugins/userVoiceShow/components.tsx | 6 ++---- src/plugins/userVoiceShow/index.tsx | 4 ++-- src/plugins/userVoiceShow/style.css | 10 ---------- src/utils/types.ts | 9 +++++---- src/webpack/common/components.ts | 2 +- src/webpack/webpack.ts | 9 ++++++--- 18 files changed, 109 insertions(+), 69 deletions(-) rename src/plugins/_api/{memberListDecorators.ts => memberListDecorators/index.tsx} (83%) create mode 100644 src/plugins/_api/memberListDecorators/style.css rename src/plugins/_api/{messageDecorations.ts => messageDecorations/index.tsx} (87%) create mode 100644 src/plugins/_api/messageDecorations/style.css diff --git a/src/api/MemberListDecorators.tsx b/src/api/MemberListDecorators.tsx index 2199f4a6c..ab5a618bf 100644 --- a/src/api/MemberListDecorators.tsx +++ b/src/api/MemberListDecorators.tsx @@ -43,20 +43,21 @@ interface DecoratorProps { export type MemberListDecoratorFactory = (props: DecoratorProps) => JSX.Element | null; type OnlyIn = "guilds" | "dms"; -export const decorators = new Map(); +export const decoratorsFactories = new Map(); export function addMemberListDecorator(identifier: string, render: MemberListDecoratorFactory, onlyIn?: OnlyIn) { - decorators.set(identifier, { render, onlyIn }); + decoratorsFactories.set(identifier, { render, onlyIn }); } export function removeMemberListDecorator(identifier: string) { - decorators.delete(identifier); + decoratorsFactories.delete(identifier); } -export function __getDecorators(props: DecoratorProps): (JSX.Element | null)[] { +export function __getDecorators(props: DecoratorProps): JSX.Element { const isInGuild = !!(props.guildId); - return Array.from( - decorators.entries(), + + const decorators = Array.from( + decoratorsFactories.entries(), ([key, { render: Decorator, onlyIn }]) => { if ((onlyIn === "guilds" && !isInGuild) || (onlyIn === "dms" && isInGuild)) return null; @@ -68,4 +69,10 @@ export function __getDecorators(props: DecoratorProps): (JSX.Element | null)[] { ); } ); + + return ( +
+ {decorators} +
+ ); } diff --git a/src/api/MessageDecorations.tsx b/src/api/MessageDecorations.tsx index 740c95876..1b94c18d9 100644 --- a/src/api/MessageDecorations.tsx +++ b/src/api/MessageDecorations.tsx @@ -48,23 +48,29 @@ export interface MessageDecorationProps { } export type MessageDecorationFactory = (props: MessageDecorationProps) => JSX.Element | null; -export const decorations = new Map(); +export const decorationsFactories = new Map(); export function addMessageDecoration(identifier: string, decoration: MessageDecorationFactory) { - decorations.set(identifier, decoration); + decorationsFactories.set(identifier, decoration); } export function removeMessageDecoration(identifier: string) { - decorations.delete(identifier); + decorationsFactories.delete(identifier); } -export function __addDecorationsToMessage(props: MessageDecorationProps): (JSX.Element | null)[] { - return Array.from( - decorations.entries(), +export function __addDecorationsToMessage(props: MessageDecorationProps): JSX.Element { + const decorations = Array.from( + decorationsFactories.entries(), ([key, Decoration]) => ( ) ); + + return ( +
+ {decorations} +
+ ); } diff --git a/src/plugins/_api/memberListDecorators.ts b/src/plugins/_api/memberListDecorators/index.tsx similarity index 83% rename from src/plugins/_api/memberListDecorators.ts rename to src/plugins/_api/memberListDecorators/index.tsx index 0dba3608f..39c82a1ed 100644 --- a/src/plugins/_api/memberListDecorators.ts +++ b/src/plugins/_api/memberListDecorators/index.tsx @@ -19,10 +19,15 @@ import { Devs } from "@utils/constants"; import definePlugin from "@utils/types"; +import managedStyle from "./style.css?managed"; + export default definePlugin({ name: "MemberListDecoratorsAPI", description: "API to add decorators to member list (both in servers and DMs)", authors: [Devs.TheSun, Devs.Ven], + + managedStyle, + patches: [ { find: ".lostPermission)", @@ -32,7 +37,7 @@ export default definePlugin({ replace: "$&vencordProps=$1," }, { match: /#{intl::GUILD_OWNER}(?=.+?decorators:(\i)\(\)).+?\1=?\(\)=>.+?children:\[/, - replace: "$&...(typeof vencordProps=='undefined'?[]:Vencord.Api.MemberListDecorators.__getDecorators(vencordProps))," + replace: "$&(typeof vencordProps=='undefined'?null:Vencord.Api.MemberListDecorators.__getDecorators(vencordProps))," } ] }, @@ -40,8 +45,8 @@ export default definePlugin({ find: "PrivateChannel.renderAvatar", replacement: { match: /decorators:(\i\.isSystemDM\(\))\?(.+?):null/, - replace: "decorators:[...Vencord.Api.MemberListDecorators.__getDecorators(arguments[0]), $1?$2:null]" + replace: "decorators:[Vencord.Api.MemberListDecorators.__getDecorators(arguments[0]),$1?$2:null]" } } - ], + ] }); diff --git a/src/plugins/_api/memberListDecorators/style.css b/src/plugins/_api/memberListDecorators/style.css new file mode 100644 index 000000000..bd4afda9d --- /dev/null +++ b/src/plugins/_api/memberListDecorators/style.css @@ -0,0 +1,11 @@ +.vc-member-list-decorators-wrapper { + display: flex; + align-items: center; + justify-content: center; + gap: 0.25em; +} + +.vc-member-list-decorators-wrapper:not(:empty) { + /* Margin to match default Discord decorators */ + margin-left: 0.25em; +} diff --git a/src/plugins/_api/messageDecorations.ts b/src/plugins/_api/messageDecorations/index.tsx similarity index 87% rename from src/plugins/_api/messageDecorations.ts rename to src/plugins/_api/messageDecorations/index.tsx index fb63a6dde..10866baea 100644 --- a/src/plugins/_api/messageDecorations.ts +++ b/src/plugins/_api/messageDecorations/index.tsx @@ -19,17 +19,22 @@ import { Devs } from "@utils/constants"; import definePlugin from "@utils/types"; +import managedStyle from "./style.css?managed"; + export default definePlugin({ name: "MessageDecorationsAPI", description: "API to add decorations to messages", authors: [Devs.TheSun], + + managedStyle, + patches: [ { find: '"Message Username"', replacement: { match: /#{intl::GUILD_COMMUNICATION_DISABLED_BOTTOM_SHEET_TITLE}.+?}\),\i(?=\])/, - replace: "$&,...Vencord.Api.MessageDecorations.__addDecorationsToMessage(arguments[0])" + replace: "$&,Vencord.Api.MessageDecorations.__addDecorationsToMessage(arguments[0])" } } - ], + ] }); diff --git a/src/plugins/_api/messageDecorations/style.css b/src/plugins/_api/messageDecorations/style.css new file mode 100644 index 000000000..5c13669c4 --- /dev/null +++ b/src/plugins/_api/messageDecorations/style.css @@ -0,0 +1,18 @@ +.vc-message-decorations-wrapper { + display: inline-flex; + align-items: center; + justify-content: center; + gap: 0.25em; +} + +.vc-message-decorations-wrapper:not(:empty) { + /* Margin to match default Discord decorators */ + margin-left: 0.25em; + + /* Align vertically */ + position: relative; + vertical-align: top; + top: 0.1rem; + height: calc(1rem + 4px); + max-height: calc(1rem + 4px) +} diff --git a/src/plugins/blurNsfw/index.ts b/src/plugins/blurNsfw/index.ts index d98f24ef1..0ab6e6b3e 100644 --- a/src/plugins/blurNsfw/index.ts +++ b/src/plugins/blurNsfw/index.ts @@ -21,12 +21,13 @@ import { setStyleVariables } from "@api/Styles"; import { Devs } from "@utils/constants"; import definePlugin, { OptionType } from "@utils/types"; -import style from "./style.css?managed"; +import managedStyle from "./style.css?managed"; export default definePlugin({ name: "BlurNSFW", description: "Blur attachments in NSFW channels until hovered", authors: [Devs.Ven], + managedStyle, patches: [ { @@ -44,14 +45,12 @@ export default definePlugin({ description: "Blur Amount (in pixels)", default: 10, onChange(v) { - setStyleVariables(style, { blurAmount: v }); + setStyleVariables(managedStyle, { blurAmount: v }); } } }), start() { - setStyleVariables(style, { blurAmount: this.settings.store.blurAmount }); - }, - - style + setStyleVariables(managedStyle, { blurAmount: this.settings.store.blurAmount }); + } }); diff --git a/src/plugins/copyEmojiMarkdown/index.tsx b/src/plugins/copyEmojiMarkdown/index.tsx index a9c018a91..58e7303a3 100644 --- a/src/plugins/copyEmojiMarkdown/index.tsx +++ b/src/plugins/copyEmojiMarkdown/index.tsx @@ -33,11 +33,11 @@ function getEmojiMarkdown(target: Target, copyUnicode: boolean): string { : `:${emojiName}:`; } - const extension = target?.firstChild.src.match( - /https:\/\/cdn\.discordapp\.com\/emojis\/\d+\.(\w+)/ - )?.[1]; + const url = new URL(target.firstChild.src); + const hasParam = url.searchParams.get("animated") === "true"; + const isGif = url.pathname.endsWith(".gif"); - return `<${extension === "gif" ? "a" : ""}:${emojiName.replace(/~\d+$/, "")}:${emojiId}>`; + return `<${(hasParam || isGif) ? "a" : ""}:${emojiName.replace(/~\d+$/, "")}:${emojiId}>`; } const settings = definePluginSettings({ @@ -55,7 +55,7 @@ export default definePlugin({ settings, contextMenus: { - "expression-picker"(children, { target }: { target: Target }) { + "expression-picker"(children, { target }: { target: Target; }) { if (target.dataset.type !== "emoji") return; children.push( diff --git a/src/plugins/gameActivityToggle/index.tsx b/src/plugins/gameActivityToggle/index.tsx index d8a37160f..37d0ca4cd 100644 --- a/src/plugins/gameActivityToggle/index.tsx +++ b/src/plugins/gameActivityToggle/index.tsx @@ -23,7 +23,7 @@ import { Devs } from "@utils/constants"; import definePlugin, { OptionType } from "@utils/types"; import { findComponentByCodeLazy } from "@webpack"; -import style from "./style.css?managed"; +import managedStyle from "./style.css?managed"; const Button = findComponentByCodeLazy(".NONE,disabled:", ".PANEL_BUTTON"); @@ -89,6 +89,8 @@ export default definePlugin({ dependencies: ["UserSettingsAPI"], settings, + managedStyle, + patches: [ { find: "#{intl::ACCOUNT_SPEAKING_WHILE_MUTED}", @@ -101,5 +103,4 @@ export default definePlugin({ GameActivityToggleButton: ErrorBoundary.wrap(GameActivityToggleButton, { noop: true }), - style }); diff --git a/src/plugins/imageZoom/index.tsx b/src/plugins/imageZoom/index.tsx index d9b3e4dea..934a5c775 100644 --- a/src/plugins/imageZoom/index.tsx +++ b/src/plugins/imageZoom/index.tsx @@ -28,7 +28,7 @@ import type { Root } from "react-dom/client"; import { Magnifier, MagnifierProps } from "./components/Magnifier"; import { ELEMENT_ID } from "./constants"; -import style from "./styles.css?managed"; +import managedStyle from "./styles.css?managed"; export const settings = definePluginSettings({ saveZoomValues: { @@ -159,6 +159,8 @@ export default definePlugin({ authors: [Devs.Aria], tags: ["ImageUtilities"], + managedStyle, + patches: [ { find: ".contain,SCALE_DOWN:", @@ -260,7 +262,5 @@ export default definePlugin({ // so componenetWillUnMount gets called if Magnifier component is still alive this.root && this.root.unmount(); this.element?.remove(); - }, - - style + } }); diff --git a/src/plugins/index.ts b/src/plugins/index.ts index 7d8bc027d..306ac737d 100644 --- a/src/plugins/index.ts +++ b/src/plugins/index.ts @@ -255,7 +255,7 @@ export function subscribeAllPluginsFluxEvents(fluxDispatcher: typeof FluxDispatc export const startPlugin = traceFunction("startPlugin", function startPlugin(p: Plugin) { const { - name, commands, contextMenus, style, userProfileBadge, + name, commands, contextMenus, managedStyle, userProfileBadge, onBeforeMessageEdit, onBeforeMessageSend, onMessageClick, renderChatBarButton, renderMemberListDecorator, renderMessageAccessory, renderMessageDecoration, renderMessagePopoverButton } = p; @@ -299,7 +299,7 @@ export const startPlugin = traceFunction("startPlugin", function startPlugin(p: } } - if (style) enableStyle(style); + if (managedStyle) enableStyle(managedStyle); if (userProfileBadge) addProfileBadge(userProfileBadge); @@ -318,7 +318,7 @@ export const startPlugin = traceFunction("startPlugin", function startPlugin(p: export const stopPlugin = traceFunction("stopPlugin", function stopPlugin(p: Plugin) { const { - name, commands, contextMenus, style, userProfileBadge, + name, commands, contextMenus, managedStyle, userProfileBadge, onBeforeMessageEdit, onBeforeMessageSend, onMessageClick, renderChatBarButton, renderMemberListDecorator, renderMessageAccessory, renderMessageDecoration, renderMessagePopoverButton } = p; @@ -360,7 +360,7 @@ export const stopPlugin = traceFunction("stopPlugin", function stopPlugin(p: Plu } } - if (style) disableStyle(style); + if (managedStyle) disableStyle(managedStyle); if (userProfileBadge) removeProfileBadge(userProfileBadge); diff --git a/src/plugins/platformIndicators/index.tsx b/src/plugins/platformIndicators/index.tsx index 4612082f5..7829295a0 100644 --- a/src/plugins/platformIndicators/index.tsx +++ b/src/plugins/platformIndicators/index.tsx @@ -133,7 +133,7 @@ function getBadges({ userId }: BadgeUserArgs): ProfileBadge[] { })); } -const PlatformIndicator = ({ user, wantMargin = true, wantTopMargin = false, small = false }: { user: User; wantMargin?: boolean; wantTopMargin?: boolean; small?: boolean; }) => { +const PlatformIndicator = ({ user, small = false }: { user: User; small?: boolean; }) => { if (!user || user.bot) return null; ensureOwnStatus(user); @@ -155,11 +155,7 @@ const PlatformIndicator = ({ user, wantMargin = true, wantTopMargin = false, sma return ( {icons} @@ -190,7 +186,7 @@ const indicatorLocations = { description: "Inside messages", onEnable: () => addMessageDecoration("platform-indicator", props => - + ), onDisable: () => removeMessageDecoration("platform-indicator") diff --git a/src/plugins/userVoiceShow/components.tsx b/src/plugins/userVoiceShow/components.tsx index 5495397fd..4666bb907 100644 --- a/src/plugins/userVoiceShow/components.tsx +++ b/src/plugins/userVoiceShow/components.tsx @@ -130,15 +130,13 @@ function VoiceChannelTooltip({ channel, isLocked }: VoiceChannelTooltipProps) { interface VoiceChannelIndicatorProps { userId: string; - isMessageIndicator?: boolean; - isProfile?: boolean; isActionButton?: boolean; shouldHighlight?: boolean; } const clickTimers = {} as Record; -export const VoiceChannelIndicator = ErrorBoundary.wrap(({ userId, isMessageIndicator, isProfile, isActionButton, shouldHighlight }: VoiceChannelIndicatorProps) => { +export const VoiceChannelIndicator = ErrorBoundary.wrap(({ userId, isActionButton, shouldHighlight }: VoiceChannelIndicatorProps) => { const channelId = useStateFromStores([VoiceStateStore], () => VoiceStateStore.getVoiceStateForUser(userId)?.channelId as string | undefined); const channel = channelId == null ? undefined : ChannelStore.getChannel(channelId); @@ -182,7 +180,7 @@ export const VoiceChannelIndicator = ErrorBoundary.wrap(({ userId, isMessageIndi {props => { const iconProps: IconProps = { ...props, - className: classes(isMessageIndicator && cl("message-indicator"), (!isProfile && !isActionButton) && cl("speaker-margin"), isActionButton && ActionButtonClasses.actionButton, shouldHighlight && ActionButtonClasses.highlight), + className: classes(isActionButton && ActionButtonClasses.actionButton, shouldHighlight && ActionButtonClasses.highlight), size: isActionButton ? 20 : undefined, onClick }; diff --git a/src/plugins/userVoiceShow/index.tsx b/src/plugins/userVoiceShow/index.tsx index f3063f590..3d119c433 100644 --- a/src/plugins/userVoiceShow/index.tsx +++ b/src/plugins/userVoiceShow/index.tsx @@ -60,7 +60,7 @@ export default definePlugin({ find: "#{intl::USER_PROFILE_LOAD_ERROR}", replacement: { match: /(\.fetchError.+?\?)null/, - replace: (_, rest) => `${rest}$self.VoiceChannelIndicator({userId:arguments[0]?.userId,isProfile:true})` + replace: (_, rest) => `${rest}$self.VoiceChannelIndicator({userId:arguments[0]?.userId})` }, predicate: () => settings.store.showInUserProfileModal }, @@ -99,7 +99,7 @@ export default definePlugin({ addMemberListDecorator("UserVoiceShow", ({ user }) => user == null ? null : ); } if (settings.store.showInMessages) { - addMessageDecoration("UserVoiceShow", ({ message }) => message?.author == null ? null : ); + addMessageDecoration("UserVoiceShow", ({ message }) => message?.author == null ? null : ); } }, diff --git a/src/plugins/userVoiceShow/style.css b/src/plugins/userVoiceShow/style.css index d172975b8..f9fd56fbf 100644 --- a/src/plugins/userVoiceShow/style.css +++ b/src/plugins/userVoiceShow/style.css @@ -13,16 +13,6 @@ color: var(--interactive-hover); } -.vc-uvs-speaker-margin { - margin-left: 4px; -} - -.vc-uvs-message-indicator { - display: inline-flex; - top: 2.5px; - position: relative; -} - .vc-uvs-tooltip-container { max-width: 300px; } diff --git a/src/utils/types.ts b/src/utils/types.ts index 6dff9d3ab..da4416d02 100644 --- a/src/utils/types.ts +++ b/src/utils/types.ts @@ -148,13 +148,14 @@ export interface PluginDef { * The key will be used as text for the button */ toolboxActions?: Record void>; - /** - * An imported managed style to be enabled only when the plugin is enabled - */ - style?: Style; tags?: string[]; + /** + * Managed style to automatically enable and disable when the plugin is enabled or disabled + */ + managedStyle?: Style; + userProfileBadge?: ProfileBadge; onMessageClick?: MessageClickListener; diff --git a/src/webpack/common/components.ts b/src/webpack/common/components.ts index dfe00e337..e31e167e8 100644 --- a/src/webpack/common/components.ts +++ b/src/webpack/common/components.ts @@ -57,7 +57,7 @@ export const Heading = waitForComponent("Heading", filters.componentB export const Select = waitForComponent("Select", filters.componentByCode('.selectPositionTop]:"top"===', '"Escape"===')); export const SearchableSelect = waitForComponent("SearchableSelect", filters.componentByCode('.selectPositionTop]:"top"===', ".multi]:")); export const Slider = waitForComponent("Slider", filters.componentByCode('"markDash".concat(')); -export const Popout = waitForComponent("Popout", filters.componentByCode("ref:this.ref,preload:")); +export const Popout = waitForComponent("Popout", filters.componentByCode("ref:this.ref,", "renderPopout:this.renderPopout,")); export const Dialog = waitForComponent("Dialog", filters.componentByCode('role:"dialog",tabIndex:-1')); export const TabBar = waitForComponent("TabBar", filters.componentByCode("ref:this.tabBarRef,className:")); export const Paginator = waitForComponent("Paginator", filters.componentByCode('rel:"prev",children:')); diff --git a/src/webpack/webpack.ts b/src/webpack/webpack.ts index 9e4ea3eb0..7ed791080 100644 --- a/src/webpack/webpack.ts +++ b/src/webpack/webpack.ts @@ -69,12 +69,12 @@ export const filters = { m.constructor?.displayName === name, componentByCode: (...code: CodeFilter): FilterFn => { - const filter = filters.byCode(...code); - return m => { + const byCodeFilter = filters.byCode(...code); + const filter = m => { let inner = m; while (inner != null) { - if (filter(inner)) return true; + if (byCodeFilter(inner)) return true; else if (!inner.$$typeof) return false; else if (inner.type) inner = inner.type; // memos else if (inner.render) inner = inner.render; // forwardRefs @@ -83,6 +83,9 @@ export const filters = { return false; }; + + filter.$$vencordProps = [...code]; + return filter; } };