Add chat bar button api ~ fixes buttons for russian users
This commit is contained in:
parent
8938f4a3cf
commit
bf977e0047
10 changed files with 325 additions and 307 deletions
123
src/api/ChatButtons.tsx
Normal file
123
src/api/ChatButtons.tsx
Normal file
|
@ -0,0 +1,123 @@
|
|||
/*
|
||||
* Vencord, a Discord client mod
|
||||
* Copyright (c) 2024 Vendicated and contributors
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import ErrorBoundary from "@components/ErrorBoundary";
|
||||
import { Logger } from "@utils/Logger";
|
||||
import { Button, ButtonLooks, ButtonWrapperClasses, Tooltip } from "@webpack/common";
|
||||
import { Channel } from "discord-types/general";
|
||||
import { HTMLProps, MouseEventHandler, ReactNode } from "react";
|
||||
|
||||
export interface ChatBarProps {
|
||||
channel: Channel;
|
||||
disabled: boolean;
|
||||
isEmpty: boolean;
|
||||
type: {
|
||||
analyticsName: string;
|
||||
attachments: boolean;
|
||||
autocomplete: {
|
||||
addReactionShortcut: boolean,
|
||||
forceChatLayer: boolean,
|
||||
reactions: boolean;
|
||||
},
|
||||
commands: {
|
||||
enabled: boolean;
|
||||
},
|
||||
drafts: {
|
||||
type: number,
|
||||
commandType: number,
|
||||
autoSave: boolean;
|
||||
},
|
||||
emojis: {
|
||||
button: boolean;
|
||||
},
|
||||
gifs: {
|
||||
button: boolean,
|
||||
allowSending: boolean;
|
||||
},
|
||||
gifts: {
|
||||
button: boolean;
|
||||
},
|
||||
permissions: {
|
||||
requireSendMessages: boolean;
|
||||
},
|
||||
showThreadPromptOnReply: boolean,
|
||||
stickers: {
|
||||
button: boolean,
|
||||
allowSending: boolean,
|
||||
autoSuggest: boolean;
|
||||
},
|
||||
users: {
|
||||
allowMentioning: boolean;
|
||||
},
|
||||
submit: {
|
||||
button: boolean,
|
||||
ignorePreference: boolean,
|
||||
disableEnterToSubmit: boolean,
|
||||
clearOnSubmit: boolean,
|
||||
useDisabledStylesOnSubmit: boolean;
|
||||
},
|
||||
uploadLongMessages: boolean,
|
||||
upsellLongMessages: {
|
||||
iconOnly: boolean;
|
||||
},
|
||||
showCharacterCount: boolean,
|
||||
sedReplace: boolean;
|
||||
};
|
||||
}
|
||||
|
||||
export type ChatBarButton = (props: ChatBarProps, isMainChat: boolean) => ReactNode;
|
||||
|
||||
const buttonFactories = new Map<string, ChatBarButton>();
|
||||
const logger = new Logger("ChatButtons");
|
||||
|
||||
export function _injectButtons(buttons: ReactNode[], props: ChatBarProps) {
|
||||
if (props.type.analyticsName !== "normal") return;
|
||||
|
||||
for (const [key, makeButton] of buttonFactories) {
|
||||
try {
|
||||
const res = makeButton(props, props.type.analyticsName === "normal");
|
||||
if (res) buttons.push(res);
|
||||
} catch (e) {
|
||||
logger.error(`Failed to render button ${key}`, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const addChatBarButton = (id: string, button: ChatBarButton) => buttonFactories.set(id, button);
|
||||
export const removeChatBarButton = (id: string) => buttonFactories.delete(id);
|
||||
|
||||
export interface ChatBarButtonProps {
|
||||
children: ReactNode;
|
||||
tooltip: string;
|
||||
onClick: MouseEventHandler<HTMLButtonElement>;
|
||||
onContextMenu?: MouseEventHandler<HTMLButtonElement>;
|
||||
buttonProps?: Omit<HTMLProps<HTMLButtonElement>, "size" | "onClick" | "onContextMenu">;
|
||||
}
|
||||
export const ChatBarButton = ErrorBoundary.wrap((props: ChatBarButtonProps) => {
|
||||
return (
|
||||
<Tooltip text={props.tooltip}>
|
||||
{({ onMouseEnter, onMouseLeave }) => (
|
||||
<div style={{ display: "flex" }}>
|
||||
<Button
|
||||
aria-label={props.tooltip}
|
||||
size=""
|
||||
look={ButtonLooks.BLANK}
|
||||
onMouseEnter={onMouseEnter}
|
||||
onMouseLeave={onMouseLeave}
|
||||
innerClassName={ButtonWrapperClasses.button}
|
||||
onClick={props.onClick}
|
||||
onContextMenu={props.onContextMenu}
|
||||
{...props.buttonProps}
|
||||
>
|
||||
<div className={ButtonWrapperClasses.buttonWrapper}>
|
||||
{props.children}
|
||||
</div>
|
||||
</Button>
|
||||
</div>
|
||||
)}
|
||||
</Tooltip>
|
||||
);
|
||||
}, { noop: true });
|
|
@ -17,6 +17,7 @@
|
|||
*/
|
||||
|
||||
import * as $Badges from "./Badges";
|
||||
import * as $ChatButtons from "./ChatButtons";
|
||||
import * as $Commands from "./Commands";
|
||||
import * as $ContextMenu from "./ContextMenu";
|
||||
import * as $DataStore from "./DataStore";
|
||||
|
@ -104,3 +105,8 @@ export const Notifications = $Notifications;
|
|||
* An api allowing you to patch and add/remove items to/from context menus
|
||||
*/
|
||||
export const ContextMenu = $ContextMenu;
|
||||
|
||||
/**
|
||||
* An API allowing you to add buttons to the chat input
|
||||
*/
|
||||
export const ChatButtons = $ChatButtons;
|
||||
|
|
22
src/plugins/_api/chatButtons.ts
Normal file
22
src/plugins/_api/chatButtons.ts
Normal file
|
@ -0,0 +1,22 @@
|
|||
/*
|
||||
* Vencord, a Discord client mod
|
||||
* Copyright (c) 2024 Vendicated and contributors
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import { Devs } from "@utils/constants";
|
||||
import definePlugin from "@utils/types";
|
||||
|
||||
export default definePlugin({
|
||||
name: "ChatInputButtonAPI",
|
||||
description: "API to add buttons to the chat input",
|
||||
authors: [Devs.Ven],
|
||||
|
||||
patches: [{
|
||||
find: 'location:"ChannelTextAreaButtons"',
|
||||
replacement: {
|
||||
match: /if\(!\i\.isMobile\)\{(?=.+?&&(\i)\.push\(.{0,50}"gift")/,
|
||||
replace: "$&Vencord.Api.ChatButtons._injectButtons($1,arguments[0]);"
|
||||
}
|
||||
}]
|
||||
});
|
|
@ -16,13 +16,14 @@
|
|||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { addChatBarButton, ChatBarButton } from "@api/ChatButtons";
|
||||
import { addButton, removeButton } from "@api/MessagePopover";
|
||||
import { definePluginSettings } from "@api/Settings";
|
||||
import ErrorBoundary from "@components/ErrorBoundary";
|
||||
import { Devs } from "@utils/constants";
|
||||
import { getStegCloak } from "@utils/dependencies";
|
||||
import definePlugin, { OptionType } from "@utils/types";
|
||||
import { Button, ButtonLooks, ButtonWrapperClasses, ChannelStore, FluxDispatcher, RestAPI, Tooltip } from "@webpack/common";
|
||||
import { ChannelStore, FluxDispatcher, RestAPI, Tooltip } from "@webpack/common";
|
||||
import { Message } from "discord-types/general";
|
||||
|
||||
import { buildDecModal } from "./components/DecryptionModal";
|
||||
|
@ -64,54 +65,32 @@ function Indicator() {
|
|||
|
||||
}
|
||||
|
||||
function ChatBarIcon(chatBoxProps: {
|
||||
type: {
|
||||
analyticsName: string;
|
||||
};
|
||||
}) {
|
||||
if (chatBoxProps.type.analyticsName !== "normal") return null;
|
||||
const ChatBarIcon: ChatBarButton = (_, isMainChat) => {
|
||||
if (!isMainChat) return null;
|
||||
|
||||
return (
|
||||
<Tooltip text="Encrypt Message">
|
||||
{({ onMouseEnter, onMouseLeave }) => (
|
||||
// size="" = Button.Sizes.NONE
|
||||
/*
|
||||
many themes set "> button" to display: none, as the gift button is
|
||||
the only directly descending button (all the other elements are divs.)
|
||||
Thus, wrap in a div here to avoid getting hidden by that.
|
||||
flex is for some reason necessary as otherwise the button goes flying off
|
||||
*/
|
||||
<div style={{ display: "flex" }}>
|
||||
<Button
|
||||
aria-haspopup="dialog"
|
||||
aria-label="Encrypt Message"
|
||||
size=""
|
||||
look={ButtonLooks.BLANK}
|
||||
onMouseEnter={onMouseEnter}
|
||||
onMouseLeave={onMouseLeave}
|
||||
innerClassName={ButtonWrapperClasses.button}
|
||||
onClick={() => buildEncModal()}
|
||||
style={{ padding: "0 2px", scale: "0.9" }}
|
||||
>
|
||||
<div className={ButtonWrapperClasses.buttonWrapper}>
|
||||
<svg
|
||||
aria-hidden
|
||||
role="img"
|
||||
width="32"
|
||||
height="32"
|
||||
viewBox={"0 0 64 64"}
|
||||
style={{ scale: "1.1" }}
|
||||
>
|
||||
<path fill="currentColor" d="M 32 9 C 24.832 9 19 14.832 19 22 L 19 27.347656 C 16.670659 28.171862 15 30.388126 15 33 L 15 49 C 15 52.314 17.686 55 21 55 L 43 55 C 46.314 55 49 52.314 49 49 L 49 33 C 49 30.388126 47.329341 28.171862 45 27.347656 L 45 22 C 45 14.832 39.168 9 32 9 z M 32 13 C 36.963 13 41 17.038 41 22 L 41 27 L 23 27 L 23 22 C 23 17.038 27.037 13 32 13 z" />
|
||||
</svg>
|
||||
</div>
|
||||
</Button>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
</Tooltip >
|
||||
<ChatBarButton
|
||||
tooltip="Encrypt Message"
|
||||
onClick={() => buildEncModal()}
|
||||
|
||||
buttonProps={{
|
||||
"aria-haspopup": "dialog",
|
||||
style: { padding: "0 2px", scale: "0.9" }
|
||||
}}
|
||||
>
|
||||
<svg
|
||||
aria-hidden
|
||||
role="img"
|
||||
width="32"
|
||||
height="32"
|
||||
viewBox={"0 0 64 64"}
|
||||
style={{ scale: "1.1" }}
|
||||
>
|
||||
<path fill="currentColor" d="M 32 9 C 24.832 9 19 14.832 19 22 L 19 27.347656 C 16.670659 28.171862 15 30.388126 15 33 L 15 49 C 15 52.314 17.686 55 21 55 L 43 55 C 46.314 55 49 52.314 49 49 L 49 33 C 49 30.388126 47.329341 28.171862 45 27.347656 L 45 22 C 45 14.832 39.168 9 32 9 z M 32 13 C 36.963 13 41 17.038 41 22 L 41 27 L 23 27 L 23 22 C 23 17.038 27.037 13 32 13 z" />
|
||||
</svg>
|
||||
</ChatBarButton>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
const settings = definePluginSettings({
|
||||
savedPasswords: {
|
||||
|
@ -125,7 +104,7 @@ export default definePlugin({
|
|||
name: "InvisibleChat",
|
||||
description: "Encrypt your Messages in a non-suspicious way!",
|
||||
authors: [Devs.SammCheese],
|
||||
dependencies: ["MessagePopoverAPI"],
|
||||
dependencies: ["MessagePopoverAPI", "ChatInputButtonAPI"],
|
||||
patches: [
|
||||
{
|
||||
// Indicator
|
||||
|
@ -135,13 +114,6 @@ export default definePlugin({
|
|||
replace: "try {$1 && $self.INV_REGEX.test($1.message.content) ? $1.content.push($self.indicator()) : null } catch {};$&"
|
||||
}
|
||||
},
|
||||
{
|
||||
find: "ChannelTextAreaButtons",
|
||||
replacement: {
|
||||
match: /(\i)\.push.{1,30}disabled:(\i),.{1,20}\},"gift"\)\)/,
|
||||
replace: "$&,(()=>{try{$2||$1.push($self.chatBarIcon(arguments[0]))}catch{}})()",
|
||||
}
|
||||
},
|
||||
],
|
||||
|
||||
EMBED_API_URL: "https://embed.sammcheese.net",
|
||||
|
@ -154,7 +126,7 @@ export default definePlugin({
|
|||
const { default: StegCloak } = await getStegCloak();
|
||||
steggo = new StegCloak(true, false);
|
||||
|
||||
addButton("invDecrypt", message => {
|
||||
addButton("InvisibleChat", message => {
|
||||
return this.INV_REGEX.test(message?.content)
|
||||
? {
|
||||
label: "Decrypt Message",
|
||||
|
@ -170,10 +142,13 @@ export default definePlugin({
|
|||
}
|
||||
: null;
|
||||
});
|
||||
|
||||
addChatBarButton("InvisibleChat", ChatBarIcon);
|
||||
},
|
||||
|
||||
stop() {
|
||||
removeButton("invDecrypt");
|
||||
removeButton("InvisibleChat");
|
||||
removeButton("InvisibleChat");
|
||||
},
|
||||
|
||||
// Gets the Embed of a Link
|
||||
|
@ -216,7 +191,6 @@ export default definePlugin({
|
|||
});
|
||||
},
|
||||
|
||||
chatBarIcon: ErrorBoundary.wrap(ChatBarIcon, { noop: true }),
|
||||
popOverIcon: () => <PopOverIcon />,
|
||||
indicator: ErrorBoundary.wrap(Indicator, { noop: true })
|
||||
});
|
||||
|
|
|
@ -16,22 +16,14 @@
|
|||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { addChatBarButton, ChatBarButton, removeChatBarButton } from "@api/ChatButtons";
|
||||
import { generateId, sendBotMessage } from "@api/Commands";
|
||||
import ErrorBoundary from "@components/ErrorBoundary";
|
||||
import { Devs } from "@utils/constants";
|
||||
import definePlugin from "@utils/types";
|
||||
import { findByPropsLazy } from "@webpack";
|
||||
import { Button, ButtonLooks, ButtonWrapperClasses, DraftStore, DraftType, SelectedChannelStore, Tooltip, UserStore, useStateFromStores } from "@webpack/common";
|
||||
import { DraftStore, DraftType, SelectedChannelStore, UserStore, useStateFromStores } from "@webpack/common";
|
||||
import { MessageAttachment } from "discord-types/general";
|
||||
|
||||
interface Props {
|
||||
type: {
|
||||
analyticsName: string;
|
||||
isEmpty: boolean;
|
||||
attachments: boolean;
|
||||
};
|
||||
}
|
||||
|
||||
const UploadStore = findByPropsLazy("getUploads");
|
||||
|
||||
const getDraft = (channelId: string) => DraftStore.getDraft(channelId, DraftType.ChannelMessage);
|
||||
|
@ -81,13 +73,13 @@ const getAttachments = async (channelId: string) =>
|
|||
);
|
||||
|
||||
|
||||
export function PreviewButton(chatBoxProps: Props) {
|
||||
const { isEmpty, attachments } = chatBoxProps.type;
|
||||
const PreviewButton: ChatBarButton = (props, isMainChat) => {
|
||||
const { isEmpty, type: { attachments } } = props;
|
||||
|
||||
const channelId = SelectedChannelStore.getChannelId();
|
||||
const draft = useStateFromStores([DraftStore], () => getDraft(channelId));
|
||||
|
||||
if (chatBoxProps.type.analyticsName !== "normal") return null;
|
||||
if (!isMainChat) return null;
|
||||
|
||||
const hasAttachments = attachments && UploadStore.getUploads(channelId, DraftType.ChannelMessage).length > 0;
|
||||
const hasContent = !isEmpty && draft?.length > 0;
|
||||
|
@ -95,47 +87,33 @@ export function PreviewButton(chatBoxProps: Props) {
|
|||
if (!hasContent && !hasAttachments) return null;
|
||||
|
||||
return (
|
||||
<Tooltip text="Preview Message">
|
||||
{tooltipProps => (
|
||||
<Button
|
||||
{...tooltipProps}
|
||||
onClick={async () =>
|
||||
sendBotMessage(
|
||||
channelId,
|
||||
{
|
||||
content: getDraft(channelId),
|
||||
author: UserStore.getCurrentUser(),
|
||||
attachments: hasAttachments ? await getAttachments(channelId) : undefined,
|
||||
}
|
||||
)}
|
||||
size=""
|
||||
look={ButtonLooks.BLANK}
|
||||
innerClassName={ButtonWrapperClasses.button}
|
||||
style={{ padding: "0 2px", height: "100%" }}
|
||||
>
|
||||
<div className={ButtonWrapperClasses.buttonWrapper}>
|
||||
<img width={24} height={24} src="https://discord.com/assets/4c5a77a89716352686f590a6f014770c.svg" />
|
||||
</div>
|
||||
</Button>
|
||||
)}
|
||||
</Tooltip>
|
||||
<ChatBarButton
|
||||
tooltip="Preview Message"
|
||||
onClick={async () =>
|
||||
sendBotMessage(
|
||||
channelId,
|
||||
{
|
||||
content: getDraft(channelId),
|
||||
author: UserStore.getCurrentUser(),
|
||||
attachments: hasAttachments ? await getAttachments(channelId) : undefined,
|
||||
}
|
||||
)}
|
||||
buttonProps={{
|
||||
style: { padding: "0 2px", height: "100%" }
|
||||
}}
|
||||
>
|
||||
<img width={24} height={24} src="https://discord.com/assets/4c5a77a89716352686f590a6f014770c.svg" />
|
||||
</ChatBarButton>
|
||||
);
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
export default definePlugin({
|
||||
name: "PreviewMessage",
|
||||
description: "Lets you preview your message before sending it.",
|
||||
authors: [Devs.Aria],
|
||||
patches: [
|
||||
{
|
||||
find: "ChannelTextAreaButtons",
|
||||
replacement: {
|
||||
match: /(\i)\.push.{1,30}disabled:(\i),.{1,20}\},"gift"\)\)/,
|
||||
replace: "$&,(()=>{try{$2||$1.push($self.chatBarIcon(arguments[0]))}catch{}})()",
|
||||
}
|
||||
},
|
||||
],
|
||||
dependencies: ["ChatInputButtonAPI"],
|
||||
|
||||
chatBarIcon: ErrorBoundary.wrap(PreviewButton, { noop: true }),
|
||||
start: () => addChatBarButton("previewMessage", PreviewButton),
|
||||
stop: () => removeChatBarButton("previewMessage"),
|
||||
});
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
|
||||
import "./styles.css";
|
||||
|
||||
import { addChatBarButton, ChatBarButton, removeChatBarButton } from "@api/ChatButtons";
|
||||
import { addPreSendListener, removePreSendListener } from "@api/MessageEvents";
|
||||
import { definePluginSettings } from "@api/Settings";
|
||||
import { classNameFactory } from "@api/Styles";
|
||||
|
@ -26,7 +27,7 @@ import { getTheme, insertTextIntoChatInputBox, Theme } from "@utils/discord";
|
|||
import { Margins } from "@utils/margins";
|
||||
import { closeModal, ModalCloseButton, ModalContent, ModalFooter, ModalHeader, ModalProps, ModalRoot, openModal } from "@utils/modal";
|
||||
import definePlugin, { OptionType } from "@utils/types";
|
||||
import { Button, ButtonLooks, ButtonWrapperClasses, Forms, Parser, Select, Tooltip, useMemo, useState } from "@webpack/common";
|
||||
import { Button, Forms, Parser, Select, useMemo, useState } from "@webpack/common";
|
||||
|
||||
const settings = definePluginSettings({
|
||||
replaceMessageContents: {
|
||||
|
@ -122,25 +123,51 @@ function PickerModal({ rootProps, close }: { rootProps: ModalProps, close(): voi
|
|||
);
|
||||
}
|
||||
|
||||
const ChatBarIcon: ChatBarButton = (_, isMainChat) => {
|
||||
if (!isMainChat) return null;
|
||||
|
||||
return (
|
||||
<ChatBarButton
|
||||
tooltip="Insert Timestamp"
|
||||
onClick={() => {
|
||||
const key = openModal(props => (
|
||||
<PickerModal
|
||||
rootProps={props}
|
||||
close={() => closeModal(key)}
|
||||
/>
|
||||
));
|
||||
}}
|
||||
buttonProps={{
|
||||
"aria-haspopup": "dialog",
|
||||
className: cl("button")
|
||||
}}
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
role="img"
|
||||
width="24"
|
||||
height="24"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<g fill="none" fill-rule="evenodd">
|
||||
<path fill="currentColor" d="M19 3h-1V1h-2v2H8V1H6v2H5c-1.11 0-1.99.9-1.99 2L3 19a2 2 0 0 0 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zm0 16H5V8h14v11zM7 10h5v5H7v-5z" />
|
||||
<rect width="24" height="24" />
|
||||
</g>
|
||||
</svg>
|
||||
</ChatBarButton>
|
||||
);
|
||||
};
|
||||
|
||||
export default definePlugin({
|
||||
name: "SendTimestamps",
|
||||
description: "Send timestamps easily via chat box button & text shortcuts. Read the extended description!",
|
||||
authors: [Devs.Ven, Devs.Tyler, Devs.Grzesiek11],
|
||||
dependencies: ["MessageEventsAPI"],
|
||||
dependencies: ["MessageEventsAPI", "ChatInputButtonAPI"],
|
||||
|
||||
settings: settings,
|
||||
|
||||
patches: [
|
||||
{
|
||||
find: "ChannelTextAreaButtons",
|
||||
replacement: {
|
||||
match: /(\i)\.push.{1,30}disabled:(\i),.{1,20}\},"gift"\)\)/,
|
||||
replace: "$&,(()=>{try{$2||$1.push($self.chatBarIcon(arguments[0]))}catch{}})()",
|
||||
}
|
||||
},
|
||||
],
|
||||
settings,
|
||||
|
||||
start() {
|
||||
addChatBarButton("SendTimestamps", ChatBarIcon);
|
||||
this.listener = addPreSendListener((_, msg) => {
|
||||
if (settings.store.replaceMessageContents) {
|
||||
msg.content = msg.content.replace(/`\d{1,2}:\d{2} ?(?:AM|PM)?`/gi, parseTime);
|
||||
|
@ -149,56 +176,10 @@ export default definePlugin({
|
|||
},
|
||||
|
||||
stop() {
|
||||
removeChatBarButton("SendTimestamps");
|
||||
removePreSendListener(this.listener);
|
||||
},
|
||||
|
||||
chatBarIcon(chatBoxProps: { type: { analyticsName: string; }; }) {
|
||||
if (chatBoxProps.type.analyticsName !== "normal") return null;
|
||||
|
||||
return (
|
||||
<Tooltip text="Insert Timestamp">
|
||||
{({ onMouseEnter, onMouseLeave }) => (
|
||||
<div style={{ display: "flex" }}>
|
||||
<Button
|
||||
aria-haspopup="dialog"
|
||||
aria-label="Insert Timestamp"
|
||||
size=""
|
||||
look={ButtonLooks.BLANK}
|
||||
onMouseEnter={onMouseEnter}
|
||||
onMouseLeave={onMouseLeave}
|
||||
innerClassName={ButtonWrapperClasses.button}
|
||||
onClick={() => {
|
||||
const key = openModal(props => (
|
||||
<PickerModal
|
||||
rootProps={props}
|
||||
close={() => closeModal(key)}
|
||||
/>
|
||||
));
|
||||
}}
|
||||
className={cl("button")}
|
||||
>
|
||||
<div className={ButtonWrapperClasses.buttonWrapper}>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
role="img"
|
||||
width="24"
|
||||
height="24"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<g fill="none" fill-rule="evenodd">
|
||||
<path fill="currentColor" d="M19 3h-1V1h-2v2H8V1H6v2H5c-1.11 0-1.99.9-1.99 2L3 19a2 2 0 0 0 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zm0 16H5V8h14v11zM7 10h5v5H7v-5z" />
|
||||
<rect width="24" height="24" />
|
||||
</g>
|
||||
</svg>
|
||||
</div>
|
||||
</Button>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
</Tooltip >
|
||||
);
|
||||
},
|
||||
|
||||
settingsAboutComponent() {
|
||||
const samples = [
|
||||
"12:00",
|
||||
|
|
|
@ -16,12 +16,12 @@
|
|||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { addChatBarButton, ChatBarButton, removeChatBarButton } from "@api/ChatButtons";
|
||||
import { addPreSendListener, removePreSendListener, SendListener } from "@api/MessageEvents";
|
||||
import { definePluginSettings } from "@api/Settings";
|
||||
import ErrorBoundary from "@components/ErrorBoundary";
|
||||
import { Devs } from "@utils/constants";
|
||||
import definePlugin, { OptionType } from "@utils/types";
|
||||
import { Button, ButtonLooks, ButtonWrapperClasses, React, Tooltip } from "@webpack/common";
|
||||
import { React, useEffect, useState } from "@webpack/common";
|
||||
|
||||
let lastState = false;
|
||||
|
||||
|
@ -41,19 +41,15 @@ const settings = definePluginSettings({
|
|||
}
|
||||
});
|
||||
|
||||
function SilentMessageToggle(chatBoxProps: {
|
||||
type: {
|
||||
analyticsName: string;
|
||||
};
|
||||
}) {
|
||||
const [enabled, setEnabled] = React.useState(lastState);
|
||||
const SilentMessageToggle: ChatBarButton = (_, isMainChat) => {
|
||||
const [enabled, setEnabled] = useState(lastState);
|
||||
|
||||
function setEnabledValue(value: boolean) {
|
||||
if (settings.store.persistState) lastState = value;
|
||||
setEnabled(value);
|
||||
}
|
||||
|
||||
React.useEffect(() => {
|
||||
useEffect(() => {
|
||||
const listener: SendListener = (_, message) => {
|
||||
if (enabled) {
|
||||
if (settings.store.autoDisable) setEnabledValue(false);
|
||||
|
@ -65,55 +61,37 @@ function SilentMessageToggle(chatBoxProps: {
|
|||
return () => void removePreSendListener(listener);
|
||||
}, [enabled]);
|
||||
|
||||
if (chatBoxProps.type.analyticsName !== "normal") return null;
|
||||
if (!isMainChat) return null;
|
||||
|
||||
return (
|
||||
<Tooltip text={enabled ? "Disable Silent Message" : "Enable Silent Message"}>
|
||||
{tooltipProps => (
|
||||
<div style={{ display: "flex" }}>
|
||||
<Button
|
||||
{...tooltipProps}
|
||||
onClick={() => setEnabledValue(!enabled)}
|
||||
size=""
|
||||
look={ButtonLooks.BLANK}
|
||||
innerClassName={ButtonWrapperClasses.button}
|
||||
style={{ padding: "0 6px" }}
|
||||
>
|
||||
<div className={ButtonWrapperClasses.buttonWrapper}>
|
||||
<svg width="24" height="24" viewBox="0 0 24 24">
|
||||
<path fill="currentColor" mask="url(#_)" d="M18 10.7101C15.1085 9.84957 13 7.17102 13 4c0-.30736.0198-.6101.0582-.907C12.7147 3.03189 12.3611 3 12 3 8.686 3 6 5.686 6 9v5c0 1.657-1.344 3-3 3v1h18v-1c-1.656 0-3-1.343-3-3v-3.2899ZM8.55493 19c.693 1.19 1.96897 2 3.44497 2s2.752-.81 3.445-2H8.55493ZM18.2624 5.50209 21 2.5V1h-4.9651v1.49791h2.4411L16 5.61088V7h5V5.50209h-2.7376Z" />
|
||||
{!enabled && <>
|
||||
<mask id="_">
|
||||
<path fill="#fff" d="M0 0h24v24H0Z" />
|
||||
<path stroke="#000" stroke-width="5.99068" d="M0 24 24 0" />
|
||||
</mask>
|
||||
<path fill="var(--status-danger)" d="m21.178 1.70703 1.414 1.414L4.12103 21.593l-1.414-1.415L21.178 1.70703Z" />
|
||||
</>}
|
||||
</svg>
|
||||
</div>
|
||||
</Button>
|
||||
</div>
|
||||
)}
|
||||
</Tooltip>
|
||||
<ChatBarButton
|
||||
tooltip={enabled ? "Disable Silent Message" : "Enable Silent Message"}
|
||||
onClick={() => setEnabledValue(!enabled)}
|
||||
buttonProps={{
|
||||
style: { padding: "0 6px" }
|
||||
}}
|
||||
>
|
||||
<svg width="24" height="24" viewBox="0 0 24 24">
|
||||
<path fill="currentColor" mask="url(#_)" d="M18 10.7101C15.1085 9.84957 13 7.17102 13 4c0-.30736.0198-.6101.0582-.907C12.7147 3.03189 12.3611 3 12 3 8.686 3 6 5.686 6 9v5c0 1.657-1.344 3-3 3v1h18v-1c-1.656 0-3-1.343-3-3v-3.2899ZM8.55493 19c.693 1.19 1.96897 2 3.44497 2s2.752-.81 3.445-2H8.55493ZM18.2624 5.50209 21 2.5V1h-4.9651v1.49791h2.4411L16 5.61088V7h5V5.50209h-2.7376Z" />
|
||||
{!enabled && <>
|
||||
<mask id="_">
|
||||
<path fill="#fff" d="M0 0h24v24H0Z" />
|
||||
<path stroke="#000" stroke-width="5.99068" d="M0 24 24 0" />
|
||||
</mask>
|
||||
<path fill="var(--status-danger)" d="m21.178 1.70703 1.414 1.414L4.12103 21.593l-1.414-1.415L21.178 1.70703Z" />
|
||||
</>}
|
||||
</svg>
|
||||
</ChatBarButton>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
export default definePlugin({
|
||||
name: "SilentMessageToggle",
|
||||
authors: [Devs.Nuckyz, Devs.CatNoir],
|
||||
description: "Adds a button to the chat bar to toggle sending a silent message.",
|
||||
dependencies: ["MessageEventsAPI"],
|
||||
|
||||
dependencies: ["MessageEventsAPI", "ChatInputButtonAPI"],
|
||||
settings,
|
||||
patches: [
|
||||
{
|
||||
find: "ChannelTextAreaButtons",
|
||||
replacement: {
|
||||
match: /(\i)\.push.{1,30}disabled:(\i),.{1,20}\},"gift"\)\)/,
|
||||
replace: "$&,(()=>{try{$2||$1.push($self.chatBarIcon(arguments[0]))}catch{}})()",
|
||||
}
|
||||
},
|
||||
],
|
||||
|
||||
chatBarIcon: ErrorBoundary.wrap(SilentMessageToggle, { noop: true }),
|
||||
start: () => addChatBarButton("SilentMessageToggle", SilentMessageToggle),
|
||||
stop: () => removeChatBarButton("SilentMessageToggle")
|
||||
});
|
||||
|
|
|
@ -16,12 +16,12 @@
|
|||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { addChatBarButton, ChatBarButton, removeChatBarButton } from "@api/ChatButtons";
|
||||
import { ApplicationCommandInputType, ApplicationCommandOptionType, findOption, sendBotMessage } from "@api/Commands";
|
||||
import { definePluginSettings } from "@api/Settings";
|
||||
import ErrorBoundary from "@components/ErrorBoundary";
|
||||
import { Devs } from "@utils/constants";
|
||||
import definePlugin, { OptionType } from "@utils/types";
|
||||
import { Button, ButtonLooks, ButtonWrapperClasses, FluxDispatcher, React, Tooltip } from "@webpack/common";
|
||||
import { FluxDispatcher, React } from "@webpack/common";
|
||||
|
||||
const settings = definePluginSettings({
|
||||
showIcon: {
|
||||
|
@ -37,45 +37,35 @@ const settings = definePluginSettings({
|
|||
}
|
||||
});
|
||||
|
||||
function SilentTypingToggle(chatBoxProps: {
|
||||
type: {
|
||||
analyticsName: string;
|
||||
};
|
||||
}) {
|
||||
const { isEnabled } = settings.use(["isEnabled"]);
|
||||
const SilentTypingToggle: ChatBarButton = (_, isMainChat) => {
|
||||
const { isEnabled, showIcon } = settings.use(["isEnabled", "showIcon"]);
|
||||
const toggle = () => settings.store.isEnabled = !settings.store.isEnabled;
|
||||
|
||||
if (chatBoxProps.type.analyticsName !== "normal") return null;
|
||||
if (!isMainChat || !showIcon) return null;
|
||||
|
||||
return (
|
||||
<Tooltip text={isEnabled ? "Disable Silent Typing" : "Enable Silent Typing"}>
|
||||
{(tooltipProps: any) => (
|
||||
<div style={{ display: "flex" }}>
|
||||
<Button
|
||||
{...tooltipProps}
|
||||
onClick={toggle}
|
||||
size=""
|
||||
look={ButtonLooks.BLANK}
|
||||
innerClassName={ButtonWrapperClasses.button}
|
||||
style={{ padding: "0 6px" }}
|
||||
>
|
||||
<div className={ButtonWrapperClasses.buttonWrapper}>
|
||||
<svg width="24" height="24" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 576 512">
|
||||
<path fill="currentColor" d="M528 448H48c-26.51 0-48-21.49-48-48V112c0-26.51 21.49-48 48-48h480c26.51 0 48 21.49 48 48v288c0 26.51-21.49 48-48 48zM128 180v-40c0-6.627-5.373-12-12-12H76c-6.627 0-12 5.373-12 12v40c0 6.627 5.373 12 12 12h40c6.627 0 12-5.373 12-12zm96 0v-40c0-6.627-5.373-12-12-12h-40c-6.627 0-12 5.373-12 12v40c0 6.627 5.373 12 12 12h40c6.627 0 12-5.373 12-12zm96 0v-40c0-6.627-5.373-12-12-12h-40c-6.627 0-12 5.373-12 12v40c0 6.627 5.373 12 12 12h40c6.627 0 12-5.373 12-12zm96 0v-40c0-6.627-5.373-12-12-12h-40c-6.627 0-12 5.373-12 12v40c0 6.627 5.373 12 12 12h40c6.627 0 12-5.373 12-12zm96 0v-40c0-6.627-5.373-12-12-12h-40c-6.627 0-12 5.373-12 12v40c0 6.627 5.373 12 12 12h40c6.627 0 12-5.373 12-12zm-336 96v-40c0-6.627-5.373-12-12-12h-40c-6.627 0-12 5.373-12 12v40c0 6.627 5.373 12 12 12h40c6.627 0 12-5.373 12-12zm96 0v-40c0-6.627-5.373-12-12-12h-40c-6.627 0-12 5.373-12 12v40c0 6.627 5.373 12 12 12h40c6.627 0 12-5.373 12-12zm96 0v-40c0-6.627-5.373-12-12-12h-40c-6.627 0-12 5.373-12 12v40c0 6.627 5.373 12 12 12h40c6.627 0 12-5.373 12-12zm96 0v-40c0-6.627-5.373-12-12-12h-40c-6.627 0-12 5.373-12 12v40c0 6.627 5.373 12 12 12h40c6.627 0 12-5.373 12-12zm-336 96v-40c0-6.627-5.373-12-12-12H76c-6.627 0-12 5.373-12 12v40c0 6.627 5.373 12 12 12h40c6.627 0 12-5.373 12-12zm288 0v-40c0-6.627-5.373-12-12-12H172c-6.627 0-12 5.373-12 12v40c0 6.627 5.373 12 12 12h232c6.627 0 12-5.373 12-12zm96 0v-40c0-6.627-5.373-12-12-12h-40c-6.627 0-12 5.373-12 12v40c0 6.627 5.373 12 12 12h40c6.627 0 12-5.373 12-12z" />
|
||||
{isEnabled && <path d="M13 432L590 48" stroke="var(--red-500)" stroke-width="72" stroke-linecap="round" />}
|
||||
</svg>
|
||||
</div>
|
||||
</Button>
|
||||
</div>
|
||||
)}
|
||||
</Tooltip>
|
||||
<ChatBarButton
|
||||
tooltip={isEnabled ? "Disable Silent Typing" : "Enable Silent Typing"}
|
||||
onClick={toggle}
|
||||
buttonProps={{
|
||||
style: { padding: "0 6px" }
|
||||
}}
|
||||
>
|
||||
<svg width="24" height="24" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 576 512">
|
||||
<path fill="currentColor" d="M528 448H48c-26.51 0-48-21.49-48-48V112c0-26.51 21.49-48 48-48h480c26.51 0 48 21.49 48 48v288c0 26.51-21.49 48-48 48zM128 180v-40c0-6.627-5.373-12-12-12H76c-6.627 0-12 5.373-12 12v40c0 6.627 5.373 12 12 12h40c6.627 0 12-5.373 12-12zm96 0v-40c0-6.627-5.373-12-12-12h-40c-6.627 0-12 5.373-12 12v40c0 6.627 5.373 12 12 12h40c6.627 0 12-5.373 12-12zm96 0v-40c0-6.627-5.373-12-12-12h-40c-6.627 0-12 5.373-12 12v40c0 6.627 5.373 12 12 12h40c6.627 0 12-5.373 12-12zm96 0v-40c0-6.627-5.373-12-12-12h-40c-6.627 0-12 5.373-12 12v40c0 6.627 5.373 12 12 12h40c6.627 0 12-5.373 12-12zm96 0v-40c0-6.627-5.373-12-12-12h-40c-6.627 0-12 5.373-12 12v40c0 6.627 5.373 12 12 12h40c6.627 0 12-5.373 12-12zm-336 96v-40c0-6.627-5.373-12-12-12h-40c-6.627 0-12 5.373-12 12v40c0 6.627 5.373 12 12 12h40c6.627 0 12-5.373 12-12zm96 0v-40c0-6.627-5.373-12-12-12h-40c-6.627 0-12 5.373-12 12v40c0 6.627 5.373 12 12 12h40c6.627 0 12-5.373 12-12zm96 0v-40c0-6.627-5.373-12-12-12h-40c-6.627 0-12 5.373-12 12v40c0 6.627 5.373 12 12 12h40c6.627 0 12-5.373 12-12zm96 0v-40c0-6.627-5.373-12-12-12h-40c-6.627 0-12 5.373-12 12v40c0 6.627 5.373 12 12 12h40c6.627 0 12-5.373 12-12zm-336 96v-40c0-6.627-5.373-12-12-12H76c-6.627 0-12 5.373-12 12v40c0 6.627 5.373 12 12 12h40c6.627 0 12-5.373 12-12zm288 0v-40c0-6.627-5.373-12-12-12H172c-6.627 0-12 5.373-12 12v40c0 6.627 5.373 12 12 12h232c6.627 0 12-5.373 12-12zm96 0v-40c0-6.627-5.373-12-12-12h-40c-6.627 0-12 5.373-12 12v40c0 6.627 5.373 12 12 12h40c6.627 0 12-5.373 12-12z" />
|
||||
{isEnabled && <path d="M13 432L590 48" stroke="var(--red-500)" stroke-width="72" stroke-linecap="round" />}
|
||||
</svg>
|
||||
</ChatBarButton>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
export default definePlugin({
|
||||
name: "SilentTyping",
|
||||
authors: [Devs.Ven, Devs.Rini],
|
||||
description: "Hide that you are typing",
|
||||
dependencies: ["CommandsAPI", "ChatInputButtonAPI"],
|
||||
settings,
|
||||
|
||||
patches: [
|
||||
{
|
||||
find: '.dispatch({type:"TYPING_START_LOCAL"',
|
||||
|
@ -84,17 +74,8 @@ export default definePlugin({
|
|||
replace: "startTyping:$self.startTyping,stop"
|
||||
}
|
||||
},
|
||||
{
|
||||
find: "ChannelTextAreaButtons",
|
||||
predicate: () => settings.store.showIcon,
|
||||
replacement: {
|
||||
match: /(\i)\.push.{1,30}disabled:(\i),.{1,20}\},"gift"\)\)/,
|
||||
replace: "$&,(()=>{try{$2||$1.push($self.chatBarIcon(arguments[0]))}catch{}})()",
|
||||
}
|
||||
},
|
||||
],
|
||||
dependencies: ["CommandsAPI"],
|
||||
settings,
|
||||
|
||||
commands: [{
|
||||
name: "silenttype",
|
||||
description: "Toggle whether you're hiding that you're typing or not.",
|
||||
|
@ -120,5 +101,6 @@ export default definePlugin({
|
|||
FluxDispatcher.dispatch({ type: "TYPING_START_LOCAL", channelId });
|
||||
},
|
||||
|
||||
chatBarIcon: ErrorBoundary.wrap(SilentTypingToggle, { noop: true }),
|
||||
start: () => addChatBarButton("SilentTyping", SilentTypingToggle),
|
||||
stop: () => removeChatBarButton("SilentTyping"),
|
||||
});
|
||||
|
|
|
@ -16,9 +16,9 @@
|
|||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { ChatBarButton } from "@api/ChatButtons";
|
||||
import { classes } from "@utils/misc";
|
||||
import { openModal } from "@utils/modal";
|
||||
import { Button, ButtonLooks, ButtonWrapperClasses, Tooltip } from "@webpack/common";
|
||||
|
||||
import { settings } from "./settings";
|
||||
import { TranslateModal } from "./TranslateModal";
|
||||
|
@ -37,42 +37,30 @@ export function TranslateIcon({ height = 24, width = 24, className }: { height?:
|
|||
);
|
||||
}
|
||||
|
||||
export function TranslateChatBarIcon({ slateProps }: { slateProps: { type: { analyticsName: string; }; }; }) {
|
||||
export const TranslateChatBarIcon: ChatBarButton = (props, isMainChat) => {
|
||||
const { autoTranslate } = settings.use(["autoTranslate"]);
|
||||
|
||||
if (slateProps.type.analyticsName !== "normal")
|
||||
return null;
|
||||
if (!isMainChat) return null;
|
||||
|
||||
const toggle = () => settings.store.autoTranslate = !autoTranslate;
|
||||
|
||||
return (
|
||||
<Tooltip text="Open Translate Modal">
|
||||
{({ onMouseEnter, onMouseLeave }) => (
|
||||
<div style={{ display: "flex" }}>
|
||||
<Button
|
||||
aria-haspopup="dialog"
|
||||
aria-label="Open Translate Modal"
|
||||
size=""
|
||||
look={ButtonLooks.BLANK}
|
||||
onMouseEnter={onMouseEnter}
|
||||
onMouseLeave={onMouseLeave}
|
||||
innerClassName={ButtonWrapperClasses.button}
|
||||
onClick={e => {
|
||||
if (e.shiftKey) return toggle();
|
||||
<ChatBarButton
|
||||
tooltip="Open Translate Modal"
|
||||
onClick={e => {
|
||||
if (e.shiftKey) return toggle();
|
||||
|
||||
openModal(props => (
|
||||
<TranslateModal rootProps={props} />
|
||||
));
|
||||
}}
|
||||
onContextMenu={() => toggle()}
|
||||
style={{ padding: "0 4px" }}
|
||||
>
|
||||
<div className={ButtonWrapperClasses.buttonWrapper}>
|
||||
<TranslateIcon className={cl({ "auto-translate": autoTranslate })} />
|
||||
</div>
|
||||
</Button>
|
||||
</div>
|
||||
)}
|
||||
</Tooltip>
|
||||
openModal(props => (
|
||||
<TranslateModal rootProps={props} />
|
||||
));
|
||||
}}
|
||||
onContextMenu={() => toggle()}
|
||||
buttonProps={{
|
||||
"aria-haspopup": "dialog",
|
||||
style: { padding: "0 4px" }
|
||||
}}
|
||||
>
|
||||
<TranslateIcon className={cl({ "auto-translate": autoTranslate })} />
|
||||
</ChatBarButton>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
|
|
@ -18,11 +18,11 @@
|
|||
|
||||
import "./styles.css";
|
||||
|
||||
import { addChatBarButton, removeChatBarButton } from "@api/ChatButtons";
|
||||
import { addContextMenuPatch, findGroupChildrenByChildId, NavContextMenuPatchCallback, removeContextMenuPatch } from "@api/ContextMenu";
|
||||
import { addAccessory, removeAccessory } from "@api/MessageAccessories";
|
||||
import { addPreSendListener, removePreSendListener } from "@api/MessageEvents";
|
||||
import { addButton, removeButton } from "@api/MessagePopover";
|
||||
import ErrorBoundary from "@components/ErrorBoundary";
|
||||
import { Devs } from "@utils/constants";
|
||||
import definePlugin from "@utils/types";
|
||||
import { ChannelStore, Menu } from "@webpack/common";
|
||||
|
@ -55,25 +55,16 @@ export default definePlugin({
|
|||
name: "Translate",
|
||||
description: "Translate messages with Google Translate",
|
||||
authors: [Devs.Ven],
|
||||
dependencies: ["MessageAccessoriesAPI", "MessagePopoverAPI", "MessageEventsAPI"],
|
||||
dependencies: ["MessageAccessoriesAPI", "MessagePopoverAPI", "MessageEventsAPI", "ChatInputButtonAPI"],
|
||||
settings,
|
||||
// not used, just here in case some other plugin wants it or w/e
|
||||
translate,
|
||||
|
||||
patches: [
|
||||
{
|
||||
find: "ChannelTextAreaButtons",
|
||||
replacement: {
|
||||
match: /(\i)\.push.{1,30}disabled:(\i),.{1,20}\},"gift"\)\)/,
|
||||
replace: "$&,(()=>{try{$2||$1.push($self.chatBarIcon(arguments[0]))}catch{}})()",
|
||||
}
|
||||
},
|
||||
],
|
||||
|
||||
start() {
|
||||
addAccessory("vc-translation", props => <TranslationAccessory message={props.message} />);
|
||||
|
||||
addContextMenuPatch("message", messageCtxPatch);
|
||||
addChatBarButton("vc-translate", TranslateChatBarIcon);
|
||||
|
||||
addButton("vc-translate", message => {
|
||||
if (!message.content) return null;
|
||||
|
@ -101,13 +92,8 @@ export default definePlugin({
|
|||
stop() {
|
||||
removePreSendListener(this.preSend);
|
||||
removeContextMenuPatch("message", messageCtxPatch);
|
||||
removeChatBarButton("vc-translate");
|
||||
removeButton("vc-translate");
|
||||
removeAccessory("vc-translation");
|
||||
},
|
||||
|
||||
chatBarIcon: (slateProps: any) => (
|
||||
<ErrorBoundary noop>
|
||||
<TranslateChatBarIcon slateProps={slateProps} />
|
||||
</ErrorBoundary>
|
||||
)
|
||||
});
|
||||
|
|
Loading…
Reference in a new issue