115 lines
4.2 KiB
TypeScript
115 lines
4.2 KiB
TypeScript
/*
|
|
* Vencord, a Discord client mod
|
|
* Copyright (c) 2024 Vendicated and contributors
|
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
|
*/
|
|
|
|
import "./style.css";
|
|
|
|
import { InfoIcon } from "@components/Icons";
|
|
import { Devs, EquicordDevs } from "@utils/constants";
|
|
import { openUserProfile } from "@utils/discord";
|
|
import { classes } from "@utils/misc";
|
|
import { t } from "@utils/translation";
|
|
import definePlugin, { StartAt } from "@utils/types";
|
|
import { Guild } from "@vencord/discord-types";
|
|
import { findByPropsLazy, findCssClassesLazy } from "@webpack";
|
|
import { Parser, Tooltip, UserStore } from "@webpack/common";
|
|
|
|
const AvatarStyles = findCssClassesLazy("avatar", "zalgo", "clickable");
|
|
const GuildManager = findByPropsLazy("joinGuild");
|
|
|
|
interface User {
|
|
id: string;
|
|
avatar: string;
|
|
global_name: string;
|
|
username: string;
|
|
}
|
|
|
|
function lurk(id: string) {
|
|
GuildManager.joinGuild(id, { lurker: true })
|
|
.then(() => { GuildManager.transitionToGuildSync(id); })
|
|
.catch(() => { throw new Error("Guild is not lurkable"); });
|
|
}
|
|
|
|
export default definePlugin({
|
|
name: "BetterInvites",
|
|
description: t("equicord.betterInvites.description"),
|
|
tags: ["Appearance", "Customisation", "Chat", "Servers"],
|
|
authors: [EquicordDevs.iamme, Devs.thororen],
|
|
patches: [
|
|
{
|
|
find: "#{intl::xdCLeM::raw}",
|
|
replacement: [
|
|
{
|
|
match: /profile:\i\}\),.{0,15}profile:\i/,
|
|
replace: "$&,invite:arguments[0].invite"
|
|
}
|
|
]
|
|
},
|
|
{
|
|
find: "isBannerVisible:!1})},",
|
|
replacement: [
|
|
{
|
|
// make the button clickable
|
|
match: /children:(\i)\.name\}\)\}\)\}\)/,
|
|
replace: "onClick:$self.Lurkable($1),$&"
|
|
},
|
|
{
|
|
// tip gets inserted in the name container, header gets inserted beside it
|
|
match: /(:(\i),disableGuildNameClick:.{0,20}\}\),\i)(\]\}\))/,
|
|
replace: "$1,$self.RenderTip(arguments[0].invite?.expires_at)$3,$self.Header(arguments[0].invite?.inviter,$2.name)"
|
|
}
|
|
]
|
|
},
|
|
],
|
|
RenderTip(expires_at: string) {
|
|
if (!expires_at) return null;
|
|
const timestamp = <>{Parser.parse(`<t:${Math.round(new Date(expires_at).getTime() / 1000)}:R>`)}</>;
|
|
const tooltipText = (
|
|
<>
|
|
{t("betterInvites.ui.expireTooltip", {
|
|
expiry: expires_at ? <>{t("equicord.betterInvites.ui.expireWill")} {timestamp}</> : <>{t("equicord.betterInvites.ui.notExpire")}</>
|
|
})}
|
|
</>
|
|
);
|
|
|
|
return (
|
|
<Tooltip text={tooltipText}>
|
|
{({ onMouseEnter, onMouseLeave }) => (
|
|
<div
|
|
className="vc-bi-tooltip"
|
|
onMouseEnter={onMouseEnter}
|
|
onMouseLeave={onMouseLeave}
|
|
>
|
|
<InfoIcon className="vc-bi-tooltip-icon" />
|
|
</div>
|
|
)}
|
|
</Tooltip>
|
|
);
|
|
},
|
|
Header(inviter: User | undefined, guildName: string) {
|
|
const userId = UserStore.getCurrentUser().id;
|
|
if (!inviter || userId === inviter.id) return null;
|
|
return (
|
|
<div className="vc-bi-header-inner">
|
|
<img
|
|
alt=""
|
|
className={classes(AvatarStyles.avatar, AvatarStyles.clickable) + " vc-bi-inviter-avatar"}
|
|
onClick={() => openUserProfile(inviter.id)}
|
|
src={inviter.avatar
|
|
? `https://cdn.discordapp.com/avatars/${inviter.id}/${inviter.avatar}.webp?size=80`
|
|
: "/assets/1f0bfc0865d324c2587920a7d80c609b.png?size=128"}
|
|
/>
|
|
<div className="vc-bi-header-text">
|
|
{t("betterInvites.ui.invitedYouTo", { inviter: inviter.global_name || inviter.username, guild: guildName })}
|
|
</div>
|
|
</div>
|
|
);
|
|
},
|
|
Lurkable: (guild?: Guild) => {
|
|
if (!guild) return null;
|
|
return new Set(guild.features).has("DISCOVERABLE") ? () => lurk(guild.id) : null;
|
|
},
|
|
startAt: StartAt.WebpackReady
|
|
});
|