feat(declutter): combine functionality of annamox & betteruserarea while adding new selectors to remove unwanted ui elements (#846)

* feat(HidePersonalization): Add a plugin that allows to hide personalization features such as avatar decorations, nameplates, profile effects, and clan tags with customizable options

* fix(HidePersonalization): Fix no predicate bool handling on clan tags

* feat(Cleanify): Introduce Cleanify plugin to enhance UI customization and migrate settings from BetterUserArea and Anammox. This plugin combines the functionality of them and adds new features

* rename(Cleanify -> Declutter): Rename plugin and add Questify conflict detection

* Update index.tsx

* Update index.tsx

* Update index.tsx

* Update index.tsx

* Update index.tsx

---------

Co-authored-by: thororen1234 <78185467+thororen1234@users.noreply.github.com>
This commit is contained in:
Jakub Bednarski 2026-03-02 03:06:15 +01:00 • committed by GitHub
parent 59a72fcf81
commit ce64a1c2e4
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 340 additions and 271 deletions

View file

@ -5,7 +5,7 @@
*/
import { isPluginEnabled } from "@api/PluginManager";
import betterUserArea from "@equicordplugins/betterUserArea";
import declutter from "@equicordplugins/declutter";
import { Devs } from "@utils/constants";
import definePlugin from "@utils/types";
import { findCssClassesLazy } from "@webpack";
@ -43,6 +43,6 @@ export default definePlugin({
},
shouldHideTooltips() {
return isPluginEnabled(betterUserArea.name) && betterUserArea.settings.store.removeButtonTooltips;
return isPluginEnabled(declutter.name) && declutter.settings.store.removeButtonTooltips;
}
});

View file

@ -1,139 +0,0 @@
/*
* 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 { Devs } from "@utils/constants";
import definePlugin, { OptionType } from "@utils/types";
export const settings = definePluginSettings({
dms: {
type: OptionType.BOOLEAN,
default: true,
description: "Remove shops above DMs list",
restartNeeded: true,
},
quests: {
type: OptionType.BOOLEAN,
default: false,
description: "Remove quests above DMs list",
restartNeeded: true,
},
serverBoost: {
type: OptionType.BOOLEAN,
default: true,
description: "Remove server boost info above channel list",
restartNeeded: true,
},
billing: {
type: OptionType.BOOLEAN,
default: true,
description: "Remove billing settings",
restartNeeded: true,
},
gift: {
type: OptionType.BOOLEAN,
default: true,
description: "Remove gift button",
restartNeeded: true,
},
emojiList: {
type: OptionType.BOOLEAN,
default: true,
description: "Remove unavailable categories from the emoji picker",
restartNeeded: true,
},
});
export default definePlugin({
name: "Anammox",
description: "Hides various features related to nitro and the store",
authors: [Devs.Kyuuhachi],
settings,
patches: [
{
// Above DMs, mouse nav
find: 'tutorialId:"direct-messages"',
replacement: [
{
match: /"nitro-tab-group"\)/,
replace: "$&&&undefined",
predicate: () => settings.store.dms
},
{
match: /"discord-shop"\)/,
replace: "$&&&undefined",
predicate: () => settings.store.dms
},
{
match: /"quests"\)/,
replace: "$&&&undefined",
predicate: () => settings.store.quests
},
],
},
{
// Above DMs, keyboard nav
find: ".hasLibraryApplication()&&!",
replacement: [
{
match: /\i\.\i\.APPLICATION_STORE,/,
replace: "/*$&*/",
},
{
match: /\i\.\i\.COLLECTIBLES_SHOP,/,
replace: "/*$&*/",
},
],
predicate: () => settings.store.dms,
},
{
// Channel list server boost progress bar
find: "useGuildActionRow",
replacement: {
match: /(GUILD_NEW_MEMBER_ACTIONS_PROGRESS_BAR\)):(\i(?:\.premiumProgressBarEnabled)?)/,
replace: "$1:null"
},
predicate: () => settings.store.serverBoost,
},
{
// Settings, sidebar
find: ".BILLING_SECTION,",
replacement: {
match: /(?<=buildLayout:\(\)=>)\[.+?\]/,
replace: "[]",
},
predicate: () => settings.store.billing,
},
{
// Gift button
find: '"sticker")',
replacement: {
match: /&&\i\.push\(\([^&]*?,"gift"\)\)/,
replace: "",
},
predicate: () => settings.store.gift,
},
{
// Emoji list
find: "#{intl::EMOJI_PICKER_EXPAND_EMOJI_SECTION}),size:",
replacement: {
match: /(\i)=\i\|\|!\i&&\i.\i.isEmojiCategoryNitroLocked\(\{[^}]*\}\);/,
replace: "$&$1||"
},
predicate: () => settings.store.emojiList,
},
{
// 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.emojiList,
}
],
});

View file

@ -1,130 +0,0 @@
/*
* 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 { Devs } from "@utils/constants";
import definePlugin, { OptionType } from "@utils/types";
const settings = definePluginSettings({
removeNameplate: {
type: OptionType.BOOLEAN,
description: "Remove nameplate styling.",
default: true,
restartNeeded: true
},
removeAudioMenus: {
type: OptionType.BOOLEAN,
description: "Remove menus next to mute and deafen buttons.",
default: true,
restartNeeded: true
},
alwaysShowUsername: {
type: OptionType.BOOLEAN,
description: "Always show username instead of status.",
default: true,
restartNeeded: true
},
removeButtonTooltips: {
type: OptionType.BOOLEAN,
description: "Remove button tooltips.",
default: false,
restartNeeded: true
},
removeAvatarDecoration: {
type: OptionType.BOOLEAN,
description: "Remove avatar decoration.",
default: true,
restartNeeded: true
},
removeUsernameStyles: {
type: OptionType.BOOLEAN,
description: "Remove username colors and effects.",
default: true,
restartNeeded: true
}
});
export default definePlugin({
name: "BetterUserArea",
description: "Customize and make the user area more clean.",
authors: [Devs.prism],
settings,
patches: [
{
find: ".NITRO_PRIVACY_PERK_BETA_COACHMARK));",
replacement: [
{
match: /,nameplate:\i,selectedGuildId:(\i),avatarDecoration/,
replace: ",nameplate:null,selectedGuildId:$1,avatarDecoration",
predicate: () => settings.store.removeNameplate
},
{
match: /hoverText:(\i),forceHover:\i,children:/g,
replace: "hoverText:$1,forceHover:!0,children:",
predicate: () => settings.store.alwaysShowUsername
},
{
match: /avatarDecoration:(.{0,70}),size:/,
replace: "avatarDecoration:void 0,size:",
predicate: () => settings.store.removeAvatarDecoration
},
{
match: /displayNameStyles:(\i),/,
replace: "displayNameStyles:void 0,",
predicate: () => settings.store.removeUsernameStyles
}
],
},
{
find: '"MicrophoneButton"',
replacement: [
{
match: /:\{tooltipText:\i\};/,
replace: ":{tooltipText:void 0};",
predicate: () => settings.store.removeButtonTooltips
},
{
match: /(?<=#{intl::MUTE}\),)className:\i\.\i,/,
replace: "",
predicate: () => settings.store.removeAudioMenus
},
{
match: /,\(0,\i\.jsxs?\)\(\i\.\i,\{.{0,600}#{intl::ACCOUNT_INPUT_OPTIONS}\)\}\)(?=\])/,
replace: "",
predicate: () => settings.store.removeAudioMenus
},
],
},
{
find: "#{intl::f+DDY/::raw},{outputDeviceName",
replacement: [
{
match: /(?<=role:"switch",)tooltipText:\i\}/,
replace: "tooltipText:void 0}",
predicate: () => settings.store.removeButtonTooltips
},
{
match: /(?<=#{intl::DEAFEN}\),)className:\i\.\i,/,
replace: "",
predicate: () => settings.store.removeAudioMenus
},
{
match: /,\(0,\i\.jsxs?\)\(\i\.\i,\{.{0,650}#{intl::ACCOUNT_OUTPUT_OPTIONS}\)\}\)(?=\])/,
replace: "",
predicate: () => settings.store.removeAudioMenus
}
],
},
{
find: "#{intl::USER_SETTINGS_WITH_BUILD_OVERRIDE}",
replacement: {
match: /tooltipText:\i,tooltipPositionKey/,
replace: "tooltipText:void 0,tooltipPositionKey"
},
predicate: () => settings.store.removeButtonTooltips
},
],
});

View file

@ -0,0 +1,334 @@
/*
* Vencord, a Discord client mod
* Copyright (c) 2026 Vendicated and contributors
* SPDX-License-Identifier: GPL-3.0-or-later
*/
import { definePluginSettings, migratePluginSetting, migratePluginSettings } from "@api/Settings";
import { HeadingSecondary } from "@components/Heading";
import { Devs, EquicordDevs } from "@utils/index";
import definePlugin, { OptionType } from "@utils/types";
migratePluginSettings("Declutter", "BetterUserArea", "Anammox");
const migrationsAnammox = [
["dms", "removeShopAboveDM"],
["quests", "removeQuestsAboveDM"],
["serverBoost", "removeServerBoostInfo"],
["billing", "removeBillingSettings"],
["gift", "removeGiftButton"],
["emojiList", "removeUnavailableEmojiPicker"],
];
for (const [oldKey, newKey] of migrationsAnammox) {
migratePluginSetting("Anammox", newKey, oldKey);
}
export const settings = definePluginSettings({
userProfileHeader: {
type: OptionType.COMPONENT,
component: () => SectionSeparator("User Profile"),
},
removeAvatarDecoration: {
type: OptionType.BOOLEAN,
description: "Remove avatar decorations.",
default: true,
restartNeeded: true,
},
removeNameplate: {
type: OptionType.BOOLEAN,
description: "Remove nameplates.",
default: true,
restartNeeded: true,
},
removeProfileEffect: {
type: OptionType.BOOLEAN,
description: "Remove profile animation effects on open.",
default: true,
restartNeeded: true,
},
removeClanTag: {
type: OptionType.BOOLEAN,
description: "Remove clan tags.",
default: true,
restartNeeded: true,
},
alwaysShowUsername: {
type: OptionType.BOOLEAN,
description: "Always show username instead of status.",
default: true,
restartNeeded: true
},
removeUsernameStyles: {
type: OptionType.BOOLEAN,
description: "Remove username colors and effects.",
default: true,
restartNeeded: true
},
friendsListHeader: {
type: OptionType.COMPONENT,
component: () => SectionSeparator("Above Friends/DMs List"),
},
removeShopAboveDM: {
type: OptionType.BOOLEAN,
description: "Remove shops above DMs list.",
default: true,
restartNeeded: true,
},
removeQuestsAboveDM: {
type: OptionType.BOOLEAN,
description: "Remove quests above DMs list.",
default: false,
restartNeeded: true,
},
miscHeader: {
type: OptionType.COMPONENT,
component: () => SectionSeparator("Misc"),
},
removeServerBoostInfo: {
type: OptionType.BOOLEAN,
description: "Remove server boost info above channel list.",
default: true,
restartNeeded: true,
},
removeBillingSettings: {
type: OptionType.BOOLEAN,
description: "Remove billing settings.",
default: true,
restartNeeded: true,
},
removeGiftButton: {
type: OptionType.BOOLEAN,
description: "Remove gift button.",
default: true,
restartNeeded: true,
},
removeUnavailableEmojiPicker: {
type: OptionType.BOOLEAN,
description: "Remove unavailable categories from the emoji picker.",
default: true,
restartNeeded: true,
},
removeAudioMenus: {
type: OptionType.BOOLEAN,
description: "Remove menus next to mute and deafen buttons.",
default: true,
restartNeeded: true
},
removeButtonTooltips: {
type: OptionType.BOOLEAN,
description: "Remove button tooltips.",
default: false,
restartNeeded: true
},
});
function SectionSeparator(title: string) {
return (
<>
<hr style={{ width: "100%" }} />
<HeadingSecondary>{title}</HeadingSecondary>
<hr style={{ width: "100%" }} />
</>
);
}
export default definePlugin({
name: "Declutter",
description: "Declutter discord ui by removing unwanted elements such as profile customizations, shops, quests and more.",
authors: [EquicordDevs.Leon135, Devs.prism, Devs.Kyuuhachi],
settings,
patches: [
{
// Avatar decoration
find: "getAvatarDecorationURL:",
replacement: {
match: /function \i\(\i\)\{(?=.{0,10}avatarDecoration)/,
replace: "$&return null;"
},
predicate: () => settings.store.removeAvatarDecoration,
},
{
// Nameplate
find: "#{intl::AVATAR_MALLOW}",
replacement: {
match: /function \i\(\i\)\{(?=.{0,25}skuId:)/,
replace: "$&return null;"
},
predicate: () => settings.store.removeNameplate,
},
{
// Profile banner animation effect
find: "bannerAdjustment,noBorderRadius",
replacement: {
match: /\i=\i=>\{(?=.{0,50}\.useReducedMotion\))/,
replace: "$&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,
},
{
// Username styles and allways show username
find: ".NITRO_PRIVACY_PERK_BETA_COACHMARK));",
replacement: [
{
match: /displayNameStyles:(\i),/,
replace: "displayNameStyles:void 0,",
predicate: () => settings.store.removeUsernameStyles
},
{
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,
}
],
});

View file

@ -1260,6 +1260,10 @@ export const EquicordDevs = Object.freeze({
name: "yash",
id: 889150838658977874n,
},
Leon135: {
name: "Leon135",
id: 309275452231385088n,
}
} satisfies Record<string, Dev>);
// iife so #__PURE__ works correctly