Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Utility classes #573

Open
wants to merge 12 commits into
base: v4.9.0
Choose a base branch
from
122 changes: 122 additions & 0 deletions src/renderer/coremods/utilityClasses/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
import { Injector } from "@replugged";
import { getByProps, getByStoreName } from "src/renderer/modules/webpack";
import { users } from "@common";
import type React from "react";
import type { Store } from "src/renderer/modules/common/flux";
import type { Message } from "discord-types/general";

const inject = new Injector();
const html = document.documentElement;

interface TabBarItemProps {
id: string;
"aria-controls"?: string;
}

interface TabBarItemType extends React.Component<TabBarItemProps> {
render(): React.ReactElement<TabBarItemProps>;
}

// Re-adds the tab bar item's ID as an always-present attribute
function tabBarItemId(): void {
const TabBarModule = getByProps<{ TabBar: { Item: { prototype: TabBarItemType } } }>("TabBar");
if (!TabBarModule) {
throw new Error("Failed to find TabBar module!");
}

inject.after(
TabBarModule.TabBar.Item.prototype,
"render",
function (this: TabBarItemType, _, res) {
if (typeof this.props.id === "string") {
res.props["aria-controls"] = `${this.props.id.replace(/\s+/g, "-").toLowerCase()}-tab`;
}
return res;
},
);
}

interface ClientThemesBackgroundStore extends Store {
gradientPreset: { id: number } | undefined; // undefined when no nitro theme is selected
}
type ThemeIDMap = Record<string, number> & Record<number, string>;

function onNitroThemeChange(store: ClientThemesBackgroundStore, ThemeIDMap: ThemeIDMap): void {
if (!store.gradientPreset) {
html.removeAttribute("data-nitro-theme");
} else {
const theme = ThemeIDMap[store.gradientPreset.id];
html.setAttribute("data-nitro-theme", theme);
}
}

// Adds the currently active nitro theme as a class on the html element
function nitroThemeClass(): void {
const ClientThemesBackgroundStore = getByStoreName<ClientThemesBackgroundStore>(
"ClientThemesBackgroundStore",
);
if (!ClientThemesBackgroundStore) {
throw new Error("Failed to find ClientThemesBackgroundStore!");
}
const ThemeIDMap = getByProps<ThemeIDMap>("MINT_APPLE");
if (!ThemeIDMap) {
throw new Error("Failed to find ThemeIDs module!");
}

// update theme attribute when theme changes
ClientThemesBackgroundStore.addChangeListener(() => {
onNitroThemeChange(ClientThemesBackgroundStore, ThemeIDMap);
});
onNitroThemeChange(ClientThemesBackgroundStore, ThemeIDMap);
}

function messageDataAttributes(): void {
const Message = getByProps<{
default: { type: (msg: { message: Message }) => React.ReactElement };
getElementFromMessage: unknown;
}>("getElementFromMessage");

if (!Message) {
throw new Error("Failed to find Message module!");
}

inject.after(Message.default, "type", ([{ message }], res) => {
const props = res.props?.children?.props?.children?.props;
if (!props) return;
props["data-is-author-self"] = message.author.id === users.getCurrentUser().id;
props["data-is-author-bot"] = message.author.bot;
// webhooks are also considered bots
if (message.author.bot) {
props["data-is-author-webhook"] = Boolean(message.webhookId);
}
props["data-author-id"] = message.author.id;
props["data-message-type"] = message.type; // raw enum value, seems consistent enough to be useful
if (message.blocked) props["data-is-blocked"] = "true";
return res;
});
}

function addHtmlClasses(): void {
if (!html.classList.contains("replugged")) {
html.classList.add("replugged");
}
}

let observer: MutationObserver;

export function start(): void {
tabBarItemId();
nitroThemeClass();
messageDataAttributes();

// generic stuff
observer = new MutationObserver(addHtmlClasses);
observer.observe(html, { attributeFilter: ["class"] });
}

export function stop(): void {
inject.uninjectAll();
Penguin-Spy marked this conversation as resolved.
Show resolved Hide resolved
observer.disconnect();
html.classList.remove("replugged");
html.removeAttribute("data-nitro-theme");
}
2 changes: 2 additions & 0 deletions src/renderer/managers/coremods.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ export namespace coremods {
export let watcher: Coremod;
export let commands: Coremod;
export let welcome: Coremod;
export let utilityClasses: Coremod;
}

export async function start(name: keyof typeof coremods): Promise<void> {
Expand All @@ -59,6 +60,7 @@ export async function startAll(): Promise<void> {
coremods.watcher = await import("../coremods/watcher");
coremods.commands = await import("../coremods/commands");
coremods.welcome = await import("../coremods/welcome");
coremods.utilityClasses = await import("../coremods/utilityClasses");

await Promise.all(
Object.entries(coremods).map(async ([name, mod]) => {
Expand Down
Loading