Plugin

MentionAvatars

Shows user avatars and role icons inside mentions

Appearance Customisation
index.tsx
Download

Source

src/plugins/mentionAvatars/index.tsx
1/*
2 * FiveCord — a Discord client mod
3 * Copyright (c) 2025 FiveCord
4 * SPDX-License-Identifier: GPL-3.0-or-later
5 */
6
7import "./styles.css";
8
9import { definePluginSettings } from "@api/Settings";
10import ErrorBoundary from "@components/ErrorBoundary";
11import { Devs } from "@utils/constants";
12import definePlugin, { OptionType } from "@utils/types";
13import { User } from "@vencord/discord-types";
14import { GuildRoleStore, SelectedGuildStore, useState } from "@webpack/common";
15
16const 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: true
22 }
23});
24
25function DefaultRoleIcon() {
26 return (
27 <svg
28 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 <path
34 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 <path
37 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 <path
40 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
46export 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 <span
77 onMouseEnter={() => setIsHovering(true)}
78 onMouseLeave={() => setIsHovering(false)}
79 >
80 <img
81 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 .... idk
92 if (!roleId) return null;
93
94 const role = GuildRoleStore.getRole(guildId, roleId);
95
96 if (!role?.icon) return <DefaultRoleIcon />;
97
98 return (
99 <img
100 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
107function getUsernameString(username: string) {
108 return settings.store.showAtSymbol
109 ? `@${username}`
110 : username;
111}
112