diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml index 74b2a418b..d79f5e490 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yml +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -14,7 +14,8 @@ body: DO NOT USE THIS FORM, unless - you are a vencord contributor - you were given explicit permission to use this form by a moderator in our support server - - you are filing a security related report + + DO NOT USE THIS FORM FOR SECURITY RELATED ISSUES. [CREATE A SECURITY ADVISORY INSTEAD.](https://github.com/Vendicated/Vencord/security/advisories/new) - type: input id: discord diff --git a/package.json b/package.json index 444587104..e2a0ecedc 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "vencord", "private": "true", - "version": "1.6.0", + "version": "1.6.2", "description": "The cutest Discord client mod", "homepage": "https://github.com/Vendicated/Vencord#readme", "bugs": { diff --git a/scripts/generateReport.ts b/scripts/generateReport.ts index c94adf9bf..4e044c94b 100644 --- a/scripts/generateReport.ts +++ b/scripts/generateReport.ts @@ -289,7 +289,7 @@ function runTime(token: string) { setTimeout(() => console.log("PUPPETEER_TEST_DONE_SIGNAL"), 1000); }, 1000)); } catch (e) { - console.error("[PUP_DEBUG]", "A fatal error occured"); + console.error("[PUP_DEBUG]", "A fatal error occurred"); console.error("[PUP_DEBUG]", e); process.exit(1); } diff --git a/src/api/ContextMenu.ts b/src/api/ContextMenu.ts index 156ae209a..d66d98c4f 100644 --- a/src/api/ContextMenu.ts +++ b/src/api/ContextMenu.ts @@ -69,7 +69,7 @@ export function addGlobalContextMenuPatch(patch: GlobalContextMenuPatchCallback) * Remove a context menu patch * @param navId The navId(s) for the context menu(s) to remove the patch * @param patch The patch to be removed - * @returns Wheter the patch was sucessfully removed from the context menu(s) + * @returns Whether the patch was successfully removed from the context menu(s) */ export function removeContextMenuPatch>(navId: T, patch: NavContextMenuPatchCallback): T extends string ? boolean : Array { const navIds = Array.isArray(navId) ? navId : [navId as string]; @@ -82,7 +82,7 @@ export function removeContextMenuPatch>(navId: /** * Remove a global context menu patch * @param patch The patch to be removed - * @returns Wheter the patch was sucessfully removed + * @returns Whether the patch was successfully removed */ export function removeGlobalContextMenuPatch(patch: GlobalContextMenuPatchCallback): boolean { return globalPatches.delete(patch); diff --git a/src/components/VencordSettings/UpdaterTab.tsx b/src/components/VencordSettings/UpdaterTab.tsx index 6766cf08a..81433960f 100644 --- a/src/components/VencordSettings/UpdaterTab.tsx +++ b/src/components/VencordSettings/UpdaterTab.tsx @@ -46,7 +46,7 @@ function withDispatcher(dispatcher: React.Dispatch if (code === "ENOENT") var err = `Command \`${path}\` not found.\nPlease install it and try again`; else { - var err = `An error occured while running \`${cmd}\`:\n`; + var err = `An error occurred while running \`${cmd}\`:\n`; err += stderr || `Code \`${code}\`. See the console for more info`; } diff --git a/src/main/updater/git.ts b/src/main/updater/git.ts index c6e5cc90a..e96026443 100644 --- a/src/main/updater/git.ts +++ b/src/main/updater/git.ts @@ -49,7 +49,9 @@ async function getRepo() { async function calculateGitChanges() { await git("fetch"); - const res = await git("log", "HEAD...origin/main", "--pretty=format:%an/%h/%s"); + const branch = await git("branch", "--show-current"); + + const res = await git("log", `HEAD...origin/${branch.stdout.trim()}`, "--pretty=format:%an/%h/%s"); const commits = res.stdout.trim(); return commits ? commits.split("\n").map(line => { diff --git a/src/plugins/_api/messageDecorations.ts b/src/plugins/_api/messageDecorations.ts index 1646ad645..b41ec0be9 100644 --- a/src/plugins/_api/messageDecorations.ts +++ b/src/plugins/_api/messageDecorations.ts @@ -27,8 +27,8 @@ export default definePlugin({ { find: '"Message Username"', replacement: { - match: /currentUserIsPremium:.{0,70}{children:\i(?=}\))/, - replace: "$&.concat(Vencord.Api.MessageDecorations.__addDecorationsToMessage(arguments[0]))" + match: /\.Messages\.GUILD_COMMUNICATION_DISABLED_BOTTOM_SHEET_TITLE.+?}\),\i(?=\])/, + replace: "$&,...Vencord.Api.MessageDecorations.__addDecorationsToMessage(arguments[0])" } } ], diff --git a/src/plugins/alwaysAnimate/index.ts b/src/plugins/alwaysAnimate/index.ts index f3ae27afd..d53e51452 100644 --- a/src/plugins/alwaysAnimate/index.ts +++ b/src/plugins/alwaysAnimate/index.ts @@ -21,16 +21,30 @@ import definePlugin from "@utils/types"; export default definePlugin({ name: "AlwaysAnimate", - description: "Animates anything that can be animated, besides status emojis.", + description: "Animates anything that can be animated", authors: [Devs.FieryFlames], patches: [ { - find: ".canAnimate", + find: "canAnimate:", all: true, + // Some modules match the find but the replacement is returned untouched + noWarn: true, replacement: { - match: /\.canAnimate\b/g, - replace: ".canAnimate || true" + match: /canAnimate:.+?(?=([,}].*?\)))/g, + replace: (m, rest) => { + const destructuringMatch = rest.match(/}=.+/); + if (destructuringMatch == null) return "canAnimate:!0"; + return m; + } + } + }, + { + // Status emojis + find: ".Messages.GUILD_OWNER,", + replacement: { + match: /(?<=\.activityEmoji,.+?animate:)\i/, + replace: "!0" } } ] diff --git a/src/plugins/betterFolders/FolderSideBar.tsx b/src/plugins/betterFolders/FolderSideBar.tsx index 6353a9716..97959873f 100644 --- a/src/plugins/betterFolders/FolderSideBar.tsx +++ b/src/plugins/betterFolders/FolderSideBar.tsx @@ -16,56 +16,44 @@ * along with this program. If not, see . */ -import { Settings } from "@api/Settings"; -import { classNameFactory } from "@api/Styles"; import ErrorBoundary from "@components/ErrorBoundary"; -import { findByPropsLazy, findStoreLazy } from "@webpack"; -import { i18n, React, useStateFromStores } from "@webpack/common"; +import { LazyComponent } from "@utils/react"; +import { find, findByPropsLazy, findStoreLazy } from "@webpack"; +import { useStateFromStores } from "@webpack/common"; +import type { CSSProperties } from "react"; -const cl = classNameFactory("vc-bf-"); -const classes = findByPropsLazy("sidebar", "guilds"); +import { ExpandedGuildFolderStore, settings } from "."; -const Animations = findByPropsLazy("a", "animated", "useTransition"); const ChannelRTCStore = findStoreLazy("ChannelRTCStore"); -const ExpandedGuildFolderStore = findStoreLazy("ExpandedGuildFolderStore"); +const Animations = findByPropsLazy("a", "animated", "useTransition"); +const GuildsBar = LazyComponent(() => find(m => m.type?.toString().includes('("guildsnav")'))); -function Guilds(props: { - className: string; - bfGuildFolders: any[]; -}) { - // @ts-expect-error - const res = Vencord.Plugins.plugins.BetterFolders.Guilds(props); - - // TODO: Make this better - const scrollerProps = res.props.children?.props?.children?.props?.children?.[1]?.props; - if (scrollerProps?.children) { - const servers = scrollerProps.children.find(c => c?.props?.["aria-label"] === i18n.Messages.SERVERS); - if (servers) scrollerProps.children = servers; - } - - return res; -} - -export default ErrorBoundary.wrap(() => { +export default ErrorBoundary.wrap(guildsBarProps => { const expandedFolders = useStateFromStores([ExpandedGuildFolderStore], () => ExpandedGuildFolderStore.getExpandedFolders()); - const fullscreen = useStateFromStores([ChannelRTCStore], () => ChannelRTCStore.isFullscreenInContext()); - - const guilds = document.querySelector(`.${classes.guilds}`); - - const visible = !!expandedFolders.size; - const className = cl("folder-sidebar", { fullscreen }); + const isFullscreen = useStateFromStores([ChannelRTCStore], () => ChannelRTCStore.isFullscreenInContext()); const Sidebar = ( - ); - if (!guilds || !Settings.plugins.BetterFolders.sidebarAnim) + const visible = !!expandedFolders.size; + const guilds = document.querySelector(guildsBarProps.className.split(" ").map(c => `.${c}`).join("")); + + // We need to display none if we are in fullscreen. Yes this seems horrible doing with css, but it's literally how Discord does it. + // Also display flex otherwise to fix scrolling + const barStyle = { + display: isFullscreen ? "none" : "flex", + } as CSSProperties; + + if (!guilds || !settings.store.sidebarAnim) { return visible - ?
{Sidebar}
+ ?
{Sidebar}
: null; + } return ( { leave={{ width: 0 }} config={{ duration: 200 }} > - {(style, show) => show && ( - - {Sidebar} - - )} + {(animationStyle, show) => + show && ( + + {Sidebar} + + ) + } ); }, { noop: true }); diff --git a/src/plugins/betterFolders/betterFolders.css b/src/plugins/betterFolders/betterFolders.css deleted file mode 100644 index 5d8fc2188..000000000 --- a/src/plugins/betterFolders/betterFolders.css +++ /dev/null @@ -1,17 +0,0 @@ -.vc-bf-folder-sidebar [class*="wrapper-"] > [class*="listItem-"]:first-of-type, -.vc-bf-folder-sidebar [class*="unreadMentionsIndicator"] { - display: none; -} - -.vc-bf-folder-sidebar [class*="expandedFolderBackground-"] { - background-color: transparent; -} - -.vc-bf-folder-sidebar { - display: flex; -} - -.vc-bf-fullscreen { - width: 0 !important; - visibility: hidden; -} diff --git a/src/plugins/betterFolders/index.ts b/src/plugins/betterFolders/index.ts deleted file mode 100644 index d41ba75c7..000000000 --- a/src/plugins/betterFolders/index.ts +++ /dev/null @@ -1,177 +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 . -*/ - -import "./betterFolders.css"; - -import { definePluginSettings } from "@api/Settings"; -import { Devs } from "@utils/constants"; -import definePlugin, { OptionType } from "@utils/types"; -import { findByPropsLazy, findLazy, findStoreLazy } from "@webpack"; -import { FluxDispatcher } from "@webpack/common"; - -import FolderSideBar from "./FolderSideBar"; - -const GuildsTree = findLazy(m => m.prototype?.convertToFolder); -const GuildFolderStore = findStoreLazy("SortedGuildStore"); -const ExpandedFolderStore = findStoreLazy("ExpandedGuildFolderStore"); -const FolderUtils = findByPropsLazy("move", "toggleGuildFolderExpand"); - -const settings = definePluginSettings({ - sidebar: { - type: OptionType.BOOLEAN, - description: "Display servers from folder on dedicated sidebar", - default: true, - }, - sidebarAnim: { - type: OptionType.BOOLEAN, - description: "Animate opening the folder sidebar", - default: true, - }, - closeAllFolders: { - type: OptionType.BOOLEAN, - description: "Close all folders when selecting a server not in a folder", - default: false, - }, - closeAllHomeButton: { - type: OptionType.BOOLEAN, - description: "Close all folders when clicking on the home button", - default: false, - }, - closeOthers: { - type: OptionType.BOOLEAN, - description: "Close other folders when opening a folder", - default: false, - }, - forceOpen: { - type: OptionType.BOOLEAN, - description: "Force a folder to open when switching to a server of that folder", - default: false, - }, -}); - -export default definePlugin({ - name: "BetterFolders", - description: "Shows server folders on dedicated sidebar and adds folder related improvements", - authors: [Devs.juby, Devs.AutumnVN], - patches: [ - { - find: '("guildsnav")', - predicate: () => settings.store.sidebar, - replacement: [ - { - match: /(\i)\(\){return \i\(\(0,\i\.jsx\)\("div",{className:\i\(\)\.guildSeparator}\)\)}/, - replace: "$&$self.Separator=$1;" - }, - - // Folder component patch - { - match: /\i\(\(function\(\i,\i,\i\){var \i=\i\.key;return.+\(\i\)},\i\)}\)\)/, - replace: "arguments[0].bfHideServers?null:$&" - }, - - // BEGIN Guilds component patch - { - match: /(\i)\.themeOverride,(.{15,25}\(function\(\){var \i=)(\i\.\i\.getGuildsTree\(\))/, - replace: "$1.themeOverride,bfPatch=$1.bfGuildFolders,$2bfPatch?$self.getGuildsTree(bfPatch,$3):$3" - }, - { - match: /return(\(0,\i\.jsx\))(\(\i,{)(folderNode:\i,setNodeRef:\i\.setNodeRef,draggable:!0,.+},\i\.id\));case/, - replace: "var bfHideServers=typeof bfPatch==='undefined',folder=$1$2bfHideServers,$3;return !bfHideServers&&arguments[1]?[$1($self.Separator,{}),folder]:folder;case" - }, - // END - - { - match: /\("guildsnav"\);return\(0,\i\.jsx\)\(.{1,6},{navigator:\i,children:\(0,\i\.jsx\)\(/, - replace: "$&$self.Guilds=" - } - ] - }, - { - find: "APPLICATION_LIBRARY,render", - predicate: () => settings.store.sidebar, - replacement: { - match: /(\(0,\i\.jsx\))\(\i\..,{className:\i\(\)\.guilds,themeOverride:\i}\)/, - replace: "$&,$1($self.FolderSideBar,{})" - } - }, - { - find: '("guildsnav")', - predicate: () => settings.store.closeAllHomeButton, - replacement: { - match: ",onClick:function(){if(!__OVERLAY__){", - replace: "$&$self.closeFolders();" - } - } - ], - - settings, - - start() { - const getGuildFolder = (id: string) => GuildFolderStore.getGuildFolders().find(f => f.guildIds.includes(id)); - - FluxDispatcher.subscribe("CHANNEL_SELECT", this.onSwitch = data => { - if (!settings.store.closeAllFolders && !settings.store.forceOpen) - return; - - if (this.lastGuildId !== data.guildId) { - this.lastGuildId = data.guildId; - - const guildFolder = getGuildFolder(data.guildId); - if (guildFolder?.folderId) { - if (settings.store.forceOpen && !ExpandedFolderStore.isFolderExpanded(guildFolder.folderId)) - FolderUtils.toggleGuildFolderExpand(guildFolder.folderId); - } else if (settings.store.closeAllFolders) - this.closeFolders(); - } - }); - - FluxDispatcher.subscribe("TOGGLE_GUILD_FOLDER_EXPAND", this.onToggleFolder = e => { - if (settings.store.closeOthers && !this.dispatching) - FluxDispatcher.wait(() => { - const expandedFolders = ExpandedFolderStore.getExpandedFolders(); - if (expandedFolders.size > 1) { - this.dispatching = true; - - for (const id of expandedFolders) if (id !== e.folderId) - FolderUtils.toggleGuildFolderExpand(id); - - this.dispatching = false; - } - }); - }); - }, - - stop() { - FluxDispatcher.unsubscribe("CHANNEL_SELECT", this.onSwitch); - FluxDispatcher.unsubscribe("TOGGLE_GUILD_FOLDER_EXPAND", this.onToggleFolder); - }, - - FolderSideBar, - - getGuildsTree(folders, oldTree) { - const tree = new GuildsTree(); - tree.root.children = oldTree.root.children.filter(e => folders.includes(e.id)); - tree.nodes = folders.map(id => oldTree.nodes[id]); - return tree; - }, - - closeFolders() { - for (const id of ExpandedFolderStore.getExpandedFolders()) - FolderUtils.toggleGuildFolderExpand(id); - }, -}); diff --git a/src/plugins/betterFolders/index.tsx b/src/plugins/betterFolders/index.tsx new file mode 100644 index 000000000..8f40d90ff --- /dev/null +++ b/src/plugins/betterFolders/index.tsx @@ -0,0 +1,307 @@ +/* + * 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 . +*/ + +import { definePluginSettings } from "@api/Settings"; +import { Devs } from "@utils/constants"; +import { proxyLazy } from "@utils/lazy"; +import definePlugin, { OptionType } from "@utils/types"; +import { findByProps, findByPropsLazy, findStoreLazy } from "@webpack"; +import { FluxDispatcher, i18n } from "@webpack/common"; + +import FolderSideBar from "./FolderSideBar"; + +enum FolderIconDisplay { + Never, + Always, + MoreThanOneFolderExpanded +} + +const GuildsTree = proxyLazy(() => findByProps("GuildsTree").GuildsTree); +const SortedGuildStore = findStoreLazy("SortedGuildStore"); +export const ExpandedGuildFolderStore = findStoreLazy("ExpandedGuildFolderStore"); +const FolderUtils = findByPropsLazy("move", "toggleGuildFolderExpand"); + +let lastGuildId = null as string | null; +let dispatchingFoldersClose = false; + +function getGuildFolder(id: string) { + return SortedGuildStore.getGuildFolders().find(folder => folder.guildIds.includes(id)); +} + +function closeFolders() { + for (const id of ExpandedGuildFolderStore.getExpandedFolders()) + FolderUtils.toggleGuildFolderExpand(id); +} + +export const settings = definePluginSettings({ + sidebar: { + type: OptionType.BOOLEAN, + description: "Display servers from folder on dedicated sidebar", + restartNeeded: true, + default: true + }, + sidebarAnim: { + type: OptionType.BOOLEAN, + description: "Animate opening the folder sidebar", + default: true + }, + closeAllFolders: { + type: OptionType.BOOLEAN, + description: "Close all folders when selecting a server not in a folder", + default: false + }, + closeAllHomeButton: { + type: OptionType.BOOLEAN, + description: "Close all folders when clicking on the home button", + restartNeeded: true, + default: false + }, + closeOthers: { + type: OptionType.BOOLEAN, + description: "Close other folders when opening a folder", + default: false + }, + forceOpen: { + type: OptionType.BOOLEAN, + description: "Force a folder to open when switching to a server of that folder", + default: false + }, + keepIcons: { + type: OptionType.BOOLEAN, + description: "Keep showing guild icons in the primary guild bar folder when it's open in the BetterFolders sidebar", + restartNeeded: true, + default: false + }, + showFolderIcon: { + type: OptionType.SELECT, + description: "Show the folder icon above the folder guilds in the BetterFolders sidebar", + options: [ + { label: "Never", value: FolderIconDisplay.Never }, + { label: "Always", value: FolderIconDisplay.Always, default: true }, + { label: "When more than one folder is expanded", value: FolderIconDisplay.MoreThanOneFolderExpanded } + ], + restartNeeded: true + } +}); + +export default definePlugin({ + name: "BetterFolders", + description: "Shows server folders on dedicated sidebar and adds folder related improvements", + authors: [Devs.juby, Devs.AutumnVN, Devs.Nuckyz], + + settings, + + patches: [ + { + find: '("guildsnav")', + predicate: () => settings.store.sidebar, + replacement: [ + // Create the isBetterFolders variable in the GuildsBar component + { + match: /(?<=let{disableAppDownload:\i=\i\.isPlatformEmbedded,isOverlay:.+?)(?=}=\i,)/, + replace: ",isBetterFolders" + }, + // If we are rendering the Better Folders sidebar, we filter out guilds that are not in folders and unexpanded folders + { + match: /(useStateFromStoresArray\).{0,25}let \i)=(\i\.\i.getGuildsTree\(\))/, + replace: (_, rest, guildsTree) => `${rest}=$self.getGuildTree(!!arguments[0].isBetterFolders,${guildsTree},arguments[0].betterFoldersExpandedIds)` + }, + // If we are rendering the Better Folders sidebar, we filter out everything but the servers and folders from the GuildsBar Guild List children + { + match: /lastTargetNode:\i\[\i\.length-1\].+?Fragment.+?\]}\)\]/, + replace: "$&.filter($self.makeGuildsBarGuildListFilter(!!arguments[0].isBetterFolders))" + }, + // If we are rendering the Better Folders sidebar, we filter out everything but the scroller for the guild list from the GuildsBar Tree children + { + match: /unreadMentionsIndicatorBottom,barClassName.+?}\)\]/, + replace: "$&.filter($self.makeGuildsBarTreeFilter(!!arguments[0].isBetterFolders))" + }, + // Export the isBetterFolders variable to the folders component + { + match: /(?<=\.Messages\.SERVERS.+?switch\((\i)\.type\){case \i\.\i\.FOLDER:.+?folderNode:\i,)/, + replace: 'isBetterFolders:typeof isBetterFolders!=="undefined"?isBetterFolders:false,' + } + ] + }, + { + // This is the parent folder component + find: ".MAX_GUILD_FOLDER_NAME_LENGTH,", + predicate: () => settings.store.sidebar && settings.store.showFolderIcon !== FolderIconDisplay.Always, + replacement: [ + { + // Modify the expanded state to instead return the list of expanded folders + match: /(useStateFromStores\).{0,20}=>)(\i\.\i)\.isFolderExpanded\(\i\)/, + replace: (_, rest, ExpandedGuildFolderStore) => `${rest}${ExpandedGuildFolderStore}.getExpandedFolders()`, + }, + { + // Modify the expanded prop to use the boolean if the above patch fails, or check if the folder is expanded from the list if it succeeds + // Also export the list of expanded folders to the child folder component if the patch above succeeds, else export undefined + match: /(?<=folderNode:(\i),expanded:)\i(?=,)/, + replace: (isExpandedOrExpandedIds, folderNote) => "" + + `typeof ${isExpandedOrExpandedIds}==="boolean"?${isExpandedOrExpandedIds}:${isExpandedOrExpandedIds}.has(${folderNote}.id),` + + `betterFoldersExpandedIds:${isExpandedOrExpandedIds} instanceof Set?${isExpandedOrExpandedIds}:void 0` + } + ] + }, + { + find: ".FOLDER_ITEM_GUILD_ICON_MARGIN);", + predicate: () => settings.store.sidebar, + replacement: [ + // We use arguments[0] to access the isBetterFolders variable in this nested folder component (the parent exports all the props so we don't have to patch it) + + // 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)/, + replace: (_, isExpanded) => `${isExpanded}=!!arguments[0].isBetterFolders&&${isExpanded};` + }, + // Disable expanding and collapsing folders transition in the normal GuildsBar sidebar + { + predicate: () => !settings.store.keepIcons, + match: /(?<=\.Messages\.SERVER_FOLDER_PLACEHOLDER.+?useTransition\)\()/, + replace: "!!arguments[0].isBetterFolders&&" + }, + // If we are rendering the normal GuildsBar sidebar, we avoid rendering guilds from folders that are expanded + { + predicate: () => !settings.store.keepIcons, + match: /expandedFolderBackground,.+?,(?=\i\(\(\i,\i,\i\)=>{let{key.{0,45}ul)(?<=selected:\i,expanded:(\i),.+?)/, + replace: (m, isExpanded) => `${m}!arguments[0].isBetterFolders&&${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: /(?<=\.wrapper,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: /(?<=\.expandedFolderBackground.+?}\),)(?=\i,)/, + replace: "!$self.shouldShowFolderIconAndBackground(!!arguments[0].isBetterFolders,arguments[0].betterFoldersExpandedIds)?null:" + } + ] + }, + { + find: "APPLICATION_LIBRARY,render", + predicate: () => settings.store.sidebar, + replacement: { + // Render the Better Folders sidebar + match: /(?<=({className:\i\.guilds,themeOverride:\i})\))/, + replace: ",$self.FolderSideBar($1)" + } + }, + { + find: ".Messages.DISCODO_DISABLED", + predicate: () => settings.store.closeAllHomeButton, + replacement: { + // Close all folders when clicking the home button + match: /(?<=onClick:\(\)=>{)(?=.{0,200}"discodo")/, + replace: "$self.closeFolders();" + } + } + ], + + flux: { + CHANNEL_SELECT(data) { + if (!settings.store.closeAllFolders && !settings.store.forceOpen) + return; + + if (lastGuildId !== data.guildId) { + lastGuildId = data.guildId; + const guildFolder = getGuildFolder(data.guildId); + + if (guildFolder?.folderId) { + if (settings.store.forceOpen && !ExpandedGuildFolderStore.isFolderExpanded(guildFolder.folderId)) { + FolderUtils.toggleGuildFolderExpand(guildFolder.folderId); + } + } else if (settings.store.closeAllFolders) { + closeFolders(); + } + } + }, + + TOGGLE_GUILD_FOLDER_EXPAND(data) { + if (settings.store.closeOthers && !dispatchingFoldersClose) { + dispatchingFoldersClose = true; + + FluxDispatcher.wait(() => { + const expandedFolders = ExpandedGuildFolderStore.getExpandedFolders(); + + if (expandedFolders.size > 1) { + for (const id of expandedFolders) if (id !== data.folderId) + FolderUtils.toggleGuildFolderExpand(id); + } + + dispatchingFoldersClose = false; + }); + } + } + }, + + getGuildTree(isBetterFolders: boolean, oldTree: any, expandedFolderIds?: Set) { + if (!isBetterFolders || expandedFolderIds == null) return oldTree; + + const newTree = new GuildsTree(); + // Children is every folder and guild which is not in a folder, this filters out only the expanded folders + newTree.root.children = oldTree.root.children.filter(guildOrFolder => expandedFolderIds.has(guildOrFolder.id)); + // Nodes is every folder and guild, even if it's in a folder, this filters out only the expanded folders and guilds inside them + newTree.nodes = Object.fromEntries( + Object.entries(oldTree.nodes) + .filter(([_, guildOrFolder]: any[]) => expandedFolderIds.has(guildOrFolder.id) || expandedFolderIds.has(guildOrFolder.parentId)) + ); + + return newTree; + }, + + makeGuildsBarGuildListFilter(isBetterFolders: boolean) { + return child => { + if (isBetterFolders) { + return child?.props?.["aria-label"] === i18n.Messages.SERVERS; + } + return true; + }; + }, + + makeGuildsBarTreeFilter(isBetterFolders: boolean) { + return child => { + if (isBetterFolders) { + return "onScroll" in child.props; + } + return true; + }; + }, + + shouldShowFolderIconAndBackground(isBetterFolders: boolean, expandedFolderIds?: Set) { + if (!isBetterFolders) return true; + + switch (settings.store.showFolderIcon) { + case FolderIconDisplay.Never: + return false; + case FolderIconDisplay.Always: + return true; + case FolderIconDisplay.MoreThanOneFolderExpanded: + return (expandedFolderIds?.size ?? 0) > 1; + default: + return true; + } + }, + + FolderSideBar: guildsBarProps => , + + closeFolders +}); diff --git a/src/plugins/betterGifAltText/index.ts b/src/plugins/betterGifAltText/index.ts index f07295704..8b4116318 100644 --- a/src/plugins/betterGifAltText/index.ts +++ b/src/plugins/betterGifAltText/index.ts @@ -45,7 +45,8 @@ export default definePlugin({ ], altify(props: any) { - if (props.alt && props.alt !== "GIF") return props.alt; + props.alt ??= "GIF"; + if (props.alt !== "GIF") return props.alt; let url: string = props.original || props.src; try { diff --git a/src/plugins/customRPC/index.tsx b/src/plugins/customRPC/index.tsx index 25ad7b3e6..feed52fde 100644 --- a/src/plugins/customRPC/index.tsx +++ b/src/plugins/customRPC/index.tsx @@ -30,6 +30,7 @@ const ActivityClassName = findByPropsLazy("activity", "buttonColor"); const Colors = findByPropsLazy("profileColors"); async function getApplicationAsset(key: string): Promise { + if (/https?:\/\/(cdn|media)\.discordapp\.(com|net)\/attachments\//.test(key)) return "mp:" + key.replace(/https?:\/\/(cdn|media)\.discordapp\.(com|net)\//, ""); return (await ApplicationAssetUtils.fetchAssetIds(settings.store.appID!, [key]))[0]; } @@ -395,7 +396,7 @@ export default definePlugin({ return ( <> - Go to Discord Deverloper Portal to create an application and + Go to Discord Developer Portal to create an application and get the application ID. diff --git a/src/plugins/dearrow/index.tsx b/src/plugins/dearrow/index.tsx index c6bf4e05d..f6b9ef952 100644 --- a/src/plugins/dearrow/index.tsx +++ b/src/plugins/dearrow/index.tsx @@ -63,7 +63,7 @@ async function embedDidMount(this: Component) { embed.rawTitle = titles[0].title; } - if (thumbnails[0]?.votes >= 0) { + if (thumbnails[0]?.votes >= 0 && thumbnails[0].timestamp) { embed.dearrow.oldThumb = embed.thumbnail.proxyURL; embed.thumbnail.proxyURL = `https://dearrow-thumb.ajay.app/api/v1/getThumbnail?videoID=${videoId}&time=${thumbnails[0].timestamp}`; } diff --git a/src/plugins/emoteCloner/index.tsx b/src/plugins/emoteCloner/index.tsx index c44731152..219ce435f 100644 --- a/src/plugins/emoteCloner/index.tsx +++ b/src/plugins/emoteCloner/index.tsx @@ -155,10 +155,15 @@ async function doClone(guildId: string, data: Sticker | Emoji) { type: Toasts.Type.SUCCESS, id: Toasts.genId() }); - } catch (e) { + } catch (e: any) { + let message = "Something went wrong (check console!)"; + try { + message = JSON.parse(e.text).message; + } catch { } + new Logger("EmoteCloner").error("Failed to clone", data.name, "to", guildId, e); Toasts.show({ - message: "Oopsie something went wrong :( Check console!!!", + message: "Failed to clone: " + message, type: Toasts.Type.FAILURE, id: Toasts.genId() }); diff --git a/src/plugins/fakeNitro/index.ts b/src/plugins/fakeNitro/index.ts index efec9a8b5..4d6b7957b 100644 --- a/src/plugins/fakeNitro/index.ts +++ b/src/plugins/fakeNitro/index.ts @@ -201,15 +201,15 @@ export default definePlugin({ predicate: () => settings.store.enableEmojiBypass, replacement: { match: /((?:canUseEmojisEverywhere|canUseAnimatedEmojis):function\(\i)\){(.+?\))(?=})/g, - replace: (_, rest, premiumCheck) => `${rest},fakeNitroIntention){${premiumCheck}||fakeNitroIntention!=null||[${EmojiIntentions.CHAT},${EmojiIntentions.GUILD_STICKER_RELATED_EMOJI}].includes(fakeNitroIntention)` + replace: (_, rest, premiumCheck) => `${rest},fakeNitroIntention){${premiumCheck}||fakeNitroIntention==null||[${EmojiIntentions.CHAT},${EmojiIntentions.GUILD_STICKER_RELATED_EMOJI}].includes(fakeNitroIntention)` } }, // Allow stickers to be sent everywhere { - find: "canUseStickersEverywhere:function", + find: "canUseCustomStickersEverywhere:function", predicate: () => settings.store.enableStickerBypass, replacement: { - match: /canUseStickersEverywhere:function\(\i\){/, + match: /canUseCustomStickersEverywhere:function\(\i\){/, replace: "$&return true;" }, }, diff --git a/src/plugins/favGifSearch/index.tsx b/src/plugins/favGifSearch/index.tsx index 0cb5166e1..592d8f547 100644 --- a/src/plugins/favGifSearch/index.tsx +++ b/src/plugins/favGifSearch/index.tsx @@ -60,7 +60,7 @@ interface Instance { } -const containerClasses: { searchBar: string; } = findByPropsLazy("searchBar", "searchHeader", "searchInput"); +const containerClasses: { searchBar: string; } = findByPropsLazy("searchBar", "searchBarFullRow"); export const settings = definePluginSettings({ searchOption: { @@ -182,7 +182,7 @@ function SearchBar({ instance, SearchBarComponent }: { instance: Instance; Searc ref={ref} autoFocus={true} className={containerClasses.searchBar} - size={SearchBarComponent.Sizes.SMALL} + size={SearchBarComponent.Sizes.MEDIUM} onChange={onChange} onClear={() => { setQuery(""); diff --git a/src/plugins/gifPaste/index.ts b/src/plugins/gifPaste/index.ts index 8c1303ba4..9ce88f9d2 100644 --- a/src/plugins/gifPaste/index.ts +++ b/src/plugins/gifPaste/index.ts @@ -33,8 +33,8 @@ export default definePlugin({ patches: [{ find: ".handleSelectGIF=", replacement: { - match: /\.handleSelectGIF=\i=>\{/, - replace: ".handleSelectGIF=function(gif){return $self.handleSelect(gif);" + match: /\.handleSelectGIF=(\i)=>\{/, + replace: ".handleSelectGIF=$1=>{if (!this.props.className) return $self.handleSelect($1);" } }], diff --git a/src/plugins/imageZoom/index.tsx b/src/plugins/imageZoom/index.tsx index 08f2e29d3..75c944ebd 100644 --- a/src/plugins/imageZoom/index.tsx +++ b/src/plugins/imageZoom/index.tsx @@ -186,6 +186,13 @@ export default definePlugin({ } ] }, + { + find: ".carouselModal", + replacement: { + match: /(?<=\.carouselModal.{0,100}onClick:)\i,/, + replace: "()=>{}," + } + } ], settings, diff --git a/src/plugins/imageZoom/styles.css b/src/plugins/imageZoom/styles.css index 09c3c8580..51e225c05 100644 --- a/src/plugins/imageZoom/styles.css +++ b/src/plugins/imageZoom/styles.css @@ -15,19 +15,17 @@ border-radius: 0; } -.vc-imgzoom-nearest-neighbor > img { - image-rendering: pixelated; /* https://googlechrome.github.io/samples/image-rendering-pixelated/index.html */ +.vc-imgzoom-nearest-neighbor>img { + image-rendering: pixelated; + + /* https://googlechrome.github.io/samples/image-rendering-pixelated/index.html */ } /* make the carousel take up less space so we can click the backdrop and exit out of it */ -[class|="carouselModal"] { - height: fit-content; - box-shadow: none; +[class*="modalCarouselWrapper_"] { + top: 0 !important; } -[class|="wrapper"]:has(> #vc-imgzoom-magnify-modal) { - position: absolute; - left: 50%; - top: 50%; - transform: translate(-50%, -50%); +[class*="carouselModal_"] { + height: 0 !important; } diff --git a/src/plugins/noMosaic/index.ts b/src/plugins/noMosaic/index.ts index 49343503d..7f9fad53c 100644 --- a/src/plugins/noMosaic/index.ts +++ b/src/plugins/noMosaic/index.ts @@ -4,28 +4,58 @@ * SPDX-License-Identifier: GPL-3.0-or-later */ +import { definePluginSettings } from "@api/Settings"; import { disableStyle, enableStyle } from "@api/Styles"; import { Devs } from "@utils/constants"; -import definePlugin from "@utils/types"; +import definePlugin, { OptionType } from "@utils/types"; import style from "./styles.css?managed"; +const settings = definePluginSettings({ + inlineVideo: { + description: "Play videos without carousel modal", + type: OptionType.BOOLEAN, + default: true, + restartNeeded: true + }, + mediaLayoutType: { + description: "Choose media layout type", + type: OptionType.SELECT, + restartNeeded: true, + options: [ + { label: "STATIC, render loading image but image isn't resposive, no problem unless discord window width is too small", value: "STATIC", default: true }, + { label: "RESPONSIVE, image is responsive but not render loading image, cause messages shift when loaded", value: "RESPONSIVE" }, + ] + } +}); + export default definePlugin({ name: "NoMosaic", authors: [Devs.AutumnVN], description: "Removes Discord new image mosaic", tags: ["image", "mosaic", "media"], + + settings, + patches: [ { find: ".oneByTwoLayoutThreeGrid", replacement: [{ match: /mediaLayoutType:\i\.\i\.MOSAIC/, - replace: 'mediaLayoutType:"RESPONSIVE"' + replace: "mediaLayoutType:$self.mediaLayoutType()", }, { match: /null!==\(\i=\i\.get\(\i\)\)&&void 0!==\i\?\i:"INVALID"/, replace: '"INVALID"', - },] + }] + }, + { + find: "renderAttachments(", + predicate: () => settings.store.inlineVideo, + replacement: { + match: /url:(\i)\.url\}\);return /, + replace: "$&$1.content_type?.startsWith('image/')&&" + } }, { find: "Messages.REMOVE_ATTACHMENT_TOOLTIP_TEXT", @@ -33,10 +63,17 @@ export default definePlugin({ match: /\i===\i\.\i\.MOSAIC/, replace: "true" } - }], + } + ], + + mediaLayoutType() { + return settings.store.mediaLayoutType; + }, + start() { enableStyle(style); }, + stop() { disableStyle(style); } diff --git a/src/plugins/noSystemBadge.discordDesktop/index.ts b/src/plugins/noSystemBadge.discordDesktop/index.ts index 591a0be03..0fbb5332a 100644 --- a/src/plugins/noSystemBadge.discordDesktop/index.ts +++ b/src/plugins/noSystemBadge.discordDesktop/index.ts @@ -25,15 +25,15 @@ export default definePlugin({ authors: [Devs.rushii], patches: [ { - find: "setSystemTrayApplications:function", + find: ",setSystemTrayApplications", replacement: [ { - match: /setBadge:function.+?},/, - replace: "setBadge:function(){}," + match: /setBadge\(\i\).+?},/, + replace: "setBadge(){}," }, { - match: /setSystemTrayIcon:function.+?},/, - replace: "setSystemTrayIcon:function(){}," + match: /setSystemTrayIcon\(\i\).+?},/, + replace: "setSystemTrayIcon(){}," } ] } diff --git a/src/plugins/onePingPerDM/index.ts b/src/plugins/onePingPerDM/index.ts index 37ca87125..ae38343db 100644 --- a/src/plugins/onePingPerDM/index.ts +++ b/src/plugins/onePingPerDM/index.ts @@ -55,10 +55,8 @@ export default definePlugin({ }], isPrivateChannelRead(message: MessageJSON) { const channelType = ChannelStore.getChannel(message.channel_id)?.type; - if (channelType !== ChannelType.DM && channelType !== ChannelType.GROUP_DM) { - return false; - } if ( + (channelType !== ChannelType.DM && channelType !== ChannelType.GROUP_DM) || (channelType === ChannelType.DM && settings.store.channelToAffect === "group_dm") || (channelType === ChannelType.GROUP_DM && settings.store.channelToAffect === "user_dm") || (settings.store.allowMentions && message.mentions.some(m => m.id === UserStore.getCurrentUser().id)) || diff --git a/src/plugins/openInApp/index.ts b/src/plugins/openInApp/index.ts index e26a01eb9..5a2641e2a 100644 --- a/src/plugins/openInApp/index.ts +++ b/src/plugins/openInApp/index.ts @@ -23,7 +23,7 @@ import { showToast, Toasts } from "@webpack/common"; import type { MouseEvent } from "react"; const ShortUrlMatcher = /^https:\/\/(spotify\.link|s\.team)\/.+$/; -const SpotifyMatcher = /^https:\/\/open\.spotify\.com\/(track|album|artist|playlist|user)\/(.+)(?:\?.+?)?$/; +const SpotifyMatcher = /^https:\/\/open\.spotify\.com\/(track|album|artist|playlist|user|episode)\/(.+)(?:\?.+?)?$/; const SteamMatcher = /^https:\/\/(steamcommunity\.com|(?:help|store)\.steampowered\.com)\/.+$/; const EpicMatcher = /^https:\/\/store\.epicgames\.com\/(.+)$/; @@ -55,8 +55,8 @@ export default definePlugin({ { find: "trackAnnouncementMessageLinkClicked({", replacement: { - match: /(?<=handleClick:function\(\)\{return (\i)\}.+?)async function \1\(.+?\)\{/, - replace: "$& if(await $self.handleLink(...arguments)) return;" + match: /(?<=handleClick:function\(\)\{return (\i)\}.+?)function \1\(.+?\)\{/, + replace: "async $& if(await $self.handleLink(...arguments)) return;" } }, // Make Spotify profile activity links open in app on web diff --git a/src/plugins/permissionsViewer/components/RolesAndUsersPermissions.tsx b/src/plugins/permissionsViewer/components/RolesAndUsersPermissions.tsx index 8d4b15790..629880467 100644 --- a/src/plugins/permissionsViewer/components/RolesAndUsersPermissions.tsx +++ b/src/plugins/permissionsViewer/components/RolesAndUsersPermissions.tsx @@ -135,9 +135,9 @@ function RolesAndUsersPermissionsComponent({ permissions, guild, modalProps, hea { permission.type === PermissionType.Role - ? role?.name || "Unknown Role" + ? role?.name ?? "Unknown Role" : permission.type === PermissionType.User - ? (user && getUniqueUsername(user)) || "Unknown User" + ? (user && getUniqueUsername(user)) ?? "Unknown User" : ( @owner diff --git a/src/plugins/pictureInPicture/index.tsx b/src/plugins/pictureInPicture/index.tsx index dc6ddb0b5..ba4aa8387 100644 --- a/src/plugins/pictureInPicture/index.tsx +++ b/src/plugins/pictureInPicture/index.tsx @@ -4,6 +4,8 @@ * SPDX-License-Identifier: GPL-3.0-or-later */ +import "./styles.css"; + import { definePluginSettings } from "@api/Settings"; import ErrorBoundary from "@components/ErrorBoundary"; import { Devs } from "@utils/constants"; @@ -28,8 +30,8 @@ export default definePlugin({ { find: ".nonMediaAttachment]", replacement: { - match: /\.nonMediaAttachment\].{0,10}children:\[\S/, - replace: "$&&&$self.renderPiPButton()," + match: /\.nonMediaAttachment\]:!(\i).{0,10}children:\[(\S)/, + replace: "$&,$1&&$2&&$self.renderPiPButton()," }, }, ], @@ -40,6 +42,7 @@ export default definePlugin({ {tooltipProps => (
diff --git a/src/plugins/previewMessage/index.tsx b/src/plugins/previewMessage/index.tsx index bc6751141..f2634ae6b 100644 --- a/src/plugins/previewMessage/index.tsx +++ b/src/plugins/previewMessage/index.tsx @@ -137,5 +137,5 @@ export default definePlugin({ }, ], - previewIcon: ErrorBoundary.wrap(PreviewButton, { noop: true }), + chatBarIcon: ErrorBoundary.wrap(PreviewButton, { noop: true }), }); diff --git a/src/plugins/showHiddenChannels/index.tsx b/src/plugins/showHiddenChannels/index.tsx index 9cdf30496..95b16d625 100644 --- a/src/plugins/showHiddenChannels/index.tsx +++ b/src/plugins/showHiddenChannels/index.tsx @@ -70,18 +70,27 @@ export default definePlugin({ // RenderLevel defines if a channel is hidden, collapsed in category, visible, etc find: ".CannotShow=", replacement: [ + // Remove the special logic for channels we don't have access to { match: /if\(!\i\.\i\.can\(\i\.\i\.VIEW_CHANNEL.+?{if\(this\.id===\i\).+?threadIds:\i}}/, replace: "" }, + // Do not check for unreads when selecting the render level if the channel is hidden + { + match: /(?=!1===\i.\i\.hasRelevantUnread\(this\.record\))/, + replace: "$self.isHiddenChannel(this.record)||" + }, + // Make channels we dont have access to be the same level as normal ones { match: /(?<=renderLevel:(\i\(this,\i\)\?\i\.Show:\i\.WouldShowIfUncollapsed).+?renderLevel:).+?(?=,)/, replace: (_, renderLevelExpression) => renderLevelExpression }, + // Make channels we dont have access to be the same level as normal ones { match: /(?<=activeJoinedRelevantThreads.+?renderLevel:.+?,threadIds:\i\(this.record.+?renderLevel:)(\i)\..+?(?=,)/, replace: (_, RenderLevels) => `${RenderLevels}.Show` }, + // Remove permission checking for getRenderLevel function { match: /(?<=getRenderLevel\(\i\){.+?return)!\i\.\i\.can\(\i\.\i\.VIEW_CHANNEL,this\.record\)\|\|/, replace: " " @@ -186,13 +195,29 @@ export default definePlugin({ ] }, { - // Hide New unreads box for hidden channels + // Hide the new version of unreads box for hidden channels find: '.displayName="ChannelListUnreadsStore"', replacement: { match: /(?<=if\(null==(\i))(?=.{0,160}?hasRelevantUnread\(\i\))/g, // Global because Discord has multiple methods like that in the same module replace: (_, channel) => `||$self.isHiddenChannel(${channel})` } }, + { + // Make the old version of unreads box not visible for hidden channels + find: "renderBottomUnread(){", + replacement: { + match: /(?=&&\i\.\i\.hasRelevantUnread\((\i\.record)\))/, + replace: "&&!$self.isHiddenChannel($1)" + } + }, + { + // Make the state of the old version of unreads box not include hidden channels + find: ".useFlattenedChannelIdListWithThreads)", + replacement: { + match: /(?=&&\i\.\i\.hasRelevantUnread\((\i)\))/, + replace: "&&!$self.isHiddenChannel($1)" + } + }, // Only render the channel header and buttons that work when transitioning to a hidden channel { find: "Missing channel in Channel.renderHeaderToolbar", @@ -389,6 +414,22 @@ export default definePlugin({ } ] }, + { + // Make the chat input bar channel list contain hidden channels + find: ",queryStaticRouteChannels(", + replacement: [ + { + // Make the getChannels call to GuildChannelStore return hidden channels + match: /(?<=queryChannels\(\i\){.+?getChannels\(\i)(?=\))/, + replace: ",true" + }, + { + // Avoid filtering out hidden channels from the channel list + match: /(?<=queryChannels\(\i\){.+?isGuildChannelType\)\((\i)\.type\))(?=&&!\i\.\i\.can\()/, + replace: "&&!$self.isHiddenChannel($1)" + } + ] + }, { find: "\"^/guild-stages/(\\\\d+)(?:/)?(\\\\d+)?\"", replacement: { diff --git a/src/plugins/showMeYourName/index.tsx b/src/plugins/showMeYourName/index.tsx index 6986f69f2..62d0645d2 100644 --- a/src/plugins/showMeYourName/index.tsx +++ b/src/plugins/showMeYourName/index.tsx @@ -47,7 +47,7 @@ export default definePlugin({ authors: [Devs.Rini, Devs.TheKodeToad], patches: [ { - find: '"Message Username"', + find: ".useCanSeeRemixBadge)", replacement: { match: /(?<=onContextMenu:\i,children:).*?\}/, replace: "$self.renderUsername(arguments[0])}" diff --git a/src/plugins/spotifyControls/spotifyStyles.css b/src/plugins/spotifyControls/spotifyStyles.css index a9b985161..9e585ebec 100644 --- a/src/plugins/spotifyControls/spotifyStyles.css +++ b/src/plugins/spotifyControls/spotifyStyles.css @@ -2,7 +2,7 @@ padding: 0.375rem 0.5rem; border-bottom: 1px solid var(--background-modifier-accent); - --vc-spotify-green: #1db954; /* so cusotm themes can easily change it */ + --vc-spotify-green: #1db954; /* so custom themes can easily change it */ } .theme-light #vc-spotify-player { @@ -167,7 +167,7 @@ } #vc-spotify-progress-bar > [class^="slider"] [class^="grabber"] { - /* these importants are neccessary, it applies a width and height through inline styles */ + /* these importants are necessary, it applies a width and height through inline styles */ height: 10px !important; width: 10px !important; background-color: var(--interactive-normal); diff --git a/src/plugins/typingTweaks/index.tsx b/src/plugins/typingTweaks/index.tsx index 62bcd41f6..d3f4a1409 100644 --- a/src/plugins/typingTweaks/index.tsx +++ b/src/plugins/typingTweaks/index.tsx @@ -112,7 +112,7 @@ export default definePlugin({ { find: "getCooldownTextStyle", replacement: { - match: /(?<=(\i)\.length\?\i.\i\.Messages.THREE_USERS_TYPING\.format\({\i:(\i),\i:(\i),\i:\i}\):)\i\.\i\.Messages\.SEVERAL_USERS_TYPING/, + match: /(?<=(\i)\.length\?\i.\i\.Messages.THREE_USERS_TYPING\.format\({\i:(\i),(?:\i:)?(\i),\i:\i}\):)\i\.\i\.Messages\.SEVERAL_USERS_TYPING/, replace: (_, users, a, b) => `$self.buildSeveralUsers({ a: ${a}, b: ${b}, count: ${users}.length - 2 })` }, predicate: () => settings.store.alternativeFormatting diff --git a/src/plugins/vencordToolbox/index.css b/src/plugins/vencordToolbox/index.css index 8b509868f..a1c85ad50 100644 --- a/src/plugins/vencordToolbox/index.css +++ b/src/plugins/vencordToolbox/index.css @@ -1,12 +1,16 @@ .vc-toolbox-btn, -.vc-toolbox-btn svg { +.vc-toolbox-btn>svg { -webkit-app-region: no-drag; } -.vc-toolbox-btn svg { +.vc-toolbox-btn>svg { color: var(--interactive-normal); } -:is(.vc-toolbox-btn:hover, .vc-toolbox-btn[class*="selected"]) svg { +.vc-toolbox-btn[class*="selected"]>svg { color: var(--interactive-active); } + +.vc-toolbox-btn:hover>svg { + color: var(--interactive-hover); +} diff --git a/src/plugins/vencordToolbox/index.tsx b/src/plugins/vencordToolbox/index.tsx index ba55fdeef..cd266c6f2 100644 --- a/src/plugins/vencordToolbox/index.tsx +++ b/src/plugins/vencordToolbox/index.tsx @@ -89,10 +89,10 @@ function VencordPopout(onClose: () => void) { ); } -function VencordPopoutIcon() { +function VencordPopoutIcon(isShown: boolean) { return ( - - + + ); } @@ -114,7 +114,7 @@ function VencordPopoutButton() { className="vc-toolbox-btn" onClick={() => setShow(v => !v)} tooltip={isShown ? null : "Vencord Toolbox"} - icon={VencordPopoutIcon} + icon={() => VencordPopoutIcon(isShown)} selected={isShown} /> )} diff --git a/src/plugins/viewIcons/index.tsx b/src/plugins/viewIcons/index.tsx index fd6b7b6bf..2da3e21c2 100644 --- a/src/plugins/viewIcons/index.tsx +++ b/src/plugins/viewIcons/index.tsx @@ -173,7 +173,7 @@ export default definePlugin({ patches: [ // Make pfps clickable { - find: "onAddFriend:function", + find: "User Profile Modal - Context Menu", replacement: { match: /\{src:(\i)(?=,avatarDecoration)/, replace: "{src:$1,onClick:()=>$self.openImage($1)" diff --git a/src/plugins/webKeybinds.vencordDesktop/index.ts b/src/plugins/webKeybinds.web/index.ts similarity index 84% rename from src/plugins/webKeybinds.vencordDesktop/index.ts rename to src/plugins/webKeybinds.web/index.ts index 798713d50..12d485aac 100644 --- a/src/plugins/webKeybinds.vencordDesktop/index.ts +++ b/src/plugins/webKeybinds.web/index.ts @@ -18,19 +18,14 @@ import { Devs } from "@utils/constants"; import definePlugin from "@utils/types"; -import { findLazy, mapMangledModuleLazy } from "@webpack"; +import { findByPropsLazy } from "@webpack"; import { ComponentDispatch, FluxDispatcher, NavigationRouter, SelectedGuildStore, SettingsRouter } from "@webpack/common"; -const GuildNavBinds = mapMangledModuleLazy("mod+alt+down", { - CtrlTab: m => m.binds?.at(-1) === "ctrl+tab", - CtrlShiftTab: m => m.binds?.at(-1) === "ctrl+shift+tab", -}); - -const DigitBinds = findLazy(m => m.binds?.[0] === "mod+1"); +const KeyBinds = findByPropsLazy("JUMP_TO_GUILD", "SERVER_NEXT"); export default definePlugin({ name: "WebKeybinds", - description: "Re-adds keybinds missing in the web version of Discord: ctrl+t, ctrl+shift+t, ctrl+tab, ctrl+shift+tab, ctrl+1-9, ctrl+,", + description: "Re-adds keybinds missing in the web version of Discord: ctrl+t, ctrl+shift+t, ctrl+tab, ctrl+shift+tab, ctrl+1-9, ctrl+,. Only works fully on Vesktop/ArmCord, not inside your browser", authors: [Devs.Ven], enabledByDefault: true, @@ -57,13 +52,13 @@ export default definePlugin({ SettingsRouter.open("My Account"); break; case "Tab": - const handler = e.shiftKey ? GuildNavBinds.CtrlShiftTab : GuildNavBinds.CtrlTab; + const handler = e.shiftKey ? KeyBinds.SERVER_PREV : KeyBinds.SERVER_NEXT; handler.action(e); break; default: if (e.key >= "1" && e.key <= "9") { e.preventDefault(); - DigitBinds.action(e, `mod+${e.key}`); + KeyBinds.JUMP_TO_GUILD.action(e, `mod+${e.key}`); } break; } diff --git a/src/utils/types.ts b/src/utils/types.ts index 7b682e9b9..ff2c79af3 100644 --- a/src/utils/types.ts +++ b/src/utils/types.ts @@ -269,7 +269,7 @@ export interface DefinedSettings< store: SettingsStore & PrivateSettings; /** * React hook for getting the settings for this plugin - * @param filter optional filter to avoid rerenders for irrelavent settings + * @param filter optional filter to avoid rerenders for irrelevent settings */ use>(filter?: F[]): Pick & PrivateSettings, F>; /** Definitions of each setting */ diff --git a/src/webpack/common/stores.ts b/src/webpack/common/stores.ts index c4ebd4a95..d10b18664 100644 --- a/src/webpack/common/stores.ts +++ b/src/webpack/common/stores.ts @@ -20,7 +20,7 @@ import { proxyLazy } from "@utils/lazy"; import type * as Stores from "discord-types/stores"; // eslint-disable-next-line path-alias/no-relative -import { filters, findByCode, findByProps, findByPropsLazy, mapMangledModuleLazy } from "../webpack"; +import { filters, findByProps, findByPropsLazy, mapMangledModuleLazy } from "../webpack"; import { waitForStore } from "./internal"; import * as t from "./types/stores"; @@ -84,14 +84,7 @@ export const useStateFromStores: ( idk?: any, isEqual?: (old: T, newer: T) => boolean ) => T - // FIXME: hack to support old stable and new canary - = proxyLazy(() => { - try { - return findByProps("useStateFromStores").useStateFromStores; - } catch { - return findByCode('("useStateFromStores")'); - } - }); + = proxyLazy(() => findByProps("useStateFromStores").useStateFromStores); waitForStore("DraftStore", s => DraftStore = s); waitForStore("UserStore", s => UserStore = s); diff --git a/src/webpack/common/utils.ts b/src/webpack/common/utils.ts index 6de57c92d..04df3c07d 100644 --- a/src/webpack/common/utils.ts +++ b/src/webpack/common/utils.ts @@ -136,11 +136,4 @@ waitFor("parseTopic", m => Parser = m); export let SettingsRouter: any; waitFor(["open", "saveAccountChanges"], m => SettingsRouter = m); -// FIXME: hack to support old stable and new canary -export const PermissionsBits: t.PermissionsBits = proxyLazy(() => { - try { - return find(m => m.Permissions?.ADMINISTRATOR).Permissions; - } catch { - return find(m => typeof m.ADMINISTRATOR === "bigint"); - } -}); +export const PermissionsBits: t.PermissionsBits = proxyLazy(() => find(m => typeof m.Permissions?.ADMINISTRATOR === "bigint").Permissions); diff --git a/src/webpack/patchWebpack.ts b/src/webpack/patchWebpack.ts index 23ef99e24..b81415e61 100644 --- a/src/webpack/patchWebpack.ts +++ b/src/webpack/patchWebpack.ts @@ -29,7 +29,7 @@ let webpackChunk: any[]; const logger = new Logger("WebpackInterceptor", "#8caaee"); if (window[WEBPACK_CHUNK]) { - logger.info(`Patching ${WEBPACK_CHUNK}.push (was already existant, likely from cache!)`); + logger.info(`Patching ${WEBPACK_CHUNK}.push (was already existent, likely from cache!)`); _initWebpack(window[WEBPACK_CHUNK]); patchPush(window[WEBPACK_CHUNK]); } else {