Plugin
MentionAvatars
Shows user avatars and role icons inside mentions
1
/*2
* FiveCord — a Discord client mod3
* Copyright (c) 2025 FiveCord4
* SPDX-License-Identifier: GPL-3.0-or-later5
*/6
7
import "./styles.css";8
9
import { definePluginSettings } from "@api/Settings";10
import ErrorBoundary from "@components/ErrorBoundary";11
import { Devs } from "@utils/constants";12
import definePlugin, { OptionType } from "@utils/types";13
import { User } from "@vencord/discord-types";14
import { GuildRoleStore, SelectedGuildStore, useState } from "@webpack/common";15
16
const settings = definePluginSettings({17
showAtSymbol: {18
type: OptionType.BOOLEAN,19
displayName: "Show @ Symbol",20
description: "Whether the the @ symbol should be displayed on user mentions",21
default: true22
}23
});24
25
function DefaultRoleIcon() {26
return (27
<svg28
className="vc-mentionAvatars-icon vc-mentionAvatars-role-icon"29
xmlns="http:class="ts-cmt">//www.w3.org/2000/svg"30
viewBox="0 0 24 24"31
fill="currentColor"32
>33
<path34
d="M14 8.00598C14 10.211 12.206 12.006 10 12.006C7.795 12.006 6 10.211 6 8.00598C6 5.80098 7.794 4.00598 10 4.00598C12.206 4.00598 14 5.80098 14 8.00598ZM2 19.006C2 15.473 5.29 13.006 10 13.006C14.711 13.006 18 15.473 18 19.006V20.006H2V19.006Z"35
/>36
<path37
d="M20.0001 20.006H22.0001V19.006C22.0001 16.4433 20.2697 14.4415 17.5213 13.5352C19.0621 14.9127 20.0001 16.8059 20.0001 19.006V20.006Z"38
/>39
<path40
d="M14.8834 11.9077C16.6657 11.5044 18.0001 9.9077 18.0001 8.00598C18.0001 5.96916 16.4693 4.28218 14.4971 4.0367C15.4322 5.09511 16.0001 6.48524 16.0001 8.00598C16.0001 9.44888 15.4889 10.7742 14.6378 11.8102C14.7203 11.8418 14.8022 11.8743 14.8834 11.9077Z"41
/>42
</svg>43
);44
}45
46
export default definePlugin({47
name: "MentionAvatars",48
description: "Shows user avatars and role icons inside mentions",49
tags: ["Appearance", "Customisation"],50
authors: [Devs.Ven, Devs.SerStars],51
52
patches: [{53
find: ".USER_MENTION)",54
replacement: {55
match: /children:`@\$\{(\i\?\?\i)\}`(?<=\.useName\((\i)\).+?)/,56
replace: "children:$self.renderUsername({username:$1,user:$2})"57
}58
},59
{60
find: ".ROLE_MENTION)",61
replacement: {62
match: /children:\[\i&&.{0,100}className:\i.\i,background:!1,.{0,50}?,\i(?=\])/,63
replace: "$&,$self.renderRoleIcon(arguments[0])"64
}65
}],66
67
settings,68
69
renderUsername: ErrorBoundary.wrap((props: { user: User, username: string; }) => {70
const { user, username } = props;71
const [isHovering, setIsHovering] = useState(false);72
73
if (!user) return <>{getUsernameString(username)}</>;74
75
return (76
<span77
onMouseEnter={() => setIsHovering(true)}78
onMouseLeave={() => setIsHovering(false)}79
>80
<img81
src={user.getAvatarURL(SelectedGuildStore.getGuildId(), 16, isHovering)}82
className="vc-mentionAvatars-icon"83
style={{ borderRadius: "50%" }}84
/>85
{getUsernameString(username)}86
</span>87
);88
}, { noop: true }),89
90
renderRoleIcon: ErrorBoundary.wrap(({ roleId, guildId }: { roleId: string, guildId: string; }) => {91
// Discord uses Role Mentions for uncached users because .... idk92
if (!roleId) return null;93
94
const role = GuildRoleStore.getRole(guildId, roleId);95
96
if (!role?.icon) return <DefaultRoleIcon />;97
98
return (99
<img100
className="vc-mentionAvatars-icon vc-mentionAvatars-role-icon"101
src={`${location.protocol}class="ts-cmt">//${window.GLOBAL_ENV.CDN_HOST}/role-icons/${roleId}/${role.icon}.webp?size=24&quality=lossless`}102
/>103
);104
}, { noop: true }),105
});106
107
function getUsernameString(username: string) {108
return settings.store.showAtSymbol109
? `@${username}`110
: username;111
}112