Merge remote-tracking branch 'upstream/main'

This commit is contained in:
Panniku 2024-07-25 20:09:38 +05:30
commit e5a1161327
22 changed files with 281 additions and 203 deletions

View file

@ -1,7 +1,7 @@
{
"name": "equicord",
"private": "true",
"version": "1.9.5",
"version": "1.9.6",
"description": "The other cutest Discord client mod",
"homepage": "https://github.com/Equicord/Equicord#readme",
"bugs": {

View file

@ -67,7 +67,7 @@ export const _handleCommand = function (cmd: Command, args: Argument[], ctx: Com
sendBotMessage(ctx.channel.id, {
content: `${msg}:\n${makeCodeblock(reason)}`,
author: {
username: "Vencord"
username: "Equicord"
}
});
};

View file

@ -1,104 +0,0 @@
/*
* Vencord, a Discord client mod
* Copyright (c) 2024 Vendicated and contributors
* SPDX-License-Identifier: GPL-3.0-or-later
*/
import { localStorage } from "@utils/localStorage";
import { ModalCloseButton, ModalContent, ModalFooter, ModalHeader, ModalProps, ModalRoot, ModalSize } from "@utils/modal";
import { findByProps } from "@webpack";
import { Button, FluxDispatcher, Forms, React, showToast, Text, TextInput, Toasts, useState } from "@webpack/common";
interface AppIcon {
id: string,
iconSource: string,
name: string,
isPremium: boolean;
}
function AppIconModal(props: ModalProps) {
const [name, setName] = useState("");
const [imageUrl, setimageUrl] = useState("");
function addAppIcon(name, url) {
const appIcons = JSON.parse(localStorage.getItem("vc_app_icons") ?? "[]");
const id = `${name.replaceAll(" ", "")}_${Date.now()}`; // avoid crashing if repeated name
const icon = {
"id": id,
"iconSource": url,
"isPremium": false,
"name": name
} as AppIcon;
appIcons.push(icon);
findByProps("M9", "UZ", "QA").UZ.push(icon);
findByProps("M9", "UZ", "QA").QA[icon.id] = icon;
showToast("Added custom app icon!", Toasts.Type.SUCCESS);
props.onClose();
const oldIcon = findByProps("getCurrentDesktopIcon").getCurrentDesktopIcon();
let random_icon = Object.keys(findByProps("UZ")).filter(icon => icon !== oldIcon) as [];
random_icon = random_icon[Math.floor(Math.random() * random_icon.length)];
FluxDispatcher.dispatch({
type: "APP_ICON_UPDATED",
id: random_icon
});
FluxDispatcher.dispatch({
type: "APP_ICON_UPDATED",
id: oldIcon
});
localStorage.setItem("vc_app_icons", JSON.stringify(appIcons));
}
return <ModalRoot {...props} size={ModalSize.MEDIUM}>
<ModalHeader>
<Text color="header-primary" variant="heading-lg/semibold" tag="h1" style={{ flexGrow: 1 }}>Add a custom app icon:</Text>
<ModalCloseButton onClick={props.onClose}></ModalCloseButton>
</ModalHeader>
<ModalContent>
<br />
<Forms.FormSection title="Name">
<Forms.FormText type="description">
This name will be shown in the App Icons list.
</Forms.FormText>
<TextInput
placeholder="My awesome Custom App Icon!"
value={name}
onChange={setName}
/>
</Forms.FormSection>
<br />
<Forms.FormSection title="Image URL">
<Forms.FormText type="description">
Paste here your image URL to upload your icon (.webp, .jpg, .jpeg, .png, .gif, .ico and Discord Icons, Emojis, PFPs, etc.).
</Forms.FormText>
<TextInput
placeholder="https://cdn.discordapp.com/emojis/1098881040900173895.gif"
value={imageUrl}
onChange={setimageUrl}
/>
</Forms.FormSection>
</ModalContent>
<ModalFooter>
<Button
onClick={() => {
addAppIcon(name, imageUrl);
}}
disabled={!name || !imageUrl && imageUrl.match(/(https:\/\/www\.|http:\/\/www\.|https:\/\/|http:\/\/)?[a-zA-Z]{2,}(\.[a-zA-Z]{2,})(\.[a-zA-Z]{2,})?\/[a-zA-Z0-9]{2,}|((https:\/\/www\.|http:\/\/www\.|https:\/\/|http:\/\/)?[a-zA-Z]{2,}(\.[a-zA-Z]{2,})(\.[a-zA-Z]{2,})?)|(https:\/\/www\.|http:\/\/www\.|https:\/\/|http:\/\/)?[a-zA-Z0-9]{2,}\.[a-zA-Z0-9]{2,}\.[a-zA-Z0-9]{2,}(\.[a-zA-Z0-9]{2,})?/) !== undefined}
>
Add Icon
</Button>
<Button
onClick={props.onClose}
color={Button.Colors.PRIMARY}
look={Button.Looks.LINK}
>
Cancel
</Button>
</ModalFooter>
</ModalRoot>;
}
export default AppIconModal;

View file

@ -4,95 +4,88 @@
* SPDX-License-Identifier: GPL-3.0-or-later
*/
import { Link } from "@components/Link";
import { definePluginSettings } from "@api/Settings";
import { CodeBlock } from "@components/CodeBlock";
import { Devs, EquicordDevs } from "@utils/constants";
import { localStorage } from "@utils/localStorage";
import { closeAllModals, openModal } from "@utils/modal";
import definePlugin from "@utils/types";
import { findByProps } from "@webpack";
import { Button, FluxDispatcher, Forms, React, showToast, Toasts } from "@webpack/common";
import definePlugin, { OptionType, PluginSettingComponentDef } from "@utils/types";
import { Forms, React, TextArea } from "@webpack/common";
import AppIconModal from "./AppIconModal";
type Icon = {
id: string,
iconSource: string,
isPremium: boolean,
name: string,
};
function removeAppIcon() {
const current_icon = findByProps("getCurrentDesktopIcon").getCurrentDesktopIcon();
let icons = JSON.parse(localStorage.getItem("vc_app_icons") || "[]");
const index = icons.findIndex(icon => current_icon === icon.id);
if (index !== -1) {
icons = icons.filter(e => e.id !== current_icon);
delete findByProps("M9", "UZ", "QA").QA[current_icon];
delete findByProps("M9", "UZ", "QA").UZ[findByProps("M9", "UZ", "QA").UZ.findIndex((icon => current_icon === icon?.id))];
localStorage.setItem("vc_app_icons", JSON.stringify(icons));
showToast("Icon successfully deleted!", Toasts.Type.SUCCESS);
FluxDispatcher.dispatch({
type: "APP_ICON_UPDATED",
id: "AppIcon"
const settings = definePluginSettings({
icons: {
description: "Icons to add",
type: OptionType.COMPONENT,
restartNeeded: true,
component: iconSettingsComponent
}
});
} else {
showToast("Cannot delete native App Icons!", Toasts.Type.FAILURE);
return;
function iconSettingsComponent(props: Parameters<PluginSettingComponentDef["component"]>[0]) {
const [state, setState] = React.useState(settings.store.icons ?? "");
function handleChange(newValue: string) {
setState(newValue);
props.setValue(newValue);
}
return <Forms.FormSection>
<Forms.FormTitle>Icons</Forms.FormTitle>
<Forms.FormText>The icons you want to add.</Forms.FormText>
<CodeBlock lang="yaml" content={"# Config Format - New Lines are separators\nName: Url"} />
<TextArea type="text" value={state} onChange={handleChange} />
</Forms.FormSection>;
}
function getCustomIcons(_match: string, original: string) {
var icons: Icon[] = [];
const settingsIcons = settings.store.icons?.split("\n") as string[];
let index = 0;
for (const icon of settingsIcons) {
const matched = /([^:]+):\s*(.+)/.exec(icon);
if (!matched || matched.length < 3) continue;
const name = matched[1].trim(),
iconSource = matched[2].trim();
const idName = name
.toLowerCase()
.replace(/\s/g, "_")
.replace(/\W/g, "#");
icons.push({
id: `CustomAppIcon-${index}:${idName}`,
iconSource,
isPremium: false,
name
});
index++;
}
const outIcons = icons.map(i => JSON.stringify(i)).join(",");
return `[${original}${icons.length > 0 ? "," : ""}${outIcons}]`;
}
export default definePlugin({
name: "CustomAppIcons",
description: "Add/upload custom (In-)App Icons.",
authors: [Devs.HappyEnderman, EquicordDevs.SerStars],
description: "Allows you to add your own app icons to the list.",
authors: [Devs.nakoyasha, EquicordDevs.SimplyData],
settings,
patches: [
{
find: /\i\.\i\.APP_ICON_UPSELL/,
replacement: [
{
match: /\w+\.jsx\)\(\w+,{markAsDismissed:\w+,isCoachmark:\w+}\)/,
replace(str) {
return str + ",$self.addButtons()";
find: "APP_ICON_HOLO_WAVES}",
replacement: {
match: /\[({[^]*?})\]/,
replace: getCustomIcons,
}
}
]
}
],
start() {
const appIcons = JSON.parse(localStorage.getItem("vc_app_icons") ?? "[]");
for (const icon of appIcons) {
findByProps("M9", "UZ", "QA").UZ.push(icon);
findByProps("M9", "UZ", "QA").QA[icon.id] = icon;
}
},
stop() {
},
addButtons() {
const { editorFooter } = findByProps("editorFooter");
return (
<>
<Button color={Button.Colors.BRAND_NEW} size={Button.Sizes.MEDIUM} className={editorFooter} onClick={() => {
openModal(props => <AppIconModal {...props} />);
}}>
Add Custom App Icon
</Button>
<Button color={Button.Colors.RED} size={Button.Sizes.MEDIUM} className={editorFooter} onClick={removeAppIcon}>
Remove Custom selected App Icon
</Button>
</>
);
},
settingsAboutComponent: () => {
return (
<><Forms.FormTitle>
<Forms.FormTitle>How to use?</Forms.FormTitle>
</Forms.FormTitle>
<Forms.FormText>
<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>
<Forms.FormText>Scroll down to "In-app Icons" and click on "Preview App Icon".</Forms.FormText>
<Forms.FormText>And upload your own custom icon!</Forms.FormText>
<Forms.FormText>You can only use links when you are uploading your Custom Icon.</Forms.FormText>
</Forms.FormText></>
);
}
});

View file

@ -5,6 +5,7 @@
*/
import { addContextMenuPatch, findGroupChildrenByChildId, NavContextMenuPatchCallback, removeContextMenuPatch } from "@api/ContextMenu";
import { migratePluginSettings } from "@api/Settings";
import { Devs, EquicordDevs } from "@utils/constants";
import definePlugin from "@utils/types";
import { Menu } from "@webpack/common";
@ -22,8 +23,9 @@ const Patch: NavContextMenuPatchCallback = (children, { guild }: { guild: Guild;
}
};
migratePluginSettings("EmojiDumper", "emojiDumper");
export default definePlugin({
name: "emojiDumper",
name: "EmojiDumper",
description: "Context menu to dump and download a server's emojis.",
authors: [EquicordDevs.Cortex, Devs.Samwich, EquicordDevs.Woosh],
start() {

View file

@ -344,6 +344,7 @@ function QrModal(props: ModalProps) {
stream = str;
video.srcObject = str;
video.addEventListener("loadedmetadata", () => {
if (stopped) return stop(str);
video.play();
modalProps.current.setPreview(video);
snapshot();

View file

@ -12,7 +12,7 @@ import { openNewPluginsModal } from "./NewPluginsModal";
export default definePlugin({
name: "NewPluginsManager",
description: "Utility that notifies you when new plugins are added to Vencord",
description: "Utility that notifies you when new plugins are added to Equicord",
authors: [Devs.Sqaaakoi],
flux: {
async POST_CONNECTION_OPEN() {

View file

@ -4,11 +4,13 @@
* SPDX-License-Identifier: GPL-3.0-or-later
*/
import { migratePluginSettings } from "@api/Settings";
import { EquicordDevs } from "@utils/constants";
import definePlugin from "@utils/types";
migratePluginSettings("NoAppsAllowed", "noAppsAllowed");
export default definePlugin({
name: "noAppsAllowed",
name: "NoAppsAllowed",
description: "returns the bot's tag :skulk:",
authors: [EquicordDevs.kvba],

View file

@ -0,0 +1,149 @@
/*
* Vencord, a Discord client mod
* Copyright (c) 2024 Vendicated and contributors
* SPDX-License-Identifier: GPL-3.0-or-later
*/
import { findGroupChildrenByChildId, NavContextMenuPatchCallback } from "@api/ContextMenu";
import { DataStore } from "@api/index";
import { definePluginSettings } from "@api/Settings";
import ErrorBoundary from "@components/ErrorBoundary";
import { Devs } from "@utils/constants";
import definePlugin, { OptionType } from "@utils/types";
import { Button, Menu } from "@webpack/common";
import React, { ReactNode } from "react";
const settings = definePluginSettings({
showGif: {
type: OptionType.BOOLEAN,
description: "Whether to show a snazzy cat gif",
default: true,
restartNeeded: true
},
showMessage: {
type: OptionType.BOOLEAN,
description: "Whether to show a message detailing which id was blocked",
default: false,
restartNeeded: true
},
showButton: {
type: OptionType.BOOLEAN,
description: "Whether to show a button to unblock the gif",
default: true,
restartNeeded: true
},
blockedStickers: {
type: OptionType.STRING,
description: "The list of blocked sticker IDs (don't edit unless you know what you're doing)",
default: ""
}
});
function blockedComponentRender(sticker) {
const { showGif, showMessage, showButton } = settings.store;
const elements = [] as ReactNode[];
if (showGif) {
elements.push(
<img key="gif" src="https://files.catbox.moe/bdsc58.gif" style={{ width: "160px", borderRadius: "20px" }} />
);
}
if (showMessage) {
elements.push(
<div key="message" id="message-content-1205482612316184657" className={"markup_a7e664 messageContent__21e69"}><span>Blocked Sticker. ID: {sticker.id}, NAME: {sticker.name}</span></div>
);
}
if (showButton) {
elements.push(
<Button key="button" onClick={() => toggleBlock(sticker.id)} color={Button.Colors.RED}>Unblock {(showMessage) ? "" : sticker.name}</Button>
);
}
return <>{elements}</>;
}
const messageContextMenuPatch: NavContextMenuPatchCallback = (children, props) => {
const { favoriteableId, favoriteableType } = props ?? {};
if (!favoriteableId) return;
const menuItem = (() => {
switch (favoriteableType) {
case "sticker":
const sticker = props.message.stickerItems.find(s => s.id === favoriteableId);
if (sticker?.format_type === 3 /* LOTTIE */) return;
return buildMenuItem(favoriteableId);
}
})();
if (menuItem)
findGroupChildrenByChildId("copy-link", children)?.push(menuItem);
};
const expressionPickerPatch: NavContextMenuPatchCallback = (children, props: { target: HTMLElement; }) => {
const { id, type } = props?.target?.dataset ?? {};
if (!id) return;
if (type === "sticker" && !props.target.className?.includes("lottieCanvas")) {
children.push(buildMenuItem(id));
}
};
function buildMenuItem(name) {
return (
<Menu.MenuItem
id="add-sticker-block"
key="add-sticker-block"
label={(isStickerBlocked(name)) ? "Unblock Sticker" : "Block Sticker"}
action={() => toggleBlock(name)}
/>
);
}
function toggleBlock(name) {
if (settings.store.blockedStickers === undefined || settings.store.blockedStickers == null) {
return;
}
const excepted = isStickerBlocked(name);
if (excepted) {
settings.store.blockedStickers = settings.store.blockedStickers.split(", ").filter(item => item !== name).join(", ");
} else {
settings.store.blockedStickers = settings.store.blockedStickers.split(", ").concat(name).join(", ");
}
}
function isStickerBlocked(name) {
if (settings.store.blockedStickers === undefined || settings.store.blockedStickers == null) {
return;
}
return settings.store.blockedStickers.split(", ").includes(name);
}
export default definePlugin({
name: "StickerBlocker",
description: "Allows you to block stickers from being displayed.",
authors: [Devs.Samwich],
patches: [
{
find: /\i\.\i\.STICKER_MESSAGE/,
replacement: {
match: /}\),\(null!=\i\?\i:(\i)\)\.name]}\);/,
replace: "$& if(Vencord.Settings.plugins.StickerBlocker.blockedStickers.split(\", \").includes($1.id)) { return($self.blockedComponent($1)) }"
}
}
],
contextMenus: {
"message": messageContextMenuPatch,
"expression-picker": expressionPickerPatch,
},
start() {
DataStore.createStore("StickerBlocker", "data");
},
blockedComponent: ErrorBoundary.wrap(blockedComponentRender, { fallback: () => <p style={{ color: "red" }}>Failed to render :(</p> }),
settings,
});

View file

@ -15,7 +15,7 @@ const rootTitle = { base: null as string | null };
export const settings = definePluginSettings({
title: {
type: OptionType.STRING,
default: "Vencord",
default: "Equicord",
description: "Window title prefix",
onChange: setTitle,
},

View file

@ -241,7 +241,7 @@ async function createActivity(): Promise<Activity | undefined> {
let { type } = settings.store;
let appName = "Vencord";
let appName = "Equicord";
let details = "";
let state = "";
let imageBig = "";

View file

@ -53,6 +53,31 @@ if (IS_VESKTOP || !IS_VANILLA) {
}
});
protocol.registerFileProtocol("equicord", ({ url: unsafeUrl }, cb) => {
let url = unsafeUrl.slice("equicord://".length);
if (url.endsWith("/")) url = url.slice(0, -1);
if (url.startsWith("/themes/")) {
const theme = url.slice("/themes/".length);
const safeUrl = ensureSafePath(THEMES_DIR, theme);
if (!safeUrl) {
cb({ statusCode: 403 });
return;
}
cb(safeUrl.replace(/\?v=\d+$/, ""));
return;
}
switch (url) {
case "renderer.js.map":
case "preload.js.map":
case "patcher.js.map":
case "main.js.map":
cb(join(__dirname, url));
break;
default:
cb({ statusCode: 403 });
}
});
try {
if (RendererSettings.store.enableReactDevtools)
installExt("fmkadmapgofadopljbjfkapdkoienihi")

View file

@ -162,13 +162,13 @@ export default definePlugin({
{
name: "equicord-debug",
description: "Send Equicord debug info",
predicate: ctx => isPluginDev(UserStore.getCurrentUser()?.id) || AllowedChannelIds.includes(ctx.channel.id),
predicate: ctx => isPluginDev(UserStore.getCurrentUser()?.id) || isEquicordPluginDev(UserStore.getCurrentUser()?.id) || AllowedChannelIds.includes(ctx.channel.id),
execute: async () => ({ content: await generateDebugInfoMessage() })
},
{
name: "equicord-plugins",
description: "Send Equicord plugin list",
predicate: ctx => isPluginDev(UserStore.getCurrentUser()?.id) || AllowedChannelIds.includes(ctx.channel.id),
predicate: ctx => isPluginDev(UserStore.getCurrentUser()?.id) || isEquicordPluginDev(UserStore.getCurrentUser()?.id) || AllowedChannelIds.includes(ctx.channel.id),
execute: () => ({ content: generatePluginList() })
}
],
@ -254,7 +254,7 @@ export default definePlugin({
ContributorDmWarningCard: ErrorBoundary.wrap(({ userId }) => {
if (!isPluginDev(userId) || !isEquicordPluginDev(userId)) return null;
if (RelationshipStore.isFriend(userId) || isPluginDev(UserStore.getCurrentUser()?.id)) return null;
if (RelationshipStore.isFriend(userId) || isPluginDev(UserStore.getCurrentUser()?.id) || isEquicordPluginDev(UserStore.getCurrentUser()?.id)) return null;
return (
<Card className={`vc-plugins-restart-card ${Margins.top8}`}>

View file

@ -30,7 +30,7 @@ function onPickColor(color: number) {
updateColorVars(hexColor);
}
const saveClientTheme = findByCodeLazy('type:"UNSYNCED_USER_SETTINGS_UPDATE",settings:{useSystemTheme:null!=');
const saveClientTheme = findByCodeLazy('type:"UNSYNCED_USER_SETTINGS_UPDATE', '"system"===');
function setTheme(theme: string) {
saveClientTheme({ theme });

View file

@ -57,7 +57,7 @@ function decode(bio: string): Array<number> | null {
if (bio == null) return null;
const colorString = bio.match(
/\u{e005b}\u{e0023}([\u{e0061}-\u{e0066}\u{e0041}-\u{e0046}\u{e0030}-\u{e0039}]{6})\u{e002c}\u{e0023}([\u{e0061}-\u{e0066}\u{e0041}-\u{e0046}\u{e0030}-\u{e0039}]{6})\u{e005d}/u,
/\u{e005b}\u{e0023}([\u{e0061}-\u{e0066}\u{e0041}-\u{e0046}\u{e0030}-\u{e0039}]{1,6})\u{e002c}\u{e0023}([\u{e0061}-\u{e0066}\u{e0041}-\u{e0046}\u{e0030}-\u{e0039}]{1,6})\u{e005d}/u,
);
if (colorString != null) {
const parsed = [...colorString[0]]

View file

@ -171,7 +171,7 @@ export default definePlugin({
find: ".handleImageLoad)",
replacement: [
{
match: /dataSafeSrc:\i,children:/,
match: /placeholderVersion:\i,(?=.{0,50}children:)/,
replace: "...$self.makeProps(this),$&"
},

View file

@ -16,7 +16,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import { definePluginSettings, Settings } from "@api/Settings";
import { definePluginSettings, migratePluginSettings, Settings } from "@api/Settings";
import { Devs } from "@utils/constants";
import definePlugin, { OptionType } from "@utils/types";
@ -31,7 +31,7 @@ const settings = definePluginSettings({
},
onChange: () => {
// note: cant call the start() function from here. so i just copy pasted it (This was pointed out in the last commit i made. So this is to just clear stuff up for any future devs that work on this :D )
if (Settings.plugins.oneko.enabled) {
if (Settings.plugins.Oneko.enabled) {
document.getElementById("oneko")?.remove();
fetch("https://raw.githubusercontent.com/adryd325/oneko.js/8fa8a1864aa71cd7a794d58bc139e755e96a236c/oneko.js")
.then(x => x.text())
@ -45,8 +45,9 @@ const settings = definePluginSettings({
}
});
migratePluginSettings("Oneko", "oneko");
export default definePlugin({
name: "oneko",
name: "Oneko",
description: "cat follow mouse (real)",
// Listing adryd here because this literally just evals her script
authors: [Devs.Ven, Devs.adryd],

View file

@ -48,7 +48,7 @@ export default definePlugin({
},
patches: [
{
find: '"account";',
find: "this.isCopiedStreakGodlike",
replacement: {
// react.jsx)(AccountPanel, { ..., showTaglessAccountPanel: blah })
match: /(?<=\i\.jsxs?\)\()(\i),{(?=[^}]*?userTag:\i,hidePrivateData:)/,

View file

@ -189,7 +189,8 @@ export default definePlugin({
replacement: {
match: /avatarSrc:(\i),eventHandlers:(\i).+?"div",{...\2,/,
replace: "$&style:{cursor:\"pointer\"},onClick:()=>{$self.openImage($1)},"
}
},
all: true
},
// Old Profiles Modal pfp
{

View file

@ -271,7 +271,7 @@ function sendMsgNotif(titleString: string, content: string, message: Message) {
content: content,
useBase64Icon: true,
icon: result,
sourceApp: "Vencord"
sourceApp: "Equicord"
};
Native.sendToOverlay(msgData);
});
@ -290,7 +290,7 @@ function sendOtherNotif(content: string, titleString: string) {
content: content,
useBase64Icon: false,
icon: null,
sourceApp: "Vencord"
sourceApp: "Equicord"
};
Native.sendToOverlay(msgData);
}

View file

@ -535,7 +535,11 @@ export const Devs = /* #__PURE__*/ Object.freeze({
Antti: {
name: "Antti",
id: 312974985876471810n
}
},
Joona: {
name: "Joona",
id: 297410829589020673n
},
} satisfies Record<string, Dev>);
export const EquicordDevs = Object.freeze({
@ -707,6 +711,10 @@ export const EquicordDevs = Object.freeze({
name: "Joona",
id: 297410829589020673n
},
SimplyData: {
name: "SimplyData",
id: 301494563514613762n
},
} satisfies Record<string, Dev>);
export const SuncordDevs = /* #__PURE__*/ Object.freeze({

View file

@ -68,7 +68,7 @@ export async function compileUsercss(fileName: string) {
const preprocessorFn = preprocessors[preprocessor];
if (!preprocessorFn) {
UserCSSLogger.error("File", fileName, "requires preprocessor", preprocessor, "which isn't known to Vencord");
UserCSSLogger.error("File", fileName, "requires preprocessor", preprocessor, "which isn't known to Equicord");
return null;
}