add context menu icons to various plugins
This commit is contained in:
parent
ef29bbeb61
commit
3e03b47b45
14 changed files with 94 additions and 58 deletions
7
packages/discord-types/src/menu.d.ts
vendored
7
packages/discord-types/src/menu.d.ts
vendored
|
|
@ -1,11 +1,14 @@
|
|||
import type { ComponentType, CSSProperties, ForwardRefRenderFunction, MouseEvent, PropsWithChildren, ReactNode, UIEvent } from "react";
|
||||
import { LiteralUnion } from "type-fest";
|
||||
|
||||
type RC<C> = ComponentType<PropsWithChildren<C & Record<string, any>>>;
|
||||
|
||||
type LeadingAccessory =
|
||||
type Accessory =
|
||||
| {
|
||||
type: "icon";
|
||||
icon: ComponentType<any>;
|
||||
color?: string;
|
||||
size?: LiteralUnion<"refresh_sm", string>;
|
||||
}
|
||||
| {
|
||||
type: "emoji";
|
||||
|
|
@ -36,7 +39,7 @@ export interface Menu {
|
|||
label: ReactNode;
|
||||
action?(e: MouseEvent): void;
|
||||
icon?: ComponentType<any>;
|
||||
leadingAccessory?: LeadingAccessory;
|
||||
leadingAccessory?: Accessory;
|
||||
|
||||
color?: string;
|
||||
render?: ComponentType<any>;
|
||||
|
|
|
|||
|
|
@ -640,6 +640,20 @@ export function RightArrow(props: IconProps) {
|
|||
);
|
||||
}
|
||||
|
||||
export function TopRightArrow(props: IconProps) {
|
||||
return (
|
||||
<Icon
|
||||
{...props}
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path
|
||||
fill={props.fill || "currentColor"}
|
||||
d="M8 5a1 1 0 0 0 0 2h7.59L5.29 17.3a1 1 0 1 0 1.42 1.4L17 8.42V16a1 1 0 1 0 2 0V6a1 1 0 0 0-1-1H8Z"
|
||||
/>
|
||||
</Icon>
|
||||
);
|
||||
}
|
||||
|
||||
export function StarFilled(props: IconProps) {
|
||||
return (
|
||||
<Icon
|
||||
|
|
@ -667,3 +681,34 @@ export function StarOutlined(props: IconProps) {
|
|||
</Icon>
|
||||
);
|
||||
}
|
||||
|
||||
export function SearchIcon(props: IconProps) {
|
||||
return (
|
||||
<Icon
|
||||
{...props}
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path
|
||||
fill={props.fill || "currentColor"}
|
||||
fillRule="evenodd"
|
||||
d="M15.62 17.03a9 9 0 1 1 1.41-1.41l4.68 4.67a1 1 0 0 1-1.42 1.42l-4.67-4.68ZM17 10a7 7 0 1 1-14 0 7 7 0 0 1 14 0Z"
|
||||
clipRule="evenodd"
|
||||
/>
|
||||
</Icon>
|
||||
);
|
||||
}
|
||||
|
||||
export function EyeIcon(props: IconProps) {
|
||||
return (
|
||||
<Icon
|
||||
{...props}
|
||||
viewBox="0 0 24 24"
|
||||
fillRule="evenodd"
|
||||
>
|
||||
<path
|
||||
fill={props.fill || "currentColor"}
|
||||
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"
|
||||
/>
|
||||
</Icon>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ import { _getBadges, BadgePosition, BadgeUserArgs, ProfileBadge } from "@api/Bad
|
|||
import ErrorBoundary from "@components/ErrorBoundary";
|
||||
import { Flex } from "@components/Flex";
|
||||
import { Heart } from "@components/Heart";
|
||||
import { CopyIcon, LinkIcon } from "@components/Icons";
|
||||
import DonateButton from "@components/settings/DonateButton";
|
||||
import { openContributorModal } from "@components/settings/tabs";
|
||||
import { Devs } from "@utils/constants";
|
||||
|
|
@ -68,6 +69,7 @@ function BadgeContextMenu({ badge }: { badge: Omit<ProfileBadge, "id"> & BadgeUs
|
|||
id="vc-badge-copy-name"
|
||||
label="Copy Badge Name"
|
||||
action={() => copyWithToast(badge.description!)}
|
||||
leadingAccessory={{ type: "icon", icon: CopyIcon }}
|
||||
/>
|
||||
)}
|
||||
{badge.iconSrc && (
|
||||
|
|
@ -75,6 +77,7 @@ function BadgeContextMenu({ badge }: { badge: Omit<ProfileBadge, "id"> & BadgeUs
|
|||
id="vc-badge-copy-link"
|
||||
label="Copy Badge Image Link"
|
||||
action={() => copyWithToast(badge.iconSrc!)}
|
||||
leadingAccessory={{ type: "icon", icon: LinkIcon }}
|
||||
/>
|
||||
)}
|
||||
</Menu.Menu>
|
||||
|
|
|
|||
|
|
@ -150,6 +150,7 @@ export function buildExtraRoleContextMenuItems(role: Role, guild: Guild, popoutR
|
|||
{...popoutProps}
|
||||
>
|
||||
<div className={MenuItemClasses.label}>View Role Members</div>
|
||||
{/* FIXME: update to new icon style */}
|
||||
<div className={MenuItemClasses.iconContainer}>
|
||||
<RoleMembersIcon />
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
*/
|
||||
|
||||
import { definePluginSettings } from "@api/Settings";
|
||||
import { CopyIcon } from "@components/Icons";
|
||||
import { Devs } from "@utils/constants";
|
||||
import { copyWithToast } from "@utils/discord";
|
||||
import definePlugin, { OptionType } from "@utils/types";
|
||||
|
|
@ -69,6 +70,7 @@ export default definePlugin({
|
|||
"Success! Copied emoji markdown."
|
||||
);
|
||||
}}
|
||||
leadingAccessory={{ type: "icon", icon: CopyIcon }}
|
||||
/>
|
||||
);
|
||||
},
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@
|
|||
|
||||
import { NavContextMenuPatchCallback } from "@api/ContextMenu";
|
||||
import { isPluginEnabled } from "@api/PluginManager";
|
||||
import { LinkIcon, TopRightArrow } from "@components/Icons";
|
||||
import ExpressionClonerPlugin from "@plugins/expressionCloner";
|
||||
import { Devs } from "@utils/constants";
|
||||
import { copyWithToast } from "@utils/discord";
|
||||
|
|
@ -43,14 +44,17 @@ function buildMenuItem(sticker: PartialSticker, addBottomSeparator: boolean) {
|
|||
<Menu.MenuItem
|
||||
id="vc-copy-sticker-link"
|
||||
key="vc-copy-sticker-link"
|
||||
label="Copy Link"
|
||||
label="Copy Sticker Link"
|
||||
leadingAccessory={{ type: "icon", icon: LinkIcon }}
|
||||
action={() => copyWithToast(getUrl(sticker), "Link copied!")}
|
||||
/>
|
||||
|
||||
<Menu.MenuItem
|
||||
id="vc-open-sticker-link"
|
||||
key="vc-open-sticker-link"
|
||||
label="Open Link"
|
||||
label="Open Sticker Link"
|
||||
leadingAccessory={{ type: "icon", icon: LinkIcon }}
|
||||
trailingIndicator={{ type: "icon", icon: TopRightArrow }}
|
||||
action={() => VencordNative.native.openExternal(getUrl(sticker))}
|
||||
/>
|
||||
</Menu.MenuGroup>
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ import { migratePluginSettings } from "@api/Settings";
|
|||
import { BaseText } from "@components/BaseText";
|
||||
import { CheckedTextInput } from "@components/CheckedTextInput";
|
||||
import { Flex } from "@components/Flex";
|
||||
import { PlusIcon } from "@components/Icons";
|
||||
import { Devs } from "@utils/constants";
|
||||
import { getGuildAcronym, hasGuildFeature } from "@utils/discord";
|
||||
import { Logger } from "@utils/Logger";
|
||||
|
|
@ -327,6 +328,7 @@ function buildMenuItem(type: "Emoji" | "Sticker", fetchData: () => Promisable<Om
|
|||
id="emote-cloner"
|
||||
key="emote-cloner"
|
||||
label={`Clone ${type}`}
|
||||
leadingAccessory={{ type: "icon", icon: PlusIcon }}
|
||||
action={() =>
|
||||
openModalLazy(async () => {
|
||||
const res = await fetchData();
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ import { updateMessage } from "@api/MessageUpdater";
|
|||
import { definePluginSettings } from "@api/Settings";
|
||||
import { disableStyle, enableStyle } from "@api/Styles";
|
||||
import ErrorBoundary from "@components/ErrorBoundary";
|
||||
import { DeleteIcon, EyeIcon } from "@components/Icons";
|
||||
import { Devs, SUPPORT_CATEGORY_ID, VENBOT_USER_ID } from "@utils/constants";
|
||||
import { getIntlMessage } from "@utils/discord";
|
||||
import { Logger } from "@utils/Logger";
|
||||
|
|
@ -176,6 +177,7 @@ const patchMessageContextMenu: NavContextMenuPatchCallback = (children, props) =
|
|||
id={TOGGLE_DELETE_STYLE_ID}
|
||||
key={TOGGLE_DELETE_STYLE_ID}
|
||||
label="Toggle Deleted Highlight"
|
||||
leadingAccessory={{ type: "icon", icon: EyeIcon }}
|
||||
action={() => domElement.classList.toggle("messagelogger-deleted")}
|
||||
/>
|
||||
));
|
||||
|
|
@ -186,6 +188,7 @@ const patchMessageContextMenu: NavContextMenuPatchCallback = (children, props) =
|
|||
id={REMOVE_HISTORY_ID}
|
||||
key={REMOVE_HISTORY_ID}
|
||||
label="Remove Message History"
|
||||
leadingAccessory={{ type: "icon", icon: DeleteIcon }}
|
||||
color="danger"
|
||||
action={() => {
|
||||
clearMessageHistory(message);
|
||||
|
|
|
|||
|
|
@ -271,6 +271,7 @@ function UserContextMenu({ userId }: { userId: string; }) {
|
|||
<Menu.MenuItem
|
||||
id={cl("copy-user-id")}
|
||||
label={getIntlMessage("COPY_ID_USER")}
|
||||
leadingAccessory={{ type: "icon", icon: CopyIdIcon }}
|
||||
action={() => {
|
||||
copyToClipboard(userId);
|
||||
}}
|
||||
|
|
|
|||
|
|
@ -59,13 +59,14 @@ export const settings = definePluginSettings({
|
|||
},
|
||||
});
|
||||
|
||||
function MenuItem(guildId: string, id?: string, type?: MenuItemParentType) {
|
||||
function MenuItem(guildId: string, { id, type, withIcon }: { id?: string, type?: MenuItemParentType, withIcon?: boolean; }) {
|
||||
if (type === MenuItemParentType.User && !GuildMemberStore.isMember(guildId, id!)) return null;
|
||||
|
||||
return (
|
||||
<Menu.MenuItem
|
||||
id="perm-viewer-permissions"
|
||||
label="Permissions"
|
||||
label="View Permissions"
|
||||
leadingAccessory={withIcon ? { type: "icon", icon: SafetyIcon } : undefined}
|
||||
action={() => {
|
||||
const guild = GuildStore.getGuild(guildId);
|
||||
|
||||
|
|
@ -125,7 +126,7 @@ function MenuItem(guildId: string, id?: string, type?: MenuItemParentType) {
|
|||
);
|
||||
}
|
||||
|
||||
function makeContextMenuPatch(childId: string | string[], type?: MenuItemParentType): NavContextMenuPatchCallback {
|
||||
function makeContextMenuPatch(childId: string | string[], type?: MenuItemParentType, withIcon = false): NavContextMenuPatchCallback {
|
||||
return (children, props) => {
|
||||
if (
|
||||
!props ||
|
||||
|
|
@ -139,9 +140,9 @@ function makeContextMenuPatch(childId: string | string[], type?: MenuItemParentT
|
|||
const group = findGroupChildrenByChildId(childId, children);
|
||||
|
||||
const item = match(type)
|
||||
.with(MenuItemParentType.User, () => MenuItem(props.guildId, props.user.id, type))
|
||||
.with(MenuItemParentType.Channel, () => MenuItem(props.guild.id, props.channel.id, type))
|
||||
.with(MenuItemParentType.Guild, () => MenuItem(props.guild.id))
|
||||
.with(MenuItemParentType.User, () => MenuItem(props.guildId, { id: props.user.id, type, withIcon }))
|
||||
.with(MenuItemParentType.Channel, () => MenuItem(props.guild.id, { id: props.channel.id, type, withIcon }))
|
||||
.with(MenuItemParentType.Guild, () => MenuItem(props.guild.id, { withIcon }))
|
||||
.otherwise(() => null);
|
||||
|
||||
if (item == null) return;
|
||||
|
|
@ -214,6 +215,6 @@ export default definePlugin({
|
|||
"user-context": makeContextMenuPatch("roles", MenuItemParentType.User),
|
||||
"channel-context": makeContextMenuPatch(["mute-channel", "unmute-channel"], MenuItemParentType.Channel),
|
||||
"guild-context": makeContextMenuPatch("privacy", MenuItemParentType.Guild),
|
||||
"guild-header-popout": makeContextMenuPatch("privacy", MenuItemParentType.Guild)
|
||||
"guild-header-popout": makeContextMenuPatch("privacy", MenuItemParentType.Guild, true)
|
||||
}
|
||||
});
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@
|
|||
|
||||
import { ChatBarButton, ChatBarButtonFactory } from "@api/ChatButtons";
|
||||
import { generateId, sendBotMessage } from "@api/Commands";
|
||||
import { EyeIcon } from "@components/Icons";
|
||||
import { Devs } from "@utils/constants";
|
||||
import definePlugin, { IconComponent, StartAt } from "@utils/types";
|
||||
import { CloudUpload, MessageAttachment } from "@vencord/discord-types";
|
||||
|
|
@ -75,17 +76,12 @@ const getAttachments = async (channelId: string) =>
|
|||
|
||||
const PreviewIcon: IconComponent = ({ height = 20, width = 20, className }) => {
|
||||
return (
|
||||
<svg
|
||||
fill="currentColor"
|
||||
fillRule="evenodd"
|
||||
<EyeIcon
|
||||
width={width}
|
||||
height={height}
|
||||
className={className}
|
||||
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>
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
import { findGroupChildrenByChildId, NavContextMenuPatchCallback } from "@api/ContextMenu";
|
||||
import { definePluginSettings } from "@api/Settings";
|
||||
import { Flex } from "@components/Flex";
|
||||
import { SearchIcon } from "@components/Icons";
|
||||
import { Devs } from "@utils/constants";
|
||||
import definePlugin, { OptionType } from "@utils/types";
|
||||
import { Menu } from "@webpack/common";
|
||||
|
|
@ -89,6 +89,7 @@ function makeSearchItem(src: string) {
|
|||
label="Search Text"
|
||||
key="search-text"
|
||||
id="vc-search-text"
|
||||
leadingAccessory={{ type: "icon", icon: SearchIcon }}
|
||||
>
|
||||
{Object.keys(Engines).map(engine => {
|
||||
const key = "vc-search-content-" + engine;
|
||||
|
|
@ -96,20 +97,8 @@ function makeSearchItem(src: string) {
|
|||
<Menu.MenuItem
|
||||
key={key}
|
||||
id={key}
|
||||
label={
|
||||
<Flex gap="0.5em" alignItems="center">
|
||||
<img
|
||||
style={{
|
||||
borderRadius: "50%"
|
||||
}}
|
||||
aria-hidden="true"
|
||||
height={16}
|
||||
width={16}
|
||||
src={`https://icons.duckduckgo.com/ip3/${new URL(Engines[engine]).hostname}.ico`}
|
||||
/>
|
||||
{engine}
|
||||
</Flex>
|
||||
}
|
||||
label={engine}
|
||||
leadingAccessory={{ type: "image", src: `https://icons.duckduckgo.com/ip3/${new URL(Engines[engine]).hostname}.ico` }}
|
||||
action={() => search(src, Engines[engine])}
|
||||
/>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -17,8 +17,7 @@
|
|||
*/
|
||||
|
||||
import { findGroupChildrenByChildId, NavContextMenuPatchCallback } from "@api/ContextMenu";
|
||||
import { Flex } from "@components/Flex";
|
||||
import { OpenExternalIcon } from "@components/Icons";
|
||||
import { OpenExternalIcon, SearchIcon } from "@components/Icons";
|
||||
import { Devs } from "@utils/constants";
|
||||
import definePlugin from "@utils/types";
|
||||
import { Menu } from "@webpack/common";
|
||||
|
|
@ -43,6 +42,7 @@ function makeSearchItem(src: string) {
|
|||
label="Search Image"
|
||||
key="search-image"
|
||||
id="search-image"
|
||||
leadingAccessory={{ type: "icon", icon: SearchIcon }}
|
||||
>
|
||||
{Object.keys(Engines).map((engine, i) => {
|
||||
const key = "search-image-" + engine;
|
||||
|
|
@ -50,20 +50,8 @@ function makeSearchItem(src: string) {
|
|||
<Menu.MenuItem
|
||||
key={key}
|
||||
id={key}
|
||||
label={
|
||||
<Flex alignItems="center" gap="0.5em">
|
||||
<img
|
||||
style={{
|
||||
borderRadius: "50%",
|
||||
}}
|
||||
aria-hidden="true"
|
||||
height={16}
|
||||
width={16}
|
||||
src={`https://icons.duckduckgo.com/ip3/${new URL(Engines[engine]).host}.ico`}
|
||||
/>
|
||||
{engine}
|
||||
</Flex>
|
||||
}
|
||||
label={engine}
|
||||
leadingAccessory={{ type: "image", src: `https://icons.duckduckgo.com/ip3/${new URL(Engines[engine]).host}.ico` }}
|
||||
action={() => search(src, Engines[engine])}
|
||||
/>
|
||||
);
|
||||
|
|
@ -71,12 +59,8 @@ function makeSearchItem(src: string) {
|
|||
<Menu.MenuItem
|
||||
key="search-image-all"
|
||||
id="search-image-all"
|
||||
label={
|
||||
<Flex alignItems="center" gap="0.5em">
|
||||
<OpenExternalIcon height={16} width={16} />
|
||||
All
|
||||
</Flex>
|
||||
}
|
||||
label="All"
|
||||
leadingAccessory={{ type: "icon", icon: OpenExternalIcon }}
|
||||
action={() => Object.values(Engines).forEach(e => search(src, e))}
|
||||
/>
|
||||
</Menu.MenuItem>
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
*/
|
||||
|
||||
import { findGroupChildrenByChildId, NavContextMenuPatchCallback } from "@api/ContextMenu";
|
||||
import { InfoIcon } from "@components/Icons";
|
||||
import { Devs } from "@utils/constants";
|
||||
import definePlugin from "@utils/types";
|
||||
import { Guild } from "@vencord/discord-types";
|
||||
|
|
@ -12,13 +13,14 @@ import { Menu } from "@webpack/common";
|
|||
|
||||
import { openGuildInfoModal } from "./GuildInfoModal";
|
||||
|
||||
const Patch: NavContextMenuPatchCallback = (children, { guild }: { guild: Guild; }) => {
|
||||
const makePatch: (showIcon: boolean) => NavContextMenuPatchCallback = showIcon => (children, { guild }: { guild: Guild; }) => {
|
||||
const group = findGroupChildrenByChildId("privacy", children);
|
||||
|
||||
group?.push(
|
||||
<Menu.MenuItem
|
||||
id="vc-server-info"
|
||||
label="Server Info"
|
||||
leadingAccessory={showIcon ? { type: "icon", icon: InfoIcon } : undefined}
|
||||
action={() => openGuildInfoModal(guild)}
|
||||
/>
|
||||
);
|
||||
|
|
@ -33,7 +35,7 @@ export default definePlugin({
|
|||
searchTerms: ["guild", "info", "ServerProfile"],
|
||||
|
||||
contextMenus: {
|
||||
"guild-context": Patch,
|
||||
"guild-header-popout": Patch
|
||||
"guild-context": makePatch(false),
|
||||
"guild-header-popout": makePatch(true)
|
||||
}
|
||||
});
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue