mirror of
https://github.com/Vendicated/Vencord.git
synced 2025-01-30 19:26:22 +00:00
230 lines
9.7 KiB
TypeScript
230 lines
9.7 KiB
TypeScript
|
/*
|
||
|
* 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 <https://www.gnu.org/licenses/>.
|
||
|
*/
|
||
|
|
||
|
import { definePluginSettings } from "@api/Settings";
|
||
|
import { Devs } from "@utils/constants";
|
||
|
import definePlugin, { OptionType } from "@utils/types";
|
||
|
import { findByPropsLazy, findStoreLazy } from "@webpack";
|
||
|
import { FluxDispatcher, i18n } from "@webpack/common";
|
||
|
|
||
|
import FolderSideBar from "./FolderSideBar";
|
||
|
|
||
|
const GuildFolderStore = 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 GuildFolderStore.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",
|
||
|
restartNeeded: true,
|
||
|
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
|
||
|
}
|
||
|
});
|
||
|
|
||
|
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 everything but the servers and folders from the GuildsBar Guild List children
|
||
|
{
|
||
|
match: /lastTargetNode:\i\[\i\.length-1\].+?Fragment.+?\]}\)\]/,
|
||
|
replace: '$&.filter($self.makeGuildsBarGuildListFilter(typeof isBetterFolders!=="undefined"?isBetterFolders:false))'
|
||
|
},
|
||
|
// 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(typeof isBetterFolders!=="undefined"?isBetterFolders:false))'
|
||
|
},
|
||
|
// 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,'
|
||
|
},
|
||
|
// Avoid rendering servers that are not in folders in the Better Folders sidebar
|
||
|
{
|
||
|
match: /(?<=\.Messages\.SERVERS.+?switch\((\i)\.type\){case \i\.\i\.FOLDER:.+?GUILD:)/,
|
||
|
replace: 'if((typeof isBetterFolders!=="undefined"?isBetterFolders:false)&&$1.parentId==null)return null;'
|
||
|
}
|
||
|
]
|
||
|
},
|
||
|
{
|
||
|
find: ".FOLDER_ITEM_GUILD_ICON_MARGIN);",
|
||
|
replacement: [
|
||
|
// Create the isBetterFolders variable in the nested folders component (the parent exports all the props so we don't have to patch it)
|
||
|
{
|
||
|
match: /(?<=let{folderNode:\i,setNodeRef:\i,)/,
|
||
|
replace: "isBetterFolders,"
|
||
|
},
|
||
|
// 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
|
||
|
{
|
||
|
match: /(?<=let{folderNode:\i,setNodeRef:\i,.+?expanded:(\i).+?;)(?=let)/,
|
||
|
replace: '$1=(typeof isBetterFolders!=="undefined"?isBetterFolders:false)?$1:false;'
|
||
|
},
|
||
|
// If we are rendering the Better Folders sidebar, we filter out folders that are not expanded
|
||
|
{
|
||
|
match: /(?=return\(0,\i.\i\)\("div")(?<=selected:\i,expanded:(\i),.+?)/,
|
||
|
replace: (_, expanded) => `if((typeof isBetterFolders!=="undefined"?isBetterFolders:false)&&!${expanded})return null;`
|
||
|
}
|
||
|
// This code is required for the plugin to work, but we don't need it right now because we are making Discord think the folder is always collapsed
|
||
|
// If we no longer want to make Discord think the folder is always collapsed, we can use this code for the plugin to work
|
||
|
// One reason to no longer want that is to make better icons (the mini guild icons) no longer show
|
||
|
/* // Disable expanding and collapsing folders transition in the normal GuildsBar sidebar
|
||
|
{
|
||
|
match: /(?<=\.Messages\.SERVER_FOLDER_PLACEHOLDER.+?useTransition\)\()/,
|
||
|
replace: '(typeof isBetterFolders!=="undefined"?isBetterFolders:false)&&'
|
||
|
},
|
||
|
// If we are rendering the normal GuildsBar sidebar, we avoid rendering guilds from folders that are expanded
|
||
|
{
|
||
|
match: /expandedFolderBackground,.+?,(?=\i\(\(\i,\i,\i\)=>{let{key.{0,45}ul)(?<=selected:\i,expanded:(\i),.+?)/,
|
||
|
replace: (m, expanded) => `${m}((typeof isBetterFolders!=="undefined"?isBetterFolders:false)||!${expanded})&&`
|
||
|
} */
|
||
|
]
|
||
|
},
|
||
|
{
|
||
|
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;
|
||
|
});
|
||
|
}
|
||
|
}
|
||
|
},
|
||
|
|
||
|
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;
|
||
|
};
|
||
|
},
|
||
|
|
||
|
FolderSideBar: guildsBarProps => <FolderSideBar {...guildsBarProps} />,
|
||
|
|
||
|
closeFolders
|
||
|
});
|