diff --git a/package.json b/package.json index 60d5fcad6..db34f0e40 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "equicord", "private": "true", - "version": "1.13.4", + "version": "1.13.5", "description": "The other cutest Discord client mod", "homepage": "https://github.com/Equicord/Equicord#readme", "bugs": { @@ -121,4 +121,4 @@ "engines": { "node": ">=18" } -} +} \ No newline at end of file diff --git a/packages/discord-types/src/common/Activity.d.ts b/packages/discord-types/src/common/Activity.d.ts index 677ee963e..ba7c647d3 100644 --- a/packages/discord-types/src/common/Activity.d.ts +++ b/packages/discord-types/src/common/Activity.d.ts @@ -3,8 +3,10 @@ import { ActivityFlags, ActivityStatusDisplayType, ActivityType } from "../../en export interface ActivityAssets { large_image?: string; large_text?: string; + large_url?: string; small_image?: string; small_text?: string; + small_url?: string; } export interface ActivityButton { diff --git a/src/equicordplugins/equicordToolbox/index.tsx b/src/equicordplugins/equicordToolbox/index.tsx index 84b8c6884..e1c2e5f9b 100644 --- a/src/equicordplugins/equicordToolbox/index.tsx +++ b/src/equicordplugins/equicordToolbox/index.tsx @@ -25,7 +25,7 @@ import { Devs } from "@utils/constants"; import definePlugin from "@utils/types"; import { findComponentByCodeLazy } from "@webpack"; import { Menu, Popout, useRef, useState } from "@webpack/common"; -import type { ReactNode } from "react"; +import type { PropsWithChildren, ReactNode } from "react"; const HeaderBarIcon = findComponentByCodeLazy(".HEADER_BAR_BADGE_TOP:", '.iconBadge,"top"'); @@ -154,16 +154,20 @@ export default definePlugin({ { find: '?"BACK_FORWARD_NAVIGATION":', replacement: { - // TODO: (?:\.button) is for stable compat and should be removed soon:tm: - match: /focusSectionProps:"HELP".{0,20},className:(\i(?:\.button)?)\}\),/, - replace: "$& $self.renderVencordPopoutButton($1)," + match: /(?<=trailing:.{0,50})\i\.Fragment,\{(?=.+?className:(\i))/, + replace: "$self.TrailingWrapper,{className:$1," } } ], - renderVencordPopoutButton: (buttonClass: string) => ( - - - - ) + TrailingWrapper({ children, className }: PropsWithChildren<{ className: string; }>) { + return ( + <> + {children} + + + + + ); + }, }); diff --git a/src/equicordplugins/universalMention/index.tsx b/src/equicordplugins/universalMention/index.tsx new file mode 100644 index 000000000..033d871ed --- /dev/null +++ b/src/equicordplugins/universalMention/index.tsx @@ -0,0 +1,65 @@ +/* + * Vencord, a Discord client mod + * Copyright (c) 2025 Vendicated and contributors + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +import { definePluginSettings } from "@api/Settings"; +import { Paragraph } from "@components/Paragraph"; +import { EquicordDevs } from "@utils/constants"; +import definePlugin, { OptionType } from "@utils/types"; +import { User } from "@vencord/discord-types"; +import { ChannelStore, UserStore } from "@webpack/common"; + +const settings = definePluginSettings({ + globalMention: { + type: OptionType.BOOLEAN, + description: "Mention users from any server, not just the current one", + default: false, + restartNeeded: true + }, + onlyDMUsers: { + type: OptionType.BOOLEAN, + description: "Only show users you've had DMs with", + default: false, + restartNeeded: true + } +}); + +export default definePlugin({ + name: "UniversalMention", + authors: [EquicordDevs.justjxke], + description: "Mention any user, regardless of channel access.", + settings, + settingsAboutComponent: () => ( + + Using Global Mention can cause performance issues and show an absurd amount of users in the autocomplete. + + ), + + patches: [ + { + find: ",queryMentionResults(", + replacement: [ + { + match: /(filter:\i).{0,75}context:\i\}\)(?=,allowSnowflake)/, + replace: "$1=>true", + }, + { + match: /(?<=\i=)\i\.\i\.getMembers\(.{0,25}\)\.filter\(\i\)/g, + replace: "$self.useFilter()", + predicate: () => settings.store.globalMention || settings.store.onlyDMUsers, + }, + { + match: /(?<=\i=)\i\.recipients\.map\(.{0,100}:null\}\}\)/, + replace: "$self.useFilter(true)", + } + ], + }, + ], + useFilter(map: boolean = false) { + const foundUsers = Object.values(UserStore.getUsers()) as User[]; + const users = settings.store.onlyDMUsers ? foundUsers.filter(user => ChannelStore.getDMFromUserId(user.id)) : foundUsers; + return map ? users.map(user => ({ userId: user.id, nick: null })) : users; + } +}); diff --git a/src/plugins/customRPC/RpcSettings.tsx b/src/plugins/customRPC/RpcSettings.tsx index 845c088cf..637d049e3 100644 --- a/src/plugins/customRPC/RpcSettings.tsx +++ b/src/plugins/customRPC/RpcSettings.tsx @@ -73,6 +73,11 @@ function isNumberValid(value: number) { return true; } +function isUrlValid(value: string) { + if (value && !/^https?:\/\/.+/.test(value)) return "Must be a valid URL."; + return true; +} + function isImageKeyValid(value: string) { if (/https?:\/\/(cdn|media)\.discordapp\.(com|net)\//.test(value)) return "Don't use a Discord link. Use an Imgur image link instead."; if (/https?:\/\/(?!i\.)?imgur\.com\//.test(value)) return "Imgur link must be a direct link to the image (e.g. https://i.imgur.com/...). Right click the image and click 'Copy image address'"; @@ -180,8 +185,15 @@ export function RPCSettings() { { settingsKey: "appName", label: "Application Name", isValid: makeValidator(128, true) }, ]} /> - - + + + @@ -211,21 +225,23 @@ export function RPCSettings() { { settingsKey: "imageBig", label: "Large Image URL/Key", isValid: isImageKeyValid }, { settingsKey: "imageBigTooltip", label: "Large Image Text", isValid: maxLength128 }, ]} /> + + diff --git a/src/plugins/customRPC/index.tsx b/src/plugins/customRPC/index.tsx index c28a007e2..072d9cad8 100644 --- a/src/plugins/customRPC/index.tsx +++ b/src/plugins/customRPC/index.tsx @@ -62,15 +62,19 @@ export const settings = definePluginSettings({ appID?: string; appName?: string; details?: string; + detailsURL?: string; state?: string; + stateURL?: string; type?: ActivityType; streamLink?: string; timestampMode?: TimestampMode; startTime?: number; endTime?: number; imageBig?: string; + imageBigURL?: string; imageBigTooltip?: string; imageSmall?: string; + imageSmallURL?: string; imageSmallTooltip?: string; buttonOneText?: string; buttonOneURL?: string; @@ -85,14 +89,18 @@ async function createActivity(): Promise { appID, appName, details, + detailsURL, state, + stateURL, type, streamLink, startTime, endTime, imageBig, + imageBigURL, imageBigTooltip, imageSmall, + imageSmallURL, imageSmallTooltip, buttonOneText, buttonOneURL, @@ -139,6 +147,14 @@ async function createActivity(): Promise { break; } + if (detailsURL) { + activity.details_url = detailsURL; + } + + if (stateURL) { + activity.state_url = stateURL; + } + if (buttonOneText) { activity.buttons = [ buttonOneText, @@ -156,7 +172,8 @@ async function createActivity(): Promise { if (imageBig) { activity.assets = { large_image: await getApplicationAsset(imageBig), - large_text: imageBigTooltip || undefined + large_text: imageBigTooltip || undefined, + large_url: imageBigURL || undefined }; } @@ -164,7 +181,8 @@ async function createActivity(): Promise { activity.assets = { ...activity.assets, small_image: await getApplicationAsset(imageSmall), - small_text: imageSmallTooltip || undefined + small_text: imageSmallTooltip || undefined, + small_url: imageSmallURL || undefined }; } diff --git a/src/plugins/experiments/index.tsx b/src/plugins/experiments/index.tsx index 946697ae5..31240bff3 100644 --- a/src/plugins/experiments/index.tsx +++ b/src/plugins/experiments/index.tsx @@ -96,7 +96,7 @@ export default definePlugin({ }, // Enable experiment embed on sent experiment links { - find: "dev://experiment/", + find: ".experimentOverride,children", replacement: [ { match: /\i\.isStaff\(\)/, @@ -104,7 +104,7 @@ export default definePlugin({ }, // Fix some tricky experiments name causing a client crash { - match: /.getExperimentBucketName.+?if\(null==(\i)\|\|null==\i(?=\)return null;)/, + match: /if\(null==(\i)\|\|null==\i(?=\)return null;)/, replace: "$&||({})[$1]!=null" } ]