mirror of
https://github.com/Equicord/Equicord.git
synced 2025-02-24 00:59:09 -05:00
Add customUserColors (#150)
* add preferFriends to showMeYourName * Add customUserColors * pressing enter closes modal * please update your discord types package * sowwy.. * Do A Settings Check For Typing Tweaks * Do a proper import on rolecoloreverywhere --------- Co-authored-by: thororen <78185467+thororen1234@users.noreply.github.com>
This commit is contained in:
parent
f385879b4b
commit
7ca3bbb8e6
5 changed files with 244 additions and 3 deletions
95
src/equicordplugins/customUserColors/SetColorModal.tsx
Normal file
95
src/equicordplugins/customUserColors/SetColorModal.tsx
Normal file
|
@ -0,0 +1,95 @@
|
|||
/*
|
||||
* Vencord, a Discord client mod
|
||||
* Copyright (c) 2025 Vendicated and contributors
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import { set } from "@api/DataStore";
|
||||
import { classNameFactory } from "@api/Styles";
|
||||
import { Margins } from "@utils/margins";
|
||||
import { ModalCloseButton, ModalContent, ModalFooter, ModalHeader, ModalProps, ModalRoot } from "@utils/modal";
|
||||
import { findComponentByCodeLazy } from "@webpack";
|
||||
import { Button, Forms, useState } from "@webpack/common";
|
||||
|
||||
import { colors, DATASTORE_KEY } from "./index";
|
||||
|
||||
interface ColorPickerProps {
|
||||
color: number;
|
||||
showEyeDropper?: boolean;
|
||||
suggestedColors?: string[];
|
||||
onChange(value: number | null): void;
|
||||
}
|
||||
const ColorPicker = findComponentByCodeLazy<ColorPickerProps>("#{intl::USER_SETTINGS_PROFILE_COLOR_SELECT_COLOR}", ".BACKGROUND_PRIMARY)");
|
||||
|
||||
const cl = classNameFactory("vc-customColors-");
|
||||
|
||||
export function SetColorModal({ userId, modalProps }: { userId: string, modalProps: ModalProps; }) {
|
||||
|
||||
const userColor = colors[userId];
|
||||
|
||||
const initialColor = parseInt(colors[userId], 16) || 372735;
|
||||
// color picker default to current color set for user (if null it's 0x05afff :3 )
|
||||
|
||||
const [colorPickerColor, setColorPickerColor] = useState(initialColor);
|
||||
// hex color code as an int (NOT rgb 0-255)
|
||||
|
||||
|
||||
function setUserColor(color: number) {
|
||||
setColorPickerColor(color);
|
||||
}
|
||||
|
||||
function handleKey(e: KeyboardEvent) {
|
||||
if (e.key === "Enter")
|
||||
saveUserColor();
|
||||
}
|
||||
|
||||
async function saveUserColor() {
|
||||
colors[userId] = colorPickerColor.toString(16).padStart(6, "0");
|
||||
await set(DATASTORE_KEY, colors);
|
||||
modalProps.onClose();
|
||||
}
|
||||
|
||||
async function deleteUserColor() {
|
||||
delete colors[userId];
|
||||
await set(DATASTORE_KEY, colors);
|
||||
modalProps.onClose();
|
||||
}
|
||||
|
||||
return (
|
||||
<ModalRoot {...modalProps}>
|
||||
<ModalHeader className={cl("modal-header")}>
|
||||
<Forms.FormTitle tag="h2">
|
||||
Custom Color
|
||||
</Forms.FormTitle>
|
||||
<ModalCloseButton onClick={modalProps.onClose} />
|
||||
</ModalHeader>
|
||||
<ModalContent className={cl("modal-content")} onKeyDown={handleKey}>
|
||||
<section className={Margins.bottom16}>
|
||||
<Forms.FormTitle tag="h3">
|
||||
Pick a color
|
||||
</Forms.FormTitle>
|
||||
<ColorPicker
|
||||
color={colorPickerColor}
|
||||
onChange={setUserColor}
|
||||
showEyeDropper={false}
|
||||
/>
|
||||
</section>
|
||||
</ModalContent>
|
||||
|
||||
<ModalFooter className={cl("modal-footer")}>
|
||||
<Button
|
||||
color={Button.Colors.RED}
|
||||
onClick={deleteUserColor}
|
||||
>
|
||||
Delete Entry
|
||||
</Button>
|
||||
<Button
|
||||
color={Button.Colors.BRAND}
|
||||
onClick={saveUserColor}
|
||||
>
|
||||
Save
|
||||
</Button>
|
||||
</ModalFooter>
|
||||
</ModalRoot>
|
||||
);
|
||||
}
|
119
src/equicordplugins/customUserColors/index.tsx
Normal file
119
src/equicordplugins/customUserColors/index.tsx
Normal file
|
@ -0,0 +1,119 @@
|
|||
/*
|
||||
* Vencord, a Discord client mod
|
||||
* Copyright (c) 2025 Vendicated and contributors
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import "./styles.css";
|
||||
|
||||
import { NavContextMenuPatchCallback } from "@api/ContextMenu";
|
||||
import { get } from "@api/DataStore";
|
||||
import { definePluginSettings, Settings } from "@api/Settings";
|
||||
import { EquicordDevs } from "@utils/constants";
|
||||
import { openModal } from "@utils/modal";
|
||||
import definePlugin, { OptionType } from "@utils/types";
|
||||
import { extractAndLoadChunksLazy } from "@webpack";
|
||||
import { Menu, UserStore } from "@webpack/common";
|
||||
import { User } from "discord-types/general";
|
||||
|
||||
import { SetColorModal } from "./SetColorModal";
|
||||
|
||||
export const DATASTORE_KEY = "equicord-customcolors";
|
||||
export let colors: Record<string, string> = {};
|
||||
(async () => {
|
||||
colors = await get<Record<string, string>>(DATASTORE_KEY) || {};
|
||||
})();
|
||||
|
||||
const requireSettingsMenu = extractAndLoadChunksLazy(['name:"UserSettings"'], /createPromise:.{0,20}(\i\.\i\("?.+?"?\).*?).then\(\i\.bind\(\i,"?(.+?)"?\)\).{0,50}"UserSettings"/);
|
||||
// needed for color picker to be available without opening settings (ty pindms!!)
|
||||
const userContextMenuPatch: NavContextMenuPatchCallback = (children, { user }: { user: User; }) => {
|
||||
if (user?.id == null) return;
|
||||
|
||||
const setCustomColorItem = (
|
||||
<Menu.MenuItem
|
||||
label="Set Color"
|
||||
id="set-color"
|
||||
action={async () => {
|
||||
await requireSettingsMenu();
|
||||
openModal(modalProps => <SetColorModal userId={user.id} modalProps={modalProps} />);
|
||||
}}
|
||||
/>
|
||||
);
|
||||
|
||||
children.push(<Menu.MenuSeparator />, setCustomColorItem);
|
||||
|
||||
};
|
||||
|
||||
export function getCustomColorString(userId: string, withHash?: boolean): string | undefined {
|
||||
if (!colors[userId] || !Settings.plugins.customUserColors.enabled)
|
||||
return;
|
||||
|
||||
if (withHash)
|
||||
return `#${colors[userId]}`;
|
||||
|
||||
return colors[userId];
|
||||
}
|
||||
|
||||
const settings = definePluginSettings({
|
||||
DmList: {
|
||||
type: OptionType.BOOLEAN,
|
||||
description: "Users with custom colors defined will have their name in the dm list colored",
|
||||
default: true,
|
||||
},
|
||||
colorInServers: {
|
||||
type: OptionType.BOOLEAN,
|
||||
description: "If name colors should be changed within servers",
|
||||
default: true,
|
||||
}
|
||||
});
|
||||
|
||||
export default definePlugin({
|
||||
name: "customUserColors",
|
||||
description: "Lets you add a custom color to any user, anywhere! Highly recommend to use with typingTweaks and roleColorEverywhere",
|
||||
authors: [EquicordDevs.mochienya],
|
||||
contextMenus: { "user-context": userContextMenuPatch },
|
||||
settings,
|
||||
requireSettingsMenu,
|
||||
getCustomColorString,
|
||||
|
||||
patches: [
|
||||
{
|
||||
// this also affects name headers in chats outside of servers
|
||||
find: /type:\i\.\i\.Types\.REMIX/,
|
||||
replacement: {
|
||||
match: /style:"username".*?void 0/,
|
||||
replace: "style:{color:$self.colorIfServer(arguments[0])}"
|
||||
}
|
||||
},
|
||||
{
|
||||
predicate: () => settings.store.DmList,
|
||||
find: /muted:\i=!1,highlighted:\i=!1/,
|
||||
replacement: {
|
||||
match: /(nameAndDecorators,)/,
|
||||
replace: "$1style:{color:$self.colorDMList(arguments[0])},"
|
||||
},
|
||||
},
|
||||
],
|
||||
|
||||
colorDMList(a: any): string | undefined {
|
||||
try {
|
||||
// @ts-ignore
|
||||
const { id } = UserStore.findByTag(a.avatar.props["aria-label"]);
|
||||
// get user id by props on avatars having username as aria label
|
||||
const colorString = getCustomColorString(id, true);
|
||||
if (colorString)
|
||||
return colorString;
|
||||
return "inherit";
|
||||
} catch { return; } // if you have a group in your dms then discord will crash on load without this
|
||||
},
|
||||
|
||||
colorIfServer(a: any): string | undefined {
|
||||
const roleColor = a.author.colorString;
|
||||
|
||||
if (a.channel.guild_id && !settings.store.colorInServers)
|
||||
return roleColor;
|
||||
|
||||
const color = getCustomColorString(a.message.author.id, true);
|
||||
return color ?? roleColor;
|
||||
}
|
||||
});
|
16
src/equicordplugins/customUserColors/styles.css
Normal file
16
src/equicordplugins/customUserColors/styles.css
Normal file
|
@ -0,0 +1,16 @@
|
|||
.vc-customColors-modal-header {
|
||||
place-content: center;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.vc-customColors-modal-header h1 {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.vc-customColors-modal-content {
|
||||
padding: 1em;
|
||||
}
|
||||
|
||||
.vc-customColors-modal-footer {
|
||||
gap: 16px;
|
||||
}
|
|
@ -16,7 +16,7 @@
|
|||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { definePluginSettings } from "@api/Settings";
|
||||
import { definePluginSettings, Settings } from "@api/Settings";
|
||||
import ErrorBoundary from "@components/ErrorBoundary";
|
||||
import { makeRange } from "@components/PluginSettings/components";
|
||||
import { Devs } from "@utils/constants";
|
||||
|
@ -24,6 +24,7 @@ import { Logger } from "@utils/Logger";
|
|||
import definePlugin, { OptionType } from "@utils/types";
|
||||
import { findByCodeLazy } from "@webpack";
|
||||
import { ChannelStore, GuildMemberStore, GuildStore } from "@webpack/common";
|
||||
import { getCustomColorString } from "@equicordplugins/customUserColors";
|
||||
|
||||
const useMessageAuthor = findByCodeLazy('"Result cannot be null because the message is not null"');
|
||||
|
||||
|
@ -164,6 +165,9 @@ export default definePlugin({
|
|||
|
||||
getColorString(userId: string, channelOrGuildId: string) {
|
||||
try {
|
||||
if (Settings.plugins.customUserColors.enabled)
|
||||
return getCustomColorString(userId, true);
|
||||
|
||||
const guildId = ChannelStore.getChannel(channelOrGuildId)?.guild_id ?? GuildStore.getGuild(channelOrGuildId)?.id;
|
||||
if (guildId == null) return null;
|
||||
|
||||
|
|
|
@ -16,13 +16,14 @@
|
|||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { definePluginSettings } from "@api/Settings";
|
||||
import { definePluginSettings, Settings } from "@api/Settings";
|
||||
import ErrorBoundary from "@components/ErrorBoundary";
|
||||
import { Devs } from "@utils/constants";
|
||||
import { openUserProfile } from "@utils/discord";
|
||||
import definePlugin, { OptionType } from "@utils/types";
|
||||
import { Avatar, GuildMemberStore, React, RelationshipStore } from "@webpack/common";
|
||||
import { User } from "discord-types/general";
|
||||
import { getCustomColorString } from "@equicordplugins/customUserColors";
|
||||
import { PropsWithChildren } from "react";
|
||||
|
||||
const settings = definePluginSettings({
|
||||
|
@ -57,6 +58,12 @@ interface Props {
|
|||
guildId: string;
|
||||
}
|
||||
|
||||
function TypingUserColor(guildId: string, userId: string) {
|
||||
if (!settings.store.showRoleColors) return;
|
||||
if (Settings.plugins.customUserColors.enabled) return getCustomColorString(userId, true);
|
||||
return GuildMemberStore.getMember(guildId, userId)?.colorString;
|
||||
}
|
||||
|
||||
const TypingUser = ErrorBoundary.wrap(function ({ user, guildId }: Props) {
|
||||
return (
|
||||
<strong
|
||||
|
@ -68,7 +75,7 @@ const TypingUser = ErrorBoundary.wrap(function ({ user, guildId }: Props) {
|
|||
display: "grid",
|
||||
gridAutoFlow: "column",
|
||||
gap: "4px",
|
||||
color: settings.store.showRoleColors ? GuildMemberStore.getMember(guildId, user.id)?.colorString : undefined,
|
||||
color: typingUserColor(guildId, user.id),
|
||||
cursor: "pointer"
|
||||
}}
|
||||
>
|
||||
|
|
Loading…
Add table
Reference in a new issue