ContentWarning: Add OnClick Setting
This commit is contained in:
parent
2b2cb6a17e
commit
3719a7520d
6 changed files with 335 additions and 204 deletions
|
|
@ -4,8 +4,11 @@
|
|||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import "./styles.css";
|
||||
|
||||
import { DataStore } from "@api/index";
|
||||
import { definePluginSettings } from "@api/Settings";
|
||||
import { classNameFactory } from "@api/Styles";
|
||||
import { Flex } from "@components/Flex";
|
||||
import { HeadingTertiary } from "@components/Heading";
|
||||
import { DeleteIcon } from "@components/Icons";
|
||||
|
|
@ -14,6 +17,8 @@ import { useForceUpdater } from "@utils/react";
|
|||
import definePlugin, { OptionType } from "@utils/types";
|
||||
import { Button, TextInput, useState } from "@webpack/common";
|
||||
|
||||
const cl = classNameFactory("vc-content-warning-");
|
||||
|
||||
const WORDS_KEY = "ContentWarning_words";
|
||||
|
||||
let triggerWords = [""];
|
||||
|
|
@ -29,26 +34,31 @@ function safeMatchesRegex(s: string, r: string) {
|
|||
|
||||
function TriggerContainer({ child }) {
|
||||
const [visible, setVisible] = useState(false);
|
||||
const { onClick } = settings.store;
|
||||
|
||||
const className = onClick ? cl("container") : "";
|
||||
|
||||
if (visible) {
|
||||
return child;
|
||||
} else {
|
||||
return (<div onClick={() => setVisible(true)}>
|
||||
<div style={{
|
||||
filter: "blur(4px) brightness(70%)",
|
||||
transition: "filter 0.2s ease-in-out",
|
||||
cursor: "pointer",
|
||||
}}
|
||||
return (
|
||||
<div
|
||||
className={className}
|
||||
onClick={() => onClick && setVisible(true)}
|
||||
onMouseEnter={event => {
|
||||
event.currentTarget.style.filter = "none";
|
||||
if (!onClick) {
|
||||
event.currentTarget.className = cl("enter");
|
||||
}
|
||||
}}
|
||||
onMouseLeave={event => {
|
||||
event.currentTarget.style.filter = "blur(4px) brightness(70%)";
|
||||
if (!onClick) {
|
||||
event.currentTarget.className = cl("leave");
|
||||
}
|
||||
}}
|
||||
>
|
||||
{child}
|
||||
</div>
|
||||
</div>);
|
||||
</div >
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -118,36 +128,43 @@ function FlaggedWords() {
|
|||
);
|
||||
});
|
||||
|
||||
return (<>
|
||||
<HeadingTertiary>Flagged Words</HeadingTertiary>
|
||||
{inputs}
|
||||
</>);
|
||||
return (
|
||||
<>
|
||||
<HeadingTertiary>Flagged Words</HeadingTertiary>
|
||||
{inputs}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
const settings = definePluginSettings({
|
||||
flagged: {
|
||||
type: OptionType.COMPONENT,
|
||||
component: () => <FlaggedWords />,
|
||||
},
|
||||
onClick: {
|
||||
type: OptionType.BOOLEAN,
|
||||
description: "Only show trigger content on click instead of hover",
|
||||
default: false,
|
||||
}
|
||||
});
|
||||
|
||||
export default definePlugin({
|
||||
name: "ContentWarning",
|
||||
authors: [EquicordDevs.camila314],
|
||||
description: "Allows you to specify certain trigger words that will be blurred by default. Hovering on the blurred content will reveal it.",
|
||||
description: "Allows you to specify certain trigger words that will be blurred by default. Hovering/Clicking on the blurred content will reveal it.",
|
||||
settings,
|
||||
patches: [
|
||||
{
|
||||
find: ".VOICE_HANGOUT_INVITE?",
|
||||
replacement: {
|
||||
match: /(compact:\i}=(\i).+?)(\(0,.+\}\)\]\}\))/,
|
||||
replace: "$1 $self.modify($2,$3)"
|
||||
replace: "$1 $self.modify(arguments[0].message,$3)"
|
||||
}
|
||||
}
|
||||
],
|
||||
|
||||
modify(e, child) {
|
||||
if (triggerWords.some(word => safeMatchesRegex(e.message.content, word))) {
|
||||
modify(message, child) {
|
||||
if (triggerWords.some(w => safeMatchesRegex(message.content, w))) {
|
||||
return <TriggerContainer child={child} />;
|
||||
} else {
|
||||
return child;
|
||||
|
|
|
|||
13
src/equicordplugins/contentWarning/styles.css
Normal file
13
src/equicordplugins/contentWarning/styles.css
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
.vc-content-warning-container {
|
||||
filter: blur(5px) brightness(30%);
|
||||
transition: filter 0.2s ease-in-out;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.vc-content-warning-enter {
|
||||
filter: none;
|
||||
}
|
||||
|
||||
.vc-content-warning-leave {
|
||||
filter: blur(5px) brightness(30%);
|
||||
}
|
||||
|
|
@ -9,9 +9,9 @@ import "./styles.css";
|
|||
import { NavContextMenuPatchCallback } from "@api/ContextMenu";
|
||||
import ErrorBoundary from "@components/ErrorBoundary";
|
||||
import { Devs } from "@utils/constants";
|
||||
import { getCurrentChannel, getCurrentGuild } from "@utils/discord";
|
||||
import { getCurrentChannel } from "@utils/discord";
|
||||
import definePlugin from "@utils/types";
|
||||
import { Channel, User } from "@vencord/discord-types";
|
||||
import { Channel, Guild, User } from "@vencord/discord-types";
|
||||
import {
|
||||
DefaultExtractAndLoadChunksRegex,
|
||||
extractAndLoadChunksLazy,
|
||||
|
|
@ -26,14 +26,19 @@ import {
|
|||
ChannelRouter,
|
||||
ChannelStore,
|
||||
FluxDispatcher,
|
||||
GuildStore,
|
||||
Menu,
|
||||
MessageActions,
|
||||
MessageStore,
|
||||
PermissionsBits,
|
||||
PermissionStore,
|
||||
PopoutActions,
|
||||
React,
|
||||
RelationshipStore,
|
||||
SelectedChannelStore,
|
||||
SelectedGuildStore,
|
||||
useCallback,
|
||||
useEffect,
|
||||
useLayoutEffect,
|
||||
UserStore,
|
||||
useState,
|
||||
useStateFromStores
|
||||
|
|
@ -50,61 +55,87 @@ const { HeaderBar, /* HeaderBarIcon*/ } = mapMangledModuleLazy(".themedMobile]:"
|
|||
// from toolbox
|
||||
const HeaderBarIcon = findComponentByCodeLazy(".HEADER_BAR_BADGE_TOP:", '.iconBadge,"top"');
|
||||
|
||||
const ArrowsLeftRightIcon = () => {
|
||||
return <svg aria-hidden="true" role="img" xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" viewBox="0 0 24 24"><path fill="var(--interactive-normal)" d="M2.3 7.7a1 1 0 0 1 0-1.4l4-4a1 1 0 0 1 1.4 1.4L5.42 6H21a1 1 0 1 1 0 2H5.41l2.3 2.3a1 1 0 1 1-1.42 1.4l-4-4ZM17.7 21.7l4-4a1 1 0 0 0 0-1.4l-4-4a1 1 0 0 0-1.4 1.4l2.29 2.3H3a1 1 0 1 0 0 2h15.59l-2.3 2.3a1 1 0 0 0 1.42 1.4Z"></path></svg>;
|
||||
const { ForumView } = mapMangledModuleLazy("forum-grid-header-section-", {
|
||||
ForumView: filters.byCode("sidebarState")
|
||||
});
|
||||
|
||||
const ArrowsLeftRightIcon = ({ color, ...rest }) => {
|
||||
return (
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
role="img"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
fill={color}
|
||||
viewBox="0 0 24 24"
|
||||
{...rest}>
|
||||
<path d="M2.3 7.7a1 1 0 0 1 0-1.4l4-4a1 1 0 0 1 1.4 1.4L5.42 6H21a1 1 0 1 1 0 2H5.41l2.3 2.3a1 1 0 1 1-1.42 1.4l-4-4ZM17.7 21.7l4-4a1 1 0 0 0 0-1.4l-4-4a1 1 0 0 0-1.4 1.4l2.29 2.3H3a1 1 0 1 0 0 2h15.59l-2.3 2.3a1 1 0 0 0 1.42 1.4Z" />
|
||||
</svg>
|
||||
);
|
||||
};
|
||||
|
||||
const WindowLaunchIcon = findComponentByCodeLazy("1-1h6a1 1 0 1 0 0-2H5Z");
|
||||
const XSmallIcon = findComponentByCodeLazy("1.4L12 13.42l5.3 5.3Z");
|
||||
const Chat = findComponentByCodeLazy("filterAfterTimestamp:", "chatInputType");
|
||||
const Resize = findComponentByCodeLazy("sidebarType:", ".RESIZE_HANDLE_WIDTH");
|
||||
const Resize = findComponentByCodeLazy("sidebarType:", "RESIZE_HANDLE_WIDTH)");
|
||||
const ChannelHeader = findComponentByCodeLazy(".forumPostTitle]:", '"channel-".concat');
|
||||
const PopoutWindow = findComponentByCodeLazy("Missing guestWindow reference");
|
||||
const FullChannelView = findComponentByCodeLazy("showFollowButton:(null");
|
||||
const WanderingCubesLoading = findComponentByCodeLazy('="wanderingCubes"');
|
||||
|
||||
// love
|
||||
const ppStyle = findLazy(m => m?.popoutContent && Object.keys(m).length === 1);
|
||||
|
||||
const ChatInputTypes = findByPropsLazy("FORM", "NORMAL");
|
||||
const Sidebars = findByPropsLazy("ThreadSidebar", "MessageRequestSidebar");
|
||||
const ChatClasses = findByPropsLazy("threadSidebarOpen");
|
||||
|
||||
const ChannelSectionStore = findStoreLazy("ChannelSectionStore");
|
||||
|
||||
const requireChannelContextMenu = extractAndLoadChunksLazy(["&&this.handleActivitiesPopoutClose(),"], new RegExp(DefaultExtractAndLoadChunksRegex.source + ".{1,150}isFavorite"));
|
||||
const requireChannelContextMenu = extractAndLoadChunksLazy(
|
||||
["&&this.handleActivitiesPopoutClose(),"],
|
||||
new RegExp(DefaultExtractAndLoadChunksRegex.source + ".{1,150}isFavorite")
|
||||
);
|
||||
|
||||
const requireForumView = extractAndLoadChunksLazy(
|
||||
["Missing channel in Channel.renderHeaderToolbar"],
|
||||
new RegExp(DefaultExtractAndLoadChunksRegex.source + '.{1,150}name:"ForumChannel"')
|
||||
);
|
||||
|
||||
interface ContextMenuProps {
|
||||
channel: Channel;
|
||||
guildId?: string;
|
||||
user: User;
|
||||
}
|
||||
const MakeContextMenu = (id: string, guildId: string | null) => {
|
||||
return (
|
||||
<Menu.MenuItem
|
||||
id={`vc-sidebar-chat-${id}`}
|
||||
label={"Open Sidebar Chat"}
|
||||
action={() => {
|
||||
FluxDispatcher.dispatch({
|
||||
// @ts-ignore
|
||||
type: "VC_SIDEBAR_CHAT_NEW",
|
||||
guildId,
|
||||
id,
|
||||
});
|
||||
}}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
function MakeContextCallback(name: "user" | "channel"): NavContextMenuPatchCallback {
|
||||
return (children, { user, channel }: ContextMenuProps) => {
|
||||
const isUser = name === "user";
|
||||
if (isUser && !user) return;
|
||||
if (!isUser && (!channel || channel.type === 4)) return;
|
||||
const UserContextPatch: NavContextMenuPatchCallback = (children, args: { user: User; }) => {
|
||||
const checks = [
|
||||
args.user,
|
||||
args.user.id !== UserStore.getCurrentUser().id,
|
||||
];
|
||||
if (checks.some(check => !check)) return;
|
||||
children.push(MakeContextMenu(args.user.id, null));
|
||||
};
|
||||
|
||||
if (isUser && user.id === UserStore.getCurrentUser().id) return;
|
||||
if (!isUser && (!PermissionStore.can(PermissionsBits.VIEW_CHANNEL, channel) && channel.type !== 3)) return;
|
||||
|
||||
children.push(
|
||||
<Menu.MenuItem
|
||||
id={`vc-sidebar-chat-${name}`}
|
||||
label={"Open Sidebar Chat"}
|
||||
action={() => {
|
||||
FluxDispatcher.dispatch({
|
||||
// @ts-ignore
|
||||
type: "NEW_SIDEBAR_CHAT",
|
||||
isUser,
|
||||
guildId: channel.guild_id,
|
||||
id: isUser ? user.id : channel.id,
|
||||
});
|
||||
}}
|
||||
/>
|
||||
);
|
||||
};
|
||||
}
|
||||
const ChannelContextPatch: NavContextMenuPatchCallback = (children, args: { channel: Channel; }) => {
|
||||
const checks = [
|
||||
args.channel,
|
||||
args.channel.type !== 4, // categories
|
||||
PermissionStore.can(PermissionsBits.VIEW_CHANNEL, args.channel),
|
||||
];
|
||||
if (checks.some(check => !check)) return;
|
||||
children.push(MakeContextMenu(args.channel.id, args.channel.guild_id));
|
||||
};
|
||||
|
||||
export default definePlugin({
|
||||
name: "SidebarChat",
|
||||
|
|
@ -113,140 +144,204 @@ export default definePlugin({
|
|||
patches: [
|
||||
{
|
||||
find: 'case"pendingFriends":',
|
||||
replacement: {
|
||||
match: /return(\(0,\i\.jsxs?\)\(\i\.\i,{}\))}/,
|
||||
replace: "return [$1, $self.renderSidebar()]}"
|
||||
}
|
||||
group: true,
|
||||
replacement: [
|
||||
{
|
||||
match: /channel_renderer"\);/,
|
||||
replace: "$&const vc_SidebarChat=$self.renderSidebar();"
|
||||
},
|
||||
{
|
||||
match: /return(\(0,\i\.jsxs?\)\(\i\.\i,{}\))}/,
|
||||
replace: "return [$1, vc_SidebarChat]}"
|
||||
},
|
||||
{
|
||||
match: /(case \i\.\i.+?return)(.+?);(?=.+?params\.messageId)(?<=channel_renderer".+?)/g,
|
||||
replace: "$1[$2, vc_SidebarChat];",
|
||||
predicate: () => settings.store.patchCommunity
|
||||
}
|
||||
]
|
||||
},
|
||||
],
|
||||
|
||||
settings,
|
||||
|
||||
contextMenus: {
|
||||
"user-context": MakeContextCallback("user"),
|
||||
"channel-context": MakeContextCallback("channel"),
|
||||
"thread-context": MakeContextCallback("channel"),
|
||||
"gdm-context": MakeContextCallback("channel"),
|
||||
"user-context": UserContextPatch,
|
||||
"channel-context": ChannelContextPatch,
|
||||
"thread-context": ChannelContextPatch,
|
||||
"gdm-context": ChannelContextPatch,
|
||||
},
|
||||
|
||||
renderSidebar: ErrorBoundary.wrap(() => {
|
||||
const { guild, channel, /* width*/ } = useStateFromStores([SidebarStore], () => SidebarStore.getFullState());
|
||||
const [width, setWidth] = useState(0);
|
||||
toolboxActions: {
|
||||
"Open Previous Chat"() {
|
||||
FluxDispatcher.dispatch({
|
||||
// @ts-ignore
|
||||
type: "VC_SIDEBAR_CHAT_PREVIOUS",
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
renderSidebar() {
|
||||
const { guild, channel /* width*/ } = useStateFromStores(
|
||||
[SidebarStore, GuildStore, ChannelStore], () => {
|
||||
const { channelId, guildId } = SidebarStore.getState();
|
||||
return {
|
||||
guild: GuildStore.getGuild(guildId),
|
||||
channel: ChannelStore.getChannel(channelId)
|
||||
};
|
||||
}, []
|
||||
);
|
||||
|
||||
const [channelSidebar, guildSidebar] = useStateFromStores(
|
||||
[ChannelSectionStore],
|
||||
() => [
|
||||
ChannelSectionStore.getSidebarState(getCurrentChannel()?.id),
|
||||
ChannelSectionStore.getGuildSidebarState(getCurrentGuild()?.id),
|
||||
]
|
||||
[ChannelSectionStore, SelectedChannelStore, ChannelStore], () => {
|
||||
const currentChannelId = SelectedChannelStore.getChannelId();
|
||||
const currentGuildId = SelectedGuildStore.getGuildId();
|
||||
return [
|
||||
ChannelSectionStore.getSidebarState(currentChannelId),
|
||||
ChannelSectionStore.getGuildSidebarState(currentGuildId),
|
||||
];
|
||||
}, []
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
if (channel) {
|
||||
if (MessageStore.getLastMessage(channel.id)) return;
|
||||
MessageActions.fetchMessages({
|
||||
channelId: channel.id,
|
||||
limit: 50,
|
||||
});
|
||||
}
|
||||
}, [channel]);
|
||||
if (!channel?.id || MessageStore.getLastMessage(channel.id)) return;
|
||||
MessageActions.fetchMessages({
|
||||
channelId: channel.id,
|
||||
limit: 50,
|
||||
});
|
||||
}, [channel?.id]);
|
||||
|
||||
useEffect(() => {
|
||||
if (width === 0) setWidth(window.innerWidth);
|
||||
const [width, setWidth] = useState(window.innerWidth);
|
||||
|
||||
useLayoutEffect(() => {
|
||||
const handleResize = () => setWidth(window.innerWidth);
|
||||
|
||||
window.addEventListener("resize", handleResize);
|
||||
return () => {
|
||||
window.removeEventListener("resize", handleResize);
|
||||
};
|
||||
return () => window.removeEventListener("resize", handleResize);
|
||||
}, []);
|
||||
|
||||
const [View, setViewComponent] = useState<React.ReactNode>(null);
|
||||
|
||||
useEffect(() => {
|
||||
if (!channel) return;
|
||||
|
||||
// @ts-expect-error
|
||||
if (channel.isForumLikeChannel()) {
|
||||
requireForumView().then(() => {
|
||||
setViewComponent(
|
||||
<ForumView
|
||||
channel={channel}
|
||||
guild={guild}
|
||||
sidebarState={null}
|
||||
/>
|
||||
);
|
||||
});
|
||||
|
||||
setViewComponent(
|
||||
<div className={ChatClasses.loader}>
|
||||
<WanderingCubesLoading />
|
||||
</div>
|
||||
);
|
||||
} else {
|
||||
setViewComponent(
|
||||
<Chat
|
||||
channel={channel}
|
||||
guild={guild}
|
||||
chatInputType={ChatInputTypes.SIDEBAR}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}, [channel]);
|
||||
|
||||
if (!channel || channelSidebar || guildSidebar) return null;
|
||||
|
||||
return (
|
||||
<Resize
|
||||
sidebarType={Sidebars.MessageRequestSidebar}
|
||||
maxWidth={~~(width * 0.31)/* width - 690*/
|
||||
}
|
||||
>
|
||||
<HeaderBar
|
||||
toolbar={
|
||||
<>
|
||||
<HeaderBarIcon
|
||||
icon={ArrowsLeftRightIcon}
|
||||
tooltip="Switch channels"
|
||||
onClick={() => {
|
||||
const currentChannel = getCurrentChannel()!;
|
||||
FluxDispatcher.dispatch({
|
||||
// @ts-ignore
|
||||
type: "NEW_SIDEBAR_CHAT",
|
||||
isUser: currentChannel.id === "1",
|
||||
guildId: currentChannel?.guild_id,
|
||||
id: currentChannel.id,
|
||||
});
|
||||
ChannelRouter.transitionToChannel(channel.id);
|
||||
}}
|
||||
/>
|
||||
<HeaderBarIcon
|
||||
icon={WindowLaunchIcon}
|
||||
tooltip="Popout Chat"
|
||||
onClick={async () => {
|
||||
await requireChannelContextMenu();
|
||||
PopoutActions.open(
|
||||
`DISCORD_VC_SC-${channel.id}`,
|
||||
() => <RenderPopout channel={channel} />,
|
||||
{
|
||||
defaultWidth: 854,
|
||||
defaultHeight: 480
|
||||
});
|
||||
}}
|
||||
/>
|
||||
<HeaderBarIcon
|
||||
icon={XSmallIcon}
|
||||
tooltip="Close Sidebar Chat"
|
||||
onClick={() => {
|
||||
FluxDispatcher.dispatch({
|
||||
// @ts-ignore
|
||||
type: "CLOSE_SIDEBAR_CHAT",
|
||||
});
|
||||
}}
|
||||
/>
|
||||
</>
|
||||
}
|
||||
<ErrorBoundary noop>
|
||||
<Resize
|
||||
sidebarType={Sidebars.MessageRequestSidebar}
|
||||
maxWidth={~~(width * 0.31)/* width - 690*/}
|
||||
>
|
||||
<ChannelHeader
|
||||
channel={channel}
|
||||
channelName={channel?.name}
|
||||
guild={guild}
|
||||
parentChannel={ChannelStore.getChannel(channel?.parent_id)}
|
||||
/>
|
||||
</HeaderBar>
|
||||
<Chat
|
||||
channel={channel}
|
||||
guild={guild}
|
||||
chatInputType={ChatInputTypes.SIDEBAR}
|
||||
/>
|
||||
</Resize>
|
||||
<Header channel={channel} guild={guild} />
|
||||
{View}
|
||||
</Resize>
|
||||
</ErrorBoundary>
|
||||
);
|
||||
}),
|
||||
},
|
||||
});
|
||||
|
||||
const RenderPopout = ErrorBoundary.wrap(({ channel }: { channel: Channel; }) => {
|
||||
const Header = ({ guild, channel }: { guild: Guild; channel: Channel; }) => {
|
||||
const recipientId = channel.isPrivate() ? channel.getRecipientId() as string : null;
|
||||
|
||||
const name = useStateFromStores([UserStore, RelationshipStore], () => {
|
||||
if (!recipientId || channel.name) return channel.name;
|
||||
|
||||
const user = UserStore.getUser(recipientId);
|
||||
return RelationshipStore.getNickname(recipientId) || user?.globalName || user?.username;
|
||||
}, [recipientId, channel.name]);
|
||||
|
||||
const parentChannel = useStateFromStores(
|
||||
[ChannelStore], () => ChannelStore.getChannel(channel?.parent_id),
|
||||
[channel?.parent_id]
|
||||
);
|
||||
|
||||
// @ts-ignore
|
||||
const closeSidebar = () => FluxDispatcher.dispatch({ type: "VC_SIDEBAR_CHAT_CLOSE", });
|
||||
|
||||
const openPopout = useCallback(async () => {
|
||||
await requireChannelContextMenu();
|
||||
PopoutActions.open(
|
||||
`DISCORD_VC_SC-${channel.id}`,
|
||||
() => <RenderPopout channel={channel} name={name} />,
|
||||
{
|
||||
defaultWidth: 854,
|
||||
defaultHeight: 480,
|
||||
}
|
||||
);
|
||||
}, [channel, name]);
|
||||
|
||||
const switchChannels = useCallback(() => {
|
||||
const mainChannel = getCurrentChannel()!;
|
||||
FluxDispatcher.dispatch({
|
||||
// @ts-ignore
|
||||
type: "VC_SIDEBAR_CHAT_NEW",
|
||||
guildId: mainChannel.guild_id,
|
||||
id: mainChannel.id,
|
||||
});
|
||||
ChannelRouter.transitionToChannel(channel.id);
|
||||
}, [channel.id]);
|
||||
|
||||
return (
|
||||
<HeaderBar
|
||||
toolbar={
|
||||
<>
|
||||
<HeaderBarIcon icon={ArrowsLeftRightIcon} tooltip="Switch channels" onClick={switchChannels} />
|
||||
<HeaderBarIcon icon={WindowLaunchIcon} tooltip="Popout Chat" onClick={openPopout} />
|
||||
<HeaderBarIcon icon={XSmallIcon} tooltip="Close Sidebar Chat" onClick={closeSidebar} />
|
||||
</>
|
||||
}
|
||||
>
|
||||
<ChannelHeader
|
||||
channel={channel}
|
||||
channelName={name}
|
||||
guild={guild}
|
||||
parentChannel={parentChannel}
|
||||
/>
|
||||
</HeaderBar>
|
||||
);
|
||||
};
|
||||
|
||||
const RenderPopout = ErrorBoundary.wrap(({ channel, name }: { channel: Channel; name: string; }) => {
|
||||
// Copy from an unexported function of the one they use in the experiment
|
||||
// right click a channel and search withTitleBar:!0,windowKey
|
||||
const { Provider } = React.createContext<string | undefined>(undefined);
|
||||
const selectedChannel = ChannelStore.getChannel(channel.id);
|
||||
return (
|
||||
<PopoutWindow
|
||||
withTitleBar={true}
|
||||
windowKey={`DISCORD_VC_SC-${selectedChannel.id}`}
|
||||
title={selectedChannel.name}
|
||||
channelId={selectedChannel.id}
|
||||
withTitleBar
|
||||
windowKey={`DISCORD_VC_SC-${channel.id}`}
|
||||
title={name || "Vencord"}
|
||||
channelId={channel.id}
|
||||
contentClassName={ppStyle.popoutContent}
|
||||
>
|
||||
<Provider value={selectedChannel.guild_id}>
|
||||
<FullChannelView providedChannel={selectedChannel} />
|
||||
</Provider>
|
||||
<FullChannelView providedChannel={channel} />
|
||||
</PopoutWindow>
|
||||
);
|
||||
});
|
||||
|
|
|
|||
|
|
@ -7,86 +7,84 @@
|
|||
import { definePluginSettings } from "@api/Settings";
|
||||
import { proxyLazy } from "@utils/lazy";
|
||||
import { OptionType } from "@utils/types";
|
||||
import { FluxEmitter, FluxStore } from "@vencord/discord-types";
|
||||
import { findByPropsLazy } from "@webpack";
|
||||
import { ChannelActionCreators, ChannelStore, FluxDispatcher, GuildStore } from "@webpack/common";
|
||||
import { Flux as TFlux } from "@vencord/discord-types";
|
||||
import { ChannelActionCreators, Flux as FluxWP, FluxDispatcher } from "@webpack/common";
|
||||
|
||||
interface IFlux {
|
||||
PersistedStore: typeof FluxStore;
|
||||
Emitter: FluxEmitter;
|
||||
interface IFlux extends TFlux {
|
||||
PersistedStore: TFlux["Store"];
|
||||
}
|
||||
const Flux: IFlux = findByPropsLazy("connectStores");
|
||||
|
||||
export const settings = definePluginSettings({
|
||||
persistSidebar: {
|
||||
type: OptionType.BOOLEAN,
|
||||
description: "Keep the sidebar chat open across Discord restarts",
|
||||
default: true,
|
||||
},
|
||||
patchCommunity: {
|
||||
type: OptionType.BOOLEAN,
|
||||
description: "Patch things like the Channel Browser or Members tab that community servers have.",
|
||||
default: true,
|
||||
restartNeeded: true,
|
||||
}
|
||||
});
|
||||
|
||||
interface SidebarData {
|
||||
isUser: boolean;
|
||||
guildId: string;
|
||||
id: string;
|
||||
}
|
||||
|
||||
export const SidebarStore = proxyLazy(() => {
|
||||
let guildId = "";
|
||||
let channelId = "";
|
||||
let width = 0;
|
||||
class SidebarStore extends Flux.PersistedStore {
|
||||
const current = {
|
||||
guildId: "",
|
||||
channelId: "",
|
||||
width: 0
|
||||
};
|
||||
|
||||
let previous = { ...current };
|
||||
|
||||
class SidebarStore extends (FluxWP as IFlux).PersistedStore {
|
||||
static persistKey = "SidebarStore";
|
||||
|
||||
// @ts-ignore
|
||||
initialize(previous: { guildId?: string; channelId?: string; width?: number; } | undefined) {
|
||||
if (!settings.store.persistSidebar || !previous) return;
|
||||
const { guildId: prevGId, channelId: prevCId, width: prevWidth } = previous;
|
||||
guildId = prevGId || "";
|
||||
channelId = prevCId || "";
|
||||
width = prevWidth || 0;
|
||||
initialize(previousState: { guildId?: string; channelId?: string; width?: number; } | undefined) {
|
||||
if (!settings.store.persistSidebar || !previousState) return;
|
||||
const { guildId, channelId, width } = previousState;
|
||||
current.guildId = guildId || "";
|
||||
current.channelId = channelId || "";
|
||||
current.width = width || 0;
|
||||
}
|
||||
|
||||
getState() {
|
||||
return {
|
||||
guildId,
|
||||
channelId,
|
||||
width
|
||||
};
|
||||
}
|
||||
|
||||
getFullState() {
|
||||
return {
|
||||
guild: GuildStore.getGuild(guildId),
|
||||
channel: ChannelStore.getChannel(channelId),
|
||||
width
|
||||
};
|
||||
return current;
|
||||
}
|
||||
}
|
||||
|
||||
const store = new SidebarStore(FluxDispatcher, {
|
||||
// @ts-ignore
|
||||
async NEW_SIDEBAR_CHAT({ isUser, guildId: newGId, id }: SidebarData) {
|
||||
guildId = newGId || "";
|
||||
async VC_SIDEBAR_CHAT_NEW({ guildId: newGId, id }: { guildId: string | null; id: string; }) {
|
||||
previous = { ...current };
|
||||
|
||||
if (!isUser) {
|
||||
channelId = id;
|
||||
current.guildId = newGId || "";
|
||||
|
||||
if (current.guildId) {
|
||||
current.channelId = id;
|
||||
store.emitChange();
|
||||
return;
|
||||
}
|
||||
|
||||
channelId = await ChannelActionCreators.getOrEnsurePrivateChannel(id);
|
||||
current.channelId = await ChannelActionCreators.getOrEnsurePrivateChannel(id);
|
||||
store.emitChange();
|
||||
},
|
||||
|
||||
CLOSE_SIDEBAR_CHAT() {
|
||||
guildId = "";
|
||||
channelId = "";
|
||||
VC_SIDEBAR_CHAT_PREVIOUS() {
|
||||
if (previous.channelId) {
|
||||
current.guildId = previous.guildId;
|
||||
current.channelId = previous.channelId;
|
||||
}
|
||||
store.emitChange();
|
||||
},
|
||||
|
||||
/* SIDEBAR_CHAT_WIDTH({ newWidth }: { newWidth: number; }) {
|
||||
width = newWidth;
|
||||
VC_SIDEBAR_CHAT_CLOSE() {
|
||||
previous = { ...current };
|
||||
current.guildId = "";
|
||||
current.channelId = "";
|
||||
store.emitChange();
|
||||
}*/
|
||||
},
|
||||
});
|
||||
|
||||
return store;
|
||||
|
|
|
|||
|
|
@ -5,3 +5,7 @@
|
|||
line-clamp: 1;
|
||||
white-space: unset;
|
||||
}
|
||||
|
||||
[class^="page_"] > * {
|
||||
min-width: 0;
|
||||
}
|
||||
|
|
@ -2,6 +2,10 @@
|
|||
flex: none !important;
|
||||
}
|
||||
|
||||
.voice-user-button-container {
|
||||
padding-right: 4px;
|
||||
}
|
||||
|
||||
div[class^='list_'][class*='collapsed_'] .voice-user-buttons {
|
||||
display: none;
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue