diff --git a/src/plugins/customFolderIcons/README.md b/src/plugins/customFolderIcons/README.md
new file mode 100644
index 000000000..9b67e4eba
--- /dev/null
+++ b/src/plugins/customFolderIcons/README.md
@@ -0,0 +1,14 @@
+# CustomFolderIcons
+
+Allows you to set custom images/svgs as folder icons
+
+Available as "Change Icon" in the folder context menu
+
+![the context menu with the "Change Icon" button](https://github.com/sadan4/Vencord/assets/117494111/3dfb843c-6964-4ac3-a0b9-8772569953d3)
+
+![an image of some example custom folder icons](https://github.com/sadan4/Vencord/assets/117494111/c5324ab1-3b7a-4286-8cb5-41c0ceb2ea44)
+
+![the modal used to customize the folder icons](https://github.com/sadan4/Vencord/assets/117494111/1426d350-56db-4687-8052-6c1b1ce873a1)
+
+
+
diff --git a/src/plugins/customFolderIcons/components.tsx b/src/plugins/customFolderIcons/components.tsx
new file mode 100644
index 000000000..aab5ee129
--- /dev/null
+++ b/src/plugins/customFolderIcons/components.tsx
@@ -0,0 +1,124 @@
+/*
+ * Vencord, a Discord client mod
+ * Copyright (c) 2024 sadan
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+import { closeModal, ModalContent, ModalHeader, ModalRoot, openModalLazy } from "@utils/modal";
+import { Button, Menu, Slider, TextInput, useState } from "@webpack/common";
+
+import settings, { folderIconsData } from "./settings";
+import { folderProp, int2rgba, setFolderData } from "./util";
+
+export function ImageModal(folderProps: folderProp) {
+ const [data, setData] = useState(((settings.store.folderIcons ?? {}) as folderIconsData)[folderProps.folderId]?.url ?? "");
+ const [size, setSize] = useState(100);
+ return (
+ <>
+ {
+ setData(val);
+ }}
+ placeholder="https://example.com/image.png"
+ >
+
+
+ {data && <>
+
Change the size of the folder icon
+ {
+ setSize(v);
+ }}
+ maxValue={200}
+ minValue={25}
+ // [25, 200]
+ markers={Array.apply(0, Array(176)).map((_, i) => i + 25)}
+ stickToMarkers={true}
+ keyboardStep={1}
+ renderMarker={() => null} />
+ >}
+
+
+
+
+ >
+ );
+}
+export function RenderPreview({ folderProps, url, size }: { folderProps: folderProp; url: string; size: number; }) {
+ if (!url) return null;
+ return (
+
+
+
+ );
+}
+
+export function makeContextItem(a: folderProp) {
+ return (
+ {
+ openModalLazy(async () => {
+ return props => (
+
+
+
+ Set a New Icon.
+
+
+
+
+
+
+ You might have to hover the folder after setting in order for it to refresh.
+
+
+ );
+ },
+ {
+ modalKey: "custom-folder-icon"
+ });
+ }}/>
+ );
+}
diff --git a/src/plugins/customFolderIcons/index.tsx b/src/plugins/customFolderIcons/index.tsx
new file mode 100644
index 000000000..b86ae09bf
--- /dev/null
+++ b/src/plugins/customFolderIcons/index.tsx
@@ -0,0 +1,60 @@
+/*
+ * Vencord, a Discord client mod
+ * Copyright (c) 2024 sadan
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+import { Devs } from "@utils/constants";
+import definePlugin from "@utils/types";
+
+import { makeContextItem } from "./components";
+import settings, { folderIconsData } from "./settings";
+import { folderProp, int2rgba } from "./util";
+
+export default definePlugin({
+ settings,
+ name: "CustomFolderIcons",
+ description: "Customize folder icons with any png",
+ authors: [
+ Devs.sadan
+ ],
+ patches: [
+ {
+ find: ".expandedFolderIconWrapper",
+ replacement: {
+ match: /(return.{0,80}expandedFolderIconWrapper.*,)(\(0,..jsxs\)\(.*]}\))/,
+ replace: "$1$self.shouldReplace(arguments[0])?$self.replace(arguments[0]):$2"
+ }
+ }
+ ],
+ contextMenus: {
+ "guild-context": (menuItems, props: folderProp) => {
+ if(!("folderId" in props)) return;
+ menuItems.push(makeContextItem(props));
+ }
+ },
+ shouldReplace(props: any): boolean{
+ return !!((settings.store.folderIcons as folderIconsData)?.[props.folderNode.id]?.url);
+ },
+ replace(props: any){
+ const folderSettings = (settings.store.folderIcons as folderIconsData);
+ if(folderSettings && folderSettings[props.folderNode.id]){
+ const data = folderSettings[props.folderNode.id];
+ return (
+
+
+
+ );
+ }
+ }
+});
diff --git a/src/plugins/customFolderIcons/settings.tsx b/src/plugins/customFolderIcons/settings.tsx
new file mode 100644
index 000000000..dbe15526a
--- /dev/null
+++ b/src/plugins/customFolderIcons/settings.tsx
@@ -0,0 +1,29 @@
+/*
+ * Vencord, a Discord client mod
+ * Copyright (c) 2024 sadan
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+import { definePluginSettings } from "@api/Settings";
+import { OptionType } from "@utils/types";
+
+export interface folderIcon{
+ url: string,
+ size: number,
+}
+export type folderIconsData = Record;
+
+const settings = definePluginSettings({
+ solidIcon: {
+ type: OptionType.BOOLEAN,
+ default: false,
+ description: "Use a solid background on the background of the image"
+ },
+ folderIcons: {
+ type: OptionType.COMPONENT,
+ hidden: true,
+ description: "folder icon settings",
+ component: () => <>>
+ }
+});
+export default settings;
diff --git a/src/plugins/customFolderIcons/util.tsx b/src/plugins/customFolderIcons/util.tsx
new file mode 100644
index 000000000..efb37e3dc
--- /dev/null
+++ b/src/plugins/customFolderIcons/util.tsx
@@ -0,0 +1,29 @@
+/*
+ * Vencord, a Discord client mod
+ * Copyright (c) 2024 sadan
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+import settings, { folderIcon, folderIconsData } from "./settings";
+
+export async function setFolderData(props: folderProp, newData: folderIcon) {
+ if(!settings.store.folderIcons){
+ settings.store.folderIcons = {};
+ }
+ const folderSettings = (settings.store.folderIcons as folderIconsData);
+ folderSettings[props.folderId] = newData;
+}
+export interface folderProp {
+ folderId: string;
+ folderColor: number;
+}
+/**
+ * @param rgbVal RGB value
+ * @param alpha alpha bewteen zero and 1
+ */
+export function int2rgba(rgbVal: number, alpha: number = 1) {
+ const b = rgbVal & 0xFF,
+ g = (rgbVal & 0xFF00) >>> 8,
+ r = (rgbVal & 0xFF0000) >>> 16;
+ return `rgba(${[r, g, b].join(",")},${alpha})`;
+}