From f81f7768f8f20e8886fdbbcc7813657d9fe1e991 Mon Sep 17 00:00:00 2001 From: Paul Date: Sat, 3 Jul 2021 22:17:53 +0100 Subject: [PATCH] New design for server roles editor. --- external/lang | 2 +- package.json | 2 +- src/components/ui/Button.tsx | 1 + src/components/ui/Checkbox.tsx | 10 ++ src/context/intermediate/Intermediate.tsx | 3 +- src/context/intermediate/modals/Input.tsx | 14 +- src/pages/settings/server/Panes.module.scss | 33 ++++- src/pages/settings/server/Roles.tsx | 148 +++++++++++--------- yarn.lock | 8 +- 9 files changed, 145 insertions(+), 76 deletions(-) diff --git a/external/lang b/external/lang index ec907eb6..9bb62d11 160000 --- a/external/lang +++ b/external/lang @@ -1 +1 @@ -Subproject commit ec907eb606a3e1d5046bef503caa0585f6bcbc22 +Subproject commit 9bb62d1185f7e6f7a3821751797e30cb41e74bf8 diff --git a/package.json b/package.json index a8960994..595b73b7 100644 --- a/package.json +++ b/package.json @@ -78,7 +78,7 @@ "react-router-dom": "^5.2.0", "react-scroll": "^1.8.2", "redux": "^4.1.0", - "revolt.js": "4.3.3-alpha.6", + "revolt.js": "4.3.3-alpha.7", "rimraf": "^3.0.2", "sass": "^1.35.1", "shade-blend-color": "^1.0.0", diff --git a/src/components/ui/Button.tsx b/src/components/ui/Button.tsx index 9c4b3a2b..8582a193 100644 --- a/src/components/ui/Button.tsx +++ b/src/components/ui/Button.tsx @@ -61,6 +61,7 @@ export default styled.button` &:hover { filter: brightness(1.2); + background: var(--error); } &:disabled { diff --git a/src/components/ui/Checkbox.tsx b/src/components/ui/Checkbox.tsx index 32020bac..bc87c5cc 100644 --- a/src/components/ui/Checkbox.tsx +++ b/src/components/ui/Checkbox.tsx @@ -31,6 +31,15 @@ const CheckboxBase = styled.label` background: var(--background); } } + + &[disabled] { + opacity: 0.5; + cursor: unset; + + &:hover { + background: unset; + } + } `; const CheckboxContent = styled.span` @@ -52,6 +61,7 @@ const Checkmark = styled.div<{ checked: boolean }>` width: 24px; height: 24px; display: grid; + flex-shrink: 0; border-radius: 4px; place-items: center; transition: 0.2s ease all; diff --git a/src/context/intermediate/Intermediate.tsx b/src/context/intermediate/Intermediate.tsx index 89298064..0b2929ae 100644 --- a/src/context/intermediate/Intermediate.tsx +++ b/src/context/intermediate/Intermediate.tsx @@ -31,7 +31,8 @@ export type Screen = { type: "create_channel", target: Servers.Server } )) | ({ id: "special_input" } & ( - { type: "create_group" | "create_server" | "set_custom_status" | "add_friend" } + { type: "create_group" | "create_server" | "set_custom_status" | "add_friend" } | + { type: "create_role", server: string, callback: (id: string) => void } )) | { id: "_input"; diff --git a/src/context/intermediate/modals/Input.tsx b/src/context/intermediate/modals/Input.tsx index f25b9921..d57ba8d8 100644 --- a/src/context/intermediate/modals/Input.tsx +++ b/src/context/intermediate/modals/Input.tsx @@ -68,7 +68,8 @@ export function InputModal({ } type SpecialProps = { onClose: () => void } & ( - { type: "create_group" | "create_server" | "set_custom_status" | "add_friend" } + { type: "create_group" | "create_server" | "set_custom_status" | "add_friend" } | + { type: "create_role", server: string, callback: (id: string) => void } ) export function SpecialInputModal(props: SpecialProps) { @@ -112,6 +113,17 @@ export function SpecialInputModal(props: SpecialProps) { }} />; } + case "create_role": { + return } + field={} + callback={async name => { + const role = await client.servers.createRole(props.server, name); + props.callback(role.id); + }} + />; + } case "set_custom_status": { return arr.map(x => x >>> 0); + // ! FIXME: bad code :) export function Roles({ server }: Props) { - const [ selected, setSelected ] = useState('default'); + const [ role, setRole ] = useState('default'); + const { openScreen } = useIntermediate(); const client = useContext(AppContext); - const roles = server.roles ?? {}; - const keys = [ 'default', ...Object.keys(roles) ]; - const defaultRole = { name: 'Default', permissions: server.default_permissions }; - const selectedRole: Servers.Role = selected === 'default' ? defaultRole : roles[selected]; - - if (!selectedRole) { - useEffect(() => setSelected('default'), [ ]); - return null; + if (role !== 'default' && typeof roles[role] === 'undefined') { + useEffect(() => setRole('default')); + return; } - const [ p, setPerm ] = useState([ - selectedRole.permissions[0] >>> 0, - selectedRole.permissions[1] >>> 0, - ]); + const v = (id: string) => I32ToU32(id === 'default' ? server.default_permissions : roles[id].permissions) + const [ perm, setPerm ] = useState(v(role)); + useEffect(() => setPerm(v(role)), [ role, roles[role]?.permissions ]); - useEffect(() => { - setPerm([ - selectedRole.permissions[0] >>> 0, - selectedRole.permissions[1] >>> 0, - ]); - }, [ selected, selectedRole.permissions ]); - - const [ name, setName ] = useState(''); + const modified = !isEqual(perm, v(role)); + const save = () => client.servers.setPermissions(server._id, role, { server: perm[0], channel: perm[1] }); + const deleteRole = () => { + setRole('default'); + client.servers.deleteRole(server._id, role); + }; return (
- This section is under construction.
-

- { keys +
+

+ + openScreen({ id: 'special_input', type: 'create_role', server: server._id, callback: id => setRole(id) })} /> +
+ { [ 'default', ...Object.keys(roles) ] .map(id => { - let role: Servers.Role = id === 'default' ? defaultRole : roles[id]; - - return ( - selected && setSelected(id)}> - { role.name } - - ) + if (id === 'default') { + return ( + setRole('default')}> + + + ) + } else { + return ( + setRole(id)}> + { roles[id].name } + + ) + } }) } -
- setName(e.currentTarget.value)} /> -
-

{ selectedRole.name }

- { Object.keys(ServerPermission) - .map(perm => { - let value = ServerPermission[perm as keyof typeof ServerPermission]; +
+

{ role === 'default' ? : roles[role].name }

+ +
+
+ + { Object.keys(ServerPermission) + .map(key => { + if (key === 'View') return; + let value = ServerPermission[key as keyof typeof ServerPermission]; - return ( - 0} onChange={c => setPerm([ c ? (p[0] | value) : (p[0] ^ value), p[1] ])}> - { perm } - - ) - }) - } -

channel permmissions

- { Object.keys(ChannelPermission) - .map(perm => { - let value = ChannelPermission[perm as keyof typeof ChannelPermission]; + return ( + 0} + onChange={() => setPerm([ perm[0] ^ value, perm[1] ])} + description={}> + + + ) + }) + } +
+
+ + { Object.keys(ChannelPermission) + .map(key => { + if (key === 'ManageChannel') return; + let value = ChannelPermission[key as keyof typeof ChannelPermission]; - return ( - >> 0) & value) > 0} onChange={c => setPerm([ p[0], c ? (p[1] | value) : (p[1] ^ value) ])}> - { perm } - - ) - }) - } - + return ( + >> 0) & value) > 0} + onChange={() => setPerm([ perm[0], perm[1] ^ value ])} + disabled={key === 'View'} + description={}> + + + ) + }) + } +
+
+ + { role !== 'default' && } +
); diff --git a/yarn.lock b/yarn.lock index 1a95434b..292ec6d8 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3420,10 +3420,10 @@ reusify@^1.0.4: resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76" integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw== -revolt.js@4.3.3-alpha.6: - version "4.3.3-alpha.6" - resolved "https://registry.yarnpkg.com/revolt.js/-/revolt.js-4.3.3-alpha.6.tgz#054e685a5c0dac2c7ae3e2aa454d1965218cb2b0" - integrity sha512-u1/xf+YSQr8DbKsO0raym+F05R75bqYadrPWaIie3m2s2p7ZWeamHlfWIKJlmDO5AL+Lg3xoZWoLwuRHrD1K/Q== +revolt.js@4.3.3-alpha.7: + version "4.3.3-alpha.7" + resolved "https://registry.yarnpkg.com/revolt.js/-/revolt.js-4.3.3-alpha.7.tgz#de6ecef444e8368aac3753761e2e10f516f50712" + integrity sha512-oi76A+EIxrD+tVRTU8s2LISFBpvMf0kpinw5rdukoc1VWpl0bCC6Kko26yC7lhVkWGLTZxHMOKaUkgbOgy0flA== dependencies: "@insertish/mutable" "1.1.0" axios "^0.19.2"