fix Vencord context menu entries having no icon (#4518)

This commit is contained in:
theo 2026-08-17 17:23:54 +01:00 • committed by GitHub
parent 30ba4da010
commit 79759ffa7e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
13 changed files with 45 additions and 0 deletions

View file

@ -2,6 +2,22 @@ import type { ComponentType, CSSProperties, ForwardRefRenderFunction, MouseEvent
type RC<C> = ComponentType<PropsWithChildren<C & Record<string, any>>>; type RC<C> = ComponentType<PropsWithChildren<C & Record<string, any>>>;
type LeadingAccessory =
| {
type: "icon";
icon: ComponentType<any>;
}
| {
type: "emoji";
emojiId?: string;
src?: string;
animated?: boolean;
}
| {
type: "image";
src: string;
};
export interface Menu { export interface Menu {
Menu: RC<{ Menu: RC<{
navId: string; navId: string;
@ -20,6 +36,7 @@ export interface Menu {
label: ReactNode; label: ReactNode;
action?(e: MouseEvent): void; action?(e: MouseEvent): void;
icon?: ComponentType<any>; icon?: ComponentType<any>;
leadingAccessory?: LeadingAccessory;
color?: string; color?: string;
render?: ComponentType<any>; render?: ComponentType<any>;

View file

@ -90,6 +90,7 @@ export function buildExtraRoleContextMenuItems(role: Role, guild: Guild, popoutR
GuildSettingsActions.selectRole(role.id); GuildSettingsActions.selectRole(role.id);
}} }}
icon={PencilIcon} icon={PencilIcon}
leadingAccessory={{ type: "icon", icon: PencilIcon }}
/> />
), ),
role.colorString && ( role.colorString && (
@ -99,6 +100,7 @@ export function buildExtraRoleContextMenuItems(role: Role, guild: Guild, popoutR
label="Copy Role Color" label="Copy Role Color"
action={() => copyToClipboard(role.colorString!)} action={() => copyToClipboard(role.colorString!)}
icon={AppearanceIcon} icon={AppearanceIcon}
leadingAccessory={{ type: "icon", icon: AppearanceIcon }}
/> />
) )
].filter(isTruthy); ].filter(isTruthy);
@ -117,6 +119,7 @@ export function buildExtraRoleContextMenuItems(role: Role, guild: Guild, popoutR
}); });
}} }}
icon={ImageIcon} icon={ImageIcon}
leadingAccessory={{ type: "icon", icon: ImageIcon }}
/> />
), ),
popoutRef && ( popoutRef && (
@ -185,6 +188,7 @@ export function openRoleContextMenu(event: React.MouseEvent<HTMLElement>, { guil
id="vc-better-role-context-copy-role-id" id="vc-better-role-context-copy-role-id"
label={getIntlMessage("COPY_ID_ROLE")} label={getIntlMessage("COPY_ID_ROLE")}
icon={CopyIdIcon} icon={CopyIdIcon}
leadingAccessory={{ type: "icon", icon: CopyIdIcon }}
action={() => copyToClipboard(role.id)} action={() => copyToClipboard(role.id)}
/> />
</Menu.Menu> </Menu.Menu>

View file

@ -70,6 +70,7 @@ export const addViewStreamContext: NavContextMenuPatchCallback = (children, { us
label="View Stream Preview" label="View Stream Preview"
id="view-stream-preview" id="view-stream-preview"
icon={ScreenshareIcon} icon={ScreenshareIcon}
leadingAccessory={{ type: "icon", icon: ScreenshareIcon }}
action={() => stream && handleViewPreview(stream)} action={() => stream && handleViewPreview(stream)}
disabled={!stream} disabled={!stream}
/> />

View file

@ -39,6 +39,7 @@ const UserContextMenuPatch: NavContextMenuPatchCallback = (children, { user }: U
label="Copy User URL" label="Copy User URL"
action={() => copyToClipboard(`<https://discord.com/users/${user.id}>`)} action={() => copyToClipboard(`<https://discord.com/users/${user.id}>`)}
icon={LinkIcon} icon={LinkIcon}
leadingAccessory={{ type: "icon", icon: LinkIcon }}
/> />
); );
}; };

View file

@ -23,6 +23,7 @@ export default function DecorationContextMenu({ decoration }: { decoration: Deco
id={cl("decoration-context-menu-copy-hash")} id={cl("decoration-context-menu-copy-hash")}
label="Copy Decoration Hash" label="Copy Decoration Hash"
icon={CopyIcon} icon={CopyIcon}
leadingAccessory={{ type: "icon", icon: CopyIcon }}
action={() => copyToClipboard(decoration.hash)} action={() => copyToClipboard(decoration.hash)}
/> />
{decoration.authorId === UserStore.getCurrentUser().id && {decoration.authorId === UserStore.getCurrentUser().id &&
@ -31,6 +32,7 @@ export default function DecorationContextMenu({ decoration }: { decoration: Deco
label="Delete Decoration" label="Delete Decoration"
color="danger" color="danger"
icon={DeleteIcon} icon={DeleteIcon}
leadingAccessory={{ type: "icon", icon: DeleteIcon }}
action={() => openModal(props => ( action={() => openModal(props => (
<ConfirmModal <ConfirmModal
{...props} {...props}

View file

@ -89,6 +89,7 @@ const makeContextMenuPatch: (shouldAddIcon: boolean) => NavContextMenuPatchCallb
label="Apply NewGuildSettings" label="Apply NewGuildSettings"
id="vc-newguildsettings-apply" id="vc-newguildsettings-apply"
icon={shouldAddIcon ? CogWheel : void 0} icon={shouldAddIcon ? CogWheel : void 0}
leadingAccessory={shouldAddIcon ? { type: "icon", icon: CogWheel } : void 0}
action={() => applyDefaultSettings(guild.id)} action={() => applyDefaultSettings(guild.id)}
/> />
); );

View file

@ -230,6 +230,7 @@ function RoleContextMenu({ guild, roleId, onClose }: { guild: Guild; roleId: str
id={cl("copy-role-id")} id={cl("copy-role-id")}
label={getIntlMessage("COPY_ID_ROLE")} label={getIntlMessage("COPY_ID_ROLE")}
icon={CopyIdIcon} icon={CopyIdIcon}
leadingAccessory={{ type: "icon", icon: CopyIdIcon }}
action={() => copyToClipboard(roleId)} action={() => copyToClipboard(roleId)}
/> />
@ -240,6 +241,7 @@ function RoleContextMenu({ guild, roleId, onClose }: { guild: Guild; roleId: str
id={cl("view-as-role")} id={cl("view-as-role")}
label={getIntlMessage("VIEW_AS_ROLE")} label={getIntlMessage("VIEW_AS_ROLE")}
icon={ViewAsRoleIcon} icon={ViewAsRoleIcon}
leadingAccessory={{ type: "icon", icon: ViewAsRoleIcon }}
action={() => { action={() => {
onClose(); onClose();
FluxDispatcher.dispatch({ FluxDispatcher.dispatch({

View file

@ -50,6 +50,7 @@ const guildPopoutPatch: NavContextMenuPatchCallback = (children, { guild }: { gu
label="View Reviews" label="View Reviews"
id="vc-rdb-server-reviews" id="vc-rdb-server-reviews"
icon={OpenExternalIcon} icon={OpenExternalIcon}
leadingAccessory={{ type: "icon", icon: OpenExternalIcon }}
action={() => openReviewsModal(guild.id, guild.name, ReviewType.Server)} action={() => openReviewsModal(guild.id, guild.name, ReviewType.Server)}
/> />
); );
@ -62,6 +63,7 @@ const userContextPatch: NavContextMenuPatchCallback = (children, { user }: { use
label="View Reviews" label="View Reviews"
id="vc-rdb-user-reviews" id="vc-rdb-user-reviews"
icon={OpenExternalIcon} icon={OpenExternalIcon}
leadingAccessory={{ type: "icon", icon: OpenExternalIcon }}
action={() => openReviewsModal(user.id, user.username, ReviewType.User)} action={() => openReviewsModal(user.id, user.username, ReviewType.User)}
/> />
); );

View file

@ -84,18 +84,21 @@ function CopyContextMenu({ name, type, path }: { type: string; name: string; pat
label={`Copy ${type} Name`} label={`Copy ${type} Name`}
action={() => copyWithToast(name)} action={() => copyWithToast(name)}
icon={CopyIcon} icon={CopyIcon}
leadingAccessory={{ type: "icon", icon: CopyIcon }}
/> />
<Menu.MenuItem <Menu.MenuItem
id="vc-spotify-copy-link" id="vc-spotify-copy-link"
label={`Copy ${type} Link`} label={`Copy ${type} Link`}
action={() => copyWithToast("https://open.spotify.com" + path)} action={() => copyWithToast("https://open.spotify.com" + path)}
icon={LinkIcon} icon={LinkIcon}
leadingAccessory={{ type: "icon", icon: LinkIcon }}
/> />
<Menu.MenuItem <Menu.MenuItem
id="vc-spotify-open" id="vc-spotify-open"
label={`Open ${type} in Spotify`} label={`Open ${type} in Spotify`}
action={() => SpotifyStore.openExternal(path)} action={() => SpotifyStore.openExternal(path)}
icon={OpenExternalIcon} icon={OpenExternalIcon}
leadingAccessory={{ type: "icon", icon: OpenExternalIcon }}
/> />
</Menu.Menu> </Menu.Menu>
); );
@ -225,6 +228,7 @@ function AlbumContextMenu({ track }: { track: Track; }) {
label="Open Album" label="Open Album"
action={() => SpotifyStore.openExternal(`/album/${track.album.id}`)} action={() => SpotifyStore.openExternal(`/album/${track.album.id}`)}
icon={OpenExternalIcon} icon={OpenExternalIcon}
leadingAccessory={{ type: "icon", icon: OpenExternalIcon }}
/> />
<Menu.MenuItem <Menu.MenuItem
key="view-cover" key="view-cover"
@ -233,6 +237,7 @@ function AlbumContextMenu({ track }: { track: Track; }) {
// trolley // trolley
action={() => openImageModal(track.album.image)} action={() => openImageModal(track.album.image)}
icon={ImageIcon} icon={ImageIcon}
leadingAccessory={{ type: "icon", icon: ImageIcon }}
/> />
<Menu.MenuControlItem <Menu.MenuControlItem
id="spotify-volume" id="spotify-volume"

View file

@ -41,6 +41,7 @@ const messageCtxPatch: NavContextMenuPatchCallback = (children, { message }: { m
id="vc-trans" id="vc-trans"
label="Translate" label="Translate"
icon={TranslateIcon} icon={TranslateIcon}
leadingAccessory={{ type: "icon", icon: TranslateIcon }}
action={async () => { action={async () => {
const trans = await translate("received", content); const trans = await translate("received", content);
handleTranslate(message.id, trans); handleTranslate(message.id, trans);

View file

@ -49,6 +49,7 @@ const messageContextMenuPatch: NavContextMenuPatchCallback = (
label={isEmbedSuppressed ? "Unsuppress Embeds" : "Suppress Embeds"} label={isEmbedSuppressed ? "Unsuppress Embeds" : "Suppress Embeds"}
color={isEmbedSuppressed ? undefined : "danger"} color={isEmbedSuppressed ? undefined : "danger"}
icon={isEmbedSuppressed ? ImageVisible : ImageInvisible} icon={isEmbedSuppressed ? ImageVisible : ImageInvisible}
leadingAccessory={{ type: "icon", icon: isEmbedSuppressed ? ImageVisible : ImageInvisible }}
action={() => action={() =>
RestAPI.patch({ RestAPI.patch({
url: Constants.Endpoints.MESSAGE(channel.id, messageId), url: Constants.Endpoints.MESSAGE(channel.id, messageId),

View file

@ -117,6 +117,7 @@ const UserContext: NavContextMenuPatchCallback = (children, { user, guildId }: U
label="View Avatar" label="View Avatar"
action={() => openAvatar(IconUtils.getUserAvatarURL(user, true))} action={() => openAvatar(IconUtils.getUserAvatarURL(user, true))}
icon={ImageIcon} icon={ImageIcon}
leadingAccessory={{ type: "icon", icon: ImageIcon }}
/> />
{memberAvatar && ( {memberAvatar && (
<Menu.MenuItem <Menu.MenuItem
@ -129,6 +130,7 @@ const UserContext: NavContextMenuPatchCallback = (children, { user, guildId }: U
canAnimate: true canAnimate: true
}))} }))}
icon={ImageIcon} icon={ImageIcon}
leadingAccessory={{ type: "icon", icon: ImageIcon }}
/> />
)} )}
{avatarDecoration && ( {avatarDecoration && (
@ -141,6 +143,7 @@ const UserContext: NavContextMenuPatchCallback = (children, { user, guildId }: U
canAnimate: true canAnimate: true
})!)} })!)}
icon={ImageIcon} icon={ImageIcon}
leadingAccessory={{ type: "icon", icon: ImageIcon }}
/> />
)} )}
</Menu.MenuGroup> </Menu.MenuGroup>
@ -167,6 +170,7 @@ const GuildContext: NavContextMenuPatchCallback = (children, { guild }: GuildCon
})!) })!)
} }
icon={ImageIcon} icon={ImageIcon}
leadingAccessory={{ type: "icon", icon: ImageIcon }}
/> />
) : null} ) : null}
{banner ? ( {banner ? (
@ -177,6 +181,7 @@ const GuildContext: NavContextMenuPatchCallback = (children, { guild }: GuildCon
openBanner(IconUtils.getGuildBannerURL(guild, true)!) openBanner(IconUtils.getGuildBannerURL(guild, true)!)
} }
icon={ImageIcon} icon={ImageIcon}
leadingAccessory={{ type: "icon", icon: ImageIcon }}
/> />
) : null} ) : null}
</Menu.MenuGroup> </Menu.MenuGroup>
@ -195,6 +200,7 @@ const GroupDMContext: NavContextMenuPatchCallback = (children, { channel }: Grou
openAvatar(IconUtils.getChannelIconURL(channel)!) openAvatar(IconUtils.getChannelIconURL(channel)!)
} }
icon={ImageIcon} icon={ImageIcon}
leadingAccessory={{ type: "icon", icon: ImageIcon }}
/> />
</Menu.MenuGroup> </Menu.MenuGroup>
)); ));

View file

@ -151,6 +151,7 @@ function MakeContextCallback(name: "Guild" | "Role" | "User" | "Channel" | "Mess
label="View Raw" label="View Raw"
action={action} action={action}
icon={CopyRawIcon} icon={CopyRawIcon}
leadingAccessory={{ type: "icon", icon: CopyRawIcon }}
/> />
); );
}; };
@ -169,6 +170,7 @@ const devContextCallback: NavContextMenuPatchCallback = (children, { id }: { id:
label="View Raw" label="View Raw"
action={() => openViewRawModal(JSON.stringify(role, null, 4), "Role")} action={() => openViewRawModal(JSON.stringify(role, null, 4), "Role")}
icon={CopyRawIcon} icon={CopyRawIcon}
leadingAccessory={{ type: "icon", icon: CopyRawIcon }}
/> />
); );
}; };