mirror of
https://github.com/Vendicated/Vencord.git
synced 2025-01-10 18:06:22 +00:00
Merge branch 'dev' into remix
This commit is contained in:
commit
8e660bad9f
22 changed files with 420 additions and 347 deletions
|
@ -118,11 +118,15 @@ const installerBin = await ensureBinary();
|
|||
|
||||
console.log("Now running Installer...");
|
||||
|
||||
execFileSync(installerBin, {
|
||||
stdio: "inherit",
|
||||
env: {
|
||||
...process.env,
|
||||
VENCORD_USER_DATA_DIR: BASE_DIR,
|
||||
VENCORD_DEV_INSTALL: "1"
|
||||
}
|
||||
});
|
||||
try {
|
||||
execFileSync(installerBin, {
|
||||
stdio: "inherit",
|
||||
env: {
|
||||
...process.env,
|
||||
VENCORD_USER_DATA_DIR: BASE_DIR,
|
||||
VENCORD_DEV_INSTALL: "1"
|
||||
}
|
||||
});
|
||||
} catch {
|
||||
console.error("Something went wrong. Please check the logs above.");
|
||||
}
|
||||
|
|
4
src/api/ChatButton.css
Normal file
4
src/api/ChatButton.css
Normal file
|
@ -0,0 +1,4 @@
|
|||
.vc-chatbar-button {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
128
src/api/ChatButtons.tsx
Normal file
128
src/api/ChatButtons.tsx
Normal file
|
@ -0,0 +1,128 @@
|
|||
/*
|
||||
* Vencord, a Discord client mod
|
||||
* Copyright (c) 2024 Vendicated and contributors
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import "./ChatButton.css";
|
||||
|
||||
import ErrorBoundary from "@components/ErrorBoundary";
|
||||
import { Logger } from "@utils/Logger";
|
||||
import { waitFor } from "@webpack";
|
||||
import { Button, ButtonLooks, ButtonWrapperClasses, Tooltip } from "@webpack/common";
|
||||
import { Channel } from "discord-types/general";
|
||||
import { HTMLProps, MouseEventHandler, ReactNode } from "react";
|
||||
|
||||
let ChannelTextAreaClasses: Record<"button" | "buttonContainer", string>;
|
||||
waitFor(["buttonContainer", "channelTextArea"], m => ChannelTextAreaClasses = m);
|
||||
|
||||
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; }) => JSX.Element | null;
|
||||
|
||||
const buttonFactories = new Map<string, ChatBarButton>();
|
||||
const logger = new Logger("ChatButtons");
|
||||
|
||||
export function _injectButtons(buttons: ReactNode[], props: ChatBarProps) {
|
||||
if (props.disabled) return;
|
||||
|
||||
for (const [key, Button] of buttonFactories) {
|
||||
buttons.push(
|
||||
<ErrorBoundary noop key={key} onError={e => logger.error(`Failed to render ${key}`, e.error)}>
|
||||
<Button {...props} isMainChat={props.type.analyticsName === "normal"} />
|
||||
</ErrorBoundary>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
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 className={`expression-picker-chat-input-button ${ChannelTextAreaClasses?.buttonContainer ?? ""} vc-chatbar-button`}>
|
||||
<Button
|
||||
aria-label={props.tooltip}
|
||||
size=""
|
||||
look={ButtonLooks.BLANK}
|
||||
onMouseEnter={onMouseEnter}
|
||||
onMouseLeave={onMouseLeave}
|
||||
innerClassName={`${ButtonWrapperClasses.button} ${ChannelTextAreaClasses?.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;
|
||||
|
|
|
@ -129,6 +129,15 @@ if (!IS_VANILLA) {
|
|||
});
|
||||
|
||||
process.env.DATA_DIR = join(app.getPath("userData"), "..", "Vencord");
|
||||
|
||||
// Monkey patch commandLine to disable WidgetLayering: Fix DevTools context menus https://github.com/electron/electron/issues/38790
|
||||
const originalAppend = app.commandLine.appendSwitch;
|
||||
app.commandLine.appendSwitch = function (...args) {
|
||||
if (args[0] === "disable-features" && !args[1]?.includes("WidgetLayering")) {
|
||||
args[1] += ",WidgetLayering";
|
||||
}
|
||||
return originalAppend.apply(this, args);
|
||||
};
|
||||
} else {
|
||||
console.log("[Vencord] Running in vanilla mode. Not loading Vencord");
|
||||
}
|
||||
|
|
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]);"
|
||||
}
|
||||
}]
|
||||
});
|
|
@ -140,11 +140,11 @@ export const defaultRules = [
|
|||
"tt_content",
|
||||
"lr@yandex.*",
|
||||
"redircnt@yandex.*",
|
||||
"feature@youtube.com",
|
||||
"kw@youtube.com",
|
||||
"si@youtube.com",
|
||||
"pp@youtube.com",
|
||||
"si@youtu.be",
|
||||
"feature@*.youtube.com",
|
||||
"kw@*.youtube.com",
|
||||
"si@*.youtube.com",
|
||||
"pp@*.youtube.com",
|
||||
"si@*.youtu.be",
|
||||
"wt_zmc",
|
||||
"utm_source",
|
||||
"utm_content",
|
||||
|
|
|
@ -16,8 +16,9 @@ app.on("browser-window-created", (_, win) => {
|
|||
|
||||
frame.executeJavaScript(`
|
||||
new MutationObserver(() => {
|
||||
let err = document.querySelector(".ytp-error-content-wrap-subreason span")?.textContent;
|
||||
if (err && err.includes("blocked it from display")) window.location.reload()
|
||||
if(
|
||||
document.querySelector('div.ytp-error-content-wrap-subreason a[href^="https://www.youtube.com/watch?v="]')
|
||||
) location.reload()
|
||||
}).observe(document.body, { childList: true, subtree:true });
|
||||
`);
|
||||
}
|
||||
|
|
|
@ -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,31 @@ 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",
|
||||
}}
|
||||
>
|
||||
<svg
|
||||
aria-hidden
|
||||
role="img"
|
||||
width="24"
|
||||
height="24"
|
||||
viewBox={"0 0 64 64"}
|
||||
style={{ scale: "1.39", translate: "0 -1px" }}
|
||||
>
|
||||
<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 +103,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 +113,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",
|
||||
|
@ -151,10 +122,7 @@ export default definePlugin({
|
|||
),
|
||||
settings,
|
||||
async start() {
|
||||
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 +138,16 @@ export default definePlugin({
|
|||
}
|
||||
: null;
|
||||
});
|
||||
|
||||
addChatBarButton("InvisibleChat", ChatBarIcon);
|
||||
|
||||
const { default: StegCloak } = await getStegCloak();
|
||||
steggo = new StegCloak(true, false);
|
||||
},
|
||||
|
||||
stop() {
|
||||
removeButton("invDecrypt");
|
||||
removeButton("InvisibleChat");
|
||||
removeButton("InvisibleChat");
|
||||
},
|
||||
|
||||
// Gets the Embed of a Link
|
||||
|
@ -216,7 +190,6 @@ export default definePlugin({
|
|||
});
|
||||
},
|
||||
|
||||
chatBarIcon: ErrorBoundary.wrap(ChatBarIcon, { noop: true }),
|
||||
popOverIcon: () => <PopOverIcon />,
|
||||
indicator: ErrorBoundary.wrap(Indicator, { noop: true })
|
||||
});
|
||||
|
|
|
@ -198,7 +198,7 @@ export default definePlugin({
|
|||
replacement: [
|
||||
// make the tag show the right text
|
||||
{
|
||||
match: /(switch\((\i)\){.+?)case (\i(?:\.\i)?)\.BOT:default:(\i)=(\i\.\i\.Messages)\.BOT_TAG_BOT/,
|
||||
match: /(switch\((\i)\){.+?)case (\i(?:\.\i)?)\.BOT:default:(\i)=.{0,40}(\i\.\i\.Messages)\.BOT_TAG_BOT/,
|
||||
replace: (_, origSwitch, variant, tags, displayedText, strings) =>
|
||||
`${origSwitch}default:{${displayedText} = $self.getTagText(${tags}[${variant}], ${strings})}`
|
||||
},
|
||||
|
|
|
@ -24,7 +24,7 @@ const settings = definePluginSettings({
|
|||
export default definePlugin({
|
||||
name: "PictureInPicture",
|
||||
description: "Adds picture in picture to videos (next to the Download button)",
|
||||
authors: [Devs.Lumap],
|
||||
authors: [Devs.Nobody],
|
||||
settings,
|
||||
patches: [
|
||||
{
|
||||
|
|
|
@ -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 definePlugin, { StartAt } 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,11 @@ const getAttachments = async (channelId: string) =>
|
|||
);
|
||||
|
||||
|
||||
export function PreviewButton(chatBoxProps: Props) {
|
||||
const { isEmpty, attachments } = chatBoxProps.type;
|
||||
|
||||
const PreviewButton: ChatBarButton = ({ isMainChat, isEmpty, type: { attachments } }) => {
|
||||
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 +85,47 @@ 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: {
|
||||
translate: "0 2px"
|
||||
}
|
||||
}}
|
||||
>
|
||||
<svg
|
||||
fill="currentColor"
|
||||
fillRule="evenodd"
|
||||
width="24"
|
||||
height="24"
|
||||
viewBox="0 0 24 24"
|
||||
style={{ scale: "1.096", translate: "0 -1px" }}
|
||||
>
|
||||
<path d="M22.89 11.7c.07.2.07.4 0 .6C22.27 13.9 19.1 21 12 21c-7.11 0-10.27-7.11-10.89-8.7a.83.83 0 0 1 0-.6C1.73 10.1 4.9 3 12 3c7.11 0 10.27 7.11 10.89 8.7Zm-4.5-3.62A15.11 15.11 0 0 1 20.85 12c-.38.88-1.18 2.47-2.46 3.92C16.87 17.62 14.8 19 12 19c-2.8 0-4.87-1.38-6.39-3.08A15.11 15.11 0 0 1 3.15 12c.38-.88 1.18-2.47 2.46-3.92C7.13 6.38 9.2 5 12 5c2.8 0 4.87 1.38 6.39 3.08ZM15.56 11.77c.2-.1.44.02.44.23a4 4 0 1 1-4-4c.21 0 .33.25.23.44a2.5 2.5 0 0 0 3.32 3.32Z" />
|
||||
</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"],
|
||||
// start early to ensure we're the first plugin to add our button
|
||||
// This makes the popping in less awkward
|
||||
startAt: StartAt.Init,
|
||||
|
||||
chatBarIcon: ErrorBoundary.wrap(PreviewButton, { noop: true }),
|
||||
start: () => addChatBarButton("previewMessage", PreviewButton),
|
||||
stop: () => removeChatBarButton("previewMessage"),
|
||||
});
|
||||
|
|
|
@ -25,16 +25,17 @@ function onClick() {
|
|||
const channels: Array<any> = [];
|
||||
|
||||
Object.values(GuildStore.getGuilds()).forEach(guild => {
|
||||
GuildChannelStore.getChannels(guild.id).SELECTABLE.forEach((c: { channel: { id: string; }; }) => {
|
||||
if (!ReadStateStore.hasUnread(c.channel.id)) return;
|
||||
GuildChannelStore.getChannels(guild.id).SELECTABLE
|
||||
.concat(GuildChannelStore.getChannels(guild.id).VOCAL)
|
||||
.forEach((c: { channel: { id: string; }; }) => {
|
||||
if (!ReadStateStore.hasUnread(c.channel.id)) return;
|
||||
|
||||
channels.push({
|
||||
channelId: c.channel.id,
|
||||
// messageId: c.channel?.lastMessageId,
|
||||
messageId: ReadStateStore.lastMessageId(c.channel.id),
|
||||
readStateType: 0
|
||||
channels.push({
|
||||
channelId: c.channel.id,
|
||||
messageId: ReadStateStore.lastMessageId(c.channel.id),
|
||||
readStateType: 0
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
FluxDispatcher.dispatch({
|
||||
|
|
|
@ -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,49 @@ 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" }}
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
role="img"
|
||||
width="24"
|
||||
height="24"
|
||||
viewBox="0 0 24 24"
|
||||
style={{ scale: "1.2" }}
|
||||
>
|
||||
<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 +174,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",
|
||||
|
|
|
@ -42,10 +42,6 @@
|
|||
margin-bottom: 1em;
|
||||
}
|
||||
|
||||
.vc-st-button {
|
||||
padding: 0 6px;
|
||||
}
|
||||
|
||||
.vc-st-button svg {
|
||||
transform: scale(1.1) translateY(1px);
|
||||
}
|
||||
|
|
|
@ -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,39 @@ 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)}
|
||||
>
|
||||
<svg
|
||||
width="24"
|
||||
height="24"
|
||||
viewBox="0 0 24 24"
|
||||
style={{ scale: "1.2" }}
|
||||
>
|
||||
<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,32 @@ 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}
|
||||
>
|
||||
<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 +71,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 +98,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,11 @@
|
|||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { ChatBarButton } from "@api/ChatButtons";
|
||||
import { Margins } from "@utils/margins";
|
||||
import { classes } from "@utils/misc";
|
||||
import { openModal } from "@utils/modal";
|
||||
import { Button, ButtonLooks, ButtonWrapperClasses, Tooltip } from "@webpack/common";
|
||||
import { Alerts, Forms } from "@webpack/common";
|
||||
|
||||
import { settings } from "./settings";
|
||||
import { TranslateModal } from "./TranslateModal";
|
||||
|
@ -37,42 +39,49 @@ export function TranslateIcon({ height = 24, width = 24, className }: { height?:
|
|||
);
|
||||
}
|
||||
|
||||
export function TranslateChatBarIcon({ slateProps }: { slateProps: { type: { analyticsName: string; }; }; }) {
|
||||
export const TranslateChatBarIcon: ChatBarButton = ({ isMainChat }) => {
|
||||
const { autoTranslate } = settings.use(["autoTranslate"]);
|
||||
|
||||
if (slateProps.type.analyticsName !== "normal")
|
||||
return null;
|
||||
if (!isMainChat) return null;
|
||||
|
||||
const toggle = () => settings.store.autoTranslate = !autoTranslate;
|
||||
const toggle = () => {
|
||||
const newState = !autoTranslate;
|
||||
settings.store.autoTranslate = newState;
|
||||
if (newState && settings.store.showAutoTranslateAlert !== false)
|
||||
Alerts.show({
|
||||
title: "Vencord Auto-Translate Enabled",
|
||||
body: <>
|
||||
<Forms.FormText>
|
||||
You just enabled auto translate (by right clicking the Translate icon). Any message you send will automatically be translated before being sent.
|
||||
</Forms.FormText>
|
||||
<Forms.FormText className={Margins.top16}>
|
||||
If this was an accident, disable it again, or it will change your message content before sending.
|
||||
</Forms.FormText>
|
||||
</>,
|
||||
cancelText: "Disable Auto-Translate",
|
||||
confirmText: "Got it",
|
||||
secondaryConfirmText: "Don't show again",
|
||||
onConfirmSecondary: () => settings.store.showAutoTranslateAlert = false,
|
||||
onCancel: () => settings.store.autoTranslate = false
|
||||
});
|
||||
};
|
||||
|
||||
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"
|
||||
}}
|
||||
>
|
||||
<TranslateIcon className={cl({ "auto-translate": autoTranslate, "chat-button": true })} />
|
||||
</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>
|
||||
)
|
||||
});
|
||||
|
|
|
@ -49,4 +49,6 @@ export const settings = definePluginSettings({
|
|||
description: "Automatically translate your messages before sending. You can also shift/right click the translate button to toggle this",
|
||||
default: false
|
||||
}
|
||||
});
|
||||
}).withPrivateSettings<{
|
||||
showAutoTranslateAlert: boolean;
|
||||
}>();
|
||||
|
|
|
@ -35,3 +35,7 @@
|
|||
.vc-trans-auto-translate {
|
||||
color: var(--green-360);
|
||||
}
|
||||
|
||||
.vc-trans-chat-button {
|
||||
scale: 1.085;
|
||||
}
|
||||
|
|
|
@ -42,6 +42,10 @@ export interface Dev {
|
|||
* If you are fine with attribution but don't want the badge, add badge: false
|
||||
*/
|
||||
export const Devs = /* #__PURE__*/ Object.freeze({
|
||||
Nobody: {
|
||||
name: "Nobody",
|
||||
id: 0n,
|
||||
},
|
||||
Ven: {
|
||||
name: "Vendicated",
|
||||
id: 343383572805058560n
|
||||
|
@ -359,10 +363,6 @@ export const Devs = /* #__PURE__*/ Object.freeze({
|
|||
name: "bb010g",
|
||||
id: 72791153467990016n,
|
||||
},
|
||||
Lumap: {
|
||||
name: "lumap",
|
||||
id: 635383782576357407n
|
||||
},
|
||||
Dolfies: {
|
||||
name: "Dolfies",
|
||||
id: 852892297661906993n,
|
||||
|
|
Loading…
Reference in a new issue