From b4f16f0d00c3b677462541ba4a0b51728d0bad2d Mon Sep 17 00:00:00 2001
From: Paul
Date: Mon, 16 Aug 2021 17:02:24 +0100
Subject: [PATCH] Handle role hoisting / ranking. Closes #76 and closes #75.
---
.../common/messaging/attachments/Grid.tsx | 2 +
.../navigation/right/MemberSidebar.tsx | 54 +++++++++++++------
src/pages/settings/server/Roles.tsx | 48 +++++++++++++++--
3 files changed, 85 insertions(+), 19 deletions(-)
diff --git a/src/components/common/messaging/attachments/Grid.tsx b/src/components/common/messaging/attachments/Grid.tsx
index 88c99772..8d87007f 100644
--- a/src/components/common/messaging/attachments/Grid.tsx
+++ b/src/components/common/messaging/attachments/Grid.tsx
@@ -14,6 +14,8 @@ const Grid = styled.div<{ width: number; height: number }>`
max-height: min(${(props) => props.height}px, var(--attachment-max-height));
+ // This is a hack for browsers not supporting aspect-ratio.
+ // Stolen from https://codepen.io/una/pen/BazyaOM.
@supports not (
aspect-ratio: ${(props) => props.width} / ${(props) => props.height}
) {
diff --git a/src/components/navigation/right/MemberSidebar.tsx b/src/components/navigation/right/MemberSidebar.tsx
index 635efba4..29af6091 100644
--- a/src/components/navigation/right/MemberSidebar.tsx
+++ b/src/components/navigation/right/MemberSidebar.tsx
@@ -1,8 +1,10 @@
/* eslint-disable react-hooks/rules-of-hooks */
import { observer } from "mobx-react-lite";
import { useParams } from "react-router-dom";
+import { Role } from "revolt-api/types/Servers";
import { Presence } from "revolt-api/types/Users";
import { Channel } from "revolt.js/dist/maps/Channels";
+import { Server } from "revolt.js/dist/maps/Servers";
import { User } from "revolt.js/dist/maps/Users";
import { useContext, useEffect, useMemo } from "preact/hooks";
@@ -41,22 +43,42 @@ function useEntries(channel: Channel, keys: string[], isServer?: boolean) {
const categoryInfo: { [key: string]: string } = {};
+ let roles: Server["roles"];
+ let roleList: string[];
+ if (
+ channel.channel_type === "TextChannel" ||
+ channel.channel_type === "VoiceChannel"
+ ) {
+ roles = channel.server!.roles;
+ if (roles) {
+ const list = Object.keys(roles)
+ .map((id) => {
+ return [id, roles![id], roles![id].rank ?? 0] as [
+ string,
+ Role,
+ number,
+ ];
+ })
+ .filter(([, role]) => role.hoist);
+
+ list.sort((b, a) => b[2] - a[2]);
+
+ list.forEach(([id, role]) => {
+ if (categories[id]) return;
+ categories[id] = [];
+ categoryInfo[id] = role.name;
+ });
+
+ roleList = list.map((x) => x[0]);
+ }
+ }
+
keys.forEach((key) => {
- let u, s;
+ let u;
if (isServer) {
const { server, user } = JSON.parse(key);
if (server !== channel.server_id) return;
u = client.users.get(user);
- s = client.servers.get(server);
-
- if (s?.roles) {
- for (const id of Object.keys(s.roles)) {
- if (categories[id]) continue;
- // Check if hoisted.
- categories[id] = [];
- categoryInfo[id] = s.roles[id].name;
- }
- }
} else {
u = client.users.get(key);
}
@@ -72,14 +94,14 @@ function useEntries(channel: Channel, keys: string[], isServer?: boolean) {
} else {
if (isServer) {
// Sort users into hoisted roles here.
- if (member?.roles && s?.roles) {
+ if (member?.roles && roles) {
let success = false;
- for (const id of member.roles) {
- if (categories[id]) {
- categories[id].push(entry);
+ for (const role of roleList) {
+ if (member.roles.includes(role)) {
+ categories[role].push(entry);
success = true;
+ break;
}
- break;
}
if (success) return;
diff --git a/src/pages/settings/server/Roles.tsx b/src/pages/settings/server/Roles.tsx
index 91f8f2f5..8a1946f0 100644
--- a/src/pages/settings/server/Roles.tsx
+++ b/src/pages/settings/server/Roles.tsx
@@ -38,6 +38,8 @@ export const Roles = observer(({ server }: Props) => {
const {
name: roleName,
colour: roleColour,
+ hoist: roleHoist,
+ rank: roleRank,
permissions,
} = roles[role] ?? {};
@@ -54,6 +56,8 @@ export const Roles = observer(({ server }: Props) => {
const [perm, setPerm] = useState(getPermissions(role));
const [name, setName] = useState(roleName);
+ const [hoist, setHoist] = useState(roleHoist);
+ const [rank, setRank] = useState(roleRank);
const [colour, setColour] = useState(roleColour);
useEffect(
@@ -62,12 +66,16 @@ export const Roles = observer(({ server }: Props) => {
);
useEffect(() => setName(roleName), [role, roleName]);
+ useEffect(() => setHoist(roleHoist), [role, roleHoist]);
+ useEffect(() => setRank(roleRank), [role, roleRank]);
useEffect(() => setColour(roleColour), [role, roleColour]);
const modified =
!isEqual(perm, getPermissions(role)) ||
!isEqual(name, roleName) ||
- !isEqual(colour, roleColour);
+ !isEqual(colour, roleColour) ||
+ !isEqual(hoist, roleHoist) ||
+ !isEqual(rank, roleRank);
const save = () => {
if (!isEqual(perm, getPermissions(role))) {
@@ -77,8 +85,13 @@ export const Roles = observer(({ server }: Props) => {
});
}
- if (!isEqual(name, roleName) || !isEqual(colour, roleColour)) {
- server.editRole(role, { name, colour });
+ if (
+ !isEqual(name, roleName) ||
+ !isEqual(colour, roleColour) ||
+ !isEqual(hoist, roleHoist) ||
+ !isEqual(rank, roleRank)
+ ) {
+ server.editRole(role, { name, colour, hoist, rank });
}
};
@@ -163,6 +176,17 @@ export const Roles = observer(({ server }: Props) => {
/>
+
+ Role Options
+
+ setHoist(v)}
+ description="Display this role above others.">
+ Hoist Role
+
+
+
>
)}
@@ -228,6 +252,24 @@ export const Roles = observer(({ server }: Props) => {
)}
+ {role !== "default" && (
+ <>
+
+
+ Experimental Role Ranking
+
+
+
+ setRank(parseInt(e.currentTarget.value))
+ }
+ contrast
+ />
+
+
+ >
+ )}
);