PermissionsViewer: add to simplified profiles

This commit is contained in:
Vendicated 2024-06-26 14:38:50 +02:00
parent 705da29df5
commit 6d4c9339dc
No known key found for this signature in database
GPG key ID: D66986BAF75ECF18
7 changed files with 140 additions and 6 deletions

View file

@ -31,10 +31,20 @@ export interface ExpandableHeaderProps {
headerText: string;
children: React.ReactNode;
buttons?: React.ReactNode[];
forceOpen?: boolean;
}
export function ExpandableHeader({ children, onMoreClick, buttons, moreTooltipText, defaultState = false, onDropDownClick, headerText }: ExpandableHeaderProps) {
const [showContent, setShowContent] = useState(defaultState);
export function ExpandableHeader({
children,
onMoreClick,
buttons,
moreTooltipText,
onDropDownClick,
headerText,
defaultState = false,
forceOpen = false,
}: ExpandableHeaderProps) {
const [showContent, setShowContent] = useState(defaultState || forceOpen);
return (
<>
@ -90,6 +100,7 @@ export function ExpandableHeader({ children, onMoreClick, buttons, moreTooltipTe
setShowContent(v => !v);
onDropDownClick?.(showContent);
}}
disabled={forceOpen}
>
<svg
width="24"

View file

@ -290,3 +290,21 @@ export function NoEntrySignIcon(props: IconProps) {
</Icon>
);
}
export function SafetyIcon(props: IconProps) {
return (
<Icon
{...props}
className={classes(props.className, "vc-safety-icon")}
viewBox="0 0 24 24"
>
<path
fill="currentColor"
fillRule="evenodd"
clipRule="evenodd"
d="M4.27 5.22A2.66 2.66 0 0 0 3 7.5v2.3c0 5.6 3.3 10.68 8.42 12.95.37.17.79.17 1.16 0A14.18 14.18 0 0 0 21 9.78V7.5c0-.93-.48-1.78-1.27-2.27l-6.17-3.76a3 3 0 0 0-3.12 0L4.27 5.22ZM6 7.68l6-3.66V12H6.22C6.08 11.28 6 10.54 6 9.78v-2.1Zm6 12.01V12h5.78A11.19 11.19 0 0 1 12 19.7Z"
/>
</Icon>
);
}

View file

@ -43,7 +43,7 @@ const Classes = proxyLazyWebpack(() =>
))
) as Record<"roles" | "rolePill" | "rolePillBorder" | "desaturateUserColors" | "flex" | "alignCenter" | "justifyCenter" | "svg" | "background" | "dot" | "dotBorderColor" | "roleCircle" | "dotBorderBase" | "flex" | "alignCenter" | "justifyCenter" | "wrap" | "root" | "role" | "roleRemoveButton" | "roleDot" | "roleFlowerStar" | "roleRemoveIcon" | "roleRemoveIconFocused" | "roleVerifiedIcon" | "roleName" | "roleNameOverflow" | "actionButton" | "overflowButton" | "addButton" | "addButtonIcon" | "overflowRolesPopout" | "overflowRolesPopoutArrowWrapper" | "overflowRolesPopoutArrow" | "popoutBottom" | "popoutTop" | "overflowRolesPopoutHeader" | "overflowRolesPopoutHeaderIcon" | "overflowRolesPopoutHeaderText" | "roleIcon", string>;
function UserPermissionsComponent({ guild, guildMember, showBorder }: { guild: Guild; guildMember: GuildMember; showBorder: boolean; }) {
function UserPermissionsComponent({ guild, guildMember, showBorder, forceOpen = false }: { guild: Guild; guildMember: GuildMember; showBorder: boolean; forceOpen?: boolean; }) {
const stns = settings.use(["permissionsSortOrder"]);
const [rolePermissions, userPermissions] = useMemo(() => {
@ -95,6 +95,7 @@ function UserPermissionsComponent({ guild, guildMember, showBorder }: { guild: G
return (
<ExpandableHeader
forceOpen={forceOpen}
headerText="Permissions"
moreTooltipText="Role Details"
onMoreClick={() =>

View file

@ -20,15 +20,22 @@ import "./styles.css";
import { findGroupChildrenByChildId, NavContextMenuPatchCallback } from "@api/ContextMenu";
import { definePluginSettings } from "@api/Settings";
import ErrorBoundary from "@components/ErrorBoundary";
import { SafetyIcon } from "@components/Icons";
import { Devs } from "@utils/constants";
import { classes } from "@utils/misc";
import definePlugin, { OptionType } from "@utils/types";
import { ChannelStore, GuildMemberStore, GuildStore, Menu, PermissionsBits, UserStore } from "@webpack/common";
import { findByPropsLazy } from "@webpack";
import { Button, ChannelStore, Dialog, GuildMemberStore, GuildStore, Menu, PermissionsBits, Popout, TooltipContainer, UserStore } from "@webpack/common";
import type { Guild, GuildMember } from "discord-types/general";
import openRolesAndUsersPermissionsModal, { PermissionType, RoleOrUserPermission } from "./components/RolesAndUsersPermissions";
import UserPermissions from "./components/UserPermissions";
import { getSortedRoles, sortPermissionOverwrites } from "./utils";
const PopoutClasses = findByPropsLazy("container", "scroller", "list");
const RoleButtonClasses = findByPropsLazy("button", "buttonInner", "icon", "text");
export const enum PermissionsSortOrder {
HighestRole,
LowestRole
@ -168,10 +175,45 @@ export default definePlugin({
match: /showBorder:(.{0,60})}\),(?<=guild:(\i),guildMember:(\i),.+?)/,
replace: (m, showBoder, guild, guildMember) => `${m}$self.UserPermissions(${guild},${guildMember},${showBoder}),`
}
},
{
find: ".VIEW_ALL_ROLES,",
replacement: {
match: /children:"\+"\.concat\(\i\.length-\i\.length\).{0,20}\}\),/,
replace: "$&$self.ViewPermissionsButton(arguments[0]),"
}
}
],
UserPermissions: (guild: Guild, guildMember: GuildMember | undefined, showBoder: boolean) => !!guildMember && <UserPermissions guild={guild} guildMember={guildMember} showBorder={showBoder} />,
UserPermissions: (guild: Guild, guildMember: GuildMember | undefined, showBorder: boolean) =>
!!guildMember && <UserPermissions guild={guild} guildMember={guildMember} showBorder={showBorder} />,
ViewPermissionsButton: ErrorBoundary.wrap(({ guild, guildMember }: { guild: Guild; guildMember: GuildMember; }) => (
<Popout
position="bottom"
align="center"
renderPopout={() => (
<Dialog className={PopoutClasses.container} style={{ width: "500px" }}>
<UserPermissions guild={guild} guildMember={guildMember} showBorder forceOpen />
</Dialog>
)}
>
{popoutProps => (
<TooltipContainer text="View Permissions">
<Button
{...popoutProps}
color={Button.Colors.CUSTOM}
look={Button.Looks.FILLED}
size={Button.Sizes.NONE}
innerClassName={classes(RoleButtonClasses.buttonInner, RoleButtonClasses.icon)}
className={classes(RoleButtonClasses.button, RoleButtonClasses.icon, "vc-permviewer-role-button")}
>
<SafetyIcon height="16" width="16" />
</Button>
</TooltipContainer>
)}
</Popout>
), { noop: true }),
contextMenus: {
"user-context": makeContextMenuPatch("roles", MenuItemParentType.User),

View file

@ -149,3 +149,21 @@
.vc-permviewer-perms-perms-item .vc-info-icon:hover {
color: var(--interactive-active);
}
/* copy pasted from discord cause impossible to webpack find */
.vc-permviewer-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-permviewer-role-button {
background: rgb(var(--bg-overlay-color)/var(--bg-overlay-opacity-6));
border-color: var(--profile-body-border-color)
}

View file

@ -33,6 +33,7 @@ export let Card: t.Card;
export let Button: t.Button;
export let Switch: t.Switch;
export let Tooltip: t.Tooltip;
export let TooltipContainer: t.TooltipContainer;
export let TextInput: t.TextInput;
export let TextArea: t.TextArea;
export let Text: t.Text;
@ -66,6 +67,7 @@ waitFor(["FormItem", "Button"], m => {
Button,
FormSwitch: Switch,
Tooltip,
TooltipContainer,
TextInput,
TextArea,
Text,

View file

@ -101,6 +101,28 @@ export type Tooltip = ComponentType<{
export type TooltipPositions = Record<"BOTTOM" | "CENTER" | "LEFT" | "RIGHT" | "TOP" | "WINDOW_CENTER", string>;
export type TooltipContainer = ComponentType<PropsWithChildren<{
text: ReactNode;
element?: "div" | "span";
"aria-label"?: string | false;
delay?: number;
/** Tooltip.Colors.BLACK */
color?: string;
/** TooltipPositions.TOP */
position?: string;
spacing?: number;
className?: string;
tooltipClassName?: string | null;
tooltipContentClassName?: string | null;
allowOverflow?: boolean;
forceOpen?: boolean;
hideOnClick?: boolean;
disableTooltipPointerEvents?: boolean;
}>>;
export type Card = ComponentType<PropsWithChildren<HTMLProps<HTMLDivElement> & {
editable?: boolean;
outline?: boolean;
@ -110,6 +132,26 @@ export type Card = ComponentType<PropsWithChildren<HTMLProps<HTMLDivElement> & {
Types: Record<"BRAND" | "CUSTOM" | "DANGER" | "PRIMARY" | "SUCCESS" | "WARNING", string>;
};
export type ComboboxPopout = ComponentType<PropsWithChildren<{
value: Set<any>;
placeholder: string;
children(query: string): ReactNode[];
onChange(value: any): void;
itemToString?: (item: any) => string;
onClose?(): void;
className?: string;
listClassName?: string;
autoFocus?: boolean;
multiSelect?: boolean;
maxVisibleItems?: number;
showScrollbar?: boolean;
}>>;
export type Button = ComponentType<PropsWithChildren<Omit<HTMLProps<HTMLButtonElement>, "size"> & {
/** Button.Looks.FILLED */
look?: string;
@ -375,7 +417,7 @@ export type Popout = ComponentType<{
Animation: typeof PopoutAnimation;
};
export type Dialog = ComponentType<PropsWithChildren<any>>;
export type Dialog = ComponentType<JSX.IntrinsicElements["div"]>;
type Resolve = (data: { theme: "light" | "dark", saturation: number; }) => {
hex(): string;