From ab3f718e6de0675f0b6c5dda745dd4135bd47041 Mon Sep 17 00:00:00 2001 From: Katalina Date: Thu, 8 Jul 2021 16:51:00 -0500 Subject: [PATCH] Feat/editor as preview (#294) * try editor as preview * add databinding for editor actions and message * add actions, reordering base interactions * add drag and drop ordering for categoriers * category skeleton * fix linting issues * add role list and add button, non-functional * bump packages * add role search prototype * yarn.lock sync * fix lint * remove cfw-emulator bin --- package.json | 8 +- packages/api/index.ts | 2 + packages/backend-emulator/package.json | 3 - .../atoms/breakpoints/BreakpointText.tsx | 26 + .../design-system/atoms/breakpoints/index.ts | 1 + .../atoms/button/Button.styled.ts | 7 + .../atoms/text-input/TextInput.tsx | 17 +- .../atoms/toggle/Toggle.styled.tsx | 6 +- .../EditableServerMessage.stories.tsx | 26 + .../EditableServerMessage.tsx | 37 + .../editable-server-message/index.ts | 1 + .../EditorCategoryShort.spec.tsx | 12 - .../EditorCategoryShort.stories.tsx | 30 - .../EditorCategoryShort.styled.ts | 60 -- .../EditorCategoryShort.tsx | 31 - .../molecules/editor-category-short/index.ts | 1 - .../EditorCategory.stories.tsx | 35 +- .../editor-category/EditorCategory.styled.ts | 77 +- .../editor-category/EditorCategory.tsx | 261 +++---- .../molecules/editor-category/index.ts | 2 +- .../organisms/app-shell/AppShell.styled.tsx | 4 +- .../organisms/app-shell/AppShell.tsx | 5 +- .../EditorCategoriesTab.stories.tsx | 12 - .../EditorCategoriesTab.styled.ts | 8 - .../EditorCategoriesTab.tsx | 39 - .../organisms/editor-categories-tab/index.ts | 1 - .../editor-details-tab/EditorDetailsTab.tsx | 20 - .../organisms/editor-details-tab/index.ts | 1 - .../editor-shell/EditorShell.stories.tsx | 10 +- .../organisms/editor-shell/EditorShell.tsx | 76 +- .../organisms/masthead/Masthead.stories.tsx | 13 + .../organisms/masthead/Masthead.styled.tsx | 26 + .../organisms/masthead/Secondary.tsx | 46 ++ .../design-system/organisms/masthead/index.ts | 1 + .../ServerCategoryEditor.styled.ts | 49 ++ .../ServerCategoryEditor.tsx | 203 ++++++ .../organisms/server-category-editor/index.ts | 1 + packages/design-system/package.json | 28 +- .../templates/editor/Editor.stories.tsx | 10 + .../design-system/templates/editor/Editor.tsx | 2 +- packages/web/package.json | 16 +- packages/web/src/pages/editor.tsx | 4 +- yarn.lock | 680 ++++++++++-------- 43 files changed, 1157 insertions(+), 741 deletions(-) create mode 100644 packages/design-system/atoms/breakpoints/BreakpointText.tsx create mode 100644 packages/design-system/molecules/editable-server-message/EditableServerMessage.stories.tsx create mode 100644 packages/design-system/molecules/editable-server-message/EditableServerMessage.tsx create mode 100644 packages/design-system/molecules/editable-server-message/index.ts delete mode 100644 packages/design-system/molecules/editor-category-short/EditorCategoryShort.spec.tsx delete mode 100644 packages/design-system/molecules/editor-category-short/EditorCategoryShort.stories.tsx delete mode 100644 packages/design-system/molecules/editor-category-short/EditorCategoryShort.styled.ts delete mode 100644 packages/design-system/molecules/editor-category-short/EditorCategoryShort.tsx delete mode 100644 packages/design-system/molecules/editor-category-short/index.ts delete mode 100644 packages/design-system/organisms/editor-categories-tab/EditorCategoriesTab.stories.tsx delete mode 100644 packages/design-system/organisms/editor-categories-tab/EditorCategoriesTab.styled.ts delete mode 100644 packages/design-system/organisms/editor-categories-tab/EditorCategoriesTab.tsx delete mode 100644 packages/design-system/organisms/editor-categories-tab/index.ts delete mode 100644 packages/design-system/organisms/editor-details-tab/EditorDetailsTab.tsx delete mode 100644 packages/design-system/organisms/editor-details-tab/index.ts create mode 100644 packages/design-system/organisms/masthead/Secondary.tsx create mode 100644 packages/design-system/organisms/server-category-editor/ServerCategoryEditor.styled.ts create mode 100644 packages/design-system/organisms/server-category-editor/ServerCategoryEditor.tsx create mode 100644 packages/design-system/organisms/server-category-editor/index.ts diff --git a/package.json b/package.json index f3b1f86..6f369ce 100644 --- a/package.json +++ b/package.json @@ -36,12 +36,12 @@ "test": "jest" }, "devDependencies": { - "@types/enzyme": "^3.10.8", - "@types/lodash": "^4.14.170", + "@types/enzyme": "^3.10.9", + "@types/lodash": "^4.14.171", "@wojtekmaj/enzyme-adapter-react-17": "^0.6.2", "enzyme": "^3.11.0", "enzyme-adapter-react-16": "^1.15.6", - "husky": "^6.0.0", + "husky": "^7.0.1", "is-ci": "^3.0.0", "jest": "26.6.0", "jest-enzyme": "^7.1.2", @@ -59,7 +59,7 @@ "stylelint-config-styled-components": "^0.1.1", "stylelint-prettier": "^1.2.0", "ts-jest": "^26.0.0", - "typescript": "^4.3.4" + "typescript": "^4.3.5" }, "resolutions": { "webpack": "4.44.2" diff --git a/packages/api/index.ts b/packages/api/index.ts index b0669da..36e40f0 100644 --- a/packages/api/index.ts +++ b/packages/api/index.ts @@ -8,6 +8,7 @@ import { LoginBounce } from './handlers/login-bounce'; import { LoginCallback } from './handlers/login-callback'; import { RevokeSession } from './handlers/revoke-session'; import { SyncFromLegacy } from './handlers/sync-from-legacy'; +import { UpdateGuild } from './handlers/update-guild'; import { UpdateRoles } from './handlers/update-roles'; import { Router } from './router'; import { respond } from './utils/api-tools'; @@ -28,6 +29,7 @@ router.add('POST', 'revoke-session', RevokeSession); router.add('GET', 'get-slug', GetSlug); router.add('GET', 'get-picker-data', GetPickerData); router.add('PATCH', 'update-roles', UpdateRoles); +router.add('PATCH', 'update-guild', UpdateGuild); router.add('POST', 'sync-from-legacy', SyncFromLegacy); router.add('POST', 'clear-guild-cache', ClearGuildCache); diff --git a/packages/backend-emulator/package.json b/packages/backend-emulator/package.json index 0e7e59e..7c81e71 100644 --- a/packages/backend-emulator/package.json +++ b/packages/backend-emulator/package.json @@ -1,9 +1,6 @@ { "name": "@roleypoly/worker-emulator", "version": "0.1.0", - "bin": { - "cfw-emulator": "./main.js" - }, "scripts": { "build": "node main.js --build", "start": "node main.js" diff --git a/packages/design-system/atoms/breakpoints/BreakpointText.tsx b/packages/design-system/atoms/breakpoints/BreakpointText.tsx new file mode 100644 index 0000000..a04a01b --- /dev/null +++ b/packages/design-system/atoms/breakpoints/BreakpointText.tsx @@ -0,0 +1,26 @@ +import styled, { css } from 'styled-components'; +import { onSmallScreen } from './Breakpoints'; + +const ShowOnSmall = styled.span` + display: none; + ${onSmallScreen(css` + display: initial; + `)} +`; + +const ShowOnLarge = styled.span` + display: initial; + ${onSmallScreen(css` + display: none; + `)} +`; + +export const BreakpointText = (props: { small: string; large: string }) => { + const { small, large } = props; + return ( + <> + {small} + {large} + + ); +}; diff --git a/packages/design-system/atoms/breakpoints/index.ts b/packages/design-system/atoms/breakpoints/index.ts index d72bd04..fea0bcd 100644 --- a/packages/design-system/atoms/breakpoints/index.ts +++ b/packages/design-system/atoms/breakpoints/index.ts @@ -1,3 +1,4 @@ export * from './BreakpointProvider'; export * from './Breakpoints'; +export * from './BreakpointText'; export * from './Context'; diff --git a/packages/design-system/atoms/button/Button.styled.ts b/packages/design-system/atoms/button/Button.styled.ts index 26d3247..49819ea 100644 --- a/packages/design-system/atoms/button/Button.styled.ts +++ b/packages/design-system/atoms/button/Button.styled.ts @@ -67,6 +67,13 @@ const colors = { background-color: ${palette.taupe200}; } `, + silent: css` + background: none; + border-color: transparent; + :hover { + background-color: ${palette.taupe200}; + } + `, }; const sizes = { diff --git a/packages/design-system/atoms/text-input/TextInput.tsx b/packages/design-system/atoms/text-input/TextInput.tsx index 2abf17c..9bfbec3 100644 --- a/packages/design-system/atoms/text-input/TextInput.tsx +++ b/packages/design-system/atoms/text-input/TextInput.tsx @@ -94,18 +94,27 @@ const StyledTextarea = styled.textarea` export const MultilineTextInput = ( props: TextInputProps & { rows?: number } ) => { - const { ...rest } = props; + const { children, ...rest } = props; const [value, setValue] = React.useState(String(props.value)); - const rows = Math.min(10, Math.max(props.rows || 2, value.split(/\r?\n/).length)); + const rows = React.useMemo( + () => Math.min(10, Math.max(props.rows || 2, value.split(/\r?\n/).length)), + [value] + ); + + React.useEffect(() => { + setValue(String(props.value)); + }, [props.value]); + return ( { setValue(eventData.target.value); props.onChange?.(eventData); }} - /> + > + {value} + ); }; diff --git a/packages/design-system/atoms/toggle/Toggle.styled.tsx b/packages/design-system/atoms/toggle/Toggle.styled.tsx index d4df415..8342f58 100644 --- a/packages/design-system/atoms/toggle/Toggle.styled.tsx +++ b/packages/design-system/atoms/toggle/Toggle.styled.tsx @@ -20,9 +20,9 @@ export const ToggleState = styled.div` export const ToggleSwitch = styled.div<{ state: boolean }>` display: inline-block; background-color: ${(props) => (props.state ? palette.green200 : 'rgba(0,0,0,0.45)')}; - height: 1.3em; - width: 2.6em; - border-radius: 1.3em; + height: 1.375rem; + width: 2.675rem; + border-radius: 1.375rem; position: relative; border: 1px solid rgba(0, 0, 0, 0.1); top: 0.23em; diff --git a/packages/design-system/molecules/editable-server-message/EditableServerMessage.stories.tsx b/packages/design-system/molecules/editable-server-message/EditableServerMessage.stories.tsx new file mode 100644 index 0000000..aa1fa0f --- /dev/null +++ b/packages/design-system/molecules/editable-server-message/EditableServerMessage.stories.tsx @@ -0,0 +1,26 @@ +import * as React from 'react'; +import { mastheadSlugs } from '../../fixtures/storyData'; +import { EditableServerMessage } from './EditableServerMessage'; +export default { + title: 'Molecules/Editable Server Message', + component: EditableServerMessage, + args: { + value: 'Hello World', + guild: mastheadSlugs[1], + }, +}; + +export const editableServerMessage = (args) => { + const [value, setValue] = React.useState(args.value); + React.useEffect(() => { + setValue(args.value); + }, [args.value]); + + return ( + setValue(message)} + /> + ); +}; diff --git a/packages/design-system/molecules/editable-server-message/EditableServerMessage.tsx b/packages/design-system/molecules/editable-server-message/EditableServerMessage.tsx new file mode 100644 index 0000000..40cbb20 --- /dev/null +++ b/packages/design-system/molecules/editable-server-message/EditableServerMessage.tsx @@ -0,0 +1,37 @@ +import { palette } from '@roleypoly/design-system/atoms/colors'; +import { FaderOpacity } from '@roleypoly/design-system/atoms/fader'; +import { MultilineTextInput } from '@roleypoly/design-system/atoms/text-input'; +import { + AmbientLarge, + Text as TextTypo, +} from '@roleypoly/design-system/atoms/typography'; +import { MessageBox } from '@roleypoly/design-system/organisms/role-picker/RolePicker.styled'; +import { GuildSlug } from '@roleypoly/types'; +import { GoEyeClosed } from 'react-icons/go'; + +type Props = { + guild: GuildSlug; + onChange: (newMessage: string) => void; + value: string; +}; + +export const EditableServerMessage = (props: Props) => ( + + Server Message + props.onChange(event.target.value)} + placeholder={`Hey friend from ${props.guild.name}! Pick your roles!`} + > + {props.value} + + + Shows a message to your server members. + +  Since the message is empty, this won't show up.    + + + + +); diff --git a/packages/design-system/molecules/editable-server-message/index.ts b/packages/design-system/molecules/editable-server-message/index.ts new file mode 100644 index 0000000..ba5bfc9 --- /dev/null +++ b/packages/design-system/molecules/editable-server-message/index.ts @@ -0,0 +1 @@ +export * from './EditableServerMessage'; diff --git a/packages/design-system/molecules/editor-category-short/EditorCategoryShort.spec.tsx b/packages/design-system/molecules/editor-category-short/EditorCategoryShort.spec.tsx deleted file mode 100644 index e6c6cf7..0000000 --- a/packages/design-system/molecules/editor-category-short/EditorCategoryShort.spec.tsx +++ /dev/null @@ -1,12 +0,0 @@ -import { mockCategory } from '@roleypoly/design-system/fixtures/storyData'; -import { render } from '@testing-library/react'; -import { EditorCategoryShort } from './EditorCategoryShort'; - -it('triggers onOpen when clicked', async () => { - const onOpen = jest.fn(); - const view = render(); - - view.getByRole('menuitem')?.click(); - - expect(onOpen).toHaveBeenCalled(); -}); diff --git a/packages/design-system/molecules/editor-category-short/EditorCategoryShort.stories.tsx b/packages/design-system/molecules/editor-category-short/EditorCategoryShort.stories.tsx deleted file mode 100644 index bc2b0a5..0000000 --- a/packages/design-system/molecules/editor-category-short/EditorCategoryShort.stories.tsx +++ /dev/null @@ -1,30 +0,0 @@ -import { mockCategory } from '@roleypoly/design-system/fixtures/storyData'; -import ReactTooltip from 'react-tooltip'; -import styled from 'styled-components'; -import { EditorCategoryShort } from './EditorCategoryShort'; - -const decorator = (story) => ( - - {story()} - - -); - -export default { - title: 'Molecules/Short Category', - component: EditorCategoryShort, - args: { - category: mockCategory, - }, - decorators: [decorator], -}; - -const Wrapper = styled.div` - box-shadow: 0 0 10px #000; -`; - -export const shortEditor = (args) => ; -export const shortEditorHidden = (args) => ; -shortEditorHidden.args = { - category: { ...mockCategory, hidden: true }, -}; diff --git a/packages/design-system/molecules/editor-category-short/EditorCategoryShort.styled.ts b/packages/design-system/molecules/editor-category-short/EditorCategoryShort.styled.ts deleted file mode 100644 index 2b9c2a0..0000000 --- a/packages/design-system/molecules/editor-category-short/EditorCategoryShort.styled.ts +++ /dev/null @@ -1,60 +0,0 @@ -import { transitions } from '@roleypoly/design-system/atoms/timings'; -import styled from 'styled-components'; - -export const GrabberBox = styled.div` - display: flex; - align-items: center; - justify-content: center; - margin-right: 1em; - flex: 0; - cursor: grab; - position: relative; - - ::before { - content: ''; - position: absolute; - top: -5px; - left: -8px; - width: 32px; - height: 32px; - background-color: rgba(0, 0, 0, 0.25); - opacity: 0; - border-radius: 50%; - transition: opacity ${transitions.actionable}s ease-in-out; - } - - &:hover { - ::before { - opacity: 1; - } - } -`; - -export const Opener = styled.div` - opacity: 0; - transition: opacity ${transitions.actionable}s ease-in-out; -`; - -export const Container = styled.div` - display: flex; - padding: 1em; - cursor: pointer; - - &:hover { - ${Opener} { - opacity: 1; - } - } -`; - -export const Name = styled.div` - position: relative; - top: -2px; - margin-right: 1em; -`; - -export const Flags = styled.div``; - -export const Void = styled.div` - flex: 1; -`; diff --git a/packages/design-system/molecules/editor-category-short/EditorCategoryShort.tsx b/packages/design-system/molecules/editor-category-short/EditorCategoryShort.tsx deleted file mode 100644 index 67f1712..0000000 --- a/packages/design-system/molecules/editor-category-short/EditorCategoryShort.tsx +++ /dev/null @@ -1,31 +0,0 @@ -import { Category } from '@roleypoly/types'; -import { DragEventHandler, MouseEventHandler } from 'react'; -import { GoEyeClosed, GoGrabber, GoKebabHorizontal } from 'react-icons/go'; -import { - Container, - Flags, - GrabberBox, - Name, - Opener, - Void, -} from './EditorCategoryShort.styled'; - -type ShortProps = { - category: Category; - onDrag?: DragEventHandler; - onOpen?: MouseEventHandler; -}; - -export const EditorCategoryShort = (props: ShortProps) => ( - - - - - {props.category.name} - {props.category.hidden && } - - - - - -); diff --git a/packages/design-system/molecules/editor-category-short/index.ts b/packages/design-system/molecules/editor-category-short/index.ts deleted file mode 100644 index 0840f96..0000000 --- a/packages/design-system/molecules/editor-category-short/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from './EditorCategoryShort'; diff --git a/packages/design-system/molecules/editor-category/EditorCategory.stories.tsx b/packages/design-system/molecules/editor-category/EditorCategory.stories.tsx index 332c913..e7f2156 100644 --- a/packages/design-system/molecules/editor-category/EditorCategory.stories.tsx +++ b/packages/design-system/molecules/editor-category/EditorCategory.stories.tsx @@ -1,19 +1,30 @@ import * as React from 'react'; -import { mockCategory, roleCategory, roleCategory2 } from '../../fixtures/storyData'; +import { mockCategory, roleCategory } from '../../fixtures/storyData'; import { EditorCategory } from './EditorCategory'; export default { - title: 'Molecules/Editor/Category', + title: 'Molecules/Editor Category', + component: EditorCategory, + args: { + title: 'Pronouns', + roles: roleCategory, + category: mockCategory, + selectedRoles: [], + }, }; -export const CategoryEditor = () => { - const [categoryData, setCategoryData] = React.useState(mockCategory); - return ( - setCategoryData(category)} - uncategorizedRoles={roleCategory} - guildRoles={[...roleCategory, ...roleCategory2]} - /> - ); +export const Default = (args) => { + return ; +}; +export const Single = (args) => { + return ; +}; +Single.args = { + type: 'single', +}; +export const Multi = (args) => { + return ; +}; +Multi.args = { + type: 'multi', }; diff --git a/packages/design-system/molecules/editor-category/EditorCategory.styled.ts b/packages/design-system/molecules/editor-category/EditorCategory.styled.ts index b3cf806..b8e9c31 100644 --- a/packages/design-system/molecules/editor-category/EditorCategory.styled.ts +++ b/packages/design-system/molecules/editor-category/EditorCategory.styled.ts @@ -1,13 +1,78 @@ -import styled from 'styled-components'; +import { onSmallScreen } from '@roleypoly/design-system/atoms/breakpoints'; +import { palette } from '@roleypoly/design-system/atoms/colors'; +import { transitions } from '@roleypoly/design-system/atoms/timings'; +import styled, { css } from 'styled-components'; + +export const Head = styled.div` + margin: 7px 5px; + line-height: 200%; + display: flex; + align-items: center; + justify-content: space-between; +`; + +export const HeadTitle = styled.div` + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; +`; + +export const HeadSub = styled.div` + flex-shrink: 0; + margin-top: -4px; +`; + +export const Box = styled.div` + display: flex; + align-items: top; + justify-content: space-between; + flex-wrap: wrap; +`; + +export const Section = styled.div<{ big?: boolean }>` + padding: 7px 5px; + flex: 1 2 ${(props) => (props.big ? '100%' : '50%')}; + ${onSmallScreen(css` + flex-basis: 100%; + `)} +`; export const RoleContainer = styled.div` display: flex; - margin: 10px; flex-wrap: wrap; - & > div { - /* This should be a Role element */ - border: 1px solid rgba(0, 0, 0, 0.15); - margin: 1px; + margin: 2.5px; } `; + +export const AddRoleButton = styled.div<{ long?: boolean }>` + border: 2px solid ${palette.taupe500}; + color: ${palette.taupe500}; + border-radius: 24px; + 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); + box-shadow: 0 1px 1px rgba(0, 0, 0, 0.1); + } + + &:active { + 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 57787ef..d6485ad 100644 --- a/packages/design-system/molecules/editor-category/EditorCategory.tsx +++ b/packages/design-system/molecules/editor-category/EditorCategory.tsx @@ -1,142 +1,159 @@ -import { FaderOpacity } from '@roleypoly/design-system/atoms/fader'; import { Popover } from '@roleypoly/design-system/atoms/popover'; import { Role } from '@roleypoly/design-system/atoms/role'; -import { Space } from '@roleypoly/design-system/atoms/space'; -import { TextInput, TextInputWithIcon } from '@roleypoly/design-system/atoms/text-input'; +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, CategoryType, Role as RoleType } from '@roleypoly/types'; +import { Category as CategoryT, CategoryType, Role as RoleT } from '@roleypoly/types'; +import { sortBy, uniq } from 'lodash'; import * as React from 'react'; -import { GoSearch } from 'react-icons/go'; -import { RoleContainer } from './EditorCategory.styled'; +import { GoPlus } from 'react-icons/go'; +import ReactTooltip from 'react-tooltip'; +import { AddRoleButton, Box, RoleContainer, Section } from './EditorCategory.styled'; -type Props = { - category: Category; - uncategorizedRoles: RoleType[]; - guildRoles: RoleType[]; - onChange: (category: Category) => void; +export type CategoryProps = { + title: string; + roles: RoleT[]; + category: CategoryT; + unselectedRoles: RoleT[]; + onChange: (updatedCategory: CategoryT) => void; }; -const typeEnumToSwitch = (typeData: CategoryType) => { - if (typeData === CategoryType.Single) { - return 'Single'; - } else { - return 'Multiple'; - } -}; +export const EditorCategory = (props: CategoryProps) => { + const [searchOpen, setSearchOpen] = React.useState(false); -const switchToTypeEnum = (typeData: 'Single' | 'Multiple') => { - if (typeData === 'Single') { - return CategoryType.Single; - } else { - return CategoryType.Multi; - } -}; - -export const EditorCategory = (props: Props) => { - const [roleSearchPopoverActive, setRoleSearchPopoverActive] = React.useState(false); - const [roleSearchTerm, updateSearchTerm] = React.useState(''); - - const onUpdate = - (key: keyof typeof props.category, pred?: (newValue: any) => any) => - (newValue: any) => { - props.onChange({ - ...props.category, - [key]: pred ? pred(newValue) : newValue, - }); - }; - - const handleRoleSelect = (role: RoleType) => { - setRoleSearchPopoverActive(false); - updateSearchTerm(''); - props.onChange({ - ...props.category, - roles: [...props.category.roles, role.id], - }); + const updateValue = (key: T, value: CategoryT[T]) => { + props.onChange({ ...props.category, [key]: value }); }; - const handleRoleDeselect = (role: RoleType) => () => { - props.onChange({ - ...props.category, - roles: props.category.roles.filter((x) => x !== role.id), - }); + const handleRoleDelete = (role: RoleT) => () => { + const updatedRoles = props.category.roles.filter((r) => r !== role.id); + 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 ( -
- Category Name - x.target.value)} - /> - - - -
- - x ? CategoryType.Multi : CategoryType.Single - )} - > - Allow users to pick multiple roles - -
- - -
- - Hide category from users - -
- - - Roles - setRoleSearchPopoverActive(false)} - > - {() => ( - updateSearchTerm(newTerm)} - /> - )} - - - } - placeholder={'Type or drag a role...'} - onFocus={() => setRoleSearchPopoverActive(true)} - value={roleSearchTerm} - onChange={(x) => updateSearchTerm(x.target.value)} + +
+
+ Category Name +
+ updateValue('name', event.target.value)} /> - - {props.category.roles.map((id) => { - const role = props.guildRoles.find((x) => x.id === id); - if (!role) { - return <>; - } +
- return ( - - ); - })} +
+
+ Options +
+
+ updateValue('hidden', value)} + > + Show this category to members + + + updateValue('type', value ? CategoryType.Multi : CategoryType.Single) + } + > + Let members pick more than one role + +
+
+ +
+
+ Roles +
+ + {props.roles.length > 0 ? ( + <> + {sortBy(props.roles, 'position').map((role) => ( + + ))} + + + ) : ( + + )} + setSearchOpen(false)} + unselectedRoles={props.unselectedRoles} + onSelect={handleRoleAdd} + /> - -
+ + + + + ); +}; + +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/molecules/editor-category/index.ts b/packages/design-system/molecules/editor-category/index.ts index 67c2556..f50a935 100644 --- a/packages/design-system/molecules/editor-category/index.ts +++ b/packages/design-system/molecules/editor-category/index.ts @@ -1 +1 @@ -export * from './EditorCategory'; +export { EditorCategory } from './EditorCategory'; diff --git a/packages/design-system/organisms/app-shell/AppShell.styled.tsx b/packages/design-system/organisms/app-shell/AppShell.styled.tsx index 9ff0c68..bc0b6bb 100644 --- a/packages/design-system/organisms/app-shell/AppShell.styled.tsx +++ b/packages/design-system/organisms/app-shell/AppShell.styled.tsx @@ -2,9 +2,9 @@ import { palette } from '@roleypoly/design-system/atoms/colors'; import { fontCSS } from '@roleypoly/design-system/atoms/fonts'; import styled, { createGlobalStyle } from 'styled-components'; -export const Content = styled.div<{ small?: boolean }>` +export const Content = styled.div<{ small?: boolean; double?: boolean }>` margin: 0 auto; - margin-top: 50px; + margin-top: ${(props) => (props.double ? '100px' : '50px')}; width: ${(props) => (props.small ? '960px' : '1024px')}; max-width: 98vw; max-height: calc(100vh - 50px); diff --git a/packages/design-system/organisms/app-shell/AppShell.tsx b/packages/design-system/organisms/app-shell/AppShell.tsx index 2e348cd..f19e2d5 100644 --- a/packages/design-system/organisms/app-shell/AppShell.tsx +++ b/packages/design-system/organisms/app-shell/AppShell.tsx @@ -11,6 +11,7 @@ export type AppShellProps = { user?: DiscordUser; showFooter?: boolean; small?: boolean; + double?: boolean; activeGuildId?: string | null; guilds?: GuildSlug[]; recentGuilds?: string[]; @@ -56,7 +57,9 @@ export const AppShell = (props: AppShellProps) => ( )} <> - {props.children} + + {props.children} + {props.showFooter &&