diff --git a/packages/design-system/molecules/editor-category/EditorCategory.styled.ts b/packages/design-system/molecules/editor-category/EditorCategory.styled.ts index e6bfd40..b8e9c31 100644 --- a/packages/design-system/molecules/editor-category/EditorCategory.styled.ts +++ b/packages/design-system/molecules/editor-category/EditorCategory.styled.ts @@ -45,17 +45,17 @@ export const RoleContainer = styled.div` } `; -export const AddRoleButton = styled.div` +export const AddRoleButton = styled.div<{ long?: boolean }>` border: 2px solid ${palette.taupe500}; color: ${palette.taupe500}; border-radius: 24px; - width: 32px; height: 32px; display: flex; align-items: center; justify-content: center; cursor: pointer; transition: all ${transitions.actionable}s ease-in-out; + &:hover { background-color: ${palette.taupe100}; transform: translateY(-2px); @@ -66,4 +66,13 @@ export const AddRoleButton = styled.div` transform: translateY(0); box-shadow: none; } + + ${(props) => + props.long + ? css` + padding: 0 14px; + ` + : css` + width: 32px; + `}; `; diff --git a/packages/design-system/molecules/editor-category/EditorCategory.tsx b/packages/design-system/molecules/editor-category/EditorCategory.tsx index fb5ec58..d6485ad 100644 --- a/packages/design-system/molecules/editor-category/EditorCategory.tsx +++ b/packages/design-system/molecules/editor-category/EditorCategory.tsx @@ -1,9 +1,11 @@ +import { Popover } from '@roleypoly/design-system/atoms/popover'; import { Role } from '@roleypoly/design-system/atoms/role'; import { TextInput } from '@roleypoly/design-system/atoms/text-input'; import { Toggle } from '@roleypoly/design-system/atoms/toggle'; import { Text } from '@roleypoly/design-system/atoms/typography'; +import { RoleSearch } from '@roleypoly/design-system/molecules/role-search'; import { Category as CategoryT, CategoryType, Role as RoleT } from '@roleypoly/types'; -import { sortBy } from 'lodash'; +import { sortBy, uniq } from 'lodash'; import * as React from 'react'; import { GoPlus } from 'react-icons/go'; import ReactTooltip from 'react-tooltip'; @@ -13,10 +15,13 @@ export type CategoryProps = { title: string; roles: RoleT[]; category: CategoryT; + unselectedRoles: RoleT[]; onChange: (updatedCategory: CategoryT) => void; }; export const EditorCategory = (props: CategoryProps) => { + const [searchOpen, setSearchOpen] = React.useState(false); + const updateValue = (key: T, value: CategoryT[T]) => { props.onChange({ ...props.category, [key]: value }); }; @@ -26,6 +31,16 @@ export const EditorCategory = (props: CategoryProps) => { updateValue('roles', updatedRoles); }; + const handleRoleAdd = (role: RoleT) => { + const updatedRoles = uniq([...props.category.roles, role.id]); + updateValue('roles', updatedRoles); + setSearchOpen(false); + }; + + const handleSearchOpen = () => { + setSearchOpen(true); + }; + return (
@@ -65,21 +80,32 @@ export const EditorCategory = (props: CategoryProps) => { Roles - {sortBy(props.roles, 'position').map((role) => ( - 0 ? ( + <> + {sortBy(props.roles, 'position').map((role) => ( + + ))} + + + ) : ( + - ))} - - - + )} + setSearchOpen(false)} + unselectedRoles={props.unselectedRoles} + onSelect={handleRoleAdd} + />
@@ -87,3 +113,47 @@ export const EditorCategory = (props: CategoryProps) => {
); }; + +const RoleAddButton = (props: { + onClick: () => void; + tooltipId: string; + long?: boolean; +}) => ( + + {props.long && <>Add a role  } + + +); + +const RoleSearchPopover = (props: { + onSelect: (role: RoleT) => void; + onExit: (type: string) => void; + isOpen: boolean; + unselectedRoles: RoleT[]; +}) => { + const [searchTerm, setSearchTerm] = React.useState(''); + + return ( + + {() => ( + + )} + + ); +}; diff --git a/packages/design-system/organisms/editor-shell/EditorShell.tsx b/packages/design-system/organisms/editor-shell/EditorShell.tsx index c47ea3b..e8e0dd5 100644 --- a/packages/design-system/organisms/editor-shell/EditorShell.tsx +++ b/packages/design-system/organisms/editor-shell/EditorShell.tsx @@ -17,7 +17,6 @@ export type EditorShellProps = { export const EditorShell = (props: EditorShellProps) => { const [guild, setGuild] = React.useState(props.guild); - const [reorderMode, setReorderMode] = React.useState(false); React.useEffect(() => { setGuild(props.guild); @@ -43,10 +42,10 @@ export const EditorShell = (props: EditorShellProps) => { props.onGuildChange?.(guild); }; - const hasChanges = React.useMemo( - () => !deepEqual(guild.data, props.guild.data), - [guild.data, props.guild.data] - ); + const hasChanges = React.useMemo(() => !deepEqual(guild.data, props.guild.data), [ + guild.data, + props.guild.data, + ]); return ( <> diff --git a/packages/design-system/organisms/server-category-editor/ServerCategoryEditor.tsx b/packages/design-system/organisms/server-category-editor/ServerCategoryEditor.tsx index 5271852..c476828 100644 --- a/packages/design-system/organisms/server-category-editor/ServerCategoryEditor.tsx +++ b/packages/design-system/organisms/server-category-editor/ServerCategoryEditor.tsx @@ -6,7 +6,7 @@ import { EditorCategory } from '@roleypoly/design-system/molecules/editor-catego import { CategoryContainer } from '@roleypoly/design-system/organisms/role-picker/RolePicker.styled'; import { Category, CategoryType, PresentableGuild, Role } from '@roleypoly/types'; import KSUID from 'ksuid'; -import { sortBy } from 'lodash'; +import { flatten, sortBy } from 'lodash'; import React from 'react'; import { DragDropContext, Draggable, Droppable, DropResult } from 'react-beautiful-dnd'; import { CgReorder } from 'react-icons/cg'; @@ -31,6 +31,11 @@ const forceOrder = (categories: Category[]) => export const ServerCategoryEditor = (props: Props) => { const [reorderMode, setReorderMode] = React.useState(false); + const unselectedRoles = React.useMemo(() => { + const selectedRoles = flatten(props.guild.data.categories.map((c) => c.roles)); + return props.guild.roles.filter((r) => !selectedRoles.includes(r.id)); + }, [props.guild.data.categories, props.guild.roles]); + const updateSingleCategory = (category: Category) => { const newCategories = props.guild.data.categories.map((c) => { if (c.id === category.id) { @@ -85,6 +90,7 @@ export const ServerCategoryEditor = (props: Props) => { props.guild.roles.find((r) => r.id === role)) diff --git a/packages/design-system/package.json b/packages/design-system/package.json index 7b0cc41..4f8d3e2 100644 --- a/packages/design-system/package.json +++ b/packages/design-system/package.json @@ -19,6 +19,7 @@ "react-helmet": "^6.1.0", "react-icons": "^4.2.0", "react-is": "^17.0.2", + "react-tiny-popover": "^6.0.5", "react-tooltip": "^4.2.21", "styled-components": "^5.3.0", "styled-normalize": "^8.0.7" diff --git a/yarn.lock b/yarn.lock index 13c70f7..750ae03 100644 --- a/yarn.lock +++ b/yarn.lock @@ -14183,6 +14183,11 @@ react-textarea-autosize@^8.3.0: use-composed-ref "^1.0.0" use-latest "^1.0.0" +react-tiny-popover@^6.0.5: + version "6.0.5" + resolved "https://registry.yarnpkg.com/react-tiny-popover/-/react-tiny-popover-6.0.5.tgz#2d5eb21d8a2758396ffa5bf5b761baac87dd6297" + integrity sha512-na6ZghMy5kqTPFSATb1pdSHO+/MikZvUxNk+zjXlz+gMXgiaOVuik5AiC5Oyj4yHpPf0nxoOmVQOmOmuDob6+A== + react-tooltip@^4.2.21: version "4.2.21" resolved "https://registry.yarnpkg.com/react-tooltip/-/react-tooltip-4.2.21.tgz#840123ed86cf33d50ddde8ec8813b2960bfded7f"