mirror of
https://github.com/Equicord/Equicord.git
synced 2025-06-20 11:57:02 -04:00
feat(ChannelTabs): Improves tab management/behaviour (#285)
* basically instead of changing the current tab: -if there is a tab for that channel: swap to the channel tab -if there isnt a tab for that channel it creates a new one -there is a 3 second (you can change it in settings) grace period for when you are quickly switching tabs so your tabs dont get filled also added background (and border to the active tab) to the tabs so it works better with custom themes that have image backgrounds * made the improvements settings * better regex (ty thororen) * Update style.css --------- Co-authored-by: thororen <78185467+thororen1234@users.noreply.github.com>
This commit is contained in:
parent
dd6920d20a
commit
6096013c65
5 changed files with 100 additions and 10 deletions
|
@ -52,16 +52,25 @@ export default function ChannelsTabsContainer(props: BasicChannelTabsProps) {
|
|||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
(Vencord.Plugins.plugins.ChannelTabs as any).containerHeight = ref.current?.clientHeight;
|
||||
if (ref.current) {
|
||||
try {
|
||||
(Vencord.Plugins.plugins.ChannelTabs as any).containerHeight = ref.current.clientHeight;
|
||||
} catch { }
|
||||
}
|
||||
}, [userId, showBookmarkBar]);
|
||||
|
||||
useEffect(() => {
|
||||
_update();
|
||||
}, [widerTabsAndBookmarks]);
|
||||
|
||||
useEffect(() => {
|
||||
if (userId) {
|
||||
handleChannelSwitch(props);
|
||||
saveTabs(userId);
|
||||
}
|
||||
}, [userId, props.channelId, props.guildId]);
|
||||
|
||||
if (!userId) return null;
|
||||
handleChannelSwitch(props);
|
||||
saveTabs(userId);
|
||||
|
||||
return (
|
||||
<div
|
||||
|
@ -121,4 +130,4 @@ export function ChannelTabsPreview(p) {
|
|||
</Flex>
|
||||
</>
|
||||
);
|
||||
}
|
||||
}
|
|
@ -15,7 +15,7 @@ import { Channel, Message } from "discord-types/general";
|
|||
import { JSX } from "react";
|
||||
|
||||
import ChannelsTabsContainer from "./components/ChannelTabsContainer";
|
||||
import { BasicChannelTabsProps, createTab, settings } from "./util";
|
||||
import { BasicChannelTabsProps, createTab, handleChannelSwitch, settings } from "./util";
|
||||
import * as ChannelTabsUtils from "./util";
|
||||
|
||||
const contextMenuPatch: NavContextMenuPatchCallback = (children, props: { channel: Channel, messageId?: string; }) =>
|
||||
|
@ -52,6 +52,14 @@ export default definePlugin({
|
|||
replace: "$1$4$self.render,{currentChannel:$2,children:$3})$5"
|
||||
}
|
||||
},
|
||||
// intercept channel navigation to switch/create tabs
|
||||
{
|
||||
find: "transitionToGuild",
|
||||
replacement: {
|
||||
match: /transitionToGuild\(([^,]+),([^)]+)\)/,
|
||||
replace: "$&;$self.handleNavigation($1,$2)"
|
||||
}
|
||||
},
|
||||
// ctrl click to open in new tab in inbox unread
|
||||
{
|
||||
find: ".messageContainer,onKeyDown",
|
||||
|
@ -113,5 +121,14 @@ export default definePlugin({
|
|||
createTab(tab, false, message.id);
|
||||
},
|
||||
|
||||
handleNavigation(guildId: string, channelId: string) {
|
||||
if (!guildId || !channelId) return;
|
||||
|
||||
// wait for discord to update channel data
|
||||
requestAnimationFrame(() => {
|
||||
handleChannelSwitch({ guildId, channelId });
|
||||
});
|
||||
},
|
||||
|
||||
util: ChannelTabsUtils,
|
||||
});
|
||||
});
|
|
@ -145,6 +145,9 @@
|
|||
width: 12rem;
|
||||
min-width: 0;
|
||||
margin-right: 0.25rem;
|
||||
background-color: var(--background-primary);
|
||||
border: 1px solid var(--background-modifier-accent);
|
||||
transition: background-color 0.15s ease;
|
||||
}
|
||||
|
||||
.vc-channeltabs-tab.vc-channeltabs-wider:not(.vc-channeltabs-tab-compact) {
|
||||
|
@ -159,6 +162,7 @@
|
|||
.vc-channeltabs-tab-selected {
|
||||
background: var(--bg-overlay-selected);
|
||||
background-color: var(--background-modifier-selected);
|
||||
border-color: var(--brand-500);
|
||||
}
|
||||
|
||||
/* channel type container */
|
||||
|
|
|
@ -71,7 +71,32 @@ export const settings = definePluginSettings({
|
|||
type: OptionType.BOOLEAN,
|
||||
default: false,
|
||||
restartNeeded: false
|
||||
},
|
||||
switchToExistingTab: {
|
||||
type: OptionType.BOOLEAN,
|
||||
description: "Switch to tab if it already exists for the channel you're navigating to",
|
||||
default: false,
|
||||
restartNeeded: false
|
||||
},
|
||||
createNewTabIfNotExists: {
|
||||
type: OptionType.BOOLEAN,
|
||||
description: "Create a new tab if one doesn't exist for the channel you're navigating to",
|
||||
default: false,
|
||||
restartNeeded: false
|
||||
},
|
||||
enableRapidNavigation: {
|
||||
type: OptionType.BOOLEAN,
|
||||
description: "Enable rapid navigation behavior - quickly navigating between channels will replace the current tab instead of creating new ones",
|
||||
default: false,
|
||||
restartNeeded: false
|
||||
},
|
||||
rapidNavigationThreshold: {
|
||||
type: OptionType.SLIDER,
|
||||
description: "Time window (in milliseconds) for rapid navigation. Within this time, new channels replace the current tab instead of creating new ones.",
|
||||
markers: [500, 1000, 1500, 2000, 3000, 5000, 10000],
|
||||
default: 3000,
|
||||
stickToMarkers: false,
|
||||
}
|
||||
});
|
||||
|
||||
export const CircleQuestionIcon = findComponentByCodeLazy("10.58l-3.3-3.3a1");
|
||||
export const CircleQuestionIcon = findComponentByCodeLazy("10.58l-3.3-3.3a1");
|
|
@ -128,11 +128,46 @@ export function closeTabsToTheLeft(id: number) {
|
|||
else update();
|
||||
}
|
||||
|
||||
let lastNavigationTime = 0;
|
||||
|
||||
export function handleChannelSwitch(ch: BasicChannelTabsProps) {
|
||||
const tab = openTabs.find(c => c.id === currentlyOpenTab);
|
||||
if (tab === undefined) return logger.error("Couldn't find the currently open channel " + currentlyOpenTab, openTabs);
|
||||
const existingTab = openTabs.find(tab => tab.channelId === ch.channelId && tab.guildId === ch.guildId);
|
||||
|
||||
if (tab.channelId !== ch.channelId) openTabs[openTabs.indexOf(tab)] = { id: tab.id, compact: tab.compact, ...ch };
|
||||
// First check: switch to existing tab if setting enabled and tab exists
|
||||
if (settings.store.switchToExistingTab && existingTab) {
|
||||
moveToTab(existingTab.id);
|
||||
return;
|
||||
}
|
||||
|
||||
// Second check: create new tab if setting enabled
|
||||
if (settings.store.createNewTabIfNotExists) {
|
||||
// Apply rapid navigation logic when creating new tabs
|
||||
const now = Date.now();
|
||||
const isRapidNavigation = now - lastNavigationTime < settings.store.rapidNavigationThreshold;
|
||||
lastNavigationTime = now;
|
||||
|
||||
if (isRapidNavigation && settings.store.enableRapidNavigation) {
|
||||
// Replace current tab content instead of creating new one
|
||||
const currentTab = openTabs.find(t => t.id === currentlyOpenTab);
|
||||
if (currentTab) {
|
||||
currentTab.channelId = ch.channelId;
|
||||
currentTab.guildId = ch.guildId;
|
||||
update();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Create new tab (normal behavior)
|
||||
createTab(ch, true);
|
||||
return;
|
||||
}
|
||||
|
||||
// Default behavior: replace current tab content
|
||||
if (tab && tab.channelId !== ch.channelId) {
|
||||
openTabs[openTabs.indexOf(tab)] = { id: tab.id, compact: tab.compact, ...ch };
|
||||
update();
|
||||
}
|
||||
}
|
||||
|
||||
export function hasClosedTabs() {
|
||||
|
@ -271,4 +306,4 @@ export function useGhostTabs() {
|
|||
setCount(0);
|
||||
};
|
||||
return new Array<JSX.Element>(count).fill(<div className={cl("tab", "ghost-tab")} />);
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue