({});
+ React.useEffect(() => setBadges(fetchBadges(userId) ?? {}), [userId]);
+
+ if (!badges) return null;
+ const globalBadges: JSX.Element[] = [];
+ const badgeModal: JSX.Element[] = [];
+
+ Object.keys(badges).forEach(mod => {
+ if (!badges[mod] || !Array.isArray(badges[mod]) || badges[mod].length === 0) return;
+
+ badges[mod].forEach(badge => {
+ if (!badge || !badge.tooltip || !badge.badge) return;
+
+ const modDisplay = serviceMap[mod.toLowerCase()] || mod;
+ const prefix = settings.store.showPrefix ? `(${modDisplay})` : "";
+ const suffix = settings.store.showSuffix ? `(${modDisplay})` : "";
+ const displayName = `${prefix} ${badge.tooltip} ${suffix}`;
+
+ if (mod.toLowerCase() === "badgevault") {
+ badge.custom = true;
+ }
+
+ globalBadges.push();
+ badgeModal.push();
+ });
+ });
+ badgeImages = badgeModal;
+
+ return (
+ openBadgeModal(UserStore.getUser(userId))}
+ >
+ {globalBadges}
+
+ );
+};
diff --git a/src/equicordplugins/globalBadges/badgeModal.tsx b/src/equicordplugins/globalBadges/badgeModal.tsx
new file mode 100644
index 000000000..e2682ffde
--- /dev/null
+++ b/src/equicordplugins/globalBadges/badgeModal.tsx
@@ -0,0 +1,68 @@
+/*
+ * Vencord, a Discord client mod
+ * Copyright (c) 2025 Vendicated and contributors
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+import ErrorBoundary from "@components/ErrorBoundary";
+import { ModalContent, ModalRoot, openModal } from "@utils/modal";
+import { User } from "@vencord/discord-types";
+import { Forms, React, Tooltip } from "@webpack/common";
+
+import { badgeImages } from "./badgeComponent";
+import { cl } from "./utils";
+
+export const BadgeModalComponent = ({ name, img }: { name: string, img: string; }) => {
+ return (
+
+ {(tooltipProps: any) => (
+
+ )}
+
+ );
+};
+
+export function BadgeModal({ user }: { user: User; }) {
+ return (
+ <>
+
+

+
{user.username}
+
+ {badgeImages.length ? (
+
+ {user.username} has {badgeImages.length} global badges.
+
+ ) : (
+
+ {user.username} has no global badges.
+
+ )}
+ {!!badgeImages.length && (
+
+ {badgeImages}
+
+ )}
+ >
+ );
+}
+
+export function openBadgeModal(user: User) {
+ openModal(modalprops =>
+
+
+
+
+
+
+
+ );
+}
diff --git a/src/equicordplugins/globalBadges/index.tsx b/src/equicordplugins/globalBadges/index.tsx
index 9be95b77c..68bdb475b 100644
--- a/src/equicordplugins/globalBadges/index.tsx
+++ b/src/equicordplugins/globalBadges/index.tsx
@@ -1,126 +1,17 @@
/*
- * Vencord, a modification for Discord's desktop app
- * Copyright (c) 2022 Vendicated and contributors
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
-*/
+ * Vencord, a Discord client mod
+ * Copyright (c) 2025 Vendicated and contributors
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
import { addProfileBadge, BadgePosition, ProfileBadge, removeProfileBadge } from "@api/Badges";
-import { definePluginSettings } from "@api/Settings";
-import { classNameFactory } from "@api/Styles";
-import ErrorBoundary from "@components/ErrorBoundary";
import { Devs, EquicordDevs } from "@utils/constants";
-import { ModalContent, ModalRoot, openModal } from "@utils/modal";
-import definePlugin, { OptionType } from "@utils/types";
-import { User } from "@vencord/discord-types";
-import { Forms, React, Tooltip, UserStore } from "@webpack/common";
-import { JSX } from "react";
+import definePlugin from "@utils/types";
+import { React } from "@webpack/common";
-type CustomBadge = string | {
- name: string;
- badge: string;
- custom?: boolean;
-};
-
-interface BadgeCache {
- badges: { [mod: string]: CustomBadge[]; };
- expires: number;
-}
-
-let badgeImages;
-
-// const API_URL = "https://clientmodbadges-api.herokuapp.com/";
-const API_URL = "https://globalbadges.equicord.org/";
-const cache = new Map();
-const EXPIRES = 1000 * 60 * 15;
-
-const fetchBadges = (id: string): BadgeCache["badges"] | undefined => {
- const cachedValue = cache.get(id);
- if (!cache.has(id) || (cachedValue && cachedValue.expires < Date.now())) {
- fetch(`${API_URL}users/${id}`)
- .then(res => res.json() as Promise)
- .then(body => {
- cache.set(id, { badges: body, expires: Date.now() + EXPIRES });
- return body;
- })
- .catch(() => null);
- } else if (cachedValue) {
- return cachedValue.badges;
- }
-};
-
-const BadgeComponent = ({ name, img }: { name: string, img: string; }) => {
- return (
-
- {(tooltipProps: any) => (
-
- )}
-
- );
-};
-
-const GlobalBadges = ({ userId }: { userId: string; }) => {
- const [badges, setBadges] = React.useState({});
- React.useEffect(() => setBadges(fetchBadges(userId) ?? {}), [userId]);
-
- if (!badges) return null;
- const globalBadges: JSX.Element[] = [];
- const badgeModal: JSX.Element[] = [];
-
- Object.keys(badges).forEach(mod => {
- if (mod.toLowerCase() === "vencord") return;
- if (mod.toLowerCase() === "equicord") return;
- if (mod.toLowerCase() === "badgevault" && !settings.store.showCustom) return;
- badges[mod].forEach(badge => {
- if (typeof badge === "string") {
- const fullNames = { "hunter": "Bug Hunter", "early": "Early User" };
- badge = {
- name: fullNames[badge as string] ? fullNames[badge as string] : badge,
- badge: `${API_URL}badges/${mod}/${(badge as string).replace(mod, "").trim().split(" ")[0]}`
- };
- } else if (typeof badge === "object") badge.custom = true;
- const cleanName = badge.name.replace(mod, "").trim();
- const prefix = settings.store.showPrefix ? mod : "";
- if (!badge.custom) badge.name = `${prefix} ${cleanName.charAt(0).toUpperCase() + cleanName.slice(1)}`;
- if (badge.custom) {
- if (cleanName.toLowerCase().includes(mod)) return;
- else if (prefix) badge.name = `${cleanName} (${prefix})`.replaceAll(" ()", "");
- }
- globalBadges.push();
- badgeModal.push();
- });
- });
- badgeImages = badgeModal;
-
- return (
- openBadgeModal(UserStore.getUser(userId))}
- >
- {globalBadges}
-
- );
-};
+import { GlobalBadges } from "./badgeComponent";
+import { settings } from "./settings";
+import { fetchBadges } from "./utils";
const Badge: ProfileBadge = {
component: b => ,
@@ -129,21 +20,6 @@ const Badge: ProfileBadge = {
key: "GlobalBadges"
};
-const settings = definePluginSettings({
- showPrefix: {
- type: OptionType.BOOLEAN,
- description: "Shows the Mod as Prefix",
- default: true,
- restartNeeded: false
- },
- showCustom: {
- type: OptionType.BOOLEAN,
- description: "Show Custom Badges",
- default: true,
- restartNeeded: false
- }
-});
-
export default definePlugin({
name: "GlobalBadges",
description: "Adds global badges from other client mods",
@@ -152,69 +28,3 @@ export default definePlugin({
start: () => addProfileBadge(Badge),
stop: () => removeProfileBadge(Badge),
});
-
-/*
-Badge duping fix for modal lines below
-L39 the value for everything below
-L81 for not reusing globalbadges const
-L100 for the size of the badges
-L103 actual dupe fix
-L109 is when clicking the badge open the modal
-Everything below is related to the badge modal
-*/
-const cl = classNameFactory("vc-author-modal-");
-
-const BadgeModalComponent = ({ name, img }: { name: string, img: string; }) => {
- return (
-
- {(tooltipProps: any) => (
-
- )}
-
- );
-};
-
-function BadgeModal({ user }: { user: User; }) {
- return (
- <>
-
-

-
{user.username}
-
- {badgeImages.length ? (
-
- {user.username} has {badgeImages.length} global badges.
-
- ) : (
-
- {user.username} has no global badges.
-
- )}
- {!!badgeImages.length && (
-
- {badgeImages}
-
- )}
- >
- );
-}
-
-function openBadgeModal(user: User) {
- openModal(modalprops =>
-
-
-
-
-
-
-
- );
-}
diff --git a/src/equicordplugins/globalBadges/settings.ts b/src/equicordplugins/globalBadges/settings.ts
new file mode 100644
index 000000000..a8c37f5e3
--- /dev/null
+++ b/src/equicordplugins/globalBadges/settings.ts
@@ -0,0 +1,77 @@
+/*
+ * Vencord, a Discord client mod
+ * Copyright (c) 2025 Vendicated and contributors
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+import { definePluginSettings } from "@api/Settings";
+import { OptionType } from "@utils/types";
+
+export const settings = definePluginSettings({
+ showPrefix: {
+ type: OptionType.BOOLEAN,
+ description: "Shows the Mod as Prefix",
+ default: true,
+ restartNeeded: false
+ },
+ showSuffix: {
+ type: OptionType.BOOLEAN,
+ description: "Shows the Mod as Suffix",
+ default: false,
+ restartNeeded: false
+ },
+ showCustom: {
+ type: OptionType.BOOLEAN,
+ description: "Show Custom Badges",
+ default: true,
+ restartNeeded: false
+ },
+ showNekocord: {
+ type: OptionType.BOOLEAN,
+ description: "Show Nekocord Badges",
+ default: true,
+ restartNeeded: false
+ },
+ showReviewDB: {
+ type: OptionType.BOOLEAN,
+ description: "Show ReviewDB Badges",
+ default: true,
+ restartNeeded: false
+ },
+ showAero: {
+ type: OptionType.BOOLEAN,
+ description: "Show Aero Badges",
+ default: true,
+ restartNeeded: false
+ },
+ showAliucord: {
+ type: OptionType.BOOLEAN,
+ description: "Show Aliucord Badges",
+ default: true,
+ restartNeeded: false
+ },
+ showRa1ncord: {
+ type: OptionType.BOOLEAN,
+ description: "Show Ra1ncord Badges",
+ default: true,
+ restartNeeded: false
+ },
+ showVelocity: {
+ type: OptionType.BOOLEAN,
+ description: "Show Velocity Badges",
+ default: true,
+ restartNeeded: false
+ },
+ showEnmity: {
+ type: OptionType.BOOLEAN,
+ description: "Show Enmity Badges",
+ default: true,
+ restartNeeded: false
+ },
+ showReplugged: {
+ type: OptionType.BOOLEAN,
+ description: "Show Replugged Badges",
+ default: true,
+ restartNeeded: false
+ }
+});
diff --git a/src/equicordplugins/globalBadges/types.ts b/src/equicordplugins/globalBadges/types.ts
new file mode 100644
index 000000000..fc06b9265
--- /dev/null
+++ b/src/equicordplugins/globalBadges/types.ts
@@ -0,0 +1,16 @@
+/*
+ * Vencord, a Discord client mod
+ * Copyright (c) 2025 Vendicated and contributors
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+export type CustomBadge = {
+ tooltip: string;
+ badge: string;
+ custom?: boolean;
+};
+
+export interface BadgeCache {
+ badges: { [mod: string]: CustomBadge[]; };
+ expires: number;
+}
diff --git a/src/equicordplugins/globalBadges/utils.ts b/src/equicordplugins/globalBadges/utils.ts
new file mode 100644
index 000000000..6c715b5d9
--- /dev/null
+++ b/src/equicordplugins/globalBadges/utils.ts
@@ -0,0 +1,58 @@
+/*
+ * Vencord, a Discord client mod
+ * Copyright (c) 2025 Vendicated and contributors
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+import { classNameFactory } from "@api/Styles";
+
+import { settings } from "./settings";
+import { BadgeCache } from "./types";
+
+const API_URL = "https://badges.equicord.org/";
+const cache = new Map();
+const EXPIRES = 1000 * 60 * 15;
+
+export const cl = classNameFactory("vc-author-modal-");
+export const serviceMap = {
+ "nekocord": "Nekocord",
+ "reviewdb": "ReviewDB",
+ "aero": "Aero",
+ "aliucord": "Aliucord",
+ "ra1ncord": "Ra1ncord",
+ "velocity": "Velocity",
+ "enmity": "Enmity",
+ "replugged": "Replugged",
+ "badgevault": "BadgeVault"
+};
+
+export const fetchBadges = (id: string): BadgeCache["badges"] | undefined => {
+ const cachedValue = cache.get(id);
+ if (!cache.has(id) || (cachedValue && cachedValue.expires < Date.now())) {
+ const services: string[] = [];
+ if (settings.store.showNekocord) services.push("nekocord");
+ if (settings.store.showReviewDB) services.push("reviewdb");
+ if (settings.store.showAero) services.push("aero");
+ if (settings.store.showAliucord) services.push("aliucord");
+ if (settings.store.showRa1ncord) services.push("ra1ncord");
+ if (settings.store.showVelocity) services.push("velocity");
+ if (settings.store.showEnmity) services.push("enmity");
+ if (settings.store.showReplugged) services.push("replugged");
+ if (settings.store.showCustom) services.push("badgevault");
+
+ if (services.length === 0) {
+ cache.set(id, { badges: {}, expires: Date.now() + EXPIRES });
+ return {};
+ }
+
+ fetch(`${API_URL}${id}?seperated=true&services=${services.join(",")}`)
+ .then(res => res.json() as Promise<{ status: number; badges: BadgeCache["badges"]; }>)
+ .then(body => {
+ cache.set(id, { badges: body.badges, expires: Date.now() + EXPIRES });
+ return body.badges;
+ })
+ .catch(() => null);
+ } else if (cachedValue) {
+ return cachedValue.badges;
+ }
+};