Refactor ContextMenuAPI (#2236)
This commit is contained in:
parent
612fdf8952
commit
42a9fa2d47
25 changed files with 220 additions and 245 deletions
|
@ -17,22 +17,20 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { Logger } from "@utils/Logger";
|
import { Logger } from "@utils/Logger";
|
||||||
|
import { Menu, React } from "@webpack/common";
|
||||||
import type { ReactElement } from "react";
|
import type { ReactElement } from "react";
|
||||||
|
|
||||||
type ContextMenuPatchCallbackReturn = (() => void) | void;
|
|
||||||
/**
|
/**
|
||||||
* @param children The rendered context menu elements
|
* @param children The rendered context menu elements
|
||||||
* @param args Any arguments passed into making the context menu, like the guild, channel, user or message for example
|
* @param args Any arguments passed into making the context menu, like the guild, channel, user or message for example
|
||||||
* @returns A callback which is only ran once used to modify the context menu elements (Use to avoid duplicates)
|
|
||||||
*/
|
*/
|
||||||
export type NavContextMenuPatchCallback = (children: Array<ReactElement | null>, ...args: Array<any>) => ContextMenuPatchCallbackReturn;
|
export type NavContextMenuPatchCallback = (children: Array<ReactElement | null>, ...args: Array<any>) => void;
|
||||||
/**
|
/**
|
||||||
* @param navId The navId of the context menu being patched
|
* @param navId The navId of the context menu being patched
|
||||||
* @param children The rendered context menu elements
|
* @param children The rendered context menu elements
|
||||||
* @param args Any arguments passed into making the context menu, like the guild, channel, user or message for example
|
* @param args Any arguments passed into making the context menu, like the guild, channel, user or message for example
|
||||||
* @returns A callback which is only ran once used to modify the context menu elements (Use to avoid duplicates)
|
|
||||||
*/
|
*/
|
||||||
export type GlobalContextMenuPatchCallback = (navId: string, children: Array<ReactElement | null>, ...args: Array<any>) => ContextMenuPatchCallbackReturn;
|
export type GlobalContextMenuPatchCallback = (navId: string, children: Array<ReactElement | null>, ...args: Array<any>) => void;
|
||||||
|
|
||||||
const ContextMenuLogger = new Logger("ContextMenu");
|
const ContextMenuLogger = new Logger("ContextMenu");
|
||||||
|
|
||||||
|
@ -93,14 +91,19 @@ export function removeGlobalContextMenuPatch(patch: GlobalContextMenuPatchCallba
|
||||||
* @param id The id of the child. If an array is specified, all ids will be tried
|
* @param id The id of the child. If an array is specified, all ids will be tried
|
||||||
* @param children The context menu children
|
* @param children The context menu children
|
||||||
*/
|
*/
|
||||||
export function findGroupChildrenByChildId(id: string | string[], children: Array<ReactElement | null>, _itemsArray?: Array<ReactElement | null>): Array<ReactElement | null> | null {
|
export function findGroupChildrenByChildId(id: string | string[], children: Array<ReactElement | null>): Array<ReactElement | null> | null {
|
||||||
for (const child of children) {
|
for (const child of children) {
|
||||||
if (child == null) continue;
|
if (child == null) continue;
|
||||||
|
|
||||||
|
if (Array.isArray(child)) {
|
||||||
|
const found = findGroupChildrenByChildId(id, child);
|
||||||
|
if (found !== null) return found;
|
||||||
|
}
|
||||||
|
|
||||||
if (
|
if (
|
||||||
(Array.isArray(id) && id.some(id => child.props?.id === id))
|
(Array.isArray(id) && id.some(id => child.props?.id === id))
|
||||||
|| child.props?.id === id
|
|| child.props?.id === id
|
||||||
) return _itemsArray ?? null;
|
) return children;
|
||||||
|
|
||||||
let nextChildren = child.props?.children;
|
let nextChildren = child.props?.children;
|
||||||
if (nextChildren) {
|
if (nextChildren) {
|
||||||
|
@ -109,7 +112,7 @@ export function findGroupChildrenByChildId(id: string | string[], children: Arra
|
||||||
child.props.children = nextChildren;
|
child.props.children = nextChildren;
|
||||||
}
|
}
|
||||||
|
|
||||||
const found = findGroupChildrenByChildId(id, nextChildren, nextChildren);
|
const found = findGroupChildrenByChildId(id, nextChildren);
|
||||||
if (found !== null) return found;
|
if (found !== null) return found;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -126,9 +129,12 @@ interface ContextMenuProps {
|
||||||
onClose: (callback: (...args: Array<any>) => any) => void;
|
onClose: (callback: (...args: Array<any>) => any) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
const patchedMenus = new WeakSet();
|
export function _usePatchContextMenu(props: ContextMenuProps) {
|
||||||
|
props = {
|
||||||
|
...props,
|
||||||
|
children: cloneMenuChildren(props.children),
|
||||||
|
};
|
||||||
|
|
||||||
export function _patchContextMenu(props: ContextMenuProps) {
|
|
||||||
props.contextMenuApiArguments ??= [];
|
props.contextMenuApiArguments ??= [];
|
||||||
const contextMenuPatches = navPatches.get(props.navId);
|
const contextMenuPatches = navPatches.get(props.navId);
|
||||||
|
|
||||||
|
@ -137,8 +143,7 @@ export function _patchContextMenu(props: ContextMenuProps) {
|
||||||
if (contextMenuPatches) {
|
if (contextMenuPatches) {
|
||||||
for (const patch of contextMenuPatches) {
|
for (const patch of contextMenuPatches) {
|
||||||
try {
|
try {
|
||||||
const callback = patch(props.children, ...props.contextMenuApiArguments);
|
patch(props.children, ...props.contextMenuApiArguments);
|
||||||
if (!patchedMenus.has(props)) callback?.();
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
ContextMenuLogger.error(`Patch for ${props.navId} errored,`, err);
|
ContextMenuLogger.error(`Patch for ${props.navId} errored,`, err);
|
||||||
}
|
}
|
||||||
|
@ -147,12 +152,30 @@ export function _patchContextMenu(props: ContextMenuProps) {
|
||||||
|
|
||||||
for (const patch of globalPatches) {
|
for (const patch of globalPatches) {
|
||||||
try {
|
try {
|
||||||
const callback = patch(props.navId, props.children, ...props.contextMenuApiArguments);
|
patch(props.navId, props.children, ...props.contextMenuApiArguments);
|
||||||
if (!patchedMenus.has(props)) callback?.();
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
ContextMenuLogger.error("Global patch errored,", err);
|
ContextMenuLogger.error("Global patch errored,", err);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
patchedMenus.add(props);
|
return props;
|
||||||
|
}
|
||||||
|
|
||||||
|
function cloneMenuChildren(obj: ReactElement | Array<ReactElement | null> | null) {
|
||||||
|
if (Array.isArray(obj)) {
|
||||||
|
return obj.map(cloneMenuChildren);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (React.isValidElement(obj)) {
|
||||||
|
obj = React.cloneElement(obj);
|
||||||
|
|
||||||
|
if (
|
||||||
|
obj?.props?.children &&
|
||||||
|
(obj.type !== Menu.MenuControlItem || obj.type === Menu.MenuControlItem && obj.props.control != null)
|
||||||
|
) {
|
||||||
|
obj.props.children = cloneMenuChildren(obj.props.children);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return obj;
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,15 +22,15 @@ import definePlugin from "@utils/types";
|
||||||
export default definePlugin({
|
export default definePlugin({
|
||||||
name: "ContextMenuAPI",
|
name: "ContextMenuAPI",
|
||||||
description: "API for adding/removing items to/from context menus.",
|
description: "API for adding/removing items to/from context menus.",
|
||||||
authors: [Devs.Nuckyz, Devs.Ven],
|
authors: [Devs.Nuckyz, Devs.Ven, Devs.Kyuuhachi],
|
||||||
required: true,
|
required: true,
|
||||||
|
|
||||||
patches: [
|
patches: [
|
||||||
{
|
{
|
||||||
find: "♫ (つ。◕‿‿◕。)つ ♪",
|
find: "♫ (つ。◕‿‿◕。)つ ♪",
|
||||||
replacement: {
|
replacement: {
|
||||||
match: /let{navId:/,
|
match: /(?=let{navId:)(?<=function \i\((\i)\).+?)/,
|
||||||
replace: "Vencord.Api.ContextMenu._patchContextMenu(arguments[0]);$&"
|
replace: "$1=Vencord.Api.ContextMenu._usePatchContextMenu($1);"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
|
@ -16,7 +16,7 @@
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { addContextMenuPatch } from "@api/ContextMenu";
|
import { findGroupChildrenByChildId } from "@api/ContextMenu";
|
||||||
import { Settings } from "@api/Settings";
|
import { Settings } from "@api/Settings";
|
||||||
import { Devs } from "@utils/constants";
|
import { Devs } from "@utils/constants";
|
||||||
import definePlugin, { OptionType } from "@utils/types";
|
import definePlugin, { OptionType } from "@utils/types";
|
||||||
|
@ -30,21 +30,21 @@ export default definePlugin({
|
||||||
authors: [Devs.Ven, Devs.Megu],
|
authors: [Devs.Ven, Devs.Megu],
|
||||||
required: true,
|
required: true,
|
||||||
|
|
||||||
start() {
|
contextMenus: {
|
||||||
// The settings shortcuts in the user settings cog context menu
|
// The settings shortcuts in the user settings cog context menu
|
||||||
// read the elements from a hardcoded map which for obvious reason
|
// read the elements from a hardcoded map which for obvious reason
|
||||||
// doesn't contain our sections. This patches the actions of our
|
// doesn't contain our sections. This patches the actions of our
|
||||||
// sections to manually use SettingsRouter (which only works on desktop
|
// sections to manually use SettingsRouter (which only works on desktop
|
||||||
// but the context menu is usually not available on mobile anyway)
|
// but the context menu is usually not available on mobile anyway)
|
||||||
addContextMenuPatch("user-settings-cog", children => () => {
|
"user-settings-cog"(children) {
|
||||||
const section = children.find(c => Array.isArray(c) && c.some(it => it?.props?.id === "VencordSettings")) as any;
|
const section = findGroupChildrenByChildId("VencordSettings", children);
|
||||||
section?.forEach(c => {
|
section?.forEach(c => {
|
||||||
const id = c?.props?.id;
|
const id = c?.props?.id;
|
||||||
if (id?.startsWith("Vencord") || id?.startsWith("Vesktop")) {
|
if (id?.startsWith("Vencord") || id?.startsWith("Vesktop")) {
|
||||||
c.props.action = () => SettingsRouter.open(id);
|
c!.props.action = () => SettingsRouter.open(id);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
patches: [{
|
patches: [{
|
||||||
|
|
|
@ -16,7 +16,7 @@
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { addContextMenuPatch, NavContextMenuPatchCallback, removeContextMenuPatch } from "@api/ContextMenu";
|
import { NavContextMenuPatchCallback } from "@api/ContextMenu";
|
||||||
import { ScreenshareIcon } from "@components/Icons";
|
import { ScreenshareIcon } from "@components/Icons";
|
||||||
import { Devs } from "@utils/constants";
|
import { Devs } from "@utils/constants";
|
||||||
import { openImageModal } from "@utils/discord";
|
import { openImageModal } from "@utils/discord";
|
||||||
|
@ -60,7 +60,7 @@ export const handleViewPreview = async ({ guildId, channelId, ownerId }: Applica
|
||||||
openImageModal(previewUrl);
|
openImageModal(previewUrl);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const addViewStreamContext: NavContextMenuPatchCallback = (children, { userId }: { userId: string | bigint; }) => () => {
|
export const addViewStreamContext: NavContextMenuPatchCallback = (children, { userId }: { userId: string | bigint; }) => {
|
||||||
const stream = ApplicationStreamingStore.getAnyStreamForUser(userId);
|
const stream = ApplicationStreamingStore.getAnyStreamForUser(userId);
|
||||||
if (!stream) return;
|
if (!stream) return;
|
||||||
|
|
||||||
|
@ -89,12 +89,8 @@ export default definePlugin({
|
||||||
name: "BiggerStreamPreview",
|
name: "BiggerStreamPreview",
|
||||||
description: "This plugin allows you to enlarge stream previews",
|
description: "This plugin allows you to enlarge stream previews",
|
||||||
authors: [Devs.phil],
|
authors: [Devs.phil],
|
||||||
start: () => {
|
contextMenus: {
|
||||||
addContextMenuPatch("user-context", userContextPatch);
|
"user-context": userContextPatch,
|
||||||
addContextMenuPatch("stream-context", streamContextPatch);
|
"stream-context": streamContextPatch
|
||||||
},
|
|
||||||
stop: () => {
|
|
||||||
removeContextMenuPatch("user-context", userContextPatch);
|
|
||||||
removeContextMenuPatch("stream-context", streamContextPatch);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -16,7 +16,7 @@
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { addContextMenuPatch, NavContextMenuPatchCallback, removeContextMenuPatch } from "@api/ContextMenu";
|
import { NavContextMenuPatchCallback } from "@api/ContextMenu";
|
||||||
import { LinkIcon } from "@components/Icons";
|
import { LinkIcon } from "@components/Icons";
|
||||||
import { Devs } from "@utils/constants";
|
import { Devs } from "@utils/constants";
|
||||||
import definePlugin from "@utils/types";
|
import definePlugin from "@utils/types";
|
||||||
|
@ -29,7 +29,7 @@ interface UserContextProps {
|
||||||
user: User;
|
user: User;
|
||||||
}
|
}
|
||||||
|
|
||||||
const UserContextMenuPatch: NavContextMenuPatchCallback = (children, { user }: UserContextProps) => () => {
|
const UserContextMenuPatch: NavContextMenuPatchCallback = (children, { user }: UserContextProps) => {
|
||||||
if (!user) return;
|
if (!user) return;
|
||||||
|
|
||||||
children.push(
|
children.push(
|
||||||
|
@ -46,12 +46,7 @@ export default definePlugin({
|
||||||
name: "CopyUserURLs",
|
name: "CopyUserURLs",
|
||||||
authors: [Devs.castdrian],
|
authors: [Devs.castdrian],
|
||||||
description: "Adds a 'Copy User URL' option to the user context menu.",
|
description: "Adds a 'Copy User URL' option to the user context menu.",
|
||||||
|
contextMenus: {
|
||||||
start() {
|
"user-context": UserContextMenuPatch
|
||||||
addContextMenuPatch("user-context", UserContextMenuPatch);
|
}
|
||||||
},
|
|
||||||
|
|
||||||
stop() {
|
|
||||||
removeContextMenuPatch("user-context", UserContextMenuPatch);
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
|
|
|
@ -16,7 +16,7 @@
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { addContextMenuPatch, findGroupChildrenByChildId, NavContextMenuPatchCallback, removeContextMenuPatch } from "@api/ContextMenu";
|
import { findGroupChildrenByChildId, NavContextMenuPatchCallback } from "@api/ContextMenu";
|
||||||
import { CheckedTextInput } from "@components/CheckedTextInput";
|
import { CheckedTextInput } from "@components/CheckedTextInput";
|
||||||
import { Devs } from "@utils/constants";
|
import { Devs } from "@utils/constants";
|
||||||
import { Logger } from "@utils/Logger";
|
import { Logger } from "@utils/Logger";
|
||||||
|
@ -312,7 +312,7 @@ function isGifUrl(url: string) {
|
||||||
return new URL(url).pathname.endsWith(".gif");
|
return new URL(url).pathname.endsWith(".gif");
|
||||||
}
|
}
|
||||||
|
|
||||||
const messageContextMenuPatch: NavContextMenuPatchCallback = (children, props) => () => {
|
const messageContextMenuPatch: NavContextMenuPatchCallback = (children, props) => {
|
||||||
const { favoriteableId, itemHref, itemSrc, favoriteableType } = props ?? {};
|
const { favoriteableId, itemHref, itemSrc, favoriteableType } = props ?? {};
|
||||||
|
|
||||||
if (!favoriteableId) return;
|
if (!favoriteableId) return;
|
||||||
|
@ -341,7 +341,7 @@ const messageContextMenuPatch: NavContextMenuPatchCallback = (children, props) =
|
||||||
findGroupChildrenByChildId("copy-link", children)?.push(menuItem);
|
findGroupChildrenByChildId("copy-link", children)?.push(menuItem);
|
||||||
};
|
};
|
||||||
|
|
||||||
const expressionPickerPatch: NavContextMenuPatchCallback = (children, props: { target: HTMLElement; }) => () => {
|
const expressionPickerPatch: NavContextMenuPatchCallback = (children, props: { target: HTMLElement; }) => {
|
||||||
const { id, name, type } = props?.target?.dataset ?? {};
|
const { id, name, type } = props?.target?.dataset ?? {};
|
||||||
if (!id) return;
|
if (!id) return;
|
||||||
|
|
||||||
|
@ -363,14 +363,8 @@ export default definePlugin({
|
||||||
description: "Allows you to clone Emotes & Stickers to your own server (right click them)",
|
description: "Allows you to clone Emotes & Stickers to your own server (right click them)",
|
||||||
tags: ["StickerCloner"],
|
tags: ["StickerCloner"],
|
||||||
authors: [Devs.Ven, Devs.Nuckyz],
|
authors: [Devs.Ven, Devs.Nuckyz],
|
||||||
|
contextMenus: {
|
||||||
start() {
|
"message": messageContextMenuPatch,
|
||||||
addContextMenuPatch("message", messageContextMenuPatch);
|
"expression-picker": expressionPickerPatch
|
||||||
addContextMenuPatch("expression-picker", expressionPickerPatch);
|
|
||||||
},
|
|
||||||
|
|
||||||
stop() {
|
|
||||||
removeContextMenuPatch("message", messageContextMenuPatch);
|
|
||||||
removeContextMenuPatch("expression-picker", expressionPickerPatch);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -16,14 +16,14 @@
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { addContextMenuPatch, NavContextMenuPatchCallback, removeContextMenuPatch } from "@api/ContextMenu";
|
import { NavContextMenuPatchCallback } from "@api/ContextMenu";
|
||||||
import { definePluginSettings } from "@api/Settings";
|
import { definePluginSettings } from "@api/Settings";
|
||||||
import { disableStyle, enableStyle } from "@api/Styles";
|
import { disableStyle, enableStyle } from "@api/Styles";
|
||||||
import { makeRange } from "@components/PluginSettings/components";
|
import { makeRange } from "@components/PluginSettings/components";
|
||||||
import { Devs } from "@utils/constants";
|
import { Devs } from "@utils/constants";
|
||||||
import { debounce } from "@utils/debounce";
|
import { debounce } from "@utils/debounce";
|
||||||
import definePlugin, { OptionType } from "@utils/types";
|
import definePlugin, { OptionType } from "@utils/types";
|
||||||
import { ContextMenuApi, Menu, React, ReactDOM } from "@webpack/common";
|
import { Menu, React, ReactDOM } from "@webpack/common";
|
||||||
import type { Root } from "react-dom/client";
|
import type { Root } from "react-dom/client";
|
||||||
|
|
||||||
import { Magnifier, MagnifierProps } from "./components/Magnifier";
|
import { Magnifier, MagnifierProps } from "./components/Magnifier";
|
||||||
|
@ -80,25 +80,25 @@ export const settings = definePluginSettings({
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
const imageContextMenuPatch: NavContextMenuPatchCallback = children => () => {
|
const imageContextMenuPatch: NavContextMenuPatchCallback = children => {
|
||||||
|
const { square, nearestNeighbour } = settings.use(["square", "nearestNeighbour"]);
|
||||||
|
|
||||||
children.push(
|
children.push(
|
||||||
<Menu.MenuGroup id="image-zoom">
|
<Menu.MenuGroup id="image-zoom">
|
||||||
<Menu.MenuCheckboxItem
|
<Menu.MenuCheckboxItem
|
||||||
id="vc-square"
|
id="vc-square"
|
||||||
label="Square Lens"
|
label="Square Lens"
|
||||||
checked={settings.store.square}
|
checked={square}
|
||||||
action={() => {
|
action={() => {
|
||||||
settings.store.square = !settings.store.square;
|
settings.store.square = !square;
|
||||||
ContextMenuApi.closeContextMenu();
|
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<Menu.MenuCheckboxItem
|
<Menu.MenuCheckboxItem
|
||||||
id="vc-nearest-neighbour"
|
id="vc-nearest-neighbour"
|
||||||
label="Nearest Neighbour"
|
label="Nearest Neighbour"
|
||||||
checked={settings.store.nearestNeighbour}
|
checked={nearestNeighbour}
|
||||||
action={() => {
|
action={() => {
|
||||||
settings.store.nearestNeighbour = !settings.store.nearestNeighbour;
|
settings.store.nearestNeighbour = !nearestNeighbour;
|
||||||
ContextMenuApi.closeContextMenu();
|
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<Menu.MenuControlItem
|
<Menu.MenuControlItem
|
||||||
|
@ -196,6 +196,9 @@ export default definePlugin({
|
||||||
],
|
],
|
||||||
|
|
||||||
settings,
|
settings,
|
||||||
|
contextMenus: {
|
||||||
|
"image-context": imageContextMenuPatch
|
||||||
|
},
|
||||||
|
|
||||||
// to stop from rendering twice /shrug
|
// to stop from rendering twice /shrug
|
||||||
currentMagnifierElement: null as React.FunctionComponentElement<MagnifierProps & JSX.IntrinsicAttributes> | null,
|
currentMagnifierElement: null as React.FunctionComponentElement<MagnifierProps & JSX.IntrinsicAttributes> | null,
|
||||||
|
@ -245,7 +248,6 @@ export default definePlugin({
|
||||||
|
|
||||||
start() {
|
start() {
|
||||||
enableStyle(styles);
|
enableStyle(styles);
|
||||||
addContextMenuPatch("image-context", imageContextMenuPatch);
|
|
||||||
this.element = document.createElement("div");
|
this.element = document.createElement("div");
|
||||||
this.element.classList.add("MagnifierContainer");
|
this.element.classList.add("MagnifierContainer");
|
||||||
document.body.appendChild(this.element);
|
document.body.appendChild(this.element);
|
||||||
|
@ -256,6 +258,5 @@ export default definePlugin({
|
||||||
// so componenetWillUnMount gets called if Magnifier component is still alive
|
// so componenetWillUnMount gets called if Magnifier component is still alive
|
||||||
this.root && this.root.unmount();
|
this.root && this.root.unmount();
|
||||||
this.element?.remove();
|
this.element?.remove();
|
||||||
removeContextMenuPatch("image-context", imageContextMenuPatch);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { registerCommand, unregisterCommand } from "@api/Commands";
|
import { registerCommand, unregisterCommand } from "@api/Commands";
|
||||||
|
import { addContextMenuPatch, removeContextMenuPatch } from "@api/ContextMenu";
|
||||||
import { Settings } from "@api/Settings";
|
import { Settings } from "@api/Settings";
|
||||||
import { Logger } from "@utils/Logger";
|
import { Logger } from "@utils/Logger";
|
||||||
import { Patch, Plugin, StartAt } from "@utils/types";
|
import { Patch, Plugin, StartAt } from "@utils/types";
|
||||||
|
@ -119,7 +120,7 @@ export function startDependenciesRecursive(p: Plugin) {
|
||||||
}
|
}
|
||||||
|
|
||||||
export const startPlugin = traceFunction("startPlugin", function startPlugin(p: Plugin) {
|
export const startPlugin = traceFunction("startPlugin", function startPlugin(p: Plugin) {
|
||||||
const { name, commands, flux } = p;
|
const { name, commands, flux, contextMenus } = p;
|
||||||
|
|
||||||
if (p.start) {
|
if (p.start) {
|
||||||
logger.info("Starting plugin", name);
|
logger.info("Starting plugin", name);
|
||||||
|
@ -154,11 +155,17 @@ export const startPlugin = traceFunction("startPlugin", function startPlugin(p:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (contextMenus) {
|
||||||
|
for (const navId in contextMenus) {
|
||||||
|
addContextMenuPatch(navId, contextMenus[navId]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}, p => `startPlugin ${p.name}`);
|
}, p => `startPlugin ${p.name}`);
|
||||||
|
|
||||||
export const stopPlugin = traceFunction("stopPlugin", function stopPlugin(p: Plugin) {
|
export const stopPlugin = traceFunction("stopPlugin", function stopPlugin(p: Plugin) {
|
||||||
const { name, commands, flux } = p;
|
const { name, commands, flux, contextMenus } = p;
|
||||||
if (p.stop) {
|
if (p.stop) {
|
||||||
logger.info("Stopping plugin", name);
|
logger.info("Stopping plugin", name);
|
||||||
if (!p.started) {
|
if (!p.started) {
|
||||||
|
@ -192,5 +199,11 @@ export const stopPlugin = traceFunction("stopPlugin", function stopPlugin(p: Plu
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (contextMenus) {
|
||||||
|
for (const navId in contextMenus) {
|
||||||
|
removeContextMenuPatch(navId, contextMenus[navId]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}, p => `stopPlugin ${p.name}`);
|
}, p => `stopPlugin ${p.name}`);
|
||||||
|
|
|
@ -18,7 +18,7 @@
|
||||||
|
|
||||||
import "./messageLogger.css";
|
import "./messageLogger.css";
|
||||||
|
|
||||||
import { addContextMenuPatch, NavContextMenuPatchCallback, removeContextMenuPatch } from "@api/ContextMenu";
|
import { NavContextMenuPatchCallback } from "@api/ContextMenu";
|
||||||
import { Settings } from "@api/Settings";
|
import { Settings } from "@api/Settings";
|
||||||
import { disableStyle, enableStyle } from "@api/Styles";
|
import { disableStyle, enableStyle } from "@api/Styles";
|
||||||
import ErrorBoundary from "@components/ErrorBoundary";
|
import ErrorBoundary from "@components/ErrorBoundary";
|
||||||
|
@ -45,7 +45,7 @@ function addDeleteStyle() {
|
||||||
|
|
||||||
const REMOVE_HISTORY_ID = "ml-remove-history";
|
const REMOVE_HISTORY_ID = "ml-remove-history";
|
||||||
const TOGGLE_DELETE_STYLE_ID = "ml-toggle-style";
|
const TOGGLE_DELETE_STYLE_ID = "ml-toggle-style";
|
||||||
const patchMessageContextMenu: NavContextMenuPatchCallback = (children, props) => () => {
|
const patchMessageContextMenu: NavContextMenuPatchCallback = (children, props) => {
|
||||||
const { message } = props;
|
const { message } = props;
|
||||||
const { deleted, editHistory, id, channel_id } = message;
|
const { deleted, editHistory, id, channel_id } = message;
|
||||||
|
|
||||||
|
@ -94,13 +94,12 @@ export default definePlugin({
|
||||||
description: "Temporarily logs deleted and edited messages.",
|
description: "Temporarily logs deleted and edited messages.",
|
||||||
authors: [Devs.rushii, Devs.Ven, Devs.AutumnVN],
|
authors: [Devs.rushii, Devs.Ven, Devs.AutumnVN],
|
||||||
|
|
||||||
start() {
|
contextMenus: {
|
||||||
addDeleteStyle();
|
"message": patchMessageContextMenu
|
||||||
addContextMenuPatch("message", patchMessageContextMenu);
|
|
||||||
},
|
},
|
||||||
|
|
||||||
stop() {
|
start() {
|
||||||
removeContextMenuPatch("message", patchMessageContextMenu);
|
addDeleteStyle();
|
||||||
},
|
},
|
||||||
|
|
||||||
renderEdit(edit: { timestamp: any, content: string; }) {
|
renderEdit(edit: { timestamp: any, content: string; }) {
|
||||||
|
|
|
@ -18,7 +18,7 @@
|
||||||
|
|
||||||
import "./styles.css";
|
import "./styles.css";
|
||||||
|
|
||||||
import { addContextMenuPatch, findGroupChildrenByChildId, NavContextMenuPatchCallback, removeContextMenuPatch } from "@api/ContextMenu";
|
import { findGroupChildrenByChildId, NavContextMenuPatchCallback } from "@api/ContextMenu";
|
||||||
import { definePluginSettings } from "@api/Settings";
|
import { definePluginSettings } from "@api/Settings";
|
||||||
import { Devs } from "@utils/constants";
|
import { Devs } from "@utils/constants";
|
||||||
import definePlugin, { OptionType } from "@utils/types";
|
import definePlugin, { OptionType } from "@utils/types";
|
||||||
|
@ -125,10 +125,10 @@ function MenuItem(guildId: string, id?: string, type?: MenuItemParentType) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function makeContextMenuPatch(childId: string | string[], type?: MenuItemParentType): NavContextMenuPatchCallback {
|
function makeContextMenuPatch(childId: string | string[], type?: MenuItemParentType): NavContextMenuPatchCallback {
|
||||||
return (children, props) => () => {
|
return (children, props) => {
|
||||||
if (!props) return;
|
if (!props) return;
|
||||||
if ((type === MenuItemParentType.User && !props.user) || (type === MenuItemParentType.Guild && !props.guild) || (type === MenuItemParentType.Channel && (!props.channel || !props.guild)))
|
if ((type === MenuItemParentType.User && !props.user) || (type === MenuItemParentType.Guild && !props.guild) || (type === MenuItemParentType.Channel && (!props.channel || !props.guild)))
|
||||||
return children;
|
return;
|
||||||
|
|
||||||
const group = findGroupChildrenByChildId(childId, children);
|
const group = findGroupChildrenByChildId(childId, children);
|
||||||
|
|
||||||
|
@ -173,19 +173,10 @@ export default definePlugin({
|
||||||
|
|
||||||
UserPermissions: (guild: Guild, guildMember: GuildMember | undefined, showBoder: boolean) => !!guildMember && <UserPermissions guild={guild} guildMember={guildMember} showBorder={showBoder} />,
|
UserPermissions: (guild: Guild, guildMember: GuildMember | undefined, showBoder: boolean) => !!guildMember && <UserPermissions guild={guild} guildMember={guildMember} showBorder={showBoder} />,
|
||||||
|
|
||||||
userContextMenuPatch: makeContextMenuPatch("roles", MenuItemParentType.User),
|
contextMenus: {
|
||||||
channelContextMenuPatch: makeContextMenuPatch(["mute-channel", "unmute-channel"], MenuItemParentType.Channel),
|
"user-context": makeContextMenuPatch("roles", MenuItemParentType.User),
|
||||||
guildContextMenuPatch: makeContextMenuPatch("privacy", MenuItemParentType.Guild),
|
"channel-context": makeContextMenuPatch(["mute-channel", "unmute-channel"], MenuItemParentType.Channel),
|
||||||
|
"guild-context": makeContextMenuPatch("privacy", MenuItemParentType.Guild),
|
||||||
start() {
|
"guild-header-popout": makeContextMenuPatch("privacy", MenuItemParentType.Guild)
|
||||||
addContextMenuPatch("user-context", this.userContextMenuPatch);
|
}
|
||||||
addContextMenuPatch("channel-context", this.channelContextMenuPatch);
|
|
||||||
addContextMenuPatch(["guild-context", "guild-header-popout"], this.guildContextMenuPatch);
|
|
||||||
},
|
|
||||||
|
|
||||||
stop() {
|
|
||||||
removeContextMenuPatch("user-context", this.userContextMenuPatch);
|
|
||||||
removeContextMenuPatch("channel-context", this.channelContextMenuPatch);
|
|
||||||
removeContextMenuPatch(["guild-context", "guild-header-popout"], this.guildContextMenuPatch);
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
|
|
|
@ -16,7 +16,7 @@
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { addContextMenuPatch, findGroupChildrenByChildId, NavContextMenuPatchCallback, removeContextMenuPatch } from "@api/ContextMenu";
|
import { findGroupChildrenByChildId, NavContextMenuPatchCallback } from "@api/ContextMenu";
|
||||||
import { Menu } from "@webpack/common";
|
import { Menu } from "@webpack/common";
|
||||||
|
|
||||||
import { isPinned, movePin, PinOrder, settings, snapshotArray, togglePin } from "./settings";
|
import { isPinned, movePin, PinOrder, settings, snapshotArray, togglePin } from "./settings";
|
||||||
|
@ -50,13 +50,13 @@ function PinMenuItem(channelId: string) {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const GroupDMContext: NavContextMenuPatchCallback = (children, props) => () => {
|
const GroupDMContext: NavContextMenuPatchCallback = (children, props) => {
|
||||||
const container = findGroupChildrenByChildId("leave-channel", children);
|
const container = findGroupChildrenByChildId("leave-channel", children);
|
||||||
if (container)
|
if (container)
|
||||||
container.unshift(PinMenuItem(props.channel.id));
|
container.unshift(PinMenuItem(props.channel.id));
|
||||||
};
|
};
|
||||||
|
|
||||||
const UserContext: NavContextMenuPatchCallback = (children, props) => () => {
|
const UserContext: NavContextMenuPatchCallback = (children, props) => {
|
||||||
const container = findGroupChildrenByChildId("close-dm", children);
|
const container = findGroupChildrenByChildId("close-dm", children);
|
||||||
if (container) {
|
if (container) {
|
||||||
const idx = container.findIndex(c => c?.props?.id === "close-dm");
|
const idx = container.findIndex(c => c?.props?.id === "close-dm");
|
||||||
|
@ -64,12 +64,7 @@ const UserContext: NavContextMenuPatchCallback = (children, props) => () => {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export function addContextMenus() {
|
export const contextMenus = {
|
||||||
addContextMenuPatch("gdm-context", GroupDMContext);
|
"gdm-context": GroupDMContext,
|
||||||
addContextMenuPatch("user-context", UserContext);
|
"user-context": UserContext
|
||||||
}
|
};
|
||||||
|
|
||||||
export function removeContextMenus() {
|
|
||||||
removeContextMenuPatch("gdm-context", GroupDMContext);
|
|
||||||
removeContextMenuPatch("user-context", UserContext);
|
|
||||||
}
|
|
||||||
|
|
|
@ -20,7 +20,7 @@ import { Devs } from "@utils/constants";
|
||||||
import definePlugin from "@utils/types";
|
import definePlugin from "@utils/types";
|
||||||
import { Channel } from "discord-types/general";
|
import { Channel } from "discord-types/general";
|
||||||
|
|
||||||
import { addContextMenus, removeContextMenus } from "./contextMenus";
|
import { contextMenus } from "./contextMenus";
|
||||||
import { getPinAt, isPinned, settings, snapshotArray, sortedSnapshot, usePinnedDms } from "./settings";
|
import { getPinAt, isPinned, settings, snapshotArray, sortedSnapshot, usePinnedDms } from "./settings";
|
||||||
|
|
||||||
export default definePlugin({
|
export default definePlugin({
|
||||||
|
@ -29,9 +29,7 @@ export default definePlugin({
|
||||||
authors: [Devs.Ven, Devs.Strencher],
|
authors: [Devs.Ven, Devs.Strencher],
|
||||||
|
|
||||||
settings,
|
settings,
|
||||||
|
contextMenus,
|
||||||
start: addContextMenus,
|
|
||||||
stop: removeContextMenus,
|
|
||||||
|
|
||||||
usePinCount(channelIds: string[]) {
|
usePinCount(channelIds: string[]) {
|
||||||
const pinnedDms = usePinnedDms();
|
const pinnedDms = usePinnedDms();
|
||||||
|
|
|
@ -16,11 +16,11 @@
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { addContextMenuPatch, findGroupChildrenByChildId, NavContextMenuPatchCallback, removeContextMenuPatch } from "@api/ContextMenu";
|
import { findGroupChildrenByChildId } from "@api/ContextMenu";
|
||||||
import { definePluginSettings } from "@api/Settings";
|
import { definePluginSettings } from "@api/Settings";
|
||||||
import { Devs } from "@utils/constants";
|
import { Devs } from "@utils/constants";
|
||||||
import definePlugin, { OptionType } from "@utils/types";
|
import definePlugin, { OptionType } from "@utils/types";
|
||||||
import { ContextMenuApi, Menu } from "@webpack/common";
|
import { Menu } from "@webpack/common";
|
||||||
|
|
||||||
const settings = definePluginSettings({
|
const settings = definePluginSettings({
|
||||||
forceServerHome: {
|
forceServerHome: {
|
||||||
|
@ -30,25 +30,11 @@ const settings = definePluginSettings({
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const contextMenuPatch: NavContextMenuPatchCallback = (children, props) => () => {
|
function useForceServerHome() {
|
||||||
if (!props?.guild) return;
|
const { forceServerHome } = settings.use(["forceServerHome"]);
|
||||||
|
|
||||||
const group = findGroupChildrenByChildId("hide-muted-channels", children);
|
return forceServerHome;
|
||||||
|
}
|
||||||
group?.unshift(
|
|
||||||
<Menu.MenuCheckboxItem
|
|
||||||
key="force-server-home"
|
|
||||||
id="force-server-home"
|
|
||||||
label="Force Server Home"
|
|
||||||
checked={settings.store.forceServerHome}
|
|
||||||
action={() => {
|
|
||||||
settings.store.forceServerHome = !settings.store.forceServerHome;
|
|
||||||
ContextMenuApi.closeContextMenu();
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default definePlugin({
|
export default definePlugin({
|
||||||
name: "ResurrectHome",
|
name: "ResurrectHome",
|
||||||
|
@ -109,17 +95,25 @@ export default definePlugin({
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
|
||||||
start() {
|
useForceServerHome,
|
||||||
addContextMenuPatch("guild-context", contextMenuPatch);
|
|
||||||
},
|
|
||||||
|
|
||||||
stop() {
|
contextMenus: {
|
||||||
removeContextMenuPatch("guild-context", contextMenuPatch);
|
"guild-context"(children, props) {
|
||||||
},
|
const forceServerHome = useForceServerHome();
|
||||||
|
|
||||||
useForceServerHome() {
|
if (!props?.guild) return;
|
||||||
const { forceServerHome } = settings.use(["forceServerHome"]);
|
|
||||||
|
|
||||||
return forceServerHome;
|
const group = findGroupChildrenByChildId("hide-muted-channels", children);
|
||||||
|
|
||||||
|
group?.unshift(
|
||||||
|
<Menu.MenuCheckboxItem
|
||||||
|
key="force-server-home"
|
||||||
|
id="force-server-home"
|
||||||
|
label="Force Server Home"
|
||||||
|
checked={forceServerHome}
|
||||||
|
action={() => settings.store.forceServerHome = !forceServerHome}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -16,7 +16,7 @@
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { addContextMenuPatch, findGroupChildrenByChildId, NavContextMenuPatchCallback, removeContextMenuPatch } from "@api/ContextMenu";
|
import { findGroupChildrenByChildId, NavContextMenuPatchCallback } from "@api/ContextMenu";
|
||||||
import { Flex } from "@components/Flex";
|
import { Flex } from "@components/Flex";
|
||||||
import { OpenExternalIcon } from "@components/Icons";
|
import { OpenExternalIcon } from "@components/Icons";
|
||||||
import { Devs } from "@utils/constants";
|
import { Devs } from "@utils/constants";
|
||||||
|
@ -84,7 +84,7 @@ function makeSearchItem(src: string) {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const messageContextMenuPatch: NavContextMenuPatchCallback = (children, props) => () => {
|
const messageContextMenuPatch: NavContextMenuPatchCallback = (children, props) => {
|
||||||
if (props?.reverseImageSearchType !== "img") return;
|
if (props?.reverseImageSearchType !== "img") return;
|
||||||
|
|
||||||
const src = props.itemHref ?? props.itemSrc;
|
const src = props.itemHref ?? props.itemSrc;
|
||||||
|
@ -93,7 +93,7 @@ const messageContextMenuPatch: NavContextMenuPatchCallback = (children, props) =
|
||||||
group?.push(makeSearchItem(src));
|
group?.push(makeSearchItem(src));
|
||||||
};
|
};
|
||||||
|
|
||||||
const imageContextMenuPatch: NavContextMenuPatchCallback = (children, props) => () => {
|
const imageContextMenuPatch: NavContextMenuPatchCallback = (children, props) => {
|
||||||
if (!props?.src) return;
|
if (!props?.src) return;
|
||||||
|
|
||||||
const group = findGroupChildrenByChildId("copy-native-link", children) ?? children;
|
const group = findGroupChildrenByChildId("copy-native-link", children) ?? children;
|
||||||
|
@ -115,14 +115,8 @@ export default definePlugin({
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
contextMenus: {
|
||||||
start() {
|
"message": messageContextMenuPatch,
|
||||||
addContextMenuPatch("message", messageContextMenuPatch);
|
"image-context": imageContextMenuPatch
|
||||||
addContextMenuPatch("image-context", imageContextMenuPatch);
|
|
||||||
},
|
|
||||||
|
|
||||||
stop() {
|
|
||||||
removeContextMenuPatch("message", messageContextMenuPatch);
|
|
||||||
removeContextMenuPatch("image-context", imageContextMenuPatch);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -18,7 +18,7 @@
|
||||||
|
|
||||||
import "./style.css";
|
import "./style.css";
|
||||||
|
|
||||||
import { addContextMenuPatch, NavContextMenuPatchCallback, removeContextMenuPatch } from "@api/ContextMenu";
|
import { NavContextMenuPatchCallback } from "@api/ContextMenu";
|
||||||
import ErrorBoundary from "@components/ErrorBoundary";
|
import ErrorBoundary from "@components/ErrorBoundary";
|
||||||
import ExpandableHeader from "@components/ExpandableHeader";
|
import ExpandableHeader from "@components/ExpandableHeader";
|
||||||
import { OpenExternalIcon } from "@components/Icons";
|
import { OpenExternalIcon } from "@components/Icons";
|
||||||
|
@ -36,7 +36,7 @@ import { getCurrentUserInfo, readNotification } from "./reviewDbApi";
|
||||||
import { settings } from "./settings";
|
import { settings } from "./settings";
|
||||||
import { showToast } from "./utils";
|
import { showToast } from "./utils";
|
||||||
|
|
||||||
const guildPopoutPatch: NavContextMenuPatchCallback = (children, props: { guild: Guild, onClose(): void; }) => () => {
|
const guildPopoutPatch: NavContextMenuPatchCallback = (children, props: { guild: Guild, onClose(): void; }) => {
|
||||||
children.push(
|
children.push(
|
||||||
<Menu.MenuItem
|
<Menu.MenuItem
|
||||||
label="View Reviews"
|
label="View Reviews"
|
||||||
|
@ -53,6 +53,9 @@ export default definePlugin({
|
||||||
authors: [Devs.mantikafasi, Devs.Ven],
|
authors: [Devs.mantikafasi, Devs.Ven],
|
||||||
|
|
||||||
settings,
|
settings,
|
||||||
|
contextMenus: {
|
||||||
|
"guild-header-popout": guildPopoutPatch
|
||||||
|
},
|
||||||
|
|
||||||
patches: [
|
patches: [
|
||||||
{
|
{
|
||||||
|
@ -69,8 +72,6 @@ export default definePlugin({
|
||||||
},
|
},
|
||||||
|
|
||||||
async start() {
|
async start() {
|
||||||
addContextMenuPatch("guild-header-popout", guildPopoutPatch);
|
|
||||||
|
|
||||||
const s = settings.store;
|
const s = settings.store;
|
||||||
const { lastReviewId, notifyReviews } = s;
|
const { lastReviewId, notifyReviews } = s;
|
||||||
|
|
||||||
|
@ -127,10 +128,6 @@ export default definePlugin({
|
||||||
}, 4000);
|
}, 4000);
|
||||||
},
|
},
|
||||||
|
|
||||||
stop() {
|
|
||||||
removeContextMenuPatch("guild-header-popout", guildPopoutPatch);
|
|
||||||
},
|
|
||||||
|
|
||||||
getReviewsComponent: ErrorBoundary.wrap((user: User) => {
|
getReviewsComponent: ErrorBoundary.wrap((user: User) => {
|
||||||
const [reviewCount, setReviewCount] = useState<number>();
|
const [reviewCount, setReviewCount] = useState<number>();
|
||||||
|
|
||||||
|
|
|
@ -16,7 +16,7 @@
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { addContextMenuPatch, findGroupChildrenByChildId, NavContextMenuPatchCallback, removeContextMenuPatch } from "@api/ContextMenu";
|
import { findGroupChildrenByChildId, NavContextMenuPatchCallback } from "@api/ContextMenu";
|
||||||
import { ReplyIcon } from "@components/Icons";
|
import { ReplyIcon } from "@components/Icons";
|
||||||
import { Devs } from "@utils/constants";
|
import { Devs } from "@utils/constants";
|
||||||
import definePlugin from "@utils/types";
|
import definePlugin from "@utils/types";
|
||||||
|
@ -27,7 +27,7 @@ import { Message } from "discord-types/general";
|
||||||
|
|
||||||
const messageUtils = findByPropsLazy("replyToMessage");
|
const messageUtils = findByPropsLazy("replyToMessage");
|
||||||
|
|
||||||
const messageContextMenuPatch: NavContextMenuPatchCallback = (children, { message }: { message: Message; }) => () => {
|
const messageContextMenuPatch: NavContextMenuPatchCallback = (children, { message }: { message: Message; }) => {
|
||||||
// make sure the message is in the selected channel
|
// make sure the message is in the selected channel
|
||||||
if (SelectedChannelStore.getChannelId() !== message.channel_id) return;
|
if (SelectedChannelStore.getChannelId() !== message.channel_id) return;
|
||||||
const channel = ChannelStore.getChannel(message?.channel_id);
|
const channel = ChannelStore.getChannel(message?.channel_id);
|
||||||
|
@ -38,7 +38,7 @@ const messageContextMenuPatch: NavContextMenuPatchCallback = (children, { messag
|
||||||
const dmGroup = findGroupChildrenByChildId("pin", children);
|
const dmGroup = findGroupChildrenByChildId("pin", children);
|
||||||
if (dmGroup && !dmGroup.some(child => child?.props?.id === "reply")) {
|
if (dmGroup && !dmGroup.some(child => child?.props?.id === "reply")) {
|
||||||
const pinIndex = dmGroup.findIndex(c => c?.props.id === "pin");
|
const pinIndex = dmGroup.findIndex(c => c?.props.id === "pin");
|
||||||
return dmGroup.splice(pinIndex + 1, 0, (
|
dmGroup.splice(pinIndex + 1, 0, (
|
||||||
<Menu.MenuItem
|
<Menu.MenuItem
|
||||||
id="reply"
|
id="reply"
|
||||||
label={i18n.Messages.MESSAGE_ACTION_REPLY}
|
label={i18n.Messages.MESSAGE_ACTION_REPLY}
|
||||||
|
@ -46,12 +46,13 @@ const messageContextMenuPatch: NavContextMenuPatchCallback = (children, { messag
|
||||||
action={(e: React.MouseEvent) => messageUtils.replyToMessage(channel, message, e)}
|
action={(e: React.MouseEvent) => messageUtils.replyToMessage(channel, message, e)}
|
||||||
/>
|
/>
|
||||||
));
|
));
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// servers
|
// servers
|
||||||
const serverGroup = findGroupChildrenByChildId("mark-unread", children);
|
const serverGroup = findGroupChildrenByChildId("mark-unread", children);
|
||||||
if (serverGroup && !serverGroup.some(child => child?.props?.id === "reply")) {
|
if (serverGroup && !serverGroup.some(child => child?.props?.id === "reply")) {
|
||||||
return serverGroup.unshift((
|
serverGroup.unshift((
|
||||||
<Menu.MenuItem
|
<Menu.MenuItem
|
||||||
id="reply"
|
id="reply"
|
||||||
label={i18n.Messages.MESSAGE_ACTION_REPLY}
|
label={i18n.Messages.MESSAGE_ACTION_REPLY}
|
||||||
|
@ -59,6 +60,7 @@ const messageContextMenuPatch: NavContextMenuPatchCallback = (children, { messag
|
||||||
action={(e: React.MouseEvent) => messageUtils.replyToMessage(channel, message, e)}
|
action={(e: React.MouseEvent) => messageUtils.replyToMessage(channel, message, e)}
|
||||||
/>
|
/>
|
||||||
));
|
));
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -67,12 +69,7 @@ export default definePlugin({
|
||||||
name: "SearchReply",
|
name: "SearchReply",
|
||||||
description: "Adds a reply button to search results",
|
description: "Adds a reply button to search results",
|
||||||
authors: [Devs.Aria],
|
authors: [Devs.Aria],
|
||||||
|
contextMenus: {
|
||||||
start() {
|
"message": messageContextMenuPatch
|
||||||
addContextMenuPatch("message", messageContextMenuPatch);
|
|
||||||
},
|
|
||||||
|
|
||||||
stop() {
|
|
||||||
removeContextMenuPatch("message", messageContextMenuPatch);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { addContextMenuPatch, findGroupChildrenByChildId, NavContextMenuPatchCallback, removeContextMenuPatch } from "@api/ContextMenu";
|
import { findGroupChildrenByChildId, NavContextMenuPatchCallback } from "@api/ContextMenu";
|
||||||
import { Devs } from "@utils/constants";
|
import { Devs } from "@utils/constants";
|
||||||
import definePlugin from "@utils/types";
|
import definePlugin from "@utils/types";
|
||||||
import { Menu } from "@webpack/common";
|
import { Menu } from "@webpack/common";
|
||||||
|
@ -12,7 +12,7 @@ import { Guild } from "discord-types/general";
|
||||||
|
|
||||||
import { openGuildProfileModal } from "./GuildProfileModal";
|
import { openGuildProfileModal } from "./GuildProfileModal";
|
||||||
|
|
||||||
const Patch: NavContextMenuPatchCallback = (children, { guild }: { guild: Guild; }) => () => {
|
const Patch: NavContextMenuPatchCallback = (children, { guild }: { guild: Guild; }) => {
|
||||||
const group = findGroupChildrenByChildId("privacy", children);
|
const group = findGroupChildrenByChildId("privacy", children);
|
||||||
|
|
||||||
group?.push(
|
group?.push(
|
||||||
|
@ -29,12 +29,8 @@ export default definePlugin({
|
||||||
description: "Allows you to view info about a server by right clicking it in the server list",
|
description: "Allows you to view info about a server by right clicking it in the server list",
|
||||||
authors: [Devs.Ven, Devs.Nuckyz],
|
authors: [Devs.Ven, Devs.Nuckyz],
|
||||||
tags: ["guild", "info"],
|
tags: ["guild", "info"],
|
||||||
|
contextMenus: {
|
||||||
start() {
|
"guild-context": Patch,
|
||||||
addContextMenuPatch(["guild-context", "guild-header-popout"], Patch);
|
"guild-header-popout": Patch
|
||||||
},
|
|
||||||
|
|
||||||
stop() {
|
|
||||||
removeContextMenuPatch(["guild-context", "guild-header-popout"], Patch);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -19,7 +19,7 @@
|
||||||
import "./styles.css";
|
import "./styles.css";
|
||||||
|
|
||||||
import { addChatBarButton, removeChatBarButton } from "@api/ChatButtons";
|
import { addChatBarButton, removeChatBarButton } from "@api/ChatButtons";
|
||||||
import { addContextMenuPatch, findGroupChildrenByChildId, NavContextMenuPatchCallback, removeContextMenuPatch } from "@api/ContextMenu";
|
import { findGroupChildrenByChildId, NavContextMenuPatchCallback } from "@api/ContextMenu";
|
||||||
import { addAccessory, removeAccessory } from "@api/MessageAccessories";
|
import { addAccessory, removeAccessory } from "@api/MessageAccessories";
|
||||||
import { addPreSendListener, removePreSendListener } from "@api/MessageEvents";
|
import { addPreSendListener, removePreSendListener } from "@api/MessageEvents";
|
||||||
import { addButton, removeButton } from "@api/MessagePopover";
|
import { addButton, removeButton } from "@api/MessagePopover";
|
||||||
|
@ -32,7 +32,7 @@ import { TranslateChatBarIcon, TranslateIcon } from "./TranslateIcon";
|
||||||
import { handleTranslate, TranslationAccessory } from "./TranslationAccessory";
|
import { handleTranslate, TranslationAccessory } from "./TranslationAccessory";
|
||||||
import { translate } from "./utils";
|
import { translate } from "./utils";
|
||||||
|
|
||||||
const messageCtxPatch: NavContextMenuPatchCallback = (children, { message }) => () => {
|
const messageCtxPatch: NavContextMenuPatchCallback = (children, { message }) => {
|
||||||
if (!message.content) return;
|
if (!message.content) return;
|
||||||
|
|
||||||
const group = findGroupChildrenByChildId("copy-text", children);
|
const group = findGroupChildrenByChildId("copy-text", children);
|
||||||
|
@ -57,13 +57,15 @@ export default definePlugin({
|
||||||
authors: [Devs.Ven],
|
authors: [Devs.Ven],
|
||||||
dependencies: ["MessageAccessoriesAPI", "MessagePopoverAPI", "MessageEventsAPI", "ChatInputButtonAPI"],
|
dependencies: ["MessageAccessoriesAPI", "MessagePopoverAPI", "MessageEventsAPI", "ChatInputButtonAPI"],
|
||||||
settings,
|
settings,
|
||||||
|
contextMenus: {
|
||||||
|
"message": messageCtxPatch
|
||||||
|
},
|
||||||
// not used, just here in case some other plugin wants it or w/e
|
// not used, just here in case some other plugin wants it or w/e
|
||||||
translate,
|
translate,
|
||||||
|
|
||||||
start() {
|
start() {
|
||||||
addAccessory("vc-translation", props => <TranslationAccessory message={props.message} />);
|
addAccessory("vc-translation", props => <TranslationAccessory message={props.message} />);
|
||||||
|
|
||||||
addContextMenuPatch("message", messageCtxPatch);
|
|
||||||
addChatBarButton("vc-translate", TranslateChatBarIcon);
|
addChatBarButton("vc-translate", TranslateChatBarIcon);
|
||||||
|
|
||||||
addButton("vc-translate", message => {
|
addButton("vc-translate", message => {
|
||||||
|
@ -91,7 +93,6 @@ export default definePlugin({
|
||||||
|
|
||||||
stop() {
|
stop() {
|
||||||
removePreSendListener(this.preSend);
|
removePreSendListener(this.preSend);
|
||||||
removeContextMenuPatch("message", messageCtxPatch);
|
|
||||||
removeChatBarButton("vc-translate");
|
removeChatBarButton("vc-translate");
|
||||||
removeButton("vc-translate");
|
removeButton("vc-translate");
|
||||||
removeAccessory("vc-translation");
|
removeAccessory("vc-translation");
|
||||||
|
|
|
@ -16,7 +16,7 @@
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { addContextMenuPatch, findGroupChildrenByChildId, NavContextMenuPatchCallback, removeContextMenuPatch } from "@api/ContextMenu";
|
import { findGroupChildrenByChildId, NavContextMenuPatchCallback } from "@api/ContextMenu";
|
||||||
import { ImageInvisible, ImageVisible } from "@components/Icons";
|
import { ImageInvisible, ImageVisible } from "@components/Icons";
|
||||||
import { Devs } from "@utils/constants";
|
import { Devs } from "@utils/constants";
|
||||||
import definePlugin from "@utils/types";
|
import definePlugin from "@utils/types";
|
||||||
|
@ -24,7 +24,7 @@ import { Menu, PermissionsBits, PermissionStore, RestAPI, UserStore } from "@web
|
||||||
|
|
||||||
const EMBED_SUPPRESSED = 1 << 2;
|
const EMBED_SUPPRESSED = 1 << 2;
|
||||||
|
|
||||||
const messageContextMenuPatch: NavContextMenuPatchCallback = (children, { channel, message: { author, embeds, flags, id: messageId } }) => () => {
|
const messageContextMenuPatch: NavContextMenuPatchCallback = (children, { channel, message: { author, embeds, flags, id: messageId } }) => {
|
||||||
const isEmbedSuppressed = (flags & EMBED_SUPPRESSED) !== 0;
|
const isEmbedSuppressed = (flags & EMBED_SUPPRESSED) !== 0;
|
||||||
if (!isEmbedSuppressed && !embeds.length) return;
|
if (!isEmbedSuppressed && !embeds.length) return;
|
||||||
|
|
||||||
|
@ -56,12 +56,7 @@ export default definePlugin({
|
||||||
name: "UnsuppressEmbeds",
|
name: "UnsuppressEmbeds",
|
||||||
authors: [Devs.rad, Devs.HypedDomi],
|
authors: [Devs.rad, Devs.HypedDomi],
|
||||||
description: "Allows you to unsuppress embeds in messages",
|
description: "Allows you to unsuppress embeds in messages",
|
||||||
|
contextMenus: {
|
||||||
start() {
|
"message": messageContextMenuPatch
|
||||||
addContextMenuPatch("message", messageContextMenuPatch);
|
}
|
||||||
},
|
|
||||||
|
|
||||||
stop() {
|
|
||||||
removeContextMenuPatch("message", messageContextMenuPatch);
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
|
|
|
@ -19,7 +19,7 @@
|
||||||
import "./index.css";
|
import "./index.css";
|
||||||
|
|
||||||
import { openNotificationLogModal } from "@api/Notifications/notificationLog";
|
import { openNotificationLogModal } from "@api/Notifications/notificationLog";
|
||||||
import { Settings } from "@api/Settings";
|
import { Settings, useSettings } from "@api/Settings";
|
||||||
import ErrorBoundary from "@components/ErrorBoundary";
|
import ErrorBoundary from "@components/ErrorBoundary";
|
||||||
import { Devs } from "@utils/constants";
|
import { Devs } from "@utils/constants";
|
||||||
import definePlugin from "@utils/types";
|
import definePlugin from "@utils/types";
|
||||||
|
@ -30,6 +30,8 @@ import type { ReactNode } from "react";
|
||||||
const HeaderBarIcon = findExportedComponentLazy("Icon", "Divider");
|
const HeaderBarIcon = findExportedComponentLazy("Icon", "Divider");
|
||||||
|
|
||||||
function VencordPopout(onClose: () => void) {
|
function VencordPopout(onClose: () => void) {
|
||||||
|
const { useQuickCss } = useSettings();
|
||||||
|
|
||||||
const pluginEntries = [] as ReactNode[];
|
const pluginEntries = [] as ReactNode[];
|
||||||
|
|
||||||
for (const plugin of Object.values(Vencord.Plugins.plugins)) {
|
for (const plugin of Object.values(Vencord.Plugins.plugins)) {
|
||||||
|
@ -68,11 +70,10 @@ function VencordPopout(onClose: () => void) {
|
||||||
/>
|
/>
|
||||||
<Menu.MenuCheckboxItem
|
<Menu.MenuCheckboxItem
|
||||||
id="vc-toolbox-quickcss-toggle"
|
id="vc-toolbox-quickcss-toggle"
|
||||||
checked={Settings.useQuickCss}
|
checked={useQuickCss}
|
||||||
label={"Enable QuickCSS"}
|
label={"Enable QuickCSS"}
|
||||||
action={() => {
|
action={() => {
|
||||||
Settings.useQuickCss = !Settings.useQuickCss;
|
Settings.useQuickCss = !useQuickCss;
|
||||||
onClose();
|
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<Menu.MenuItem
|
<Menu.MenuItem
|
||||||
|
|
|
@ -16,7 +16,7 @@
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { addContextMenuPatch, NavContextMenuPatchCallback, removeContextMenuPatch } from "@api/ContextMenu";
|
import { NavContextMenuPatchCallback } from "@api/ContextMenu";
|
||||||
import { definePluginSettings } from "@api/Settings";
|
import { definePluginSettings } from "@api/Settings";
|
||||||
import { ImageIcon } from "@components/Icons";
|
import { ImageIcon } from "@components/Icons";
|
||||||
import { Devs } from "@utils/constants";
|
import { Devs } from "@utils/constants";
|
||||||
|
@ -80,7 +80,7 @@ function openImage(url: string) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const UserContext: NavContextMenuPatchCallback = (children, { user, guildId }: UserContextProps) => () => {
|
const UserContext: NavContextMenuPatchCallback = (children, { user, guildId }: UserContextProps) => {
|
||||||
if (!user) return;
|
if (!user) return;
|
||||||
const memberAvatar = GuildMemberStore.getMember(guildId!, user.id)?.avatar || null;
|
const memberAvatar = GuildMemberStore.getMember(guildId!, user.id)?.avatar || null;
|
||||||
|
|
||||||
|
@ -109,7 +109,7 @@ const UserContext: NavContextMenuPatchCallback = (children, { user, guildId }: U
|
||||||
));
|
));
|
||||||
};
|
};
|
||||||
|
|
||||||
const GuildContext: NavContextMenuPatchCallback = (children, { guild }: GuildContextProps) => () => {
|
const GuildContext: NavContextMenuPatchCallback = (children, { guild }: GuildContextProps) => {
|
||||||
if (!guild) return;
|
if (!guild) return;
|
||||||
|
|
||||||
const { id, icon, banner } = guild;
|
const { id, icon, banner } = guild;
|
||||||
|
@ -155,14 +155,9 @@ export default definePlugin({
|
||||||
|
|
||||||
openImage,
|
openImage,
|
||||||
|
|
||||||
start() {
|
contextMenus: {
|
||||||
addContextMenuPatch("user-context", UserContext);
|
"user-context": UserContext,
|
||||||
addContextMenuPatch("guild-context", GuildContext);
|
"guild-context": GuildContext
|
||||||
},
|
|
||||||
|
|
||||||
stop() {
|
|
||||||
removeContextMenuPatch("user-context", UserContext);
|
|
||||||
removeContextMenuPatch("guild-context", GuildContext);
|
|
||||||
},
|
},
|
||||||
|
|
||||||
patches: [
|
patches: [
|
||||||
|
|
|
@ -16,7 +16,7 @@
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { addContextMenuPatch, NavContextMenuPatchCallback, removeContextMenuPatch } from "@api/ContextMenu";
|
import { NavContextMenuPatchCallback } from "@api/ContextMenu";
|
||||||
import { addButton, removeButton } from "@api/MessagePopover";
|
import { addButton, removeButton } from "@api/MessagePopover";
|
||||||
import { definePluginSettings } from "@api/Settings";
|
import { definePluginSettings } from "@api/Settings";
|
||||||
import { CodeBlock } from "@components/CodeBlock";
|
import { CodeBlock } from "@components/CodeBlock";
|
||||||
|
@ -117,8 +117,8 @@ const settings = definePluginSettings({
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
function MakeContextCallback(name: "Guild" | "User" | "Channel") {
|
function MakeContextCallback(name: "Guild" | "User" | "Channel"): NavContextMenuPatchCallback {
|
||||||
const callback: NavContextMenuPatchCallback = (children, props) => () => {
|
return (children, props) => {
|
||||||
const value = props[name.toLowerCase()];
|
const value = props[name.toLowerCase()];
|
||||||
if (!value) return;
|
if (!value) return;
|
||||||
if (props.label === i18n.Messages.CHANNEL_ACTIONS_MENU_LABEL) return; // random shit like notification settings
|
if (props.label === i18n.Messages.CHANNEL_ACTIONS_MENU_LABEL) return; // random shit like notification settings
|
||||||
|
@ -141,16 +141,19 @@ function MakeContextCallback(name: "Guild" | "User" | "Channel") {
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
return callback;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
export default definePlugin({
|
export default definePlugin({
|
||||||
name: "ViewRaw",
|
name: "ViewRaw",
|
||||||
description: "Copy and view the raw content/data of any message, channel or guild",
|
description: "Copy and view the raw content/data of any message, channel or guild",
|
||||||
authors: [Devs.KingFish, Devs.Ven, Devs.rad, Devs.ImLvna],
|
authors: [Devs.KingFish, Devs.Ven, Devs.rad, Devs.ImLvna],
|
||||||
dependencies: ["MessagePopoverAPI"],
|
dependencies: ["MessagePopoverAPI"],
|
||||||
settings,
|
settings,
|
||||||
|
contextMenus: {
|
||||||
|
"guild-context": MakeContextCallback("Guild"),
|
||||||
|
"channel-context": MakeContextCallback("Channel"),
|
||||||
|
"user-context": MakeContextCallback("User")
|
||||||
|
},
|
||||||
|
|
||||||
start() {
|
start() {
|
||||||
addButton("ViewRaw", msg => {
|
addButton("ViewRaw", msg => {
|
||||||
|
@ -187,16 +190,9 @@ export default definePlugin({
|
||||||
onContextMenu: handleContextMenu
|
onContextMenu: handleContextMenu
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
addContextMenuPatch("guild-context", MakeContextCallback("Guild"));
|
|
||||||
addContextMenuPatch("channel-context", MakeContextCallback("Channel"));
|
|
||||||
addContextMenuPatch("user-context", MakeContextCallback("User"));
|
|
||||||
},
|
},
|
||||||
|
|
||||||
stop() {
|
stop() {
|
||||||
removeButton("CopyRawMessage");
|
removeButton("ViewRaw");
|
||||||
removeContextMenuPatch("guild-context", MakeContextCallback("Guild"));
|
|
||||||
removeContextMenuPatch("channel-context", MakeContextCallback("Channel"));
|
|
||||||
removeContextMenuPatch("user-context", MakeContextCallback("User"));
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -18,7 +18,7 @@
|
||||||
|
|
||||||
import "./styles.css";
|
import "./styles.css";
|
||||||
|
|
||||||
import { addContextMenuPatch, NavContextMenuPatchCallback, removeContextMenuPatch } from "@api/ContextMenu";
|
import { NavContextMenuPatchCallback } from "@api/ContextMenu";
|
||||||
import { Microphone } from "@components/Icons";
|
import { Microphone } from "@components/Icons";
|
||||||
import { Link } from "@components/Link";
|
import { Link } from "@components/Link";
|
||||||
import { Devs } from "@utils/constants";
|
import { Devs } from "@utils/constants";
|
||||||
|
@ -48,18 +48,30 @@ export type VoiceRecorder = ComponentType<{
|
||||||
|
|
||||||
const VoiceRecorder = IS_DISCORD_DESKTOP ? VoiceRecorderDesktop : VoiceRecorderWeb;
|
const VoiceRecorder = IS_DISCORD_DESKTOP ? VoiceRecorderDesktop : VoiceRecorderWeb;
|
||||||
|
|
||||||
|
const ctxMenuPatch: NavContextMenuPatchCallback = (children, props) => {
|
||||||
|
if (props.channel.guild_id && !(PermissionStore.can(PermissionsBits.SEND_VOICE_MESSAGES, props.channel) && PermissionStore.can(PermissionsBits.SEND_MESSAGES, props.channel))) return;
|
||||||
|
|
||||||
|
children.push(
|
||||||
|
<Menu.MenuItem
|
||||||
|
id="vc-send-vmsg"
|
||||||
|
label={
|
||||||
|
<div className={OptionClasses.optionLabel}>
|
||||||
|
<Microphone className={OptionClasses.optionIcon} height={24} width={24} />
|
||||||
|
<div className={OptionClasses.optionName}>Send voice message</div>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
action={() => openModal(modalProps => <Modal modalProps={modalProps} />)}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
export default definePlugin({
|
export default definePlugin({
|
||||||
name: "VoiceMessages",
|
name: "VoiceMessages",
|
||||||
description: "Allows you to send voice messages like on mobile. To do so, right click the upload button and click Send Voice Message",
|
description: "Allows you to send voice messages like on mobile. To do so, right click the upload button and click Send Voice Message",
|
||||||
authors: [Devs.Ven, Devs.Vap, Devs.Nickyux],
|
authors: [Devs.Ven, Devs.Vap, Devs.Nickyux],
|
||||||
settings,
|
settings,
|
||||||
|
contextMenus: {
|
||||||
start() {
|
"channel-attach": ctxMenuPatch
|
||||||
addContextMenuPatch("channel-attach", ctxMenuPatch);
|
|
||||||
},
|
|
||||||
|
|
||||||
stop() {
|
|
||||||
removeContextMenuPatch("channel-attach", ctxMenuPatch);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -234,20 +246,3 @@ function Modal({ modalProps }: { modalProps: ModalProps; }) {
|
||||||
</ModalRoot>
|
</ModalRoot>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const ctxMenuPatch: NavContextMenuPatchCallback = (children, props) => () => {
|
|
||||||
if (props.channel.guild_id && !(PermissionStore.can(PermissionsBits.SEND_VOICE_MESSAGES, props.channel) && PermissionStore.can(PermissionsBits.SEND_MESSAGES, props.channel))) return;
|
|
||||||
|
|
||||||
children.push(
|
|
||||||
<Menu.MenuItem
|
|
||||||
id="vc-send-vmsg"
|
|
||||||
label={
|
|
||||||
<div className={OptionClasses.optionLabel}>
|
|
||||||
<Microphone className={OptionClasses.optionIcon} height={24} width={24} />
|
|
||||||
<div className={OptionClasses.optionName}>Send voice message</div>
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
action={() => openModal(modalProps => <Modal modalProps={modalProps} />)}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
|
@ -418,6 +418,10 @@ export const Devs = /* #__PURE__*/ Object.freeze({
|
||||||
Av32000: {
|
Av32000: {
|
||||||
name: "Av32000",
|
name: "Av32000",
|
||||||
id: 593436735380127770n,
|
id: 593436735380127770n,
|
||||||
|
},
|
||||||
|
Kyuuhachi: {
|
||||||
|
name: "Kyuuhachi",
|
||||||
|
id: 236588665420251137n,
|
||||||
}
|
}
|
||||||
} satisfies Record<string, Dev>);
|
} satisfies Record<string, Dev>);
|
||||||
|
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { Command } from "@api/Commands";
|
import { Command } from "@api/Commands";
|
||||||
|
import { NavContextMenuPatchCallback } from "@api/ContextMenu";
|
||||||
import { FluxEvents } from "@webpack/types";
|
import { FluxEvents } from "@webpack/types";
|
||||||
import { Promisable } from "type-fest";
|
import { Promisable } from "type-fest";
|
||||||
|
|
||||||
|
@ -115,6 +116,10 @@ export interface PluginDef {
|
||||||
flux?: {
|
flux?: {
|
||||||
[E in FluxEvents]?: (event: any) => void;
|
[E in FluxEvents]?: (event: any) => void;
|
||||||
};
|
};
|
||||||
|
/**
|
||||||
|
* Allows you to manipulate context menus
|
||||||
|
*/
|
||||||
|
contextMenus?: Record<string, NavContextMenuPatchCallback>;
|
||||||
/**
|
/**
|
||||||
* Allows you to add custom actions to the Vencord Toolbox.
|
* Allows you to add custom actions to the Vencord Toolbox.
|
||||||
* The key will be used as text for the button
|
* The key will be used as text for the button
|
||||||
|
|
Loading…
Reference in a new issue