Plugin

CustomAppIcons

Add/upload custom (In-)App Icons.

index.tsx
Download

Source

src/plugins/customAppIcons/index.tsx
1/*
2 * FiveCord — a Discord client mod
3 * Copyright (c) 2025 FiveCord
4 * SPDX-License-Identifier: GPL-3.0-or-later
5 */
6
7import { Link } from "@components/Link";
8import { Devs } from "@utils/constants";
9import { localStorage } from "@utils/localStorage";
10import { closeAllModals, openModal } from "@utils/modal";
11import definePlugin from "@utils/types";
12import { findByProps } from "@webpack";
13import { Button, FluxDispatcher, Forms, React, showToast, Toasts } from "@webpack/common";
14
15import AppIconModal from "./AppIconModal";
16
17function removeAppIcon() {
18 const current_icon = findByProps("getCurrentDesktopIcon").getCurrentDesktopIcon();
19 let icons = JSON.parse(localStorage.getItem("vc_app_icons") || "[]");
20 const index = icons.findIndex(icon => current_icon === icon.id);
21 if (index !== -1) {
22 icons = icons.filter(e => e.id !== current_icon);
23 delete findByProps("ICONS", "ICONS_BY_ID").ICONS_BY_ID[current_icon];
24 delete findByProps("ICONS", "ICONS_BY_ID").ICONS[findByProps("ICONS", "ICONS_BY_ID").ICONS.findIndex((icon => current_icon === icon?.id))];
25 localStorage.setItem("vc_app_icons", JSON.stringify(icons));
26 showToast("Icon successfully deleted!", Toasts.Type.SUCCESS);
27 FluxDispatcher.dispatch({
28 type: "APP_ICON_UPDATED",
29 id: "AppIcon"
30 });
31 } else {
32 showToast("Cannot delete native App Icons!", Toasts.Type.FAILURE);
33 return;
34 }
35
36}
37
38
39export default definePlugin({
40 name: "CustomAppIcons",
41 description: "Add/upload custom (In-)App Icons.",
42 authors: [Devs.FiveCord],
43 patches: [
44 {
45 find: ".PremiumUpsellTypes.APP_ICON_UPSELL",
46 replacement: [
47 {
48 match: /\w+\.jsx\)\(\w+,{markAsDismissed:\w+,isCoachmark:\w+}\)/,
49 replace(str) {
50 return str + ",$self.addButtons()";
51 }
52 }
53 ]
54 }
55 ],
56
57
58 start() {
59 const appIcons = JSON.parse(localStorage.getItem("vc_app_icons") ?? "[]");
60 for (const icon of appIcons) {
61 findByProps("ICONS", "ICONS_BY_ID").ICONS.push(icon);
62 findByProps("ICONS", "ICONS_BY_ID").ICONS_BY_ID[icon.id] = icon;
63 }
64 },
65 stop() {
66
67 },
68 addButtons() {
69
70 const { editorFooter } = findByProps("editorFooter");
71 return (
72 <>
73 <Button color={Button.Colors.BRAND_NEW} size={Button.Sizes.MEDIUM} className={editorFooter} onClick={() => {
74 openModal(props => <AppIconModal {...props} />);
75 }}>
76 Add Custom App Icon
77 </Button>
78 <Button color={Button.Colors.RED} size={Button.Sizes.MEDIUM} className={editorFooter} onClick={removeAppIcon}>
79 Remove Custom selected App Icon
80 </Button>
81 </>
82 );
83 },
84
85 settingsAboutComponent: () => {
86 return (
87 <><Forms.FormTitle>
88 <Forms.FormTitle>How to use?</Forms.FormTitle>
89 </Forms.FormTitle>
90 <Forms.FormText>
91 <Forms.FormText>Go to <Link href="/settings/appearance" onClick={e => { e.preventDefault(); closeAllModals(); FluxDispatcher.dispatch({ type: "USER_SETTINGS_MODAL_SET_SECTION", section: "Appearance" }); }}>Appearance Settings</Link> tab.</Forms.FormText>
92 <Forms.FormText>Scroll down to "In-app Icons" and click on "Preview App Icon".</Forms.FormText>
93 <Forms.FormText>And upload your own custom icon!</Forms.FormText>
94 <Forms.FormText>You can only use links when you are uploading your Custom Icon.</Forms.FormText>
95 </Forms.FormText></>
96 );
97 }
98});
99