Equicord/src/plugins/_api/badges/index.tsx

394 lines
17 KiB
TypeScript
Raw Normal View History

2022-11-11 22:50:09 +00:00
/*
* 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 <https://www.gnu.org/licenses/>.
*/
import "./fixBadgeOverflow.css";
2024-06-08 05:26:03 +02:00
import { _getBadges, BadgePosition, BadgeUserArgs, ProfileBadge } from "@api/Badges";
import DonateButton from "@components/DonateButton";
import ErrorBoundary from "@components/ErrorBoundary";
import { Flex } from "@components/Flex";
import { Heart } from "@components/Heart";
import { openContributorModal } from "@components/PluginSettings/ContributorModal";
import { Devs } from "@utils/constants";
2024-06-08 05:26:03 +02:00
import { Logger } from "@utils/Logger";
import { Margins } from "@utils/margins";
import { isEquicordPluginDev, isPluginDev, isSuncordPluginDev } from "@utils/misc";
import { closeModal, Modals, openModal } from "@utils/modal";
import definePlugin from "@utils/types";
2024-06-08 05:26:03 +02:00
import { Forms, Toasts, UserStore } from "@webpack/common";
2024-06-08 05:26:03 +02:00
import { User } from "discord-types/general";
2022-11-11 22:50:09 +00:00
2024-04-18 19:53:52 -04:00
const CONTRIBUTOR_BADGE = "https://vencord.dev/assets/favicon.png";
2024-06-01 15:37:46 -04:00
const EQUICORD_CONTRIBUTOR_BADGE = "https://i.imgur.com/rJDRtUB.png";
const SUNCORD_CONTRIBUTOR_BADGE = "https://raw.githubusercontent.com/verticalsync/Suncord/main/src/assets/icon.png";
2022-11-11 22:50:09 +00:00
const ContributorBadge: ProfileBadge = {
2024-04-18 19:53:52 -04:00
description: "Vencord Contributor",
2022-11-11 22:50:09 +00:00
image: CONTRIBUTOR_BADGE,
position: BadgePosition.START,
2024-06-08 05:26:03 +02:00
shouldShow: ({ userId }) => isPluginDev(userId),
onClick: (_, { userId }) => openContributorModal(UserStore.getUser(userId))
2022-11-11 22:50:09 +00:00
};
2024-04-18 19:53:52 -04:00
const EquicordContributorBadge: ProfileBadge = {
description: "Equicord Contributor",
image: EQUICORD_CONTRIBUTOR_BADGE,
position: BadgePosition.START,
2024-06-08 10:32:39 -04:00
shouldShow: ({ userId }) => isEquicordPluginDev(userId),
2024-06-10 17:00:32 -04:00
onClick: (_, { userId }) => openContributorModal(UserStore.getUser(userId))
2024-04-18 19:53:52 -04:00
};
const SuncordContributorBadge: ProfileBadge = {
description: "Suncord Contributor",
image: SUNCORD_CONTRIBUTOR_BADGE,
position: BadgePosition.START,
shouldShow: ({ userId }) => isSuncordPluginDev(userId),
onClick: (_, { userId }) => openContributorModal(UserStore.getUser(userId))
};
let DonorBadges = {} as Record<string, Array<Record<"tooltip" | "badge", string>>>;
2024-04-18 19:15:01 -04:00
let EquicordDonorBadges = {} as Record<string, Array<Record<"tooltip" | "badge", string>>>;
2024-06-06 13:48:23 -04:00
let SuncordDonorBadges = {} as Record<string, Array<Record<"tooltip" | "badge", string>>>;
2024-04-18 19:15:01 -04:00
async function loadBadges(url: string, noCache = false) {
2023-05-02 02:55:38 +02:00
const init = {} as RequestInit;
2024-04-18 19:15:01 -04:00
if (noCache) init.cache = "no-cache";
2023-05-02 02:55:38 +02:00
2024-04-18 19:15:01 -04:00
return await fetch(url, init).then(r => r.json());
}
2024-04-17 14:29:47 -04:00
2024-04-18 19:15:01 -04:00
async function loadAllBadges(noCache = false) {
const vencordBadges = await loadBadges("https://badges.vencord.dev/badges.json", noCache);
const equicordBadges = await loadBadges("https://raw.githubusercontent.com/Equicord/Ignore/main/badges.json", noCache);
2024-06-06 13:48:23 -04:00
const suncordBadges = await loadBadges("https://raw.githubusercontent.com/verticalsync/Suncord/main/src/assets/badges.json", noCache);
2024-04-17 14:29:47 -04:00
2024-04-18 19:15:01 -04:00
DonorBadges = vencordBadges;
EquicordDonorBadges = equicordBadges;
2024-06-06 13:48:23 -04:00
SuncordDonorBadges = suncordBadges;
2023-05-02 02:55:38 +02:00
}
2024-04-18 19:15:01 -04:00
2022-11-11 22:50:09 +00:00
export default definePlugin({
name: "BadgeAPI",
description: "API to add badges to users.",
2023-04-05 22:45:14 +02:00
authors: [Devs.Megu, Devs.Ven, Devs.TheSun],
2022-11-11 22:50:09 +00:00
required: true,
patches: [
/* Patch the badge list component on user profiles */
{
2024-04-24 05:27:14 +02:00
find: 'id:"premium",',
replacement: [
2023-04-18 02:47:48 +02:00
{
2023-07-02 01:17:02 +02:00
match: /&&(\i)\.push\(\{id:"premium".+?\}\);/,
2024-06-08 05:26:03 +02:00
replace: "$&$1.unshift(...$self.getBadges(arguments[0]));",
2023-04-18 02:47:48 +02:00
},
{
2023-04-13 21:04:19 +02:00
// alt: "", aria-hidden: false, src: originalSrc
2023-10-25 15:24:06 +02:00
match: /alt:" ","aria-hidden":!0,src:(?=(\i)\.src)/,
2023-04-13 21:04:19 +02:00
// ...badge.props, ..., src: badge.image ?? ...
replace: "...$1.props,$& $1.image??"
},
2023-10-25 15:24:06 +02:00
// replace their component with ours if applicable
{
2024-05-03 22:18:31 +02:00
match: /(?<=text:(\i)\.description,spacing:12,.{0,50})children:/,
2023-10-25 15:24:06 +02:00
replace: "children:$1.component ? () => $self.renderBadgeComponent($1) :"
2023-04-13 21:04:19 +02:00
},
2023-10-25 15:24:06 +02:00
// conditionally override their onClick with badge.onClick if it exists
2023-04-13 21:04:19 +02:00
{
2023-10-25 15:24:06 +02:00
match: /href:(\i)\.link/,
2024-06-08 05:26:03 +02:00
replace: "...($1.onClick && { onClick: vcE => $1.onClick(vcE, $1) }),$&"
}
]
2024-06-08 05:26:03 +02:00
},
/* new profiles */
{
find: ".PANEL]:14",
replacement: {
match: /(?<=(\i)=\(0,\i\.\i\)\(\i\);)return 0===\i.length\?/,
replace: "$1.unshift(...$self.getBadges(arguments[0].displayProfile));$&"
2024-06-08 05:26:03 +02:00
}
},
{
find: ".description,delay:",
replacement: [
{
// alt: "", aria-hidden: false, src: originalSrc
match: /alt:" ","aria-hidden":!0,src:(?=.{0,20}(\i)\.icon)/,
// ...badge.props, ..., src: badge.image ?? ...
replace: "...$1.props,$& $1.image??"
},
{
match: /(?<=text:(\i)\.description,.{0,50})children:/,
2024-06-08 05:26:03 +02:00
replace: "children:$1.component ? $self.renderBadgeComponent({ ...$1 }) :"
2024-06-08 05:26:03 +02:00
},
// conditionally override their onClick with badge.onClick if it exists
{
match: /href:(\i)\.link/,
2024-06-08 05:26:03 +02:00
replace: "...($1.onClick && { onClick: vcE => $1.onClick(vcE, $1) }),$&"
2024-06-08 05:26:03 +02:00
}
]
2022-11-11 22:50:09 +00:00
}
],
2023-05-02 02:55:38 +02:00
toolboxActions: {
async "Refetch Badges"() {
2024-04-18 19:15:01 -04:00
await loadAllBadges(true);
2023-05-02 02:55:38 +02:00
Toasts.show({
id: Toasts.genId(),
message: "Successfully refetched badges!",
type: Toasts.Type.SUCCESS
});
}
},
async start() {
Vencord.Api.Badges.addBadge(ContributorBadge);
2024-04-18 19:53:52 -04:00
Vencord.Api.Badges.addBadge(EquicordContributorBadge);
Vencord.Api.Badges.addBadge(SuncordContributorBadge);
2024-04-18 19:15:01 -04:00
await loadAllBadges();
2023-05-02 02:55:38 +02:00
},
2024-06-08 05:26:03 +02:00
getBadges(props: { userId: string; user?: User; guildId: string; }) {
2024-06-26 18:09:21 +02:00
if (!props) return [];
2024-06-08 05:26:03 +02:00
try {
props.userId ??= props.user?.id!;
return _getBadges(props);
} catch (e) {
new Logger("BadgeAPI#hasBadges").error(e);
return [];
}
},
2023-04-05 22:45:14 +02:00
renderBadgeComponent: ErrorBoundary.wrap((badge: ProfileBadge & BadgeUserArgs) => {
const Component = badge.component!;
return <Component {...badge} />;
}, { noop: true }),
getDonorBadges(userId: string) {
return DonorBadges[userId]?.map(badge => ({
image: badge.badge,
description: badge.tooltip,
position: BadgePosition.START,
props: {
style: {
borderRadius: "50%",
transform: "scale(0.9)" // The image is a bit too big compared to default badges
}
},
onClick() {
const modalKey = openModal(props => (
<ErrorBoundary noop onError={() => {
closeModal(modalKey);
2024-04-17 14:32:29 -04:00
VencordNative.native.openExternal("https://github.com/sponsors/Vendicated");
}}>
<Modals.ModalRoot {...props}>
<Modals.ModalHeader>
<Flex style={{ width: "100%", justifyContent: "center" }}>
<Forms.FormTitle
tag="h2"
style={{
width: "100%",
textAlign: "center",
margin: 0
}}
>
<Heart />
2024-04-18 19:22:56 -04:00
Vencord Donor
</Forms.FormTitle>
</Flex>
</Modals.ModalHeader>
<Modals.ModalContent>
<Flex>
<img
role="presentation"
src="https://cdn.discordapp.com/emojis/1026533070955872337.png"
alt=""
style={{ margin: "auto" }}
/>
<img
role="presentation"
src="https://cdn.discordapp.com/emojis/1026533090627174460.png"
alt=""
style={{ margin: "auto" }}
/>
</Flex>
<div style={{ padding: "1em" }}>
<Forms.FormText>
2024-04-18 19:22:56 -04:00
This Badge is a special perk for Vencord Donors
</Forms.FormText>
<Forms.FormText className={Margins.top20}>
2024-04-18 19:22:56 -04:00
Please consider supporting the development of Vencord by becoming a donor. It would mean a lot!
</Forms.FormText>
</div>
</Modals.ModalContent>
<Modals.ModalFooter>
<Flex style={{ width: "100%", justifyContent: "center" }}>
<DonateButton />
</Flex>
</Modals.ModalFooter>
</Modals.ModalRoot>
</ErrorBoundary>
));
},
}));
2024-04-18 19:15:01 -04:00
},
getEquicordDonorBadges(userId: string) {
return EquicordDonorBadges[userId]?.map(badge => ({
image: badge.badge,
description: badge.tooltip,
position: BadgePosition.START,
props: {
style: {
borderRadius: "50%",
transform: "scale(0.9)" // The image is a bit too big compared to default badges
}
},
onClick() {
const modalKey = openModal(props => (
<ErrorBoundary noop onError={() => {
closeModal(modalKey);
// Will get my own in the future
VencordNative.native.openExternal("https://github.com/sponsors/Vendicated");
}}>
<Modals.ModalRoot {...props}>
<Modals.ModalHeader>
<Flex style={{ width: "100%", justifyContent: "center" }}>
<Forms.FormTitle
tag="h2"
style={{
width: "100%",
textAlign: "center",
margin: 0
}}
>
<Heart />
Equicord Donor
</Forms.FormTitle>
</Flex>
</Modals.ModalHeader>
<Modals.ModalContent>
<Flex>
<img
role="presentation"
src="https://cdn.discordapp.com/emojis/1026533070955872337.png"
alt=""
style={{ margin: "auto" }}
/>
<img
role="presentation"
src="https://cdn.discordapp.com/emojis/1026533090627174460.png"
alt=""
style={{ margin: "auto" }}
/>
</Flex>
<div style={{ padding: "1em" }}>
<Forms.FormText>
This Badge is a special perk for Equicord Donors
</Forms.FormText>
<Forms.FormText className={Margins.top20}>
Please consider supporting the development of Equicord by becoming a donor. It would mean a lot!!
</Forms.FormText>
</div>
</Modals.ModalContent>
<Modals.ModalFooter>
<Flex style={{ width: "100%", justifyContent: "center" }}>
<DonateButton />
</Flex>
</Modals.ModalFooter>
</Modals.ModalRoot>
</ErrorBoundary>
));
},
}));
2024-06-06 13:48:23 -04:00
},
getSuncordDonorBadges(userId: string) {
return SuncordDonorBadges[userId]?.map(badge => ({
image: badge.badge,
description: badge.tooltip,
position: BadgePosition.START,
props: {
style: {
borderRadius: "50%",
transform: "scale(0.9)" // The image is a bit too big compared to default badges
}
},
onClick() {
const modalKey = openModal(props => (
<ErrorBoundary noop onError={() => {
closeModal(modalKey);
VencordNative.native.openExternal("https://github.com/sponsors/verticalsync");
}}>
<Modals.ModalRoot {...props}>
<Modals.ModalHeader>
<Flex style={{ width: "100%", justifyContent: "center" }}>
<Forms.FormTitle
tag="h2"
style={{
width: "100%",
textAlign: "center",
margin: 0
}}
>
<Heart />
Suncord Donor
</Forms.FormTitle>
</Flex>
</Modals.ModalHeader>
<Modals.ModalContent>
<Flex>
<img
role="presentation"
src="https://cdn.discordapp.com/emojis/1026533070955872337.png"
alt=""
style={{ margin: "auto" }}
/>
<img
role="presentation"
src="https://cdn.discordapp.com/emojis/1026533090627174460.png"
alt=""
style={{ margin: "auto" }}
/>
</Flex>
<div style={{ padding: "1em" }}>
<Forms.FormText>
This Badge is a special perk for Suncord Donors
</Forms.FormText>
<Forms.FormText className={Margins.top20}>
Please consider supporting the development of Suncord by becoming a donor. It would mean a lot!!
</Forms.FormText>
</div>
</Modals.ModalContent>
<Modals.ModalFooter>
<Flex style={{ width: "100%", justifyContent: "center" }}>
<DonateButton />
</Flex>
</Modals.ModalFooter>
</Modals.ModalRoot>
</ErrorBoundary>
));
},
}));
}
2022-11-11 22:50:09 +00:00
});