forked from userplugins/in-role
Compare commits
No commits in common. "main" and "main" have entirely different histories.
5 changed files with 68 additions and 398 deletions
|
@ -4,225 +4,40 @@
|
||||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import { classNameFactory } from "@api/Styles";
|
||||||
import ErrorBoundary from "@components/ErrorBoundary";
|
import ErrorBoundary from "@components/ErrorBoundary";
|
||||||
import { InfoIcon } from "@components/Icons";
|
import { ModalCloseButton, ModalContent, ModalHeader, ModalRoot, ModalSize, openModal } from "@utils/modal";
|
||||||
import { ModalCloseButton, ModalContent, ModalHeader, ModalProps, ModalRoot, ModalSize, openModal } from "@utils/modal";
|
import { Forms, Parser } from "@webpack/common";
|
||||||
import { findByCodeLazy, findExportedComponentLazy } from "@webpack";
|
import { GuildMember } from "discord-types/general";
|
||||||
import { Constants, GuildChannelStore, GuildMemberStore, GuildStore, Parser, RestAPI, ScrollerThin, showToast, Text, Tooltip, useEffect, UserStore, useState } from "@webpack/common";
|
|
||||||
import { UnicodeEmoji } from "@webpack/types";
|
|
||||||
import type { Role } from "discord-types/general";
|
|
||||||
|
|
||||||
import { cl, GuildUtils } from "./utils";
|
const cl = classNameFactory("vc-inrole-");
|
||||||
|
|
||||||
type GetRoleIconData = (role: Role, size: number) => { customIconSrc?: string; unicodeEmoji?: UnicodeEmoji; };
|
export function showInRoleModal(members: GuildMember[], roleId: string, channelId: string) {
|
||||||
const ThreeDots = findExportedComponentLazy("Dots", "AnimatedDots");
|
openModal(props =>
|
||||||
const getRoleIconData: GetRoleIconData = findByCodeLazy("convertSurrogateToName", "customIconSrc", "unicodeEmoji");
|
|
||||||
|
|
||||||
let rolesFetched2;
|
|
||||||
let members2;
|
|
||||||
|
|
||||||
function getRoleIconSrc(role: Role) {
|
|
||||||
const icon = getRoleIconData(role, 20);
|
|
||||||
if (!icon) return;
|
|
||||||
|
|
||||||
const { customIconSrc, unicodeEmoji } = icon;
|
|
||||||
return customIconSrc ?? unicodeEmoji?.url;
|
|
||||||
}
|
|
||||||
|
|
||||||
function MembersContainer({ guildId, roleId }: { guildId: string; roleId: string; }) {
|
|
||||||
|
|
||||||
const channelId = GuildChannelStore.getChannels(guildId).SELECTABLE[0].channel.id;
|
|
||||||
|
|
||||||
// RMC: RoleMemberCounts
|
|
||||||
const [RMC, setRMC] = useState({});
|
|
||||||
useEffect(() => {
|
|
||||||
let loading = true;
|
|
||||||
const interval = setInterval(async () => {
|
|
||||||
try {
|
|
||||||
await RestAPI.get({
|
|
||||||
url: Constants.Endpoints.GUILD_ROLE_MEMBER_COUNTS(guildId)
|
|
||||||
}).then(x => {
|
|
||||||
if (x.ok) setRMC(x.body); clearInterval(interval);
|
|
||||||
});
|
|
||||||
} catch (error) { console.error("Error fetching member counts", error); }
|
|
||||||
}, 1000);
|
|
||||||
return () => { loading = false; };
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
let usersInRole = [];
|
|
||||||
const [rolesFetched, setRolesFetched] = useState(Array<string>);
|
|
||||||
useEffect(() => {
|
|
||||||
if (!rolesFetched.includes(roleId)) {
|
|
||||||
const interval = setInterval(async () => {
|
|
||||||
try {
|
|
||||||
const response = await RestAPI.get({
|
|
||||||
url: Constants.Endpoints.GUILD_ROLE_MEMBER_IDS(guildId, roleId),
|
|
||||||
});
|
|
||||||
({ body: usersInRole } = response);
|
|
||||||
await GuildUtils.requestMembersById(guildId, usersInRole, !1);
|
|
||||||
setRolesFetched([...rolesFetched, roleId]);
|
|
||||||
rolesFetched2 = rolesFetched;
|
|
||||||
clearInterval(interval);
|
|
||||||
} catch (error) { console.error("Error fetching members:", error); }
|
|
||||||
}, 1200);
|
|
||||||
return () => clearInterval(interval);
|
|
||||||
}
|
|
||||||
}, [roleId]); // Fetch roles
|
|
||||||
|
|
||||||
const [members, setMembers] = useState(GuildMemberStore.getMembers(guildId));
|
|
||||||
useEffect(() => {
|
|
||||||
const interval = setInterval(async () => {
|
|
||||||
if (usersInRole) {
|
|
||||||
const guildMembers = GuildMemberStore.getMembers(guildId);
|
|
||||||
const storedIds = guildMembers.map(user => user.userId);
|
|
||||||
usersInRole.every(id => storedIds.includes(id)) && clearInterval(interval);
|
|
||||||
if (guildMembers !== members) {
|
|
||||||
setMembers(GuildMemberStore.getMembers(guildId));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}, 500);
|
|
||||||
return () => clearInterval(interval);
|
|
||||||
}, [roleId, rolesFetched]);
|
|
||||||
|
|
||||||
const roleMembers = members.filter(x => x.roles.includes(roleId)).map(x => UserStore.getUser(x.userId));
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className={cl("modal-members")}>
|
|
||||||
<div className={cl("member-list-header")}>
|
|
||||||
<div className={cl("member-list-header-text")}>
|
|
||||||
<Text>
|
|
||||||
{roleMembers.length} loaded / {RMC[roleId] || 0} members with this role<br />
|
|
||||||
</Text>
|
|
||||||
<Tooltip text="For roles with over 100 members, only the first 100 and the cached members will be shown.">
|
|
||||||
{props => <InfoIcon {...props} />}
|
|
||||||
</Tooltip>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
<ScrollerThin orientation="auto">
|
|
||||||
{roleMembers.map(x => {
|
|
||||||
return (
|
|
||||||
<div key={x.id} className={cl("user-div")}>
|
|
||||||
<img
|
|
||||||
className={cl("user-avatar")}
|
|
||||||
src={x.getAvatarURL()}
|
|
||||||
alt=""
|
|
||||||
/>
|
|
||||||
{Parser.parse(`<@${x.id}>`, true, { channelId, viewingChannelId: channelId })}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
{
|
|
||||||
(Object.keys(RMC).length === 0) ? (
|
|
||||||
<div className={cl("member-list-footer")}>
|
|
||||||
<ThreeDots dotRadius={5} themed={true} />
|
|
||||||
</div>
|
|
||||||
) : !RMC[roleId] ? (
|
|
||||||
<Text className={cl("member-list-footer")} variant="text-md/normal">No member found with this role</Text>
|
|
||||||
) : RMC[roleId] === roleMembers.length ? (
|
|
||||||
<>
|
<>
|
||||||
<div className={cl("divider")} />
|
|
||||||
<Text className={cl("member-list-footer")} variant="text-md/normal">All members loaded</Text>
|
|
||||||
</>
|
|
||||||
) : rolesFetched.includes(roleId) ? (
|
|
||||||
<>
|
|
||||||
<div className={cl("divider")} />
|
|
||||||
<Text className={cl("member-list-footer")} variant="text-md/normal">All cached members loaded</Text>
|
|
||||||
</>
|
|
||||||
) : (
|
|
||||||
<div className={cl("member-list-footer")}>
|
|
||||||
<ThreeDots dotRadius={5} themed={true} />
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
</ScrollerThin>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
function InRoleModal({ guildId, props, roleId }: { guildId: string; props: ModalProps; roleId: string; }) {
|
|
||||||
const roleObj = GuildStore.getRoles(guildId);
|
|
||||||
const roles = Object.keys(roleObj).map(key => roleObj[key]).sort((a, b) => b.position - a.position);
|
|
||||||
|
|
||||||
const [selectedRole, selectRole] = useState(roles.find(x => x.id === roleId) || roles[0]);
|
|
||||||
|
|
||||||
let cooldown;
|
|
||||||
useEffect(() => {
|
|
||||||
const timeout = setTimeout(() => cooldown = false, 1000);
|
|
||||||
return () => clearTimeout(timeout);
|
|
||||||
}, [selectedRole]);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<ErrorBoundary>
|
<ErrorBoundary>
|
||||||
<ModalRoot {...props} size={ModalSize.LARGE}>
|
<ModalRoot {...props} size={ModalSize.DYNAMIC} fullscreenOnMobile={true} >
|
||||||
<ModalHeader>
|
<ModalHeader className={cl("header")}>
|
||||||
<Text className={cl("modal-title")} variant="heading-lg/semibold">View members with role</Text>
|
<Forms.FormText style={{ fontSize: "1.2rem", fontWeight: "bold", marginRight: "7px" }}>Members of role {
|
||||||
<ModalCloseButton onClick={props.onClose} />
|
Parser.parse(`<@&${roleId}>`, true, { channelId, viewingChannelId: channelId })
|
||||||
|
} ({members.length})</Forms.FormText>
|
||||||
|
<ModalCloseButton onClick={props.onClose} className={cl("close")} />
|
||||||
</ModalHeader>
|
</ModalHeader>
|
||||||
<ModalContent className={cl("modal-content")}>
|
<ModalContent>
|
||||||
<div className={cl("modal-container")}>
|
<div style={{ padding: "13px 20px" }} className={cl("member-list")}>
|
||||||
<ScrollerThin className={cl("modal-list")} orientation="auto">
|
|
||||||
{roles.map((role, index) => {
|
|
||||||
|
|
||||||
if (role.id === guildId) return;
|
|
||||||
|
|
||||||
const roleIconSrc = role != null ? getRoleIconSrc(role) : undefined;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div
|
|
||||||
className={cl("modal-list-item-btn")}
|
|
||||||
onClick={() => {
|
|
||||||
if (selectedRole.id === roles[index].id) return;
|
|
||||||
cooldown && !rolesFetched2.includes(roles[index].id) ? showToast("To limit ratelimiting, please wait at least a second before switching roles.")
|
|
||||||
: (selectRole(roles[index]), cooldown = true);
|
|
||||||
}}
|
|
||||||
role="button"
|
|
||||||
tabIndex={0}
|
|
||||||
key={role.id}
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
className={cl("modal-list-item", { "modal-list-item-active": selectedRole.id === role.id })}
|
|
||||||
>
|
|
||||||
<span
|
|
||||||
className={cl("modal-role-circle")}
|
|
||||||
style={{ backgroundColor: role?.colorString || "var(--primary-300)" }}
|
|
||||||
/>
|
|
||||||
{
|
{
|
||||||
roleIconSrc != null && (
|
members.length !== 0 ? members.map(member =>
|
||||||
<img
|
<>
|
||||||
className={cl("modal-role-image")}
|
<Forms.FormText className={cl("modal-member")}>
|
||||||
src={roleIconSrc}
|
{Parser.parse(`<@${member.userId}>`, true, { channelId, viewingChannelId: channelId })}
|
||||||
/>
|
</Forms.FormText>
|
||||||
)
|
</>
|
||||||
|
) : <Forms.FormText>Looks like no online cached members with that role were found. Try scrolling down on your member list to cache more users!</Forms.FormText>
|
||||||
}
|
}
|
||||||
<Text variant="text-md/normal">
|
|
||||||
{role?.name || "Unknown role"}
|
|
||||||
</Text>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</ScrollerThin>
|
|
||||||
<div className={cl("modal-divider")} />
|
|
||||||
<MembersContainer
|
|
||||||
guildId={guildId}
|
|
||||||
roleId={selectedRole.id}
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
</ModalContent>
|
</ModalContent>
|
||||||
</ModalRoot>
|
</ModalRoot>
|
||||||
</ErrorBoundary>
|
</ErrorBoundary>
|
||||||
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function showInRoleModal(guildId: string, roleId: string) {
|
|
||||||
openModal(props =>
|
|
||||||
<InRoleModal
|
|
||||||
guildId={guildId}
|
|
||||||
props={props}
|
|
||||||
roleId={roleId}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
17
icons.tsx
17
icons.tsx
|
@ -1,17 +0,0 @@
|
||||||
/*
|
|
||||||
* Vencord, a Discord client mod
|
|
||||||
* Copyright (c) 2024 Vendicated and contributors
|
|
||||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
*/
|
|
||||||
|
|
||||||
export function MemberIcon() {
|
|
||||||
return (
|
|
||||||
<svg
|
|
||||||
height="20"
|
|
||||||
width="20"
|
|
||||||
viewBox="0 0 24 24"
|
|
||||||
>
|
|
||||||
<path fill="currentColor" d="M14.5 8a3 3 0 1 0-2.7-4.3c-.2.4.06.86.44 1.12a5 5 0 0 1 2.14 3.08c.01.06.06.1.12.1ZM18.44 17.27c.15.43.54.73 1 .73h1.06c.83 0 1.5-.67 1.5-1.5a7.5 7.5 0 0 0-6.5-7.43c-.55-.08-.99.38-1.1.92-.06.3-.15.6-.26.87-.23.58-.05 1.3.47 1.63a9.53 9.53 0 0 1 3.83 4.78ZM12.5 9a3 3 0 1 1-6 0 3 3 0 0 1 6 0ZM2 20.5a7.5 7.5 0 0 1 15 0c0 .83-.67 1.5-1.5 1.5a.2.2 0 0 1-.2-.16c-.2-.96-.56-1.87-.88-2.54-.1-.23-.42-.15-.42.1v2.1a.5.5 0 0 1-.5.5h-8a.5.5 0 0 1-.5-.5v-2.1c0-.25-.31-.33-.42-.1-.32.67-.67 1.58-.88 2.54a.2.2 0 0 1-.2.16A1.5 1.5 0 0 1 2 20.5Z" />
|
|
||||||
</svg>
|
|
||||||
);
|
|
||||||
}
|
|
47
index.tsx
47
index.tsx
|
@ -7,29 +7,33 @@
|
||||||
import "./style.css";
|
import "./style.css";
|
||||||
|
|
||||||
import { ApplicationCommandInputType, ApplicationCommandOptionType, sendBotMessage } from "@api/Commands";
|
import { ApplicationCommandInputType, ApplicationCommandOptionType, sendBotMessage } from "@api/Commands";
|
||||||
import { findGroupChildrenByChildId } from "@api/ContextMenu";
|
|
||||||
import { getUserSettingLazy } from "@api/UserSettings";
|
import { getUserSettingLazy } from "@api/UserSettings";
|
||||||
|
import { InfoIcon } from "@components/Icons";
|
||||||
import { Devs } from "@utils/constants";
|
import { Devs } from "@utils/constants";
|
||||||
import { getCurrentChannel, getCurrentGuild } from "@utils/discord";
|
import { getCurrentChannel, getCurrentGuild } from "@utils/discord";
|
||||||
import definePlugin from "@utils/types";
|
import definePlugin from "@utils/types";
|
||||||
import { Forms, GuildMemberStore, GuildStore, Menu, Parser } from "@webpack/common";
|
import { Forms, GuildMemberStore, GuildStore, Menu, Parser } from "@webpack/common";
|
||||||
import { Guild, GuildMember } from "discord-types/general";
|
import { GuildMember } from "discord-types/general";
|
||||||
|
|
||||||
import { MemberIcon } from "./icons";
|
|
||||||
import { showInRoleModal } from "./RoleMembersModal";
|
import { showInRoleModal } from "./RoleMembersModal";
|
||||||
|
|
||||||
const DeveloperMode = getUserSettingLazy("appearance", "developerMode")!;
|
const DeveloperMode = getUserSettingLazy("appearance", "developerMode")!;
|
||||||
|
|
||||||
|
function getMembersInRole(roleId: string, guildId: string) {
|
||||||
|
const members = GuildMemberStore.getMembers(guildId);
|
||||||
|
const membersInRole: GuildMember[] = [];
|
||||||
|
members.forEach(member => {
|
||||||
|
if (member.roles.includes(roleId)) {
|
||||||
|
membersInRole.push(member);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return membersInRole;
|
||||||
|
}
|
||||||
|
|
||||||
export default definePlugin({
|
export default definePlugin({
|
||||||
name: "InRole",
|
name: "InRole",
|
||||||
description: "Know who is in a role with the role context menu or /inrole command (read plugin info!)",
|
description: "Know who is in a role with the role context menu or /inrole command (read plugin info!)",
|
||||||
authors: [
|
authors: [Devs.nin0dev],
|
||||||
Devs.nin0dev,
|
|
||||||
{
|
|
||||||
name: "Ryfter",
|
|
||||||
id: 898619112350183445n,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
dependencies: ["UserSettingsAPI"],
|
dependencies: ["UserSettingsAPI"],
|
||||||
start() {
|
start() {
|
||||||
// DeveloperMode needs to be enabled for the context menu to be shown
|
// DeveloperMode needs to be enabled for the context menu to be shown
|
||||||
|
@ -40,8 +44,9 @@ export default definePlugin({
|
||||||
<>
|
<>
|
||||||
<Forms.FormText style={{ fontSize: "1.2rem", marginTop: "15px", fontWeight: "bold" }}>{Parser.parse(":warning:")} Limitations</Forms.FormText>
|
<Forms.FormText style={{ fontSize: "1.2rem", marginTop: "15px", fontWeight: "bold" }}>{Parser.parse(":warning:")} Limitations</Forms.FormText>
|
||||||
<Forms.FormText style={{ marginTop: "10px", fontWeight: "500" }} >If you don't have mod permissions on the server, and that server is large (over 100 members), the plugin may be limited in the following ways:</Forms.FormText>
|
<Forms.FormText style={{ marginTop: "10px", fontWeight: "500" }} >If you don't have mod permissions on the server, and that server is large (over 100 members), the plugin may be limited in the following ways:</Forms.FormText>
|
||||||
<Forms.FormText>• Up to 100 members will be listed by default for each role. To get more, scroll down in the member list to cache more members.</Forms.FormText>
|
<Forms.FormText>• Offline members won't be listed</Forms.FormText>
|
||||||
<Forms.FormText>• However, friends will always be shown.</Forms.FormText>
|
<Forms.FormText>• Up to 100 members will be listed by default. To get more, scroll down in the member list to load more members.</Forms.FormText>
|
||||||
|
<Forms.FormText>• However, friends will always be shown regardless of their status.</Forms.FormText>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
@ -65,7 +70,7 @@ export default definePlugin({
|
||||||
return sendBotMessage(ctx.channel.id, { content: "Make sure that you are in a server." });
|
return sendBotMessage(ctx.channel.id, { content: "Make sure that you are in a server." });
|
||||||
}
|
}
|
||||||
const role = args[0].value;
|
const role = args[0].value;
|
||||||
showInRoleModal(ctx.guild.id, role);
|
showInRoleModal(getMembersInRole(role, ctx.guild.id), role, ctx.channel.id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
@ -85,21 +90,9 @@ export default definePlugin({
|
||||||
id="vc-view-inrole"
|
id="vc-view-inrole"
|
||||||
label="View Members in Role"
|
label="View Members in Role"
|
||||||
action={() => {
|
action={() => {
|
||||||
showInRoleModal(guild.id, role.id);
|
showInRoleModal(getMembersInRole(role.id, guild.id), role.id, channel.id);
|
||||||
}}
|
}}
|
||||||
icon={MemberIcon}
|
icon={InfoIcon}
|
||||||
/>
|
|
||||||
);
|
|
||||||
},
|
|
||||||
"guild-header-popout"(children, { guild }: { guild: Guild, onClose(): void; }) {
|
|
||||||
if (!guild) return;
|
|
||||||
const group = findGroupChildrenByChildId("privacy", children);
|
|
||||||
group?.push(
|
|
||||||
<Menu.MenuItem
|
|
||||||
label="View members in role"
|
|
||||||
id="inrole-menuitem"
|
|
||||||
icon={MemberIcon}
|
|
||||||
action={() => showInRoleModal(guild.id, "0")}
|
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
144
style.css
144
style.css
|
@ -1,139 +1,29 @@
|
||||||
.vc-inrole-modal-content {
|
.vc-inrole-member-list {
|
||||||
padding: 16px 4px 16px 16px;
|
max-height: 400px;
|
||||||
|
margin-top: 10px;
|
||||||
|
margin-bottom: 13px;
|
||||||
|
overflow-x: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
.vc-inrole-modal-title {
|
.vc-inrole-member-list::-webkit-scrollbar {
|
||||||
flex-grow: 1;
|
background-color: #fff1;
|
||||||
|
border-radius: 100px;
|
||||||
|
width: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.vc-inrole-modal-container {
|
.vc-inrole-member-list::-webkit-scrollbar-thumb {
|
||||||
width: 100%;
|
background-color: #fff3;
|
||||||
height: 100%;
|
border-radius: 100px;
|
||||||
display: flex;
|
|
||||||
gap: 8px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.vc-inrole-modal-list {
|
.vc-inrole-modal-member {
|
||||||
display: flex;
|
margin: 11px 0;
|
||||||
flex-direction: column;
|
|
||||||
gap: 2px;
|
|
||||||
padding-right: 8px;
|
|
||||||
max-width: 300px;
|
|
||||||
min-width: 300px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.vc-inrole-modal-list-item-btn {
|
.vc-inrole-header {
|
||||||
cursor: pointer;
|
padding-top: "15px";
|
||||||
}
|
}
|
||||||
|
|
||||||
.vc-inrole-modal-list-item {
|
.vc-inrole-close {
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
gap: 8px;
|
|
||||||
padding: 8px;
|
|
||||||
border-radius: 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.vc-inrole-modal-list-item:hover {
|
|
||||||
background-color: var(--background-modifier-hover);
|
|
||||||
}
|
|
||||||
|
|
||||||
.vc-inrole-modal-list-item-active {
|
|
||||||
background-color: var(--background-modifier-selected);
|
|
||||||
}
|
|
||||||
|
|
||||||
.vc-inrole-modal-list-item > div {
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
white-space: nowrap;
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
|
|
||||||
.vc-inrole-modal-role-circle {
|
|
||||||
border-radius: 50%;
|
|
||||||
width: 12px;
|
|
||||||
height: 12px;
|
|
||||||
flex-shrink: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.vc-inrole-modal-role-image {
|
|
||||||
width: 20px;
|
|
||||||
height: 20px;
|
|
||||||
object-fit: contain;
|
|
||||||
}
|
|
||||||
|
|
||||||
.vc-inrole-modal-divider {
|
|
||||||
width: 2px;
|
|
||||||
background-color: var(--background-modifier-active);
|
|
||||||
}
|
|
||||||
|
|
||||||
.vc-inrole-role-button {
|
|
||||||
border-radius: var(--radius-xs);
|
|
||||||
background: var(--bg-mod-faint);
|
|
||||||
color: var(--interactive-normal);
|
|
||||||
border: 1px solid var(--border-faint);
|
|
||||||
/* stylelint-disable-next-line value-no-vendor-prefix */
|
|
||||||
width: -moz-fit-content;
|
|
||||||
width: fit-content;
|
|
||||||
height: 24px;
|
|
||||||
padding: 4px
|
|
||||||
}
|
|
||||||
|
|
||||||
.custom-profile-theme .vc-inrole-role-button {
|
|
||||||
background: rgb(var(--bg-overlay-color)/var(--bg-overlay-opacity-6));
|
|
||||||
border-color: var(--profile-body-border-color)
|
|
||||||
}
|
|
||||||
|
|
||||||
.vc-inrole-user-div{
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
gap: 0.2em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.vc-inrole-modal-members {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
.vc-inrole-user-avatar {
|
|
||||||
border-radius: 50%;
|
|
||||||
padding: 5px;
|
|
||||||
width: 30px;
|
|
||||||
height: 30px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.vc-inrole-member-list-header {
|
|
||||||
background-color: var(--background-secondary);
|
|
||||||
padding: 5px;
|
|
||||||
border-radius: 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.vc-inrole-member-list-header-text {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
gap: 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.vc-inrole-member-list-header-text .vc-info-icon {
|
|
||||||
color: var(--interactive-muted);
|
|
||||||
margin-left: auto;
|
margin-left: auto;
|
||||||
cursor: pointer;
|
|
||||||
transition: color ease-in 0.1s;
|
|
||||||
}
|
|
||||||
|
|
||||||
.vc-inrole-member-list-header-text .vc-info-icon:hover {
|
|
||||||
color: var(--interactive-active);
|
|
||||||
}
|
|
||||||
|
|
||||||
.vc-inrole-member-list-footer {
|
|
||||||
padding: 5px;
|
|
||||||
text-align: center;
|
|
||||||
font-style: italic;
|
|
||||||
}
|
|
||||||
|
|
||||||
.vc-inrole-divider {
|
|
||||||
height: 2px;
|
|
||||||
width: 100%;
|
|
||||||
background-color: var(--background-modifier-active);
|
|
||||||
}
|
}
|
||||||
|
|
11
utils.ts
11
utils.ts
|
@ -1,11 +0,0 @@
|
||||||
/*
|
|
||||||
* Vencord, a Discord client mod
|
|
||||||
* Copyright (c) 2024 Vendicated and contributors
|
|
||||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
*/
|
|
||||||
|
|
||||||
import { classNameFactory } from "@api/Styles";
|
|
||||||
import { findByPropsLazy } from "@webpack";
|
|
||||||
|
|
||||||
export const cl = classNameFactory("vc-inrole-");
|
|
||||||
export const GuildUtils = findByPropsLazy("requestMembersById");
|
|
Loading…
Add table
Add a link
Reference in a new issue