Plugin

ThemeAttributes

Adds data attributes to various elements for theming purposes

Appearance Customisation
index.ts
Download

Source

src/plugins/themeAttributes/index.ts
1/*
2 * FiveCord — a Discord client mod
3 * Copyright (c) 2025 FiveCord
4 * SPDX-License-Identifier: GPL-3.0-or-later
5 */
6
7import { Devs } from "@utils/constants";
8import { Logger } from "@utils/Logger";
9import definePlugin from "@utils/types";
10import { Message } from "@vencord/discord-types";
11import { UserStore } from "@webpack/common";
12
13
14export default definePlugin({
15 name: "ThemeAttributes",
16 description: "Adds data attributes to various elements for theming purposes",
17 tags: ["Appearance", "Customisation"],
18 authors: [Devs.Ven, Devs.Board],
19
20 patches: [
21 // Add data-tab-id to all tab bar items
22 // This for examples applies to the User and Server settings sidebars
23 {
24 find: ".tabBarRef",
25 replacement: {
26 match: /style:this\.getStyle\(\),role:\i/,
27 replace: "$&,'data-tab-id':this?.props?.id"
28 }
29 },
30
31 // Add data-author-id and data-is-self to all messages
32 {
33 find: "Message must not be a thread starter message",
34 replacement: {
35 match: /"aria-setsize":-1,(?=.{0,150}?#{intl::MESSAGE_A11Y_ROLE_DESCRIPTION})/,
36 replace: "...$self.getMessageProps(arguments[0]),$&"
37 }
38 },
39
40 // add --avatar-url-<resolution> css variable to avatar img elements
41 // popout profiles
42 {
43 find: "#{intl::LABEL_WITH_ONLINE_STATUS}",
44 replacement: [
45 {
46 match: /src:(\i)\?\?void 0.{1,50}"aria-hidden":!0/,
47 replace: "$&,style:$self.getAvatarStyles($1)"
48 }
49 ]
50 },
51 // chat avatars
52 {
53 find: "showCommunicationDisabledStyles",
54 replacement: {
55 match: /src:(\i),"aria-hidden":!0/,
56 replace: "$&,style:$self.getAvatarStyles($1)"
57 }
58 }
59 ],
60
61 getAvatarStyles(src: string | null) {
62 if (typeof src !== "string" || src.startsWith("data:")) return {};
63
64 return Object.fromEntries(
65 [128, 256, 512, 1024, 2048, 4096].map(size => [
66 `--avatar-url-${size}`,
67 `url(${src.replace(/\d+$/, String(size))})`
68 ])
69 );
70 },
71
72 getMessageProps(props: { message: Message; }) {
73 try {
74 const author = props.message?.author;
75 const authorId = author?.id;
76 return {
77 "data-author-id": authorId,
78 "data-author-username": author?.username,
79 "data-is-self": authorId && authorId === UserStore.getCurrentUser()?.id,
80 };
81 } catch (e) {
82 new Logger("ThemeAttributes").error("Error in getMessageProps", e);
83 return {};
84 }
85 }
86});
87