/*
* Vencord, a Discord client mod
* Copyright (c) 2024 Vendicated and contributors
* SPDX-License-Identifier: GPL-3.0-or-later
*/
import "./style.css";
import { findGroupChildrenByChildId, NavContextMenuPatchCallback } from "@api/ContextMenu";
import ErrorBoundary from "@components/ErrorBoundary";
import { Devs, EquicordDevs } from "@utils/constants";
import definePlugin from "@utils/types";
import { ChannelStore, Menu } from "@webpack/common";
import { Channel, Message } from "discord-types/general";
import { JSX } from "react";
import ChannelsTabsContainer from "./components/ChannelTabsContainer";
import { BasicChannelTabsProps, createTab, settings } from "./util";
import * as ChannelTabsUtils from "./util";
const contextMenuPatch: NavContextMenuPatchCallback = (children, props: { channel: Channel, messageId?: string; }) =>
() => {
const { channel, messageId } = props;
const group = findGroupChildrenByChildId("channel-copy-link", children);
group?.push(
createTab({
guildId: channel.guild_id,
channelId: channel.id
}, true, messageId)}
/>
);
};
export default definePlugin({
name: "ChannelTabs",
description: "Group your commonly visited channels in tabs, like a browser",
authors: [Devs.TheSun, Devs.TheKodeToad, EquicordDevs.keifufu, Devs.Nickyux],
dependencies: ["ContextMenuAPI"],
contextMenus: {
"channel-mention-context": contextMenuPatch,
"channel-context": contextMenuPatch
},
patches: [
// add the channel tab container at the top
{
find: ".COLLECTIBLES_SHOP_FULLSCREEN))",
replacement: {
match: /(\?void 0:(\i)\.channelId.{0,300})\i\.Fragment,{/,
replace: "$1$self.render,{currentChannel:$2,"
}
},
// ctrl click to open in new tab in inbox unread
{
find: ".messageContainer,onKeyDown",
replacement: {
match: /.jumpButton,onJump:\i=>(\i)\(\i,(\i)\.id\)/,
replace: ".jumpButton,onJump: event => { if (event.ctrlKey) $self.open($2); else $1(event, $2.id) }"
}
},
// ctrl click to open in new tab in inbox mentions
{
find: ".deleteRecentMention(",
replacement: {
match: /(?<=.jumpMessageButton,onJump:)(\i)(?=.{0,20}message:(\i))/,
replace: "event => { if (event.ctrlKey) $self.open($2); else $1(event) }"
}
},
// ctrl click to open in new tab in search results
{
find: "(this,\"handleMessageClick\"",
replacement: {
match: /(?<=(\i)\.isSearchHit\));(?=null!=(\i))/,
replace: ";if ($1.ctrlKey) return $self.open($2);"
}
},
// prevent issues with the pins/inbox popouts being too tall
{
find: ".messagesPopoutWrap",
replacement: {
match: /\i&&\((\i).maxHeight.{0,5}\)/,
replace: "$&;$1.maxHeight-=$self.containerHeight"
}
}
],
settings,
containerHeight: 0,
render({ currentChannel, children }: {
currentChannel: BasicChannelTabsProps,
children: JSX.Element;
}) {
return (
<>
{children}
>
);
},
open(message: Message) {
const tab = {
channelId: message.channel_id,
guildId: ChannelStore.getChannel(message.channel_id)?.guild_id,
compact: false
};
createTab(tab, false, message.id);
},
util: ChannelTabsUtils,
});