diff --git a/src/api/Badges.ts b/src/api/Badges.ts index 82b6a63d4..9ab0f5cb2 100644 --- a/src/api/Badges.ts +++ b/src/api/Badges.ts @@ -17,9 +17,12 @@ */ import ErrorBoundary from "@components/ErrorBoundary"; +import globalBadges from "@equicordplugins/globalBadges"; import BadgeAPIPlugin from "@plugins/_api/badges"; import { ComponentType, HTMLProps } from "react"; +import { isPluginEnabled } from "./PluginManager"; + export const enum BadgePosition { START, END @@ -99,6 +102,18 @@ export function _getBadges(args: BadgeUserArgs) { const donorBadges = BadgeAPIPlugin.getDonorBadges(args.userId); const equicordDonorBadges = BadgeAPIPlugin.getEquicordDonorBadges(args.userId); + const GlobalBadges = isPluginEnabled(globalBadges.name) ? globalBadges.getGlobalBadges(args.userId) : false; + + // do globalbadges first so it shows before the contrib badges but after donor badges + if (GlobalBadges) { + badges.unshift( + ...GlobalBadges.map(badge => ({ + ...args, + ...badge, + })) + ); + } + if (donorBadges) { badges.unshift( ...donorBadges.map(badge => ({ diff --git a/src/equicordplugins/globalBadges/badgeComponent.tsx b/src/equicordplugins/globalBadges/badgeComponent.tsx deleted file mode 100644 index 19c8e8e1f..000000000 --- a/src/equicordplugins/globalBadges/badgeComponent.tsx +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Vencord, a Discord client mod - * Copyright (c) 2025 Vendicated and contributors - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -import { React, Tooltip, UserStore } from "@webpack/common"; -import { JSX } from "react"; - -import { openBadgeModal } from "./badgeModal"; -import { settings } from "./settings"; -import { BadgeCache } from "./types"; -import { cl, fetchBadges } from "./utils"; - -interface BadgeModalItem { - name: string; - rawName: string; -} - -export let badgeData; - -export const BadgeComponent = ({ name, img }: { name: string, img: string; }) => { - return ( - - {(tooltipProps: any) => ( - - )} - - ); -}; - -export 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: BadgeModalItem[] = []; - - 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 prefix = settings.store.showPrefix ? `(${mod})` : ""; - const suffix = settings.store.showSuffix ? `(${mod})` : ""; - const displayName = `${prefix} ${badge.tooltip} ${suffix}`; - - if (mod === "BadgeVault") { - badge.custom = true; - } - - globalBadges.push(); - badgeModal.push({ - name: displayName, - rawName: badge.tooltip, - ...badge - }); - }); - }); - badgeData = badgeModal; - - return ( -
openBadgeModal(UserStore.getUser(userId))} - > - {globalBadges} -
- ); -}; diff --git a/src/equicordplugins/globalBadges/badgeModal.tsx b/src/equicordplugins/globalBadges/badgeModal.tsx deleted file mode 100644 index 45c94b96c..000000000 --- a/src/equicordplugins/globalBadges/badgeModal.tsx +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Vencord, a Discord client mod - * Copyright (c) 2025 Vendicated and contributors - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -import { Button } from "@components/Button"; -import ErrorBoundary from "@components/ErrorBoundary"; -import { HeadingTertiary } from "@components/Heading"; -import { Paragraph } from "@components/Paragraph"; -import { openInviteModal } from "@utils/discord"; -import { ModalContent, ModalFooter, ModalHeader, ModalRoot, openModal } from "@utils/modal"; -import { User } from "@vencord/discord-types"; -import { React, Tooltip } from "@webpack/common"; - -import { badgeData } from "./badgeComponent"; -import { cl, INVITE_LINK } from "./utils"; - -export const BadgeModalComponent = ({ name, img }: { name: string, img: string; }) => { - return ( - <> - - {(tooltipProps: any) => ( - - )} - - - ); -}; - -export function openBadgeModal(user: User) { - const badgeDataElements = badgeData.map(badge => ( - - )); - - openModal(modalprops => ( - - - - - - {user.username} - - - - {badgeDataElements.length ? ( - <> - - {badgeDataElements.length} global badge - {badgeDataElements.length > 1 ? "s" : ""}. - -
- {badgeDataElements} -
- - ) : ( - - No global badges. - - )} -
- - - -
-
- )); -} diff --git a/src/equicordplugins/globalBadges/index.tsx b/src/equicordplugins/globalBadges/index.tsx index 9af75cd04..05c7cb7d5 100644 --- a/src/equicordplugins/globalBadges/index.tsx +++ b/src/equicordplugins/globalBadges/index.tsx @@ -6,23 +6,57 @@ import "./styles.css"; -import { addProfileBadge, BadgePosition, ProfileBadge, removeProfileBadge } from "@api/Badges"; +import { BadgePosition, ProfileBadge } from "@api/Badges"; +import { classNameFactory } from "@api/Styles"; import { Button } from "@components/Button"; +import { BadgeContextMenu } from "@plugins/_api/badges"; import { Devs, EquicordDevs } from "@utils/constants"; import { openInviteModal } from "@utils/discord"; import definePlugin from "@utils/types"; -import { React } from "@webpack/common"; +import { ContextMenuApi, React } from "@webpack/common"; -import { GlobalBadges } from "./badgeComponent"; import { settings } from "./settings"; -import { cl, fetchBadges, INVITE_LINK } from "./utils"; -const Badge: ProfileBadge = { - component: b => , - position: BadgePosition.START, - shouldShow: userInfo => !!Object.keys(fetchBadges(userInfo.userId) ?? {}).length, - key: "GlobalBadges" -}; +let GlobalBadges = {}; +let intervalId: any; +const INVITE_LINK = "kwHCJPxp8t"; +const cl = classNameFactory("vc-global-badges-"); + +async function loadBadges() { + const globalBadges = await fetch("https://badges.equicord.org/users", { cache: "no-cache" }) + .then(r => r.json()); + + const filteredUsers: Record = {}; + + for (const key in globalBadges.users) { + filteredUsers[key] = globalBadges.users[key].map(b => { + if (b.url) { + return { tooltip: b.label, badge: b.url }; + } + return b; + }).filter(b => { + const url = b.badge; + // fix this when creations updates it + return url && + url.startsWith("https://") && + !url.startsWith("https://cdn.discordapp.com") && + !url.startsWith("https://images.equicord.org") && + !(url.startsWith("https://badges.vencord.dev/badges") && !url.startsWith("https://badges.vencord.dev/badges/reviewdb")) && + // !(!settings.store.showAero && url.startsWith(":aero_icon:")) && + // !(!settings.store.showVelocity && url.startsWith("Velocity")) && + // !(!settings.store.showVelocity && url.startsWith("Official Velocity")) && + !(!settings.store.showCustom && url.startsWith("https://gb.obamabot.me")) && + !(!settings.store.showNekocord && url.startsWith("https://nekocord.dev")) && + !(!settings.store.showReviewDB && url.startsWith("https://badges.vencord.dev/badges/reviewdb")) && + !(!settings.store.showAliucord && url.startsWith("https://aliucord.com")) && + !(!settings.store.showRa1ncord && url.startsWith("https://codeberg.org/raincord/badges")) && + !(!settings.store.showEnmity && url.startsWith("https://raw.githubusercontent.com/enmity-mod/badges")); + + }); + } + + GlobalBadges = filteredUsers; +} export default definePlugin({ name: "GlobalBadges", @@ -40,6 +74,32 @@ export default definePlugin({ ), - start: () => addProfileBadge(Badge), - stop: () => removeProfileBadge(Badge), + async start() { + await loadBadges(); + clearInterval(intervalId); + intervalId = setInterval(loadBadges, 1000 * 60 * 30); + }, + async stop() { + clearInterval(intervalId); + }, + get GlobalBadges() { + return GlobalBadges; + }, + getGlobalBadges(userId: string) { + return GlobalBadges[userId]?.map(badge => ({ + iconSrc: badge.badge, + description: badge.tooltip, + position: BadgePosition.START, + props: { + style: { + borderRadius: "50%", + transform: "scale(0.9)" + } + }, + onContextMenu(event, badge) { + ContextMenuApi.openContextMenu(event, () => ); + }, + + } satisfies ProfileBadge)); + } }); diff --git a/src/equicordplugins/globalBadges/settings.ts b/src/equicordplugins/globalBadges/settings.ts index cfcbf3d1b..85e0db7f0 100644 --- a/src/equicordplugins/globalBadges/settings.ts +++ b/src/equicordplugins/globalBadges/settings.ts @@ -78,12 +78,6 @@ export const settings = definePluginSettings({ default: true, restartNeeded: false }, - showReplugged: { - type: OptionType.BOOLEAN, - description: "Show Replugged Badges", - default: true, - restartNeeded: false - }, apiUrl: { type: OptionType.STRING, description: "API to use", diff --git a/src/equicordplugins/globalBadges/styles.css b/src/equicordplugins/globalBadges/styles.css index 3b098133d..9e712cf11 100644 --- a/src/equicordplugins/globalBadges/styles.css +++ b/src/equicordplugins/globalBadges/styles.css @@ -1,61 +1,3 @@ -.vc-global-badges-badges { - align-items: center; - display: flex; - flex-wrap: nowrap; -} - -.vc-global-badges-badge { - width: 20px; - height: 20px; - gap: 1px; -} - -.vc-global-badges-modal-name { - text-transform: none; - flex-grow: 0; - background: var(--background-base-lowest); - border-radius: 0 9999px 9999px 0; - padding: 6px 0.8em 6px 0.5em; - font-size: 20px; - height: 20px; - position: relative; - text-wrap: nowrap; -} - -.vc-global-badges-modal-name::before { - content: ""; - display: block; - position: absolute; - height: 100%; - width: 32px; - background: var(--background-base-lowest); - z-index: -1; - left: -32px; - top: 0; - border-top-left-radius: 9999px; - border-bottom-left-radius: 9999px; -} - -.vc-global-badges-modal-avatar { - height: 48px; - width: 48px; - border-radius: 50%; -} - -.vc-global-badges-modal-description { - font-size: 16px; -} - -.vc-global-badges-modal-text { - margin-left: 8px; -} - -.vc-global-badges-modal-badge { - width: 50px; - height: 50px; - margin: 2px; -} - .vc-global-badges-settings-button { width: 100%; height: 50px; diff --git a/src/equicordplugins/globalBadges/types.ts b/src/equicordplugins/globalBadges/types.ts deleted file mode 100644 index fc06b9265..000000000 --- a/src/equicordplugins/globalBadges/types.ts +++ /dev/null @@ -1,16 +0,0 @@ -/* - * 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 deleted file mode 100644 index 49e348146..000000000 --- a/src/equicordplugins/globalBadges/utils.ts +++ /dev/null @@ -1,47 +0,0 @@ -/* - * 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 cache = new Map(); -const EXPIRES = 1000 * 60 * 15; - -export const cl = classNameFactory("vc-global-badges-"); -export const INVITE_LINK = "kwHCJPxp8t"; - -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(`${settings.store.apiUrl}${id}?seperated=true&capitalize=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; - } -}; diff --git a/src/equicordplugins/iRememberYou/components/ui.tsx b/src/equicordplugins/iRememberYou/components/ui.tsx index 27d530b75..0e3cb03d4 100644 --- a/src/equicordplugins/iRememberYou/components/ui.tsx +++ b/src/equicordplugins/iRememberYou/components/ui.tsx @@ -6,7 +6,7 @@ import { classNameFactory } from "@api/Styles"; import { BaseText } from "@components/BaseText"; -import { Flex } from "@components/Flex"; +import { HeadingPrimary } from "@components/Heading"; import { Paragraph } from "@components/Paragraph"; import { openUserProfile } from "@utils/discord"; import { Avatar, Clickable, React, TextInput, Tooltip, } from "@webpack/common"; @@ -44,11 +44,9 @@ function UsersCollectionRows({ usersCollection }: { usersCollection: Data["users .map(({ name, users }) => ( @@ -59,14 +57,14 @@ function UsersCollectionRows({ usersCollection }: { usersCollection: Data["users function UserRow({ user, allowOwner = true }: { user: IStorageUser, allowOwner?: boolean; }) { return ( - - - - openUserProfile(user.id)}> - - - - +
+
+ openUserProfile(user.id)}> + + + + +
{props => @@ -74,15 +72,14 @@ function UserRow({ user, allowOwner = true }: { user: IStorageUser, allowOwner?: } - - - - - - {user.id} - - - + + + {user.id} + + +
+
+
); } @@ -94,10 +91,10 @@ function SearchElement({ usersCollection }: { usersCollection: Data["usersCollec
{current && ( - +
{list.filter(user => user.tag.includes(current) || user.username.includes(current)) .map(user => )} - +
)}
); @@ -112,9 +109,9 @@ export function DataUI({ plugin, usersCollection }: { plugin: any; usersCollecti - +
- +
); } diff --git a/src/equicordplugins/iRememberYou/styles.css b/src/equicordplugins/iRememberYou/styles.css index 188f4218a..9eb1a6297 100644 --- a/src/equicordplugins/iRememberYou/styles.css +++ b/src/equicordplugins/iRememberYou/styles.css @@ -5,8 +5,15 @@ flex-direction: column; } +.vc-i-remember-you-header-name { + margin-top: 16px; +} + .vc-i-remember-you-header-btns { - gap: 8px; + display: grid; + grid-template-columns: repeat(2, minmax(0, 350px)); + gap: 10px; + margin-top: 8px; } .vc-i-remember-you-header { @@ -29,49 +36,38 @@ .vc-i-remember-you-user-avatar { cursor: pointer; - margin-right: 30px; + margin-right: 0; } .vc-i-remember-you-user-row { - margin: 0; - width: 100%; - flex-wrap: wrap; - align-items: center; + display: flex; + flex-direction: column; + gap: 6px; + padding: 4px; + align-items: flex-start; } .vc-i-remember-you-user-id { - height: min-content; + align-self: flex-start; opacity: 0.75; + height: min-content; } .vc-i-remember-you-user { - width: 500px; - gap: 250px; + display: flex; + flex-direction: row; align-items: center; - overflow-wrap: break-word; - margin-top: 5px; + gap: 8px; + width: 100%; + margin-top: 0; } .vc-i-remember-you-user-username { margin-top: 2px; } -.vc-i-remember-you-buttons { - margin-top: 10px; -} - -.vc-i-remember-you-buttons-save, -.vc-i-remember-you-buttons-cancel { - margin-left: 490px; - margin-top: 5px; - margin-bottom: 10px; -} - -.vc-i-remember-you-buttons-cancel { - margin-left: 12px; -} - -.vc-i-remember-you-buttons-reset { - cursor: pointer; - margin-left: 12px; +.vc-i-remember-you-user-tooltip { + display: flex; + flex-direction: column; + align-items: flex-start; } \ No newline at end of file diff --git a/src/plugins/_api/badges/index.tsx b/src/plugins/_api/badges/index.tsx index 873bf6705..354eae6d1 100644 --- a/src/plugins/_api/badges/index.tsx +++ b/src/plugins/_api/badges/index.tsx @@ -100,7 +100,7 @@ async function loadAllBadges(noCache = false) { let intervalId: any; -function BadgeContextMenu({ badge }: { badge: ProfileBadge & BadgeUserArgs; }) { +export function BadgeContextMenu({ badge }: { badge: ProfileBadge & BadgeUserArgs; }) { return (