diff --git a/src/equicordplugins/channelTabs/components/ChannelTabsContainer.tsx b/src/equicordplugins/channelTabs/components/ChannelTabsContainer.tsx index 20ad46e5..8ee35fc3 100644 --- a/src/equicordplugins/channelTabs/components/ChannelTabsContainer.tsx +++ b/src/equicordplugins/channelTabs/components/ChannelTabsContainer.tsx @@ -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 (
); -} +} \ No newline at end of file diff --git a/src/equicordplugins/channelTabs/index.tsx b/src/equicordplugins/channelTabs/index.tsx index 6c5aaf10..f0cc1b4f 100644 --- a/src/equicordplugins/channelTabs/index.tsx +++ b/src/equicordplugins/channelTabs/index.tsx @@ -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, -}); +}); \ No newline at end of file diff --git a/src/equicordplugins/channelTabs/style.css b/src/equicordplugins/channelTabs/style.css index 2d4f187a..b99f4c2e 100644 --- a/src/equicordplugins/channelTabs/style.css +++ b/src/equicordplugins/channelTabs/style.css @@ -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 */ diff --git a/src/equicordplugins/channelTabs/util/constants.tsx b/src/equicordplugins/channelTabs/util/constants.tsx index 04e2b078..7d72f16c 100644 --- a/src/equicordplugins/channelTabs/util/constants.tsx +++ b/src/equicordplugins/channelTabs/util/constants.tsx @@ -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"); \ No newline at end of file diff --git a/src/equicordplugins/channelTabs/util/tabs.tsx b/src/equicordplugins/channelTabs/util/tabs.tsx index 3deb257f..74773495 100644 --- a/src/equicordplugins/channelTabs/util/tabs.tsx +++ b/src/equicordplugins/channelTabs/util/tabs.tsx @@ -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(count).fill(
); -} +} \ No newline at end of file