feat(plugin): copyProfileColors + update LastActive (#225)

* feat(Copy Profile Colors) Plugin

A button added to a user's context menu to collect their colors of their profile
(https://discord.com/channels/1173279886065029291/1357341192475508876)

* Update README.md

* Updated LastActive

Clean up!

* Fixed imports
This commit is contained in:
Crxaw 2025-04-11 00:41:02 +01:00 committed by GitHub
parent c0e77e1313
commit 02d34de59b
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 145 additions and 3 deletions

View file

@ -11,7 +11,7 @@ You can join our [discord server](https://discord.gg/5Xh2W87egW) for commits, ch
### Extra included plugins
<details>
<summary>164 additional plugins</summary>
<summary>165 additional plugins</summary>
### All Platforms
@ -57,6 +57,7 @@ You can join our [discord server](https://discord.gg/5Xh2W87egW) for commits, ch
- Equissant by SomeAspy & thororen
- ExportContacts by dat_insanity
- FakeProfileThemesAndEffects by ryan
- CopyProfileColors by Crxa
- FindReply by newwares
- FixFileExtensions by thororen
- FollowVoiceUser by TheArmagan

View file

@ -0,0 +1,106 @@
/*
* Vencord, a Discord client mod
* Copyright (c) 2025 Vendicated and contributors
* SPDX-License-Identifier: GPL-3.0-or-later
*/
import { addContextMenuPatch, NavContextMenuPatchCallback, removeContextMenuPatch } from "@api/ContextMenu";
import { EquicordDevs } from "@utils/constants";
import definePlugin from "@utils/types";
import { Clipboard, Menu, Toasts, UserProfileStore } from "@webpack/common";
function getProfileColors(userId) {
try {
const profile = UserProfileStore.getUserProfile(userId);
if (!profile || !profile.themeColors || profile.themeColors.length < 2) {
return null;
}
const primaryColor = profile.themeColors[0].toString(16).padStart(6, "0");
const secondaryColor = profile.themeColors[1].toString(16).padStart(6, "0");
return { primaryColor, secondaryColor };
} catch (e) {
console.error("Failed to get profile colors:", e);
return null;
}
}
function copyProfileColors(userId) {
const colors = getProfileColors(userId);
if (!colors) {
Toasts.show({
type: Toasts.Type.FAILURE,
message: "No profile colors found!",
id: Toasts.genId()
});
return;
}
const { primaryColor, secondaryColor } = colors;
// Formatting
const formattedColors = `Primary-color #${primaryColor}, Secondary-Color #${secondaryColor}`;
try {
Clipboard.copy(formattedColors);
Toasts.show({
type: Toasts.Type.SUCCESS,
message: "Profile colors copied to clipboard!",
id: Toasts.genId()
});
} catch (e) {
console.error("Failed to copy to clipboard:", e);
Toasts.show({
type: Toasts.Type.FAILURE,
message: "Error copying profile colors!",
id: Toasts.genId()
});
}
}
export function ColorIcon() {
return (
<svg
viewBox="0 0 24 24"
width="20"
height="20"
fill="#94b3e4"
xmlns="http://www.w3.org/2000/svg"
>
<path d="M17,4H15.82A3,3,0,0,0,13,2H11A3,3,0,0,0,8.18,4H7A3,3,0,0,0,4,7V19a3,3,0,0,0,3,3H17a3,3,0,0,0,3-3V7A3,3,0,0,0,17,4ZM10,5a1,1,0,0,1,1-1h2a1,1,0,0,1,1,1V6H10Zm8,14a1,1,0,0,1-1,1H7a1,1,0,0,1-1-1V7A1,1,0,0,1,7,6H8V7A1,1,0,0,0,9,8h6a1,1,0,0,0,1-1V6h1a1,1,0,0,1,1,1Z" />
</svg>
);
}
// spawn in the context menu
const userContextMenuPatch: NavContextMenuPatchCallback = (children, { user }) => {
if (!user) return;
children.push(
<Menu.MenuItem
id="CopyProfileColors"
icon={ColorIcon}
label={<span style={{ color: "rgb(148, 179, 228)" }}>Copy Profile Colors</span>}
action={() => copyProfileColors(user.id)}
/>
);
};
export default definePlugin({
name: "CopyProfileColors",
description: "A plugin to copy people's profile gradient colors to clipboard.",
authors: [EquicordDevs.Crxa, EquicordDevs.Cortex], // Cortex is here because he showed me how to add icons <3
start() {
addContextMenuPatch("user-context", userContextMenuPatch);
addContextMenuPatch("user-profile-actions", userContextMenuPatch);
},
stop() {
// bye bye menu options
removeContextMenuPatch("user-context", userContextMenuPatch);
removeContextMenuPatch("user-profile-actions", userContextMenuPatch);
}
});

View file

@ -84,7 +84,8 @@ const ChannelContextMenuPatch: NavContextMenuPatchCallback = (children, { channe
children.push(
<Menu.MenuItem
id="LastActive"
label={<span style={{ color: "green" }}>Jump to Your Last Message</span>}
label={<span style={{ color: "#aa6746" }}>Your Last Message</span>}
icon={LastActiveIcon}
action={() => {
jumpToLastActive(channel);
}}
@ -97,13 +98,47 @@ const UserContextMenuPatch: NavContextMenuPatchCallback = (children, { user, cha
children.push(
<Menu.MenuItem
id="LastActive"
label={<span style={{ color: "green" }}>Jump to User's Last Message</span>}
label={<span style={{ color: "#aa6746" }}>User's Last Message</span>}
icon={UserLastActiveIcon}
action={() => {
jumpToLastActive(channel, user.id);
}}
/>
);
};
export function UserLastActiveIcon() {
return (
<svg
viewBox="0 0 52 52"
width="20"
height="20"
fill="#aa6746"
>
<g>
<path d="M11.4,21.6L24.9,7.9c0.6-0.6,1.6-0.6,2.2,0l13.5,13.7c0.6,0.6,0.6,1.6,0,2.2L38.4,26
c-0.6,0.6-1.6,0.6-2.2,0l-9.1-9.4c-0.6-0.6-1.6-0.6-2.2,0l-9.1,9.3c-0.6,0.6-1.6,0.6-2.2,0l-2.2-2.2C10.9,23.1,10.9,22.2,11.4,21.6
z"/>
<path d="M11.4,39.7L24.9,26c0.6-0.6,1.6-0.6,2.2,0l13.5,13.7c0.6,0.6,0.6,1.6,0,2.2l-2.2,2.2
c-0.6,0.6-1.6,0.6-2.2,0l-9.1-9.4c-0.6-0.6-1.6-0.6-2.2,0L15.8,44c-0.6,0.6-1.6,0.6-2.2,0l-2.2-2.2C10.9,41.2,10.9,40.2,11.4,39.7z
"/>
</g>
</svg>
);
}
export function LastActiveIcon() {
return (
<svg
viewBox="0 0 24 24"
width="20"
height="20"
fill="#aa6746"
xmlns="http://www.w3.org/2000/svg"
>
<path fillRule="evenodd" d="M12,2 C17.5228475,2 22,6.4771525 22,12 C22,17.5228475 17.5228475,22 12,22 C6.4771525,22 2,17.5228475 2,12 C2,6.4771525 6.4771525,2 12,2 Z M12,4 C7.581722,4 4,7.581722 4,12 C4,16.418278 7.581722,20 12,20 C16.418278,20 20,16.418278 20,12 C20,7.581722 16.418278,4 12,4 Z M12,6 C12.5128358,6 12.9355072,6.38604019 12.9932723,6.88337887 L13,7 L13,11.5857864 L14.7071068,13.2928932 C15.0976311,13.6834175 15.0976311,14.3165825 14.7071068,14.7071068 C14.3466228,15.0675907 13.7793918,15.0953203 13.3871006,14.7902954 L13.2928932,14.7071068 L11.2928932,12.7071068 C11.1366129,12.5508265 11.0374017,12.3481451 11.0086724,12.131444 L11,12 L11,7 C11,6.44771525 11.4477153,6 12,6 Z" />
</svg>
);
}
export default definePlugin({
name: "LastActive",
description: "A plugin to jump to last active message from yourself or another user in a channel/server.",