/* * Vencord, a Discord client mod * Copyright (c) 2026 Vendicated and contributors * SPDX-License-Identifier: GPL-3.0-or-later */ import "./style.css"; import { isPluginEnabled } from "@api/PluginManager"; import { definePluginSettings, migrateOldSettingToNewPlugin, migratePluginSetting, migratePluginSettings } from "@api/Settings"; import { Divider } from "@components/Divider"; import { HeadingSecondary } from "@components/Heading"; import { Notice } from "@components/Notice"; import decor from "@plugins/decor"; import { classNameFactory } from "@utils/css"; import { Devs, EquicordDevs } from "@utils/index"; import { t, Translate } from "@utils/translation"; import definePlugin, { OptionType } from "@utils/types"; import { Alerts } from "@webpack/common"; migratePluginSettings("Declutter", "BetterUserArea", "Anammox"); migrateOldSettingToNewPlugin("Declutter", "removeClanTag", "GuildTagSettings", "hideTags"); const migrationsAnammox = [ ["dms", "removeShopAboveDM"], ["quests", "removeQuestsAboveDM"], ["serverBoost", "removeServerBoostInfo"], ["billing", "removeBillingSettings"], ["gift", "removeGiftButton"], ["emojiList", "removeUnavailableEmojiPicker"], ]; for (const [oldKey, newKey] of migrationsAnammox) { migratePluginSetting("Declutter", newKey, oldKey); } const cl = classNameFactory("vc-declutter-"); export const settings = definePluginSettings({ userProfileHeader: { type: OptionType.COMPONENT, component: () => SectionSeparator(t("equicord.declutter.headers.userProfile")), }, removeAvatarDecoration: { type: OptionType.BOOLEAN, description: "Remove avatar decorations.", default: false, disabled: () => isPluginEnabled("Decor"), restartNeeded: true, }, removeNameplate: { type: OptionType.BOOLEAN, description: t("equicord.declutter.settings.removeNameplate"), default: true, restartNeeded: true, }, removeProfileEffect: { type: OptionType.BOOLEAN, description: t("equicord.declutter.settings.removeProfileEffect"), default: true, restartNeeded: true, }, removeClanTag: { type: OptionType.BOOLEAN, description: t("equicord.declutter.settings.removeClanTag"), default: true, restartNeeded: true, }, alwaysShowUsername: { type: OptionType.BOOLEAN, description: t("equicord.declutter.settings.alwaysShowUsername"), default: true, restartNeeded: true }, accessibilityNotice: { type: OptionType.COMPONENT, component: () => ( Discord already has a built-in username style option in Accessibility settings. ) }, friendsListHeader: { type: OptionType.COMPONENT, component: () => SectionSeparator(t("equicord.declutter.headers.friendsList")), }, removeShopAboveDM: { type: OptionType.BOOLEAN, description: t("equicord.declutter.settings.removeShopAboveDM"), default: false, restartNeeded: true, }, removeQuestsAboveDM: { type: OptionType.BOOLEAN, description: t("equicord.declutter.settings.removeQuestsAboveDM"), default: false, restartNeeded: true, }, miscHeader: { type: OptionType.COMPONENT, component: () => SectionSeparator(t("equicord.declutter.headers.misc")), }, removeServerBoostInfo: { type: OptionType.BOOLEAN, description: t("equicord.declutter.settings.removeServerBoostInfo"), default: true, restartNeeded: true, }, removeBillingSettings: { type: OptionType.BOOLEAN, description: t("equicord.declutter.settings.removeBillingSettings"), default: true, restartNeeded: true, }, removeGiftButton: { type: OptionType.BOOLEAN, description: t("equicord.declutter.settings.removeGiftButton"), default: true, restartNeeded: true, }, removeUnavailableEmojiPicker: { type: OptionType.BOOLEAN, description: t("equicord.declutter.settings.removeUnavailableEmojiPicker"), default: true, restartNeeded: true, }, removeAudioMenus: { type: OptionType.BOOLEAN, description: t("equicord.declutter.settings.removeAudioMenus"), default: true, restartNeeded: true }, removeButtonTooltips: { type: OptionType.BOOLEAN, description: t("equicord.declutter.settings.removeButtonTooltips"), default: false, restartNeeded: true }, }); function SectionSeparator(title: string) { return (
{title}
); } export default definePlugin({ name: "Declutter", description: t("equicord.declutter.description"), tags: ["Appearance", "Customisation"], authors: [EquicordDevs.Leon135, Devs.prism, Devs.Kyuuhachi], start() { if (isPluginEnabled("Decor") && settings.store.removeAvatarDecoration) { settings.store.removeAvatarDecoration = false; Alerts.show({ title: "Declutter", body: "Avatar decoration removal has been disabled to prevent conflicts with Decor plugin.", confirmText: "OK", // @ts-expect-error not typed confirmVariant: "critical-primary" }); } }, settings, patches: [ { // Avatar decoration find: "isAvatarDecorationAnimating:", replacement: { match: /(?<=\{avatarDecoration:.{0,40}?)(void 0!==\i\?\i:)\i(?=\)?,canAnimate:)/, replace: "$1null" }, predicate: () => settings.store.removeAvatarDecoration && !isPluginEnabled(decor.name), }, { // Nameplate find: ".MINI_PREVIEW,[", replacement: { match: /function \i\((\i)\)\{(?=let.{1,5}\{nameplate:\i,)/, replace: '$&if($1.placement!=="preview"&&$1.placement!=="mini_preview")return null;' }, predicate: () => settings.store.removeNameplate, }, { // Profile banner animation effect find: "bannerAdjustment,isHovering", replacement: { match: /\i=(\i)=>\{(?=.{0,50}\.useReducedMotion\))/, replace: "$&if(!$1.shopPreview)return null;" }, predicate: () => settings.store.removeProfileEffect, }, { // Clan tag find: ".GuildFeatures.GUILD_TAGS)", replacement: { match: /(?<=\.profile\?\.badge.{0,50}\i\)\{)/, replace: "return false;" }, predicate: () => settings.store.removeClanTag, }, { // Always show username find: ".DISPLAY_NAME_STYLES_COACHMARK)", replacement: { match: /hoverText:(\i),forceHover:\i,children:/g, replace: "hoverText:$1,forceHover:!0,children:" }, predicate: () => settings.store.alwaysShowUsername }, { // Button tooltips in user area find: '"MicrophoneButton"', replacement: [ { // Button tooltips match: /:\{tooltipText:\i\};/, replace: ":{tooltipText:void 0};", predicate: () => settings.store.removeButtonTooltips }, { // Audio menus match: /(?<=#{intl::MUTE}\),)className:\i\.\i,/, replace: "", predicate: () => settings.store.removeAudioMenus }, { // Audio menus match: /,\(0,\i\.jsxs?\)\(\i\.\i,\{.{0,600}#{intl::ACCOUNT_INPUT_OPTIONS}\)\}\)(?=\])/, replace: "", predicate: () => settings.store.removeAudioMenus }, ], }, { // Button tooltips in right click audio settings find: "#{intl::f+DDY/::raw},{outputDeviceName", replacement: [ { // Button tooltips match: /(?<=role:"switch",)tooltipText:\i\}/, replace: "tooltipText:void 0}", predicate: () => settings.store.removeButtonTooltips }, { // Audio menus match: /(?<=#{intl::DEAFEN}\),)className:\i\.\i,/, replace: "", predicate: () => settings.store.removeAudioMenus }, { // Audio menus match: /,\(0,\i\.jsxs?\)\(\i\.\i,\{.{0,650}#{intl::ACCOUNT_OUTPUT_OPTIONS}\)\}\)(?=\])/, replace: "", predicate: () => settings.store.removeAudioMenus } ], }, { // ? Another button tooltips find: "#{intl::USER_SETTINGS_WITH_BUILD_OVERRIDE}", replacement: { match: /tooltipText:\i,tooltipPositionKey/, replace: "tooltipText:void 0,tooltipPositionKey" }, predicate: () => settings.store.removeButtonTooltips }, { // Above DMs section, shops and quests find: 'tutorialId:"direct-messages"', replacement: [ { match: /"nitro-tab-group"\)/, replace: "$&&&undefined", predicate: () => settings.store.removeShopAboveDM, }, { match: /"discord-shop"\)/, replace: "$&&&undefined", predicate: () => settings.store.removeShopAboveDM }, { match: /"quests"\)/, replace: "$&&&undefined", predicate: () => settings.store.removeQuestsAboveDM }, ], }, { // Above DMs section, keyboard navigation find: ".hasLibraryApplication()&&!", replacement: [ { match: /\i\.\i\.APPLICATION_STORE,/, replace: "/*$&*/", }, { match: /\i\.\i\.COLLECTIBLES_SHOP,/, replace: "/*$&*/", }, ], predicate: () => settings.store.removeShopAboveDM, }, { // Channel list server boost progress bar find: "useGuildActionRow", replacement: { match: /(GUILD_NEW_MEMBER_ACTIONS_PROGRESS_BAR\)):(\i(?:\.premiumProgressBarEnabled)?)/, replace: "$1:null" }, predicate: () => settings.store.removeServerBoostInfo, }, { // Billing settings find: ".BILLING_SECTION,", replacement: { match: /(?<=buildLayout:\(\)=>)\[.+?\]/, replace: "[]", }, predicate: () => settings.store.removeBillingSettings, }, { // Gift button find: '"sticker")', replacement: { match: /&&\i\.push\(\([^&]*?,"gift"\)\)/, replace: "", }, predicate: () => settings.store.removeGiftButton, }, { // Emoji list find: "#{intl::EMOJI_PICKER_EXPAND_EMOJI_SECTION}),size:", replacement: { match: /(\i)=\i\|\|!\i&&\i.\i.isEmojiCategoryNitroLocked\(\{[^}]*\}\);/, replace: "$&$1||" }, predicate: () => settings.store.removeUnavailableEmojiPicker, }, { // Emoji category list find: "#{intl::EMOJI_CATEGORY_TOP_GUILD_EMOJI},{guildName:", replacement: { match: /(?<=(\i)\.unshift\((\i)\):)(?=\1\.push\(\2\))/, replace: "$2.isNitroLocked||" }, predicate: () => settings.store.removeUnavailableEmojiPicker, } ], });