diff --git a/web/components/menu.css b/web/components/menu.css --- a/web/components/menu.css +++ b/web/components/menu.css @@ -42,6 +42,14 @@ top: 24px; } +div.menuActionListRoleActions { + font-size: var(--s-font-14); + background-color: var(--menu-bg-light); + color: var(--menu-color); + stroke: var(--menu-color); + top: 20px; +} + button.menuAction { color: inherit; z-index: 1; diff --git a/web/components/menu.react.js b/web/components/menu.react.js --- a/web/components/menu.react.js +++ b/web/components/menu.react.js @@ -6,7 +6,11 @@ import css from './menu.css'; import { useRenderMenu } from '../menu-provider.react.js'; -type MenuVariant = 'thread-actions' | 'member-actions' | 'community-actions'; +type MenuVariant = + | 'thread-actions' + | 'member-actions' + | 'community-actions' + | 'role-actions'; type MenuProps = { +icon: React.Node, @@ -30,6 +34,7 @@ [css.menuActionListThreadActions]: variant === 'thread-actions', [css.menuActionListMemberActions]: variant === 'member-actions', [css.menuActionListCommunityActions]: variant === 'community-actions', + [css.menuActionListRoleActions]: variant === 'role-actions', }); const menuActionList = React.useMemo( diff --git a/web/roles/community-roles-modal.css b/web/roles/community-roles-modal.css --- a/web/roles/community-roles-modal.css +++ b/web/roles/community-roles-modal.css @@ -17,7 +17,7 @@ } .rolePanelTitle:last-of-type { - margin-right: 32px; + margin-right: 90px; } .separator { diff --git a/web/roles/community-roles-modal.react.js b/web/roles/community-roles-modal.react.js --- a/web/roles/community-roles-modal.react.js +++ b/web/roles/community-roles-modal.react.js @@ -45,6 +45,7 @@ rolePanelEntries.push( , @@ -52,7 +53,7 @@ }); return rolePanelEntries; - }, [roleNamesToMembers]); + }, [roleNamesToMembers, updatedThreadInfo]); const rolePermissionsForNewRole = React.useMemo(() => [], []); diff --git a/web/roles/role-actions-menu.css b/web/roles/role-actions-menu.css new file mode 100644 --- /dev/null +++ b/web/roles/role-actions-menu.css @@ -0,0 +1,4 @@ +.menuContainer { + color: var(--menu-color-light); + width: 10px; +} diff --git a/web/roles/role-actions-menu.react.js b/web/roles/role-actions-menu.react.js new file mode 100644 --- /dev/null +++ b/web/roles/role-actions-menu.react.js @@ -0,0 +1,82 @@ +// @flow + +import * as React from 'react'; + +import SWMansionIcon from 'lib/components/SWMansionIcon.react.js'; +import type { ThreadInfo } from 'lib/types/thread-types.js'; + +import css from './role-actions-menu.css'; +import MenuItem from '../components/menu-item.react.js'; +import Menu from '../components/menu.react.js'; + +const menuIcon = ; + +type RoleActionsMenuProps = { + +threadInfo: ThreadInfo, + +roleName: string, +}; + +function RoleActionsMenu(props: RoleActionsMenuProps): React.Node { + const { threadInfo, roleName } = props; + + const defaultRoleID = Object.keys(threadInfo.roles).find( + roleID => threadInfo.roles[roleID].isDefault, + ); + const existingRoleID = Object.keys(threadInfo.roles).find( + roleID => threadInfo.roles[roleID].name === roleName, + ); + + const isDeletableRole = + roleName !== 'Admins' && defaultRoleID !== existingRoleID; + const isEditableRole = roleName !== 'Admins'; + + const openEditRoleModal = React.useCallback(() => {}, []); + const openDeleteRoleModal = React.useCallback(() => {}, []); + + const items = React.useMemo(() => { + const availableOptions = []; + + if (isEditableRole) { + availableOptions.push({ + text: 'Edit role', + icon: 'edit-1', + onClick: openEditRoleModal, + dangerous: false, + }); + } + + if (isDeletableRole) { + availableOptions.push({ + text: 'Delete role', + icon: 'cross-circle', + onClick: openDeleteRoleModal, + dangerous: true, + }); + } + return availableOptions; + }, [isDeletableRole, isEditableRole, openDeleteRoleModal, openEditRoleModal]); + + const roleMenuItems = React.useMemo( + () => + items.map(item => ( + + )), + [items], + ); + + return ( +
+ + {roleMenuItems} + +
+ ); +} + +export default RoleActionsMenu; diff --git a/web/roles/role-panel-entry.css b/web/roles/role-panel-entry.css --- a/web/roles/role-panel-entry.css +++ b/web/roles/role-panel-entry.css @@ -1,7 +1,5 @@ .rolePanelEntry { - display: flex; - flex-direction: row; - justify-content: space-between; + display: grid; align-items: center; padding: 12px; color: var(--community-roles-text-color); @@ -13,9 +11,16 @@ } .rolePanelCountEntryContainer { - margin-right: 40px; display: flex; - align-items: flex-end; + align-items: center; + justify-content: flex-end; + grid-column: 3; +} + +.rolePanelCountAndIcon { + display: flex; + align-items: center; + margin-right: 90px; } .rolePanelCountEntry { diff --git a/web/roles/role-panel-entry.react.js b/web/roles/role-panel-entry.react.js --- a/web/roles/role-panel-entry.react.js +++ b/web/roles/role-panel-entry.react.js @@ -2,22 +2,29 @@ import * as React from 'react'; +import type { ThreadInfo } from 'lib/types/thread-types.js'; + +import RoleActionsMenu from './role-actions-menu.react.js'; import css from './role-panel-entry.css'; import CommIcon from '../CommIcon.react.js'; type RolePanelEntryProps = { + +threadInfo: ThreadInfo, +roleName: string, +memberCount: number, }; function RolePanelEntry(props: RolePanelEntryProps): React.Node { - const { roleName, memberCount } = props; + const { threadInfo, roleName, memberCount } = props; return (
{roleName}
-
{memberCount}
- +
+
{memberCount}
+ +
+
);