From 0434ab3901f28b9971e8c5d3954275f01c41c393 Mon Sep 17 00:00:00 2001 From: davy-c Date: Mon, 23 Aug 2021 18:01:48 +0900 Subject: [PATCH 01/13] initial --- src/cloud/api/feedback/index.ts | 2 +- src/cloud/api/teams/open-invites/index.ts | 13 +- src/cloud/api/users/index.ts | 2 +- .../{atoms => }/AnnouncementAlert.tsx | 56 +- src/cloud/components/App.tsx | 2 +- .../{molecules => }/AppFeedbackForm/index.tsx | 18 +- src/cloud/components/Application.tsx | 64 +- .../{atoms => }/BottomBarButton.tsx | 6 +- .../{organisms => }/CloudGlobalSearch.tsx | 30 +- .../components/{organisms => }/CloudModal.tsx | 6 +- .../{atoms => }/CodeMirrorStyle.tsx | 2 +- .../{molecules => Comments}/CommentInput.tsx | 10 +- .../{molecules => Comments}/CommentList.tsx | 8 +- .../CommentManager.tsx | 20 +- .../ThreadActionButton.tsx | 8 +- .../{molecules => Comments}/ThreadItem.tsx | 8 +- .../{molecules => Comments}/ThreadList.tsx | 6 +- .../ContentManagerArchivesBulkActions.tsx | 14 +- .../DocOnlyContentManagerBulkActions.tsx | 20 +- .../ContentManager/Actions/HeaderAction.tsx | 51 ++ .../ContentManager/Actions/RowAction.tsx | 58 ++ .../ContentManager/ContentManagerCell.tsx | 4 +- .../ContentManagerStatusFilter.tsx | 30 +- .../ContentManager/ContentManagerToolbar.tsx | 37 +- .../ContentManagerToolbarStatusPopup.tsx | 10 +- .../Rows/ContentManagerDocRow.tsx | 34 +- .../Rows/ContentManagerFolderRow.tsx | 13 +- .../ContentManager/Rows/ContentManagerRow.tsx | 10 +- .../ContentManager/Rows/EmptyRow.tsx | 2 +- .../ContentManager/SortingOption.tsx | 97 +-- .../{molecules => }/ContentManager/index.tsx | 39 +- src/cloud/components/ContentManager/styled.ts | 14 + .../molecules => DocPage}/BackLinksList.tsx | 16 +- .../DocContextMenuActions.tsx | 56 +- .../DocPageHeader.tsx | 36 +- .../{molecules => DocPage}/DocShare.tsx | 24 +- .../DocTagsList/TagsAutoCompleteInput.tsx | 32 +- .../DocTagsList/index.tsx | 18 +- .../{organisms => }/DocPage/Edit.tsx | 14 +- .../index.tsx => DocPage/EditorLayout.tsx} | 8 +- .../NewDocContextMenu.tsx | 56 +- .../{organisms => }/DocPage/SharedDocPage.tsx | 22 +- .../{organisms => }/DocPage/View.tsx | 80 +-- .../{organisms => }/DocPage/index.tsx | 46 +- src/cloud/components/DocPage/styles.ts | 23 + .../DocProperties/DocAssigneeSelect.tsx | 176 ++++++ .../DocProperties/DocDueDateSelect.tsx | 8 +- .../DocProperties/DocLabelSelectionModal.tsx | 196 +++++++ .../DocProperties/DocPropertyValueButton.tsx | 8 +- .../DocProperties/DocStatusSelect.tsx | 28 +- .../components/{atoms => }/DocStatusIcon.tsx | 14 +- .../{atoms => }/DocTagsListItem.tsx | 8 +- .../Editor/EditorAdmonitionTool.tsx | 10 +- .../Editor/EditorAdmonitionToolDropdown.tsx | 8 +- .../Editor/EditorHeaderTool.tsx | 10 +- .../Editor/EditorHeaderToolDropdown.tsx | 14 +- .../Editor/EditorIndentationStatus.tsx | 198 +++++++ .../Editor/EditorIntegrationToolButton.tsx | 14 +- .../Editor/EditorKeyMapSelect.tsx | 82 +-- .../Editor/EditorSelectionStatus.tsx | 11 +- .../Editor/EditorTemplateButton.tsx | 32 +- .../components/Editor/EditorThemeSelect.tsx | 169 ++++++ .../Editor/EditorToolButton.tsx | 12 +- .../{molecules => }/Editor/EditorToolbar.tsx | 6 +- .../Editor/EditorToolbarUpload.tsx | 6 +- .../{molecules => }/Editor/index.tsx | 170 +++--- .../{molecules => }/Editor/styled.ts | 28 +- .../{molecules => }/Editor/types.ts | 0 .../components/{atoms => }/EditorsIcons.tsx | 20 +- src/cloud/components/EmojiIcon.tsx | 49 ++ .../components/{atoms => }/ErrorBlock.tsx | 4 +- .../{organisms => }/EventSource.tsx | 32 +- .../components/FeedbackForm/ExpandingRow.tsx | 81 +++ .../{organisms => }/FeedbackForm/index.tsx | 49 +- .../{organisms => }/FeedbackForm/types.ts | 0 .../components/{atoms => }/FileListItem.tsx | 19 +- .../FolderPage/NewFolderContextMenu.tsx | 258 ++++++++ .../{organisms => }/FolderPage/index.tsx | 52 +- .../{organisms => }/FreeTrialPopup/index.tsx | 55 +- src/cloud/components/GlobalStyle.tsx | 205 ------- .../{organisms => }/ImportFlow/index.tsx | 27 +- .../molecules/ImportFlowDestination.tsx | 16 +- .../molecules/ImportFlowSources.tsx | 6 +- .../index.tsx | 10 +- .../CenteredContainer.tsx} | 2 +- .../{atoms => }/Link/AccountLink.tsx | 0 .../components/{atoms => }/Link/CloudLink.tsx | 6 +- .../components/{atoms => }/Link/DocLink.tsx | 8 +- .../{atoms => }/Link/FolderLink.tsx | 8 +- .../{atoms => }/Link/RevisionLink.tsx | 10 +- .../components/{atoms => }/Link/TagLink.tsx | 8 +- .../components/{atoms => }/Link/TeamLink.tsx | 5 +- .../{atoms => }/Link/WorkspaceLink.tsx | 8 +- .../LinkableHeader.tsx | 8 +- .../MarkdownView/MarkdownCheckbox.tsx | 0 .../SelectionTooltip.tsx | 0 .../Shortcode/github/GithubIssue.tsx | 6 +- .../Shortcode/github/GithubPr.tsx | 6 +- .../Shortcode/github/styles.ts | 2 +- .../Shortcode/github/utils.ts | 0 .../Shortcode/index.tsx | 20 +- .../TableOfContents/index.tsx | 2 +- .../{atoms => }/MarkdownView/index.tsx | 40 +- .../{atoms => }/MarkdownView/styles.ts | 2 +- .../Modal/contents/DiscountModal.tsx | 18 +- .../RevisionsModal/RevisionModalDetail.tsx | 159 +++++ .../RevisionsModal/RevisionModalNavigator.tsx | 171 ++++++ .../contents/Doc/RevisionsModal/index.tsx | 100 ++-- .../Modal/contents/FeedbackModal.tsx | 2 +- .../Modal/contents/Forms/MoveItemModal.tsx | 27 +- .../SmartFolder/CreateSmartFolderModal.tsx | 14 +- .../DateConditionValueTypeSelect.tsx | 4 +- .../SmartFolder/DocAssigneeSelect.tsx | 10 +- .../contents/SmartFolder/DocDateSelect.tsx | 6 +- .../contents/SmartFolder/DocLabelSelect.tsx | 6 +- .../contents/SmartFolder/DocStatusSelect.tsx | 8 +- .../SmartFolder/SecondaryConditionItem.tsx | 12 +- .../SecondaryConditionValueControl.tsx | 4 +- .../contents/SmartFolder/SmartFolderForm.tsx | 28 +- .../SmartFolder/UpdateSmartFolderModal.tsx | 16 +- .../Modal/contents/SmartFolder/interfaces.ts | 2 +- .../Modal/contents/TemplatesModal/index.tsx | 428 +++++++------- .../contents/Workspace/WorkspaceAccess.tsx | 62 +- .../contents/Workspace/WorkspaceModalForm.tsx | 75 +-- .../BulkInvitesForm.tsx | 20 +- .../CreateTeamForm.tsx | 27 +- .../Onboarding/FolderPageInviteSection.tsx | 172 ++++++ .../OnboardingLayout.tsx | 6 +- .../molecules => Onboarding}/UsageFormRow.tsx | 10 +- .../{molecules => }/OpenInviteSection.tsx | 50 +- .../PreferencesContextMenuWrapper.tsx | 6 +- src/cloud/components/Router.tsx | 127 ++-- .../components/{atoms => }/ServiceConnect.tsx | 16 +- .../{molecules => }/SettingsTeamForm.tsx | 20 +- .../components/SharePageTopBar/index.tsx | 54 ++ .../{molecules => }/SignInForm/EmailForm.tsx | 27 +- .../{molecules => }/SignInForm/index.tsx | 10 +- .../SmartFolderContextMenu.tsx | 46 +- .../Subscription/PlanTables.tsx | 16 +- .../Subscription/SubscriptionCostSummary.tsx | 12 +- .../Subscription/SubscriptionManagement.tsx | 90 ++- .../UpdateBillingEmailForm.tsx | 27 +- .../UpdateBillingMethodForm.tsx | 33 +- .../SubscriptionForm/UpdateBillingPromo.tsx | 26 +- .../SubscriptionForm/index.tsx | 40 +- src/cloud/components/{atoms => }/TeamIcon.tsx | 8 +- .../{molecules => }/TeamInvitesSection.tsx | 57 +- .../{atoms => }/ThreadStatusFilterControl.tsx | 16 +- .../components/{atoms => }/TitleComponent.tsx | 4 +- .../{molecules => }/TokenControl.tsx | 121 ++-- .../ControlsContextMenuBackground.tsx | 0 .../ControlsContextMenuItem.tsx | 4 +- .../ControlsContextMenu/FolderContextMenu.tsx | 30 +- .../Controls/ControlsContextMenu/styled.ts | 4 +- .../{organisms => }/Topbar/PresenceIcons.tsx | 16 +- .../{organisms => }/Topbar/SyncStatus.tsx | 36 +- src/cloud/components/UpgradeButton.tsx | 2 +- src/cloud/components/UpgradeIntroButton.tsx | 6 +- src/cloud/components/{atoms => }/UserIcon.tsx | 13 +- .../{molecules => }/ViewerDisclaimer.tsx | 12 +- .../ViewerRestrictedWrapper.tsx | 6 +- .../WorkspaceExplorer/ExplorerListItem.tsx | 10 +- .../WorkspaceExplorer/FolderExplorer.tsx | 2 +- .../WorkspaceExplorer/index.tsx | 4 +- .../WorkspaceExplorer/styled.ts | 3 +- .../WorkspacePage/WorkspaceContextMenu.tsx | 240 ++++++++ src/cloud/components/WorkspacePage/index.tsx | 224 +++++++ src/cloud/components/atoms/Badge.tsx | 42 -- src/cloud/components/atoms/Button.tsx | 342 ----------- src/cloud/components/atoms/ButtonLink.tsx | 337 ----------- src/cloud/components/atoms/Card.tsx | 21 - src/cloud/components/atoms/Checkbox.tsx | 159 ----- src/cloud/components/atoms/ClickInput.tsx | 62 -- src/cloud/components/atoms/Collapsible.tsx | 48 -- src/cloud/components/atoms/ColoredBlock.tsx | 85 --- src/cloud/components/atoms/CustomSpinner.ts | 29 - src/cloud/components/atoms/EmojiIcon.tsx | 68 --- src/cloud/components/atoms/Flexbox.tsx | 176 ------ .../components/atoms/HighlightedCode.tsx | 24 - src/cloud/components/atoms/Icon.tsx | 38 -- src/cloud/components/atoms/IconMdi.tsx | 24 - src/cloud/components/atoms/Image.tsx | 14 - .../components/atoms/IntersectionAction.tsx | 45 -- .../components/atoms/Link/CustomLink.tsx | 124 ---- src/cloud/components/atoms/PageTitle.tsx | 12 - .../components/atoms/Select/CustomSelect.tsx | 173 ------ .../atoms/Select/FuzzyFolderSelect.tsx | 105 ---- .../atoms/Select/FuzzyWorkspaceSelect.tsx | 83 --- .../components/atoms/Select/SimpleSelect.tsx | 64 -- src/cloud/components/atoms/SmallButton.tsx | 20 - src/cloud/components/atoms/Spinner.tsx | 79 --- src/cloud/components/atoms/TextInput.tsx | 174 ------ src/cloud/components/atoms/Tooltip.tsx | 98 ---- .../atoms/TopBarSideNavHideButton.tsx | 36 -- .../atoms/buttons/ButtonDropdown.tsx | 73 --- .../components/atoms/buttons/ButtonGroup.tsx | 31 - .../components/atoms/buttons/CustomButton.tsx | 139 ----- .../atoms/buttons/ScrollUpButton.tsx | 48 -- .../InviteCTAButton.tsx | 8 +- .../{molecules => buttons}/NewDocButton.tsx | 8 +- .../buttons/login/GithubLoginButton.tsx | 12 +- .../buttons/login/GoogleLoginButton.tsx | 14 +- .../{organisms => }/error/ErrorPage.tsx | 41 +- .../{organisms => }/error/ErrorSection.tsx | 8 +- .../homepage/IntegrationServiceImage.tsx | 2 +- .../{atoms => }/homepage/PageContainer.tsx | 2 +- src/cloud/components/layouts/Contents.tsx | 14 - .../components/layouts/DefaultLayout.tsx | 9 - .../components/layouts/DocEditLayout.tsx | 115 ---- .../components/layouts/RelativeContainer.tsx | 8 - .../components/molecules/Banner/index.tsx | 59 -- .../molecules/ClickableDocListItem.tsx | 73 --- .../molecules/ClickableListItem.tsx | 62 -- .../ContentManager/Actions/HeaderAction.tsx | 59 -- .../ContentManager/Actions/RowAction.tsx | 66 --- .../molecules/ContentManager/styled.ts | 41 -- .../components/molecules/DocListItem.tsx | 255 -------- .../Editor/EditorIndentationStatus.tsx | 171 ------ .../molecules/Editor/EditorThemeSelect.tsx | 169 ------ .../components/molecules/FolderDocList.tsx | 26 - .../components/molecules/FolderListItem.tsx | 143 ----- src/cloud/components/molecules/PageHeader.tsx | 51 -- .../molecules/PositionableModal/index.tsx | 49 -- .../RelativeDialog/RelativeDialog.tsx | 64 -- .../molecules/RelativeDialog/index.ts | 3 - .../molecules/RelativeDialog/styled.ts | 51 -- .../molecules/RightLayoutHeaderButtons.tsx | 86 --- src/cloud/components/molecules/TabHeaders.tsx | 70 --- .../molecules/Timeline/TimelineList.tsx | 178 ------ .../molecules/Timeline/TimelineListItem.tsx | 244 -------- .../components/molecules/ToggleSection.tsx | 55 -- .../organisms/BookmarksList/index.tsx | 171 ------ .../components/organisms/DocPage/styles.ts | 27 - .../DocProperties/DocAssigneeSelect.tsx | 297 ---------- .../DocProperties/DocLabelSelectionModal.tsx | 249 -------- .../organisms/FeedbackForm/ExpandingRow.tsx | 91 --- .../FolderPage/NewFolderContextMenu.tsx | 105 ---- src/cloud/components/organisms/InviteForm.tsx | 231 -------- .../RevisionsModal/RevisionModalDetail.tsx | 91 --- .../RevisionsModal/RevisionModalNavigator.tsx | 111 ---- .../contents/Doc/RevisionsModal/styled.ts | 156 ----- .../organisms/Modal/contents/Forms/styled.ts | 87 --- .../Workspace/CreateWorkspaceModal.tsx | 14 - .../contents/Workspace/EditWorkspaceModal.tsx | 18 - .../organisms/Modal/contents/styled.ts | 184 ------ .../components/organisms/Modal/styled.ts | 115 ---- .../RightSideTopBar/TopBarSlashSeparator.tsx | 29 - .../organisms/RightSideTopBar/styled.ts | 23 - .../organisms/SharePageTopBar/index.tsx | 20 - .../organisms/SharePageTopBar/styled.ts | 36 -- .../Sidebar/SideNavigator/SideNavIcon.tsx | 63 -- .../organisms/Sidebar/SideNavigator/styled.ts | 285 --------- .../ControlsContextMenu/TagContextMenu.tsx | 161 ----- .../organisms/Topbar/Controls/TagControls.tsx | 33 -- .../organisms/Topbar/Controls/styled.ts | 24 - .../organisms/WorkspacePage/index.tsx | 185 ------ .../{organisms => }/settings/ApiTab.tsx | 61 +- .../settings/AttachmentsTab.tsx | 97 ++- .../settings/BlockEditorTab.tsx | 26 +- .../settings/GithubIntegration.tsx | 51 +- .../{organisms => }/settings/ImportTab.tsx | 10 +- .../settings/IntegrationsTab.tsx | 49 +- .../{organisms => }/settings/MembersTab.tsx | 101 ++-- .../settings/PersonalInfoTab.tsx | 26 +- .../settings/PreferencesTab.tsx | 4 +- .../settings/SettingsComponent.tsx | 51 +- .../settings/SlackIntegration.tsx | 53 +- .../settings/SubscriptionTab.tsx | 24 +- .../{organisms => }/settings/TeamInfoTab.tsx | 16 +- .../{organisms => }/settings/TeamSubLimit.tsx | 10 +- .../{organisms => }/settings/UpgradeTab.tsx | 55 +- .../settings/UserPreferencesForm.tsx | 14 +- .../{organisms => }/settings/styled.ts | 37 +- src/cloud/lib/editor/CodeMirror.ts | 2 +- src/cloud/lib/export.ts | 8 +- src/cloud/lib/hooks/sidebar/useCloudDnd.ts | 6 +- .../hooks/sidebar/useCloudSidebarSpaces.tsx | 4 +- .../lib/hooks/sidebar/useCloudSidebarTree.tsx | 90 +-- src/cloud/lib/hooks/useCloudApi.ts | 4 +- .../lib/hooks/useCloudResourceModals.tsx | 12 +- src/cloud/lib/hooks/useCommentManagerState.ts | 2 +- src/cloud/lib/hooks/useI18n.tsx | 2 +- src/cloud/lib/hooks/useThreadMenuActions.tsx | 6 +- src/cloud/lib/hooks/useWorkspaceDelete.ts | 8 +- src/cloud/lib/href.ts | 16 - src/cloud/lib/i18n/enUS.ts | 7 + src/cloud/lib/i18n/fr.ts | 6 + src/cloud/lib/i18n/ja.ts | 6 + src/cloud/lib/i18n/types.ts | 5 + src/cloud/lib/i18n/zhCN.ts | 6 + src/cloud/lib/localStorageKeys.ts | 1 + src/cloud/lib/mappers/contentManager.ts | 8 +- src/cloud/lib/mappers/fuzzyNavigation.ts | 10 +- src/cloud/lib/mappers/topbarBreadcrumbs.ts | 10 +- src/cloud/lib/mappers/topbarTree.ts | 10 +- src/cloud/lib/stores/apiTokens/store.ts | 2 +- .../lib/stores/betaRegistration/store.ts | 2 +- src/cloud/lib/stores/comments/index.ts | 6 +- src/cloud/lib/stores/nav/store.tsx | 4 +- src/cloud/lib/stores/openInvites/index.ts | 9 + src/cloud/lib/stores/openInvites/store.ts | 80 +++ .../stores/openInvites/withOpenInvites.tsx | 16 + src/cloud/lib/stores/preferences/types.ts | 7 +- .../lib/stores/serviceConnections/store.ts | 2 +- src/cloud/lib/stores/settings/store.ts | 4 +- .../lib/stores/teamPreferences}/index.tsx | 0 .../lib/stores/teamPreferences/store.tsx | 89 +++ src/cloud/lib/stores/teamPreferences/types.ts | 13 + src/cloud/lib/styled/index.ts | 16 - src/cloud/lib/styled/keyframes.ts | 33 -- src/cloud/lib/styled/styleFunctions.ts | 553 ------------------ src/cloud/lib/styled/styled.ts | 4 - src/cloud/lib/styled/themes/dark.ts | 176 ------ src/cloud/lib/styled/themes/index.ts | 2 - src/cloud/lib/styled/themes/light.ts | 176 ------ src/cloud/lib/styled/themes/shared.ts | 52 -- src/cloud/lib/styled/themes/types.ts | 160 ----- src/cloud/lib/styled/unrounded.ts | 67 --- .../pages/[teamId]/[resourceId]/index.tsx | 11 +- src/cloud/pages/[teamId]/bookmarks.tsx | 41 -- src/cloud/pages/[teamId]/delete.tsx | 126 ++-- src/cloud/pages/[teamId]/index.tsx | 2 +- src/cloud/pages/[teamId]/invite.tsx | 36 +- .../pages/[teamId]/labels/[labelId]/index.tsx | 20 +- src/cloud/pages/[teamId]/requests/deny.tsx | 6 +- src/cloud/pages/[teamId]/shared.tsx | 8 +- .../smart-folders/[smartFolderId].tsx | 16 +- .../pages/[teamId]/status/[docStatus].tsx | 142 ----- src/cloud/pages/[teamId]/timeline.tsx | 249 -------- .../[teamId]/workspaces/[workspaceId].tsx | 14 +- src/cloud/pages/account/delete.tsx | 120 +--- src/cloud/pages/cooperate.tsx | 18 +- src/cloud/pages/oauth/[service]/callback.tsx | 18 +- src/cloud/pages/oauth2/authorize.tsx | 74 +-- src/cloud/pages/settings/index.tsx | 18 +- src/cloud/pages/shared/[link].tsx | 116 ++-- src/components/App.tsx | 16 +- src/components/Application.tsx | 4 +- .../PreferencesModal/MigrationTab.tsx | 10 +- .../PreferencesModal/PreferencesModal.tsx | 6 +- src/components/PreferencesModal/styled.tsx | 4 +- src/components/atoms/Alert.tsx | 2 +- src/components/atoms/BoostHubWebview.tsx | 3 +- src/components/atoms/PageDraggableHeader.tsx | 6 +- src/components/atoms/ProgressBar.tsx | 2 +- src/components/atoms/form.tsx | 4 +- .../molecules/BoostHubFeatureIntro.tsx | 8 +- src/components/molecules/ModalContainer.tsx | 4 +- src/components/organisms/AppNavigator.tsx | 8 +- .../organisms/BoostHubSignInForm.tsx | 6 +- src/components/organisms/CloudIntroModal.tsx | 10 +- src/components/organisms/SidebarContainer.tsx | 12 +- .../organisms/SubscribeNewsLettersForm.tsx | 2 +- .../pages/BoostHubAccountDeletePage.tsx | 2 +- src/components/pages/BoostHubLoginPage.tsx | 4 +- .../pages/BoostHubTeamsCreatePage.tsx | 4 +- .../pages/BoostHubTeamsShowPage.tsx | 6 +- src/components/pages/FsDbDeprecationPage.tsx | 6 +- src/components/pages/NotFoundErrorPage.tsx | 6 +- .../components/atoms/Badge.tsx | 0 .../components/atoms/Banner.tsx | 0 .../components/atoms/BorderSeparator.tsx | 29 + .../components/atoms/Button.tsx | 7 +- .../components/atoms/ButtonGroup.tsx | 0 src/design/components/atoms/Card.tsx | 50 ++ src/design/components/atoms/ColoredBlock.tsx | 64 ++ .../components/atoms/DoublePane.tsx | 22 +- .../components/atoms/EditableInput.tsx | 105 ++-- .../components/atoms/Flexbox.tsx | 6 + .../components/atoms/FoldingWrapper.tsx | 0 .../components/atoms/GlobalStyle.tsx | 0 .../components/atoms/Icon.tsx | 3 + src/{ => design}/components/atoms/Image.tsx | 0 .../components/atoms/LeftRightList.tsx | 0 .../components/atoms/Link.tsx | 0 .../components/atoms/NotifyIcon.tsx | 0 .../components/atoms/PageHelmet.tsx | 0 .../components/atoms/Pastille.tsx | 0 .../components/atoms/Portal.tsx | 0 .../components/atoms/PromiseWrapper.tsx | 0 .../components/atoms/RoundedImage.tsx | 0 .../components/atoms/Spinner.tsx | 0 .../components/atoms/Switch.tsx | 0 .../components/atoms/UpDownList.tsx | 0 .../components/atoms/VerticalScroller.tsx | 0 .../components/atoms/WidthEnlarger.tsx | 0 .../components/atoms/WithTooltip.tsx | 14 +- .../components/atoms/markdown/CodeFence.tsx | 0 .../molecules/ApplicationLayout.tsx | 0 .../molecules/CloseButtonWrapper.tsx | 0 .../components/molecules/ContextMenu.tsx | 0 .../components/molecules/EmojiPicker.tsx | 0 .../molecules/FlattenedBreadcrumbs.tsx | 0 .../molecules/Form/atoms/FormCheckbox.tsx | 36 ++ .../molecules/Form/atoms/FormCopyInput.tsx | 0 .../molecules/Form/atoms/FormDatePicker.tsx | 0 .../molecules/Form/atoms/FormEmoji.tsx | 0 .../molecules/Form/atoms/FormImage.tsx | 0 .../molecules/Form/atoms/FormInput.tsx | 0 .../molecules/Form/atoms/FormRadio.tsx | 0 .../molecules/Form/atoms/FormSelect.tsx | 0 .../molecules/Form/atoms/FormStripeInput.tsx | 0 .../molecules/Form/atoms/FormTextArea.tsx | 2 +- .../components/molecules/Form/index.tsx | 0 .../molecules/Form/templates/FormRow.tsx | 0 .../molecules/Form/templates/FormRowItem.tsx | 0 .../molecules/Navigation/NavigationItem.tsx | 337 +++++++++++ .../components/molecules/NotificationList.tsx | 4 +- .../components/molecules/SearchableList.tsx | 185 ++++++ .../components/molecules/UserIconList.tsx | 0 .../atoms/ContentManagerRow.tsx | 2 +- .../organisms/ContentManager/index.tsx | 0 .../molecules/ContentManagerSort.tsx | 0 .../components/organisms/Dialog/Dialog.tsx | 0 .../organisms/Dialog/atoms/DialogIcon.tsx | 0 .../Dialog/molecules/MessageBoxDialogBody.tsx | 0 .../components/organisms/EmojiInputForm.tsx | 0 .../organisms/FuzzyNavigation/index.tsx | 0 .../molecules/FuzzyNavigationItem.tsx | 0 .../atoms/MetadataContainerBreak.tsx | 0 .../organisms/MetadataContainer/index.tsx | 0 .../molecules/MetadataContainerRow.tsx | 0 .../organisms/Modal/atoms/ModalLayout.tsx | 0 .../components/organisms/Modal/index.tsx | 0 .../SearchLayout/atoms/SearchItem.tsx | 2 +- .../organisms/SearchLayout/index.tsx | 0 .../SearchLayout/molecules/SearchCategory.tsx | 0 .../Settings/atoms/SettingNavItem.tsx | 0 .../Settings/atoms/SettingTabContent.tsx | 0 .../Settings/atoms/SettingTabSelector.tsx | 0 .../components/organisms/Settings/index.tsx | 0 .../Settings/molecules/SettingSidenav.tsx | 0 .../molecules/SettingSidenavHeader.tsx | 0 .../components/organisms/ShallowTimeline.tsx | 0 .../organisms/Sidebar/atoms/SidebarButton.tsx | 2 +- .../Sidebar/atoms/SidebarContextList.tsx | 0 .../organisms/Sidebar/atoms/SidebarHeader.tsx | 0 .../Sidebar/atoms/SidebarPopOver.tsx | 0 .../Sidebar/atoms/SidebarTreeForm.tsx | 0 .../Sidebar/atoms/SidebarTreeItem.tsx | 2 +- .../components/organisms/Sidebar/index.tsx | 2 +- .../Sidebar/molecules/SidebarButtonList.tsx | 0 .../Sidebar/molecules/SidebarLink.tsx | 0 .../Sidebar/molecules/SidebarSpaces.tsx | 0 .../Sidebar/molecules/SidebarTree.tsx | 0 .../components/organisms/Toast.tsx | 0 .../Topbar/atoms/TopbarActionItem.tsx | 2 +- .../organisms/Topbar/atoms/TopbarTreeItem.tsx | 2 +- .../components/organisms/Topbar/index.tsx | 3 +- .../Topbar/molecules/TopbarBreadcrumb.tsx | 0 .../molecules/TopbarNavigationContext.tsx | 0 .../components/templates/ContentLayout.tsx | 1 + .../components/templates/ErrorLayout.tsx | 0 .../lib/codemirror/rehypeCodeMirror.ts | 0 src/{shared => design}/lib/codemirror/util.ts | 0 src/{shared => design}/lib/date.ts | 0 src/{shared => design}/lib/dnd.ts | 0 src/{shared => design}/lib/dom.ts | 0 src/{shared => design}/lib/hooks/useApi.ts | 0 .../lib/hooks/useBulkApi.ts | 0 .../lib/hooks/useCancellablePromises.ts | 0 .../lib/hooks/useNotificationState.ts | 0 .../lib/hooks/useSuggestions.ts | 0 src/{shared => design}/lib/keyboard.ts | 0 .../lib/mappers/topbarControls.ts | 0 src/{shared => design}/lib/mappers/types.ts | 0 src/{shared => design}/lib/mappers/users.ts | 0 src/{shared => design}/lib/platform.ts | 0 src/{shared => design}/lib/shortcuts.ts | 0 src/{shared => design}/lib/sidebar.ts | 0 .../lib/stores/contextMenu/index.ts | 0 .../lib/stores/contextMenu/types.ts | 0 .../lib/stores/dialog/index.tsx | 0 .../lib/stores/dialog/types.ts | 0 .../lib/stores/emoji/index.tsx | 0 .../lib/stores/emoji/types.ts | 0 .../lib/stores/integrations/index.ts | 0 src/design/lib/stores/modal/index.tsx | 2 + .../lib/stores/modal/store.ts | 2 - .../lib/stores/modal/types.ts | 0 .../lib/stores/notifications/index.ts | 0 .../lib/stores/toast/index.ts | 0 .../lib/stores/window/index.ts | 0 .../lib/stores/window/types.ts | 0 src/{shared => design}/lib/string.ts | 0 src/{shared => design}/lib/styled/common.ts | 0 src/{shared => design}/lib/styled/dark.ts | 0 src/{shared => design}/lib/styled/index.ts | 0 src/{shared => design}/lib/styled/light.ts | 0 src/{shared => design}/lib/styled/sepia.ts | 0 .../lib/styled/solarizedDark.ts | 0 .../lib/styled/styleFunctions.ts | 21 + src/{shared => design}/lib/styled/types.ts | 0 src/{shared => design}/lib/types.ts | 0 src/{shared => design}/lib/utils/array.ts | 0 src/{shared => design}/lib/utils/comments.ts | 0 src/{shared => design}/lib/utils/context.tsx | 0 src/{shared => design}/lib/utils/secret.ts | 0 src/index.tsx | 10 +- src/lib/generalStatus.ts | 2 +- src/lib/keymap.ts | 2 +- src/lib/platform.ts | 2 +- src/lib/preferences.ts | 2 +- src/lib/styled/styleFunctionsLocal.ts | 2 +- src/lib/v2/hooks/local/useLocalUI.tsx | 2 +- src/lib/v2/mappers/local/sidebarSpaces.ts | 2 +- src/mobile/components/App.tsx | 2 +- src/mobile/components/Router.tsx | 84 ++- .../components/atoms/MobileFormControl.tsx | 2 +- .../atoms/NavigationBarBackButton.tsx | 2 +- .../components/atoms/NavigationBarButton.tsx | 2 +- .../atoms/NavigationBarContainer.tsx | 4 +- .../atoms/NavigationBarIconButton.tsx | 4 +- .../components/atoms/TableHeaderItem.tsx | 4 +- src/mobile/components/atoms/TableItem.tsx | 4 +- .../atoms/UpgradeIntroModalButton.tsx | 4 +- src/mobile/components/layouts/AppLayout.tsx | 6 +- .../molecules/ContentManagerDocRow.tsx | 10 +- .../molecules/ContentManagerFolderRow.tsx | 10 +- .../molecules/ContentManagerRow.tsx | 8 +- .../ContentManagerRowLinkContent.tsx | 12 +- .../MobileContentManagerBulkActions.tsx | 10 +- .../molecules/MobileContextMenu.tsx | 10 +- .../components/organisms/ContentManager.tsx | 55 +- .../organisms/DocOnlyContentManager.tsx | 24 +- .../organisms/NativeMobileAuthForm.tsx | 4 +- .../organisms/Navigator/Navigator.tsx | 8 +- .../organisms/Navigator/NavigatorCategory.tsx | 8 +- .../Navigator/NavigatorControlItem.tsx | 6 +- .../organisms/Navigator/NavigatorItem.tsx | 14 +- .../Navigator/NavigatorNestedTreeRow.tsx | 2 +- .../Navigator/NavigatorSpaceSelector.tsx | 8 +- .../organisms/Navigator/NavigatorTree.tsx | 8 +- .../Navigator/SpaceMenuItemLabel.tsx | 4 +- .../organisms/modals/AccountSettingsTab.tsx | 10 +- .../organisms/modals/DocCreateModal.tsx | 4 +- .../organisms/modals/DocInfoModal.tsx | 27 +- .../modals/MobileDocRevisionsModal.tsx | 30 +- .../organisms/modals/MobileResourceModal.tsx | 8 +- .../modals/MobileResourceMoveModal.tsx | 8 +- .../organisms/modals/MobileSearchModal.tsx | 2 +- .../organisms/modals/MobileWorkspaceModal.tsx | 14 +- .../components/organisms/modals/Modal.tsx | 2 +- .../modals/SmartFolderCreateModal.tsx | 4 +- .../modals/SmartFolderUpdateModal.tsx | 4 +- .../organisms/modals/SpaceBillingsTab.tsx | 16 +- .../organisms/modals/SpaceMembersTab.tsx | 71 +-- .../organisms/modals/SpaceSettingsTab.tsx | 10 +- .../modals/SpaceUpgradeConfirmTab.tsx | 10 +- .../organisms/modals/SpaceUpgradeTab.tsx | 4 +- .../organisms/modals/UpgradeIntroModal.tsx | 8 +- .../organisms/modals/WorkspaceCreateModal.tsx | 99 ++-- .../modals/atoms/MobileSearchCategory.tsx | 6 +- .../modals/atoms/MobileSearchHeader.tsx | 6 +- .../modals/atoms/MobileSearchItem.tsx | 14 +- .../organisms/modals/atoms/ModalContainer.tsx | 4 +- .../modals/atoms/ModalFormWrapper.tsx | 2 +- .../DocContextMenu/DocAssigneeSelect.tsx | 8 +- .../DocContextMenu/DocDueDateSelect.tsx | 4 +- .../DocContextMenu/DocPropertyValueButton.tsx | 6 +- .../DocContextMenu/DocStatusSelect.tsx | 22 +- .../organisms/DocInfoModalShareSection.tsx | 16 +- .../organisms/DocTagsList/DocTagsListItem.tsx | 8 +- .../DocTagsList/TagsAutoCompleteInput.tsx | 14 +- .../modals/organisms/DocTagsList/index.tsx | 8 +- .../modals/organisms/DocTagsList/styled.ts | 37 +- .../modals/organisms/MobileSearchView.tsx | 12 +- .../modals/organisms/SettingsTeamForm.tsx | 8 +- .../modals/organisms/SmartFolderForm.tsx | 24 +- .../components/pages/BookmarksListPage.tsx | 22 - src/mobile/components/pages/CooperatePage.tsx | 6 +- .../components/pages/CreateTeamPage.tsx | 10 +- .../components/pages/DeleteAccountPage.tsx | 20 +- src/mobile/components/pages/DocEditPage.tsx | 22 +- src/mobile/components/pages/DocPage.tsx | 22 +- .../components/pages/DocStatusShowPage.tsx | 4 +- src/mobile/components/pages/DocViewPage.tsx | 22 +- src/mobile/components/pages/FolderPage.tsx | 7 +- .../components/pages/OpenInvitePage.tsx | 34 +- src/mobile/components/pages/RootPage.tsx | 12 +- src/mobile/components/pages/SettingsPage.tsx | 10 +- .../components/pages/SmartFolderPage.tsx | 6 +- src/mobile/components/pages/TagsShowPage.tsx | 14 +- .../components/pages/TeamDeletePage.tsx | 118 +--- src/mobile/lib/href.ts | 4 +- src/mobile/lib/sidebar/useNavigatorTree.tsx | 14 +- src/mobile/lib/useMobileResourceModals.tsx | 8 +- src/stories/Button.stories.tsx | 2 +- src/stories/utils/themes.tsx | 6 +- 589 files changed, 6449 insertions(+), 13208 deletions(-) rename src/cloud/components/{atoms => }/AnnouncementAlert.tsx (89%) rename src/cloud/components/{molecules => }/AppFeedbackForm/index.tsx (85%) rename src/cloud/components/{atoms => }/BottomBarButton.tsx (78%) rename src/cloud/components/{organisms => }/CloudGlobalSearch.tsx (87%) rename src/cloud/components/{organisms => }/CloudModal.tsx (50%) rename src/cloud/components/{atoms => }/CodeMirrorStyle.tsx (93%) rename src/cloud/components/{molecules => Comments}/CommentInput.tsx (96%) rename src/cloud/components/{molecules => Comments}/CommentList.tsx (96%) rename src/cloud/components/{organisms => Comments}/CommentManager.tsx (93%) rename src/cloud/components/{molecules => Comments}/ThreadActionButton.tsx (87%) rename src/cloud/components/{molecules => Comments}/ThreadItem.tsx (95%) rename src/cloud/components/{molecules => Comments}/ThreadList.tsx (87%) rename src/cloud/components/{molecules => }/ContentManager/Actions/ContentManagerArchivesBulkActions.tsx (90%) rename src/cloud/components/{molecules => }/ContentManager/Actions/DocOnlyContentManagerBulkActions.tsx (89%) create mode 100644 src/cloud/components/ContentManager/Actions/HeaderAction.tsx create mode 100644 src/cloud/components/ContentManager/Actions/RowAction.tsx rename src/cloud/components/{molecules => }/ContentManager/ContentManagerCell.tsx (89%) rename src/cloud/components/{molecules => }/ContentManager/ContentManagerStatusFilter.tsx (87%) rename src/cloud/components/{molecules => }/ContentManager/ContentManagerToolbar.tsx (93%) rename src/cloud/components/{molecules => }/ContentManager/ContentManagerToolbarStatusPopup.tsx (90%) rename src/cloud/components/{molecules => }/ContentManager/Rows/ContentManagerDocRow.tsx (85%) rename src/cloud/components/{molecules => }/ContentManager/Rows/ContentManagerFolderRow.tsx (85%) rename src/cloud/components/{molecules => }/ContentManager/Rows/ContentManagerRow.tsx (94%) rename src/cloud/components/{molecules => }/ContentManager/Rows/EmptyRow.tsx (91%) rename src/cloud/components/{molecules => }/ContentManager/SortingOption.tsx (66%) rename src/cloud/components/{molecules => }/ContentManager/index.tsx (91%) create mode 100644 src/cloud/components/ContentManager/styled.ts rename src/cloud/components/{organisms/EditorLayout/molecules => DocPage}/BackLinksList.tsx (75%) rename src/cloud/components/{organisms/EditorLayout/molecules => DocPage}/DocContextMenuActions.tsx (83%) rename src/cloud/components/{organisms/EditorLayout => DocPage}/DocPageHeader.tsx (89%) rename src/cloud/components/{molecules => DocPage}/DocShare.tsx (95%) rename src/cloud/components/{organisms/EditorLayout/molecules => DocPage}/DocTagsList/TagsAutoCompleteInput.tsx (88%) rename src/cloud/components/{organisms/EditorLayout/molecules => DocPage}/DocTagsList/index.tsx (87%) rename src/cloud/components/{organisms => }/DocPage/Edit.tsx (71%) rename src/cloud/components/{organisms/EditorLayout/index.tsx => DocPage/EditorLayout.tsx} (88%) rename src/cloud/components/{organisms/EditorLayout => DocPage}/NewDocContextMenu.tsx (76%) rename src/cloud/components/{organisms => }/DocPage/SharedDocPage.tsx (81%) rename src/cloud/components/{organisms => }/DocPage/View.tsx (86%) rename src/cloud/components/{organisms => }/DocPage/index.tsx (78%) create mode 100644 src/cloud/components/DocPage/styles.ts create mode 100644 src/cloud/components/DocProperties/DocAssigneeSelect.tsx rename src/cloud/components/{organisms => }/DocProperties/DocDueDateSelect.tsx (91%) create mode 100644 src/cloud/components/DocProperties/DocLabelSelectionModal.tsx rename src/cloud/components/{organisms => }/DocProperties/DocPropertyValueButton.tsx (91%) rename src/cloud/components/{organisms => }/DocProperties/DocStatusSelect.tsx (86%) rename src/cloud/components/{atoms => }/DocStatusIcon.tsx (77%) rename src/cloud/components/{atoms => }/DocTagsListItem.tsx (92%) rename src/cloud/components/{molecules => }/Editor/EditorAdmonitionTool.tsx (82%) rename src/cloud/components/{molecules => }/Editor/EditorAdmonitionToolDropdown.tsx (90%) rename src/cloud/components/{molecules => }/Editor/EditorHeaderTool.tsx (81%) rename src/cloud/components/{molecules => }/Editor/EditorHeaderToolDropdown.tsx (87%) create mode 100644 src/cloud/components/Editor/EditorIndentationStatus.tsx rename src/cloud/components/{molecules => }/Editor/EditorIntegrationToolButton.tsx (73%) rename src/cloud/components/{molecules => }/Editor/EditorKeyMapSelect.tsx (50%) rename src/cloud/components/{molecules => }/Editor/EditorSelectionStatus.tsx (80%) rename src/cloud/components/{molecules => }/Editor/EditorTemplateButton.tsx (58%) create mode 100644 src/cloud/components/Editor/EditorThemeSelect.tsx rename src/cloud/components/{molecules => }/Editor/EditorToolButton.tsx (72%) rename src/cloud/components/{molecules => }/Editor/EditorToolbar.tsx (99%) rename src/cloud/components/{molecules => }/Editor/EditorToolbarUpload.tsx (95%) rename src/cloud/components/{molecules => }/Editor/index.tsx (87%) rename src/cloud/components/{molecules => }/Editor/styled.ts (52%) rename src/cloud/components/{molecules => }/Editor/types.ts (100%) rename src/cloud/components/{atoms => }/EditorsIcons.tsx (72%) create mode 100644 src/cloud/components/EmojiIcon.tsx rename src/cloud/components/{atoms => }/ErrorBlock.tsx (92%) rename src/cloud/components/{organisms => }/EventSource.tsx (93%) create mode 100644 src/cloud/components/FeedbackForm/ExpandingRow.tsx rename src/cloud/components/{organisms => }/FeedbackForm/index.tsx (69%) rename src/cloud/components/{organisms => }/FeedbackForm/types.ts (100%) rename src/cloud/components/{atoms => }/FileListItem.tsx (69%) create mode 100644 src/cloud/components/FolderPage/NewFolderContextMenu.tsx rename src/cloud/components/{organisms => }/FolderPage/index.tsx (84%) rename src/cloud/components/{organisms => }/FreeTrialPopup/index.tsx (69%) delete mode 100644 src/cloud/components/GlobalStyle.tsx rename src/cloud/components/{organisms => }/ImportFlow/index.tsx (88%) rename src/cloud/components/{organisms => }/ImportFlow/molecules/ImportFlowDestination.tsx (84%) rename src/cloud/components/{organisms => }/ImportFlow/molecules/ImportFlowSources.tsx (95%) rename src/cloud/components/{organisms/IntroPopup => IntroducePlansPopup}/index.tsx (93%) rename src/cloud/components/{layouts/Container.tsx => Layouts/CenteredContainer.tsx} (73%) rename src/cloud/components/{atoms => }/Link/AccountLink.tsx (100%) rename src/cloud/components/{atoms => }/Link/CloudLink.tsx (85%) rename src/cloud/components/{atoms => }/Link/DocLink.tsx (89%) rename src/cloud/components/{atoms => }/Link/FolderLink.tsx (89%) rename src/cloud/components/{atoms => }/Link/RevisionLink.tsx (82%) rename src/cloud/components/{atoms => }/Link/TagLink.tsx (89%) rename src/cloud/components/{atoms => }/Link/TeamLink.tsx (93%) rename src/cloud/components/{atoms => }/Link/WorkspaceLink.tsx (89%) rename src/cloud/components/{atoms => MarkdownView}/LinkableHeader.tsx (82%) rename src/cloud/components/{atoms => }/MarkdownView/MarkdownCheckbox.tsx (100%) rename src/cloud/components/{atoms => MarkdownView}/SelectionTooltip.tsx (100%) rename src/cloud/components/{molecules => MarkdownView}/Shortcode/github/GithubIssue.tsx (93%) rename src/cloud/components/{molecules => MarkdownView}/Shortcode/github/GithubPr.tsx (93%) rename src/cloud/components/{molecules => MarkdownView}/Shortcode/github/styles.ts (92%) rename src/cloud/components/{molecules => MarkdownView}/Shortcode/github/utils.ts (100%) rename src/cloud/components/{molecules => MarkdownView}/Shortcode/index.tsx (86%) rename src/cloud/components/{molecules => MarkdownView}/TableOfContents/index.tsx (98%) rename src/cloud/components/{atoms => }/MarkdownView/index.tsx (92%) rename src/cloud/components/{atoms => }/MarkdownView/styles.ts (99%) rename src/cloud/components/{organisms => }/Modal/contents/DiscountModal.tsx (93%) create mode 100644 src/cloud/components/Modal/contents/Doc/RevisionsModal/RevisionModalDetail.tsx create mode 100644 src/cloud/components/Modal/contents/Doc/RevisionsModal/RevisionModalNavigator.tsx rename src/cloud/components/{organisms => }/Modal/contents/Doc/RevisionsModal/index.tsx (73%) rename src/cloud/components/{organisms => }/Modal/contents/FeedbackModal.tsx (64%) rename src/cloud/components/{organisms => }/Modal/contents/Forms/MoveItemModal.tsx (79%) rename src/cloud/components/{organisms => }/Modal/contents/SmartFolder/CreateSmartFolderModal.tsx (77%) rename src/cloud/components/{organisms => }/Modal/contents/SmartFolder/DateConditionValueTypeSelect.tsx (93%) rename src/cloud/components/{organisms => }/Modal/contents/SmartFolder/DocAssigneeSelect.tsx (87%) rename src/cloud/components/{organisms => }/Modal/contents/SmartFolder/DocDateSelect.tsx (96%) rename src/cloud/components/{organisms => }/Modal/contents/SmartFolder/DocLabelSelect.tsx (85%) rename src/cloud/components/{organisms => }/Modal/contents/SmartFolder/DocStatusSelect.tsx (88%) rename src/cloud/components/{organisms => }/Modal/contents/SmartFolder/SecondaryConditionItem.tsx (90%) rename src/cloud/components/{organisms => }/Modal/contents/SmartFolder/SecondaryConditionValueControl.tsx (93%) rename src/cloud/components/{organisms => }/Modal/contents/SmartFolder/SmartFolderForm.tsx (88%) rename src/cloud/components/{organisms => }/Modal/contents/SmartFolder/UpdateSmartFolderModal.tsx (86%) rename src/cloud/components/{organisms => }/Modal/contents/SmartFolder/interfaces.ts (96%) rename src/cloud/components/{organisms => }/Modal/contents/TemplatesModal/index.tsx (52%) rename src/cloud/components/{organisms => }/Modal/contents/Workspace/WorkspaceAccess.tsx (80%) rename src/cloud/components/{organisms => }/Modal/contents/Workspace/WorkspaceModalForm.tsx (80%) rename src/cloud/components/{organisms/Onboarding/molecules => Onboarding}/BulkInvitesForm.tsx (86%) rename src/cloud/components/{organisms/Onboarding/molecules => Onboarding}/CreateTeamForm.tsx (83%) create mode 100644 src/cloud/components/Onboarding/FolderPageInviteSection.tsx rename src/cloud/components/{organisms/Onboarding/layouts => Onboarding}/OnboardingLayout.tsx (84%) rename src/cloud/components/{organisms/Onboarding/molecules => Onboarding}/UsageFormRow.tsx (88%) rename src/cloud/components/{molecules => }/OpenInviteSection.tsx (85%) rename src/cloud/components/{molecules => }/PreferencesContextMenuWrapper.tsx (92%) rename src/cloud/components/{atoms => }/ServiceConnect.tsx (83%) rename src/cloud/components/{molecules => }/SettingsTeamForm.tsx (87%) create mode 100644 src/cloud/components/SharePageTopBar/index.tsx rename src/cloud/components/{molecules => }/SignInForm/EmailForm.tsx (87%) rename src/cloud/components/{molecules => }/SignInForm/index.tsx (88%) rename src/cloud/components/{organisms => }/SmartFolderContextMenu.tsx (88%) rename src/cloud/components/{organisms => }/Subscription/PlanTables.tsx (96%) rename src/cloud/components/{organisms => }/Subscription/SubscriptionCostSummary.tsx (95%) rename src/cloud/components/{organisms => }/Subscription/SubscriptionManagement.tsx (84%) rename src/cloud/components/{molecules => }/SubscriptionForm/UpdateBillingEmailForm.tsx (77%) rename src/cloud/components/{molecules => }/SubscriptionForm/UpdateBillingMethodForm.tsx (80%) rename src/cloud/components/{molecules => }/SubscriptionForm/UpdateBillingPromo.tsx (80%) rename src/cloud/components/{molecules => }/SubscriptionForm/index.tsx (84%) rename src/cloud/components/{atoms => }/TeamIcon.tsx (82%) rename src/cloud/components/{molecules => }/TeamInvitesSection.tsx (84%) rename src/cloud/components/{atoms => }/ThreadStatusFilterControl.tsx (87%) rename src/cloud/components/{atoms => }/TitleComponent.tsx (75%) rename src/cloud/components/{molecules => }/TokenControl.tsx (53%) rename src/cloud/components/{organisms => }/Topbar/Controls/ControlsContextMenu/ControlsContextMenuBackground.tsx (100%) rename src/cloud/components/{organisms => }/Topbar/Controls/ControlsContextMenu/ControlsContextMenuItem.tsx (94%) rename src/cloud/components/{organisms => }/Topbar/Controls/ControlsContextMenu/FolderContextMenu.tsx (83%) rename src/cloud/components/{organisms => }/Topbar/Controls/ControlsContextMenu/styled.ts (93%) rename src/cloud/components/{organisms => }/Topbar/PresenceIcons.tsx (83%) rename src/cloud/components/{organisms => }/Topbar/SyncStatus.tsx (55%) rename src/cloud/components/{atoms => }/UserIcon.tsx (68%) rename src/cloud/components/{molecules => }/ViewerDisclaimer.tsx (80%) rename src/cloud/components/{molecules => }/ViewerRestrictedWrapper.tsx (77%) rename src/cloud/components/{molecules => }/WorkspaceExplorer/ExplorerListItem.tsx (85%) rename src/cloud/components/{molecules => }/WorkspaceExplorer/FolderExplorer.tsx (97%) rename src/cloud/components/{molecules => }/WorkspaceExplorer/index.tsx (95%) rename src/cloud/components/{molecules => }/WorkspaceExplorer/styled.ts (95%) create mode 100644 src/cloud/components/WorkspacePage/WorkspaceContextMenu.tsx create mode 100644 src/cloud/components/WorkspacePage/index.tsx delete mode 100644 src/cloud/components/atoms/Badge.tsx delete mode 100644 src/cloud/components/atoms/Button.tsx delete mode 100644 src/cloud/components/atoms/ButtonLink.tsx delete mode 100644 src/cloud/components/atoms/Card.tsx delete mode 100644 src/cloud/components/atoms/Checkbox.tsx delete mode 100644 src/cloud/components/atoms/ClickInput.tsx delete mode 100644 src/cloud/components/atoms/Collapsible.tsx delete mode 100644 src/cloud/components/atoms/ColoredBlock.tsx delete mode 100644 src/cloud/components/atoms/CustomSpinner.ts delete mode 100644 src/cloud/components/atoms/EmojiIcon.tsx delete mode 100644 src/cloud/components/atoms/Flexbox.tsx delete mode 100644 src/cloud/components/atoms/HighlightedCode.tsx delete mode 100644 src/cloud/components/atoms/Icon.tsx delete mode 100644 src/cloud/components/atoms/IconMdi.tsx delete mode 100644 src/cloud/components/atoms/Image.tsx delete mode 100644 src/cloud/components/atoms/IntersectionAction.tsx delete mode 100644 src/cloud/components/atoms/Link/CustomLink.tsx delete mode 100644 src/cloud/components/atoms/PageTitle.tsx delete mode 100644 src/cloud/components/atoms/Select/CustomSelect.tsx delete mode 100644 src/cloud/components/atoms/Select/FuzzyFolderSelect.tsx delete mode 100644 src/cloud/components/atoms/Select/FuzzyWorkspaceSelect.tsx delete mode 100644 src/cloud/components/atoms/Select/SimpleSelect.tsx delete mode 100644 src/cloud/components/atoms/SmallButton.tsx delete mode 100644 src/cloud/components/atoms/Spinner.tsx delete mode 100644 src/cloud/components/atoms/TextInput.tsx delete mode 100644 src/cloud/components/atoms/Tooltip.tsx delete mode 100644 src/cloud/components/atoms/TopBarSideNavHideButton.tsx delete mode 100644 src/cloud/components/atoms/buttons/ButtonDropdown.tsx delete mode 100644 src/cloud/components/atoms/buttons/ButtonGroup.tsx delete mode 100644 src/cloud/components/atoms/buttons/CustomButton.tsx delete mode 100644 src/cloud/components/atoms/buttons/ScrollUpButton.tsx rename src/cloud/components/{molecules => buttons}/InviteCTAButton.tsx (93%) rename src/cloud/components/{molecules => buttons}/NewDocButton.tsx (86%) rename src/cloud/components/{atoms => }/buttons/login/GithubLoginButton.tsx (83%) rename src/cloud/components/{atoms => }/buttons/login/GoogleLoginButton.tsx (89%) rename src/cloud/components/{organisms => }/error/ErrorPage.tsx (75%) rename src/cloud/components/{organisms => }/error/ErrorSection.tsx (77%) rename src/cloud/components/{atoms => }/homepage/IntegrationServiceImage.tsx (92%) rename src/cloud/components/{atoms => }/homepage/PageContainer.tsx (89%) delete mode 100644 src/cloud/components/layouts/Contents.tsx delete mode 100644 src/cloud/components/layouts/DefaultLayout.tsx delete mode 100644 src/cloud/components/layouts/DocEditLayout.tsx delete mode 100644 src/cloud/components/layouts/RelativeContainer.tsx delete mode 100644 src/cloud/components/molecules/Banner/index.tsx delete mode 100644 src/cloud/components/molecules/ClickableDocListItem.tsx delete mode 100644 src/cloud/components/molecules/ClickableListItem.tsx delete mode 100644 src/cloud/components/molecules/ContentManager/Actions/HeaderAction.tsx delete mode 100644 src/cloud/components/molecules/ContentManager/Actions/RowAction.tsx delete mode 100644 src/cloud/components/molecules/ContentManager/styled.ts delete mode 100644 src/cloud/components/molecules/DocListItem.tsx delete mode 100644 src/cloud/components/molecules/Editor/EditorIndentationStatus.tsx delete mode 100644 src/cloud/components/molecules/Editor/EditorThemeSelect.tsx delete mode 100644 src/cloud/components/molecules/FolderDocList.tsx delete mode 100644 src/cloud/components/molecules/FolderListItem.tsx delete mode 100644 src/cloud/components/molecules/PageHeader.tsx delete mode 100644 src/cloud/components/molecules/PositionableModal/index.tsx delete mode 100644 src/cloud/components/molecules/RelativeDialog/RelativeDialog.tsx delete mode 100644 src/cloud/components/molecules/RelativeDialog/index.ts delete mode 100644 src/cloud/components/molecules/RelativeDialog/styled.ts delete mode 100644 src/cloud/components/molecules/RightLayoutHeaderButtons.tsx delete mode 100644 src/cloud/components/molecules/TabHeaders.tsx delete mode 100644 src/cloud/components/molecules/Timeline/TimelineList.tsx delete mode 100644 src/cloud/components/molecules/Timeline/TimelineListItem.tsx delete mode 100644 src/cloud/components/molecules/ToggleSection.tsx delete mode 100644 src/cloud/components/organisms/BookmarksList/index.tsx delete mode 100644 src/cloud/components/organisms/DocPage/styles.ts delete mode 100644 src/cloud/components/organisms/DocProperties/DocAssigneeSelect.tsx delete mode 100644 src/cloud/components/organisms/DocProperties/DocLabelSelectionModal.tsx delete mode 100644 src/cloud/components/organisms/FeedbackForm/ExpandingRow.tsx delete mode 100644 src/cloud/components/organisms/FolderPage/NewFolderContextMenu.tsx delete mode 100644 src/cloud/components/organisms/InviteForm.tsx delete mode 100644 src/cloud/components/organisms/Modal/contents/Doc/RevisionsModal/RevisionModalDetail.tsx delete mode 100644 src/cloud/components/organisms/Modal/contents/Doc/RevisionsModal/RevisionModalNavigator.tsx delete mode 100644 src/cloud/components/organisms/Modal/contents/Doc/RevisionsModal/styled.ts delete mode 100644 src/cloud/components/organisms/Modal/contents/Forms/styled.ts delete mode 100644 src/cloud/components/organisms/Modal/contents/Workspace/CreateWorkspaceModal.tsx delete mode 100644 src/cloud/components/organisms/Modal/contents/Workspace/EditWorkspaceModal.tsx delete mode 100644 src/cloud/components/organisms/Modal/contents/styled.ts delete mode 100644 src/cloud/components/organisms/Modal/styled.ts delete mode 100644 src/cloud/components/organisms/RightSideTopBar/TopBarSlashSeparator.tsx delete mode 100644 src/cloud/components/organisms/RightSideTopBar/styled.ts delete mode 100644 src/cloud/components/organisms/SharePageTopBar/index.tsx delete mode 100644 src/cloud/components/organisms/SharePageTopBar/styled.ts delete mode 100644 src/cloud/components/organisms/Sidebar/SideNavigator/SideNavIcon.tsx delete mode 100644 src/cloud/components/organisms/Sidebar/SideNavigator/styled.ts delete mode 100644 src/cloud/components/organisms/Topbar/Controls/ControlsContextMenu/TagContextMenu.tsx delete mode 100644 src/cloud/components/organisms/Topbar/Controls/TagControls.tsx delete mode 100644 src/cloud/components/organisms/Topbar/Controls/styled.ts delete mode 100644 src/cloud/components/organisms/WorkspacePage/index.tsx rename src/cloud/components/{organisms => }/settings/ApiTab.tsx (73%) rename src/cloud/components/{organisms => }/settings/AttachmentsTab.tsx (72%) rename src/cloud/components/{organisms => }/settings/BlockEditorTab.tsx (92%) rename src/cloud/components/{organisms => }/settings/GithubIntegration.tsx (74%) rename src/cloud/components/{organisms => }/settings/ImportTab.tsx (61%) rename src/cloud/components/{organisms => }/settings/IntegrationsTab.tsx (93%) rename src/cloud/components/{organisms => }/settings/MembersTab.tsx (83%) rename src/cloud/components/{organisms => }/settings/PersonalInfoTab.tsx (86%) rename src/cloud/components/{organisms => }/settings/PreferencesTab.tsx (72%) rename src/cloud/components/{organisms => }/settings/SettingsComponent.tsx (91%) rename src/cloud/components/{organisms => }/settings/SlackIntegration.tsx (72%) rename src/cloud/components/{organisms => }/settings/SubscriptionTab.tsx (80%) rename src/cloud/components/{organisms => }/settings/TeamInfoTab.tsx (72%) rename src/cloud/components/{organisms => }/settings/TeamSubLimit.tsx (91%) rename src/cloud/components/{organisms => }/settings/UpgradeTab.tsx (79%) rename src/cloud/components/{organisms => }/settings/UserPreferencesForm.tsx (94%) rename src/cloud/components/{organisms => }/settings/styled.ts (50%) create mode 100644 src/cloud/lib/stores/openInvites/index.ts create mode 100644 src/cloud/lib/stores/openInvites/store.ts create mode 100644 src/cloud/lib/stores/openInvites/withOpenInvites.tsx rename src/{shared/lib/stores/modal => cloud/lib/stores/teamPreferences}/index.tsx (100%) create mode 100644 src/cloud/lib/stores/teamPreferences/store.tsx create mode 100644 src/cloud/lib/stores/teamPreferences/types.ts delete mode 100644 src/cloud/lib/styled/index.ts delete mode 100644 src/cloud/lib/styled/keyframes.ts delete mode 100644 src/cloud/lib/styled/styleFunctions.ts delete mode 100644 src/cloud/lib/styled/styled.ts delete mode 100644 src/cloud/lib/styled/themes/dark.ts delete mode 100644 src/cloud/lib/styled/themes/index.ts delete mode 100644 src/cloud/lib/styled/themes/light.ts delete mode 100644 src/cloud/lib/styled/themes/shared.ts delete mode 100644 src/cloud/lib/styled/themes/types.ts delete mode 100644 src/cloud/lib/styled/unrounded.ts delete mode 100644 src/cloud/pages/[teamId]/bookmarks.tsx delete mode 100644 src/cloud/pages/[teamId]/status/[docStatus].tsx delete mode 100644 src/cloud/pages/[teamId]/timeline.tsx rename src/{shared => design}/components/atoms/Badge.tsx (100%) rename src/{shared => design}/components/atoms/Banner.tsx (100%) create mode 100644 src/design/components/atoms/BorderSeparator.tsx rename src/{shared => design}/components/atoms/Button.tsx (99%) rename src/{shared => design}/components/atoms/ButtonGroup.tsx (100%) create mode 100644 src/design/components/atoms/Card.tsx create mode 100644 src/design/components/atoms/ColoredBlock.tsx rename src/{shared => design}/components/atoms/DoublePane.tsx (70%) rename src/{cloud => design}/components/atoms/EditableInput.tsx (67%) rename src/{shared => design}/components/atoms/Flexbox.tsx (95%) rename src/{shared => design}/components/atoms/FoldingWrapper.tsx (100%) rename src/{shared => design}/components/atoms/GlobalStyle.tsx (100%) rename src/{shared => design}/components/atoms/Icon.tsx (94%) rename src/{ => design}/components/atoms/Image.tsx (100%) rename src/{shared => design}/components/atoms/LeftRightList.tsx (100%) rename src/{shared => design}/components/atoms/Link.tsx (100%) rename src/{shared => design}/components/atoms/NotifyIcon.tsx (100%) rename src/{shared => design}/components/atoms/PageHelmet.tsx (100%) rename src/{shared => design}/components/atoms/Pastille.tsx (100%) rename src/{shared => design}/components/atoms/Portal.tsx (100%) rename src/{shared => design}/components/atoms/PromiseWrapper.tsx (100%) rename src/{shared => design}/components/atoms/RoundedImage.tsx (100%) rename src/{shared => design}/components/atoms/Spinner.tsx (100%) rename src/{shared => design}/components/atoms/Switch.tsx (100%) rename src/{shared => design}/components/atoms/UpDownList.tsx (100%) rename src/{shared => design}/components/atoms/VerticalScroller.tsx (100%) rename src/{shared => design}/components/atoms/WidthEnlarger.tsx (100%) rename src/{shared => design}/components/atoms/WithTooltip.tsx (86%) rename src/{shared => design}/components/atoms/markdown/CodeFence.tsx (100%) rename src/{shared => design}/components/molecules/ApplicationLayout.tsx (100%) rename src/{shared => design}/components/molecules/CloseButtonWrapper.tsx (100%) rename src/{shared => design}/components/molecules/ContextMenu.tsx (100%) rename src/{shared => design}/components/molecules/EmojiPicker.tsx (100%) rename src/{shared => design}/components/molecules/FlattenedBreadcrumbs.tsx (100%) rename src/{shared => design}/components/molecules/Form/atoms/FormCheckbox.tsx (67%) rename src/{shared => design}/components/molecules/Form/atoms/FormCopyInput.tsx (100%) rename src/{shared => design}/components/molecules/Form/atoms/FormDatePicker.tsx (100%) rename src/{shared => design}/components/molecules/Form/atoms/FormEmoji.tsx (100%) rename src/{shared => design}/components/molecules/Form/atoms/FormImage.tsx (100%) rename src/{shared => design}/components/molecules/Form/atoms/FormInput.tsx (100%) rename src/{shared => design}/components/molecules/Form/atoms/FormRadio.tsx (100%) rename src/{shared => design}/components/molecules/Form/atoms/FormSelect.tsx (100%) rename src/{shared => design}/components/molecules/Form/atoms/FormStripeInput.tsx (100%) rename src/{shared => design}/components/molecules/Form/atoms/FormTextArea.tsx (99%) rename src/{shared => design}/components/molecules/Form/index.tsx (100%) rename src/{shared => design}/components/molecules/Form/templates/FormRow.tsx (100%) rename src/{shared => design}/components/molecules/Form/templates/FormRowItem.tsx (100%) create mode 100644 src/design/components/molecules/Navigation/NavigationItem.tsx rename src/{shared => design}/components/molecules/NotificationList.tsx (98%) create mode 100644 src/design/components/molecules/SearchableList.tsx rename src/{shared => design}/components/molecules/UserIconList.tsx (100%) rename src/{shared => design}/components/organisms/ContentManager/atoms/ContentManagerRow.tsx (99%) rename src/{shared => design}/components/organisms/ContentManager/index.tsx (100%) rename src/{shared => design}/components/organisms/ContentManager/molecules/ContentManagerSort.tsx (100%) rename src/{shared => design}/components/organisms/Dialog/Dialog.tsx (100%) rename src/{shared => design}/components/organisms/Dialog/atoms/DialogIcon.tsx (100%) rename src/{shared => design}/components/organisms/Dialog/molecules/MessageBoxDialogBody.tsx (100%) rename src/{shared => design}/components/organisms/EmojiInputForm.tsx (100%) rename src/{shared => design}/components/organisms/FuzzyNavigation/index.tsx (100%) rename src/{shared => design}/components/organisms/FuzzyNavigation/molecules/FuzzyNavigationItem.tsx (100%) rename src/{shared => design}/components/organisms/MetadataContainer/atoms/MetadataContainerBreak.tsx (100%) rename src/{shared => design}/components/organisms/MetadataContainer/index.tsx (100%) rename src/{shared => design}/components/organisms/MetadataContainer/molecules/MetadataContainerRow.tsx (100%) rename src/{shared => design}/components/organisms/Modal/atoms/ModalLayout.tsx (100%) rename src/{shared => design}/components/organisms/Modal/index.tsx (100%) rename src/{shared => design}/components/organisms/SearchLayout/atoms/SearchItem.tsx (99%) rename src/{shared => design}/components/organisms/SearchLayout/index.tsx (100%) rename src/{shared => design}/components/organisms/SearchLayout/molecules/SearchCategory.tsx (100%) rename src/{shared => design}/components/organisms/Settings/atoms/SettingNavItem.tsx (100%) rename src/{shared => design}/components/organisms/Settings/atoms/SettingTabContent.tsx (100%) rename src/{shared => design}/components/organisms/Settings/atoms/SettingTabSelector.tsx (100%) rename src/{shared => design}/components/organisms/Settings/index.tsx (100%) rename src/{shared => design}/components/organisms/Settings/molecules/SettingSidenav.tsx (100%) rename src/{shared => design}/components/organisms/Settings/molecules/SettingSidenavHeader.tsx (100%) rename src/{shared => design}/components/organisms/ShallowTimeline.tsx (100%) rename src/{shared => design}/components/organisms/Sidebar/atoms/SidebarButton.tsx (99%) rename src/{shared => design}/components/organisms/Sidebar/atoms/SidebarContextList.tsx (100%) rename src/{shared => design}/components/organisms/Sidebar/atoms/SidebarHeader.tsx (100%) rename src/{shared => design}/components/organisms/Sidebar/atoms/SidebarPopOver.tsx (100%) rename src/{shared => design}/components/organisms/Sidebar/atoms/SidebarTreeForm.tsx (100%) rename src/{shared => design}/components/organisms/Sidebar/atoms/SidebarTreeItem.tsx (99%) rename src/{shared => design}/components/organisms/Sidebar/index.tsx (98%) rename src/{shared => design}/components/organisms/Sidebar/molecules/SidebarButtonList.tsx (100%) rename src/{shared => design}/components/organisms/Sidebar/molecules/SidebarLink.tsx (100%) rename src/{shared => design}/components/organisms/Sidebar/molecules/SidebarSpaces.tsx (100%) rename src/{shared => design}/components/organisms/Sidebar/molecules/SidebarTree.tsx (100%) rename src/{shared => design}/components/organisms/Toast.tsx (100%) rename src/{shared => design}/components/organisms/Topbar/atoms/TopbarActionItem.tsx (99%) rename src/{shared => design}/components/organisms/Topbar/atoms/TopbarTreeItem.tsx (99%) rename src/{shared => design}/components/organisms/Topbar/index.tsx (99%) rename src/{shared => design}/components/organisms/Topbar/molecules/TopbarBreadcrumb.tsx (100%) rename src/{shared => design}/components/organisms/Topbar/molecules/TopbarNavigationContext.tsx (100%) rename src/{shared => design}/components/templates/ContentLayout.tsx (99%) rename src/{shared => design}/components/templates/ErrorLayout.tsx (100%) rename src/{shared => design}/lib/codemirror/rehypeCodeMirror.ts (100%) rename src/{shared => design}/lib/codemirror/util.ts (100%) rename src/{shared => design}/lib/date.ts (100%) rename src/{shared => design}/lib/dnd.ts (100%) rename src/{shared => design}/lib/dom.ts (100%) rename src/{shared => design}/lib/hooks/useApi.ts (100%) rename src/{shared => design}/lib/hooks/useBulkApi.ts (100%) rename src/{shared => design}/lib/hooks/useCancellablePromises.ts (100%) rename src/{shared => design}/lib/hooks/useNotificationState.ts (100%) rename src/{shared => design}/lib/hooks/useSuggestions.ts (100%) rename src/{shared => design}/lib/keyboard.ts (100%) rename src/{shared => design}/lib/mappers/topbarControls.ts (100%) rename src/{shared => design}/lib/mappers/types.ts (100%) rename src/{shared => design}/lib/mappers/users.ts (100%) rename src/{shared => design}/lib/platform.ts (100%) rename src/{shared => design}/lib/shortcuts.ts (100%) rename src/{shared => design}/lib/sidebar.ts (100%) rename src/{shared => design}/lib/stores/contextMenu/index.ts (100%) rename src/{shared => design}/lib/stores/contextMenu/types.ts (100%) rename src/{shared => design}/lib/stores/dialog/index.tsx (100%) rename src/{shared => design}/lib/stores/dialog/types.ts (100%) rename src/{shared => design}/lib/stores/emoji/index.tsx (100%) rename src/{shared => design}/lib/stores/emoji/types.ts (100%) rename src/{shared => design}/lib/stores/integrations/index.ts (100%) create mode 100644 src/design/lib/stores/modal/index.tsx rename src/{shared => design}/lib/stores/modal/store.ts (98%) rename src/{shared => design}/lib/stores/modal/types.ts (100%) rename src/{shared => design}/lib/stores/notifications/index.ts (100%) rename src/{shared => design}/lib/stores/toast/index.ts (100%) rename src/{shared => design}/lib/stores/window/index.ts (100%) rename src/{shared => design}/lib/stores/window/types.ts (100%) rename src/{shared => design}/lib/string.ts (100%) rename src/{shared => design}/lib/styled/common.ts (100%) rename src/{shared => design}/lib/styled/dark.ts (100%) rename src/{shared => design}/lib/styled/index.ts (100%) rename src/{shared => design}/lib/styled/light.ts (100%) rename src/{shared => design}/lib/styled/sepia.ts (100%) rename src/{shared => design}/lib/styled/solarizedDark.ts (100%) rename src/{shared => design}/lib/styled/styleFunctions.ts (94%) rename src/{shared => design}/lib/styled/types.ts (100%) rename src/{shared => design}/lib/types.ts (100%) rename src/{shared => design}/lib/utils/array.ts (100%) rename src/{shared => design}/lib/utils/comments.ts (100%) rename src/{shared => design}/lib/utils/context.tsx (100%) rename src/{shared => design}/lib/utils/secret.ts (100%) delete mode 100644 src/mobile/components/pages/BookmarksListPage.tsx diff --git a/src/cloud/api/feedback/index.ts b/src/cloud/api/feedback/index.ts index 821ace35f0..4221b5ce09 100644 --- a/src/cloud/api/feedback/index.ts +++ b/src/cloud/api/feedback/index.ts @@ -1,4 +1,4 @@ -import { UserFeedbackFormData } from '../../components/organisms/FeedbackForm/types' +import { UserFeedbackFormData } from '../../components/FeedbackForm/types' import { callApi } from '../../lib/client' export async function sendFeedback(body: UserFeedbackFormData) { diff --git a/src/cloud/api/teams/open-invites/index.ts b/src/cloud/api/teams/open-invites/index.ts index 25d5a26f53..1937c81497 100644 --- a/src/cloud/api/teams/open-invites/index.ts +++ b/src/cloud/api/teams/open-invites/index.ts @@ -1,14 +1,13 @@ import { callApi } from '../../../lib/client' -import { SerializedTeam } from '../../../interfaces/db/team' import { SerializedOpenInvite } from '../../../interfaces/db/openInvite' export interface GetOpenInviteResponseBody { invites: SerializedOpenInvite[] } -export async function getOpenInvites(team: SerializedTeam) { +export async function getOpenInvites(teamId: string) { const data = await callApi( - `api/teams/${team.id}/open-invites` + `api/teams/${teamId}/open-invites` ) return data } @@ -17,9 +16,9 @@ export interface CreateOpenInviteResponseBody { invites: SerializedOpenInvite[] } -export async function createOpenInvites(team: SerializedTeam) { +export async function createOpenInvites(teamId: string) { const data = await callApi( - `api/teams/${team.id}/open-invites`, + `api/teams/${teamId}/open-invites`, { method: 'post', } @@ -27,9 +26,9 @@ export async function createOpenInvites(team: SerializedTeam) { return data } -export async function cancelOpenInvites(team: SerializedTeam) { +export async function cancelOpenInvites(teamId: string) { const data = await callApi( - `api/teams/${team.id}/open-invites/delete`, + `api/teams/${teamId}/open-invites/delete`, { method: 'delete' } ) return data diff --git a/src/cloud/api/users/index.ts b/src/cloud/api/users/index.ts index 685ae27007..b3a10b019b 100644 --- a/src/cloud/api/users/index.ts +++ b/src/cloud/api/users/index.ts @@ -1,5 +1,5 @@ import { SerializedIcon } from '../../interfaces/db/icon' -import { UserFeedbackFormData } from '../../components/organisms/FeedbackForm/types' +import { UserFeedbackFormData } from '../../components/FeedbackForm/types' import { callApi } from '../../lib/client' export interface SaveUserRequestBody { diff --git a/src/cloud/components/atoms/AnnouncementAlert.tsx b/src/cloud/components/AnnouncementAlert.tsx similarity index 89% rename from src/cloud/components/atoms/AnnouncementAlert.tsx rename to src/cloud/components/AnnouncementAlert.tsx index b589bfe5e1..7ccd006caa 100644 --- a/src/cloud/components/atoms/AnnouncementAlert.tsx +++ b/src/cloud/components/AnnouncementAlert.tsx @@ -1,28 +1,28 @@ import React, { useMemo, useState } from 'react' -import { usePage } from '../../lib/stores/pageStore' -import styled from '../../../shared/lib/styled' -import { useOnboarding } from '../../lib/stores/onboarding' -import IconMdi from './IconMdi' +import { usePage } from '../lib/stores/pageStore' +import styled from '../../design/lib/styled' +import { useOnboarding } from '../lib/stores/onboarding' import { mdiAlertOutline, mdiClose, mdiInformationOutline, mdiOpenInNew, } from '@mdi/js' -import { useGlobalData } from '../../lib/stores/globalData' -import { PageStoreWithTeam } from '../../interfaces/pageStore' +import { useGlobalData } from '../lib/stores/globalData' +import { PageStoreWithTeam } from '../interfaces/pageStore' import { getCurrentDesktopAppVersion, useElectron, usingLegacyElectron, -} from '../../lib/stores/electron' -import { ExternalLink } from '../../../shared/components/atoms/Link' -import Button from '../../../shared/components/atoms/Button' -import { useSettings } from '../../lib/stores/settings' -import { useModal } from '../../../shared/lib/stores/modal' -import ButtonGroup from '../../../shared/components/atoms/ButtonGroup' -import { useTeamStorage } from '../../lib/stores/teamStorage' -import { freePlanMembersLimit } from '../../lib/subscription' +} from '../lib/stores/electron' +import { ExternalLink } from '../../design/components/atoms/Link' +import Button from '../../design/components/atoms/Button' +import { useSettings } from '../lib/stores/settings' +import { useModal } from '../../design/lib/stores/modal' +import ButtonGroup from '../../design/components/atoms/ButtonGroup' +import { useTeamStorage } from '../lib/stores/teamStorage' +import { freePlanMembersLimit } from '../lib/subscription' +import Icon from '../../design/components/atoms/Icon' const AnnouncementAlert = () => { const { currentSubInfo } = usePage() @@ -60,7 +60,7 @@ const AnnouncementAlert = () => {
- +

Please update the desktop app. This version is outdated (current @@ -70,7 +70,7 @@ const AnnouncementAlert = () => { className='alert__btn--close' onClick={() => setHidingOutdatedDesktopClientAlert(true)} > - +

@@ -85,7 +85,7 @@ const AnnouncementAlert = () => {
- +

We've changed the free plan. Please see @@ -107,7 +107,7 @@ const AnnouncementAlert = () => { className='alert__btn--close' onClick={() => setOnboarding({ trialAnnouncement: false })} > - +

@@ -130,7 +130,7 @@ const AnnouncementAlert = () => {
- +

@@ -146,7 +146,7 @@ const AnnouncementAlert = () => { href='https://intercom.help/boostnote-for-teams/en/articles/4354888-roles' className='alert__link' > - Viewer + Viewer {' '} role.

@@ -179,7 +179,7 @@ const AnnouncementAlert = () => {
- +

@@ -195,7 +195,7 @@ const AnnouncementAlert = () => { href='https://intercom.help/boostnote-for-teams/en/articles/4354888-roles' className='alert__link' > - Viewer + Viewer {' '} role.

@@ -213,7 +213,7 @@ const AnnouncementAlert = () => {
- +

@@ -230,7 +230,7 @@ const AnnouncementAlert = () => { href='https://intercom.help/boostnote-for-teams/en/articles/4354888-roles' className='alert__link' > - Viewer + Viewer {' '} role.

@@ -268,7 +268,7 @@ const AnnouncementAlert = () => {
- +

@@ -284,7 +284,7 @@ const AnnouncementAlert = () => { href='https://intercom.help/boostnote-for-teams/en/articles/4354888-roles' className='alert__link' > - Viewer + Viewer {' '} role.

@@ -320,7 +320,7 @@ const AnnouncementAlert = () => {
- +

@@ -329,7 +329,7 @@ const AnnouncementAlert = () => { href='https://intercom.help/boostnote-for-teams/en/articles/4354888-roles' className='alert__link' > - Viewers + Viewers {' '} have joined your space.

diff --git a/src/cloud/components/App.tsx b/src/cloud/components/App.tsx index 642f82e26e..cd795b87b9 100644 --- a/src/cloud/components/App.tsx +++ b/src/cloud/components/App.tsx @@ -14,7 +14,7 @@ import { gaTrackingId, nodeEnv, boostHubBaseUrl } from '../lib/consts' import '../lib/i18n' import { RealtimeConnProvider } from '../lib/stores/realtimeConn' -import { V2ToastProvider } from '../../shared/lib/stores/toast' +import { V2ToastProvider } from '../../design/lib/stores/toast' const App = () => { useElectron() const [accessTokenInitialized, setAccessTokenInitialized] = useState(false) diff --git a/src/cloud/components/molecules/AppFeedbackForm/index.tsx b/src/cloud/components/AppFeedbackForm/index.tsx similarity index 85% rename from src/cloud/components/molecules/AppFeedbackForm/index.tsx rename to src/cloud/components/AppFeedbackForm/index.tsx index a97ee5c527..028a0b3ee4 100644 --- a/src/cloud/components/molecules/AppFeedbackForm/index.tsx +++ b/src/cloud/components/AppFeedbackForm/index.tsx @@ -1,14 +1,14 @@ import React, { FormEvent, useState, useCallback, useRef } from 'react' -import { registerAppFeedback } from '../../../api/users/appfeedback' -import { AppFeedbackTypeOption } from '../../../interfaces/db/userAppFeedback' -import ColoredBlock from '../../atoms/ColoredBlock' +import { registerAppFeedback } from '../../api/users/appfeedback' +import { AppFeedbackTypeOption } from '../../interfaces/db/userAppFeedback' import { useEffectOnce } from 'react-use' -import { useToast } from '../../../../shared/lib/stores/toast' -import Form from '../../../../shared/components/molecules/Form' -import { useI18n } from '../../../lib/hooks/useI18n' -import { lngKeys } from '../../../lib/i18n/types' -import Button from '../../../../shared/components/atoms/Button' -import { FormSelectOption } from '../../../../shared/components/molecules/Form/atoms/FormSelect' +import { useToast } from '../../../design/lib/stores/toast' +import Form from '../../../design/components/molecules/Form' +import { useI18n } from '../../lib/hooks/useI18n' +import { lngKeys } from '../../lib/i18n/types' +import Button from '../../../design/components/atoms/Button' +import { FormSelectOption } from '../../../design/components/molecules/Form/atoms/FormSelect' +import ColoredBlock from '../../../design/components/atoms/ColoredBlock' const AppFeedbackForm = () => { const { translate } = useI18n() diff --git a/src/cloud/components/Application.tsx b/src/cloud/components/Application.tsx index fb2b3934f8..2d75b5ac72 100644 --- a/src/cloud/components/Application.tsx +++ b/src/cloud/components/Application.tsx @@ -12,7 +12,7 @@ import { useEffectOnce } from 'react-use' import { useSettings } from '../lib/stores/settings' import { shortcuts } from '../lib/shortcuts' import { useSearch } from '../lib/stores/search' -import AnnouncementAlert from './atoms/AnnouncementAlert' +import AnnouncementAlert from './AnnouncementAlert' import { newFolderEventEmitter, searchEventEmitter, @@ -22,19 +22,17 @@ import { } from '../lib/utils/events' import { usePathnameChangeEffect, useRouter } from '../lib/router' import { useNav } from '../lib/stores/nav' -import EventSource from './organisms/EventSource' -import ApplicationLayout from '../../shared/components/molecules/ApplicationLayout' +import EventSource from './EventSource' +import ApplicationLayout from '../../design/components/molecules/ApplicationLayout' import { useGlobalData } from '../lib/stores/globalData' -import { mapUsers } from '../../shared/lib/mappers/users' +import { mapUsers } from '../../design/lib/mappers/users' import { mdiCog, mdiDownload, mdiGiftOutline, - mdiImport, mdiInbox, mdiLogoutVariant, mdiMagnify, - mdiPaperclip, mdiPlusCircleOutline, mdiWeb, } from '@mdi/js' @@ -42,37 +40,37 @@ import { buildIconUrl } from '../api/files' import { sendToHost, usingElectron } from '../lib/stores/electron' import ContentLayout, { ContentLayoutProps, -} from '../../shared/components/templates/ContentLayout' +} from '../../design/components/templates/ContentLayout' import cc from 'classcat' import { useCloudResourceModals } from '../lib/hooks/useCloudResourceModals' import { mapTopbarTree } from '../lib/mappers/topbarTree' -import FuzzyNavigation from '../../shared/components/organisms/FuzzyNavigation' +import FuzzyNavigation from '../../design/components/organisms/FuzzyNavigation' import { mapFuzzyNavigationItems, mapFuzzyNavigationRecentItems, } from '../lib/mappers/fuzzyNavigation' -import { useModal } from '../../shared/lib/stores/modal' -import NewDocButton from './molecules/NewDocButton' +import { useModal } from '../../design/lib/stores/modal' +import NewDocButton from './Buttons/NewDocButton' import { useCloudSidebarTree } from '../lib/hooks/sidebar/useCloudSidebarTree' import { isTimeEligibleForDiscount } from '../lib/subscription' -import DiscountModal from './organisms/Modal/contents/DiscountModal' +import DiscountModal from './Modal/contents/DiscountModal' import { Notification as UserNotification } from '../interfaces/db/notifications' -import useNotificationState from '../../shared/lib/hooks/useNotificationState' -import { useNotifications } from '../../shared/lib/stores/notifications' +import useNotificationState from '../../design/lib/hooks/useNotificationState' +import { useNotifications } from '../../design/lib/stores/notifications' import '../lib/i18n' import { useI18n } from '../lib/hooks/useI18n' import { TFunction } from 'i18next' import { lngKeys } from '../lib/i18n/types' import Sidebar, { PopOverState, -} from '../../shared/components/organisms/Sidebar' -import SidebarHeader from '../../shared/components/organisms/Sidebar/atoms/SidebarHeader' -import SidebarButtonList from '../../shared/components/organisms/Sidebar/molecules/SidebarButtonList' -import NotifyIcon from '../../shared/components/atoms/NotifyIcon' -import { getTeamLinkHref } from './atoms/Link/TeamLink' -import SidebarButton from '../../shared/components/organisms/Sidebar/atoms/SidebarButton' -import CloudGlobalSearch from './organisms/CloudGlobalSearch' -import ViewerDisclaimer from './molecules/ViewerDisclaimer' +} from '../../design/components/organisms/Sidebar' +import SidebarHeader from '../../design/components/organisms/Sidebar/atoms/SidebarHeader' +import SidebarButtonList from '../../design/components/organisms/Sidebar/molecules/SidebarButtonList' +import NotifyIcon from '../../design/components/atoms/NotifyIcon' +import { getTeamLinkHref } from './Link/TeamLink' +import SidebarButton from '../../design/components/organisms/Sidebar/atoms/SidebarButton' +import CloudGlobalSearch from './CloudGlobalSearch' +import ViewerDisclaimer from './ViewerDisclaimer' import { useCloudSidebarSpaces } from '../lib/hooks/sidebar/useCloudSidebarSpaces' import { trackEvent } from '../api/track' import { MixpanelActionTrackTypes } from '../interfaces/analytics/mixpanel' @@ -362,13 +360,6 @@ const Application = ({ <> openSettingsTab('attachments'), - id: 'sidebar__button__attachments', - }, { label: translate(lngKeys.GeneralShared), icon: mdiWeb, @@ -378,13 +369,6 @@ const Application = ({ labelClick: () => push(getTeamLinkHref(team, 'shared')), id: 'sidebar__button__shared', }, - { - label: translate(lngKeys.GeneralImport), - icon: mdiImport, - variant: 'subtle', - labelClick: () => openSettingsTab('import'), - id: 'sidebar__button__import', - }, ]} > {isTimeEligibleForDiscount(team) && subscription == null ? ( @@ -406,15 +390,7 @@ const Application = ({ ) - }, [ - openModal, - openSettingsTab, - team, - pathname, - push, - translate, - subscription, - ]) + }, [openModal, team, pathname, push, translate, subscription]) return ( <> diff --git a/src/cloud/components/atoms/BottomBarButton.tsx b/src/cloud/components/BottomBarButton.tsx similarity index 78% rename from src/cloud/components/atoms/BottomBarButton.tsx rename to src/cloud/components/BottomBarButton.tsx index a8bfdc2088..b4267dd4d3 100644 --- a/src/cloud/components/atoms/BottomBarButton.tsx +++ b/src/cloud/components/BottomBarButton.tsx @@ -1,5 +1,5 @@ import React, { MouseEventHandler, FC } from 'react' -import styled from '../../lib/styled' +import styled from '../../design/lib/styled' interface BottomBarButtonProps { className?: string @@ -24,7 +24,7 @@ const Container = styled.button` background-color: transparent; height: 100%; border: none; - color: ${({ theme }) => theme.baseTextColor}; + color: ${({ theme }) => theme.colors.text.primary}; font-size: 14px; display: flex; align-items: center; @@ -32,6 +32,6 @@ const Container = styled.button` padding: 0 5px; cursor: pointer; &:hover { - background-color: ${({ theme }) => theme.emphasizedBackgroundColor}; + background-color: ${({ theme }) => theme.colors.background.tertiary}; } ` diff --git a/src/cloud/components/organisms/CloudGlobalSearch.tsx b/src/cloud/components/CloudGlobalSearch.tsx similarity index 87% rename from src/cloud/components/organisms/CloudGlobalSearch.tsx rename to src/cloud/components/CloudGlobalSearch.tsx index 1fce4694f6..f8fbc360bc 100644 --- a/src/cloud/components/organisms/CloudGlobalSearch.tsx +++ b/src/cloud/components/CloudGlobalSearch.tsx @@ -4,26 +4,26 @@ import { useDebounce } from 'react-use' import { GlobalSearchHistory, GlobalSearchResult, -} from '../../../shared/components/organisms/SearchLayout' -import useApi from '../../../shared/lib/hooks/useApi' +} from '../../design/components/organisms/SearchLayout' +import useApi from '../../design/lib/hooks/useApi' import { GetSearchResultsRequestQuery, getSearchResultsV2, HistoryItem, SearchResult, -} from '../../api/search' -import { SerializedDoc } from '../../interfaces/db/doc' -import { SerializedFolder } from '../../interfaces/db/folder' -import { SerializedTeam } from '../../interfaces/db/team' -import { useRouter } from '../../lib/router' -import { useSearch } from '../../lib/stores/search' -import { getDocTitle } from '../../lib/utils/patterns' -import { getDocLinkHref } from '../atoms/Link/DocLink' -import { getFolderHref } from '../atoms/Link/FolderLink' -import SearchLayout from '../../../shared/components/organisms/SearchLayout' -import { useNav } from '../../lib/stores/nav' -import { useI18n } from '../../lib/hooks/useI18n' -import { lngKeys } from '../../lib/i18n/types' +} from '../api/search' +import { SerializedDoc } from '../interfaces/db/doc' +import { SerializedFolder } from '../interfaces/db/folder' +import { SerializedTeam } from '../interfaces/db/team' +import { useRouter } from '../lib/router' +import { useSearch } from '../lib/stores/search' +import { getDocTitle } from '../lib/utils/patterns' +import { getDocLinkHref } from './Link/DocLink' +import { getFolderHref } from './Link/FolderLink' +import SearchLayout from '../../design/components/organisms/SearchLayout' +import { useNav } from '../lib/stores/nav' +import { useI18n } from '../lib/hooks/useI18n' +import { lngKeys } from '../lib/i18n/types' const contextHighlightStart = '' const contextHightlightEnd = '' diff --git a/src/cloud/components/organisms/CloudModal.tsx b/src/cloud/components/CloudModal.tsx similarity index 50% rename from src/cloud/components/organisms/CloudModal.tsx rename to src/cloud/components/CloudModal.tsx index c977d444dd..36063b2646 100644 --- a/src/cloud/components/organisms/CloudModal.tsx +++ b/src/cloud/components/CloudModal.tsx @@ -1,7 +1,7 @@ import React from 'react' -import Modal from '../../../shared/components/organisms/Modal' -import { useModal } from '../../../shared/lib/stores/modal' -import { usePathnameChangeEffect } from '../../lib/router' +import Modal from '../../design/components/organisms/Modal' +import { useModal } from '../../design/lib/stores/modal' +import { usePathnameChangeEffect } from '../lib/router' const CloudModal = () => { const { closeAllModals } = useModal() diff --git a/src/cloud/components/atoms/CodeMirrorStyle.tsx b/src/cloud/components/CodeMirrorStyle.tsx similarity index 93% rename from src/cloud/components/atoms/CodeMirrorStyle.tsx rename to src/cloud/components/CodeMirrorStyle.tsx index 0295c25610..e7f6f9e25a 100644 --- a/src/cloud/components/atoms/CodeMirrorStyle.tsx +++ b/src/cloud/components/CodeMirrorStyle.tsx @@ -1,5 +1,5 @@ import React from 'react' -import { useSettings, CodeMirrorEditorTheme } from '../../lib/stores/settings' +import { useSettings, CodeMirrorEditorTheme } from '../lib/stores/settings' interface ThemeLinkProps { appTheme: string diff --git a/src/cloud/components/molecules/CommentInput.tsx b/src/cloud/components/Comments/CommentInput.tsx similarity index 96% rename from src/cloud/components/molecules/CommentInput.tsx rename to src/cloud/components/Comments/CommentInput.tsx index 4319c5a2b6..b017bfe08b 100644 --- a/src/cloud/components/molecules/CommentInput.tsx +++ b/src/cloud/components/Comments/CommentInput.tsx @@ -1,11 +1,10 @@ import React, { useState, useCallback, useRef, useMemo } from 'react' -import Button from '../../../shared/components/atoms/Button' -import styled from '../../../shared/lib/styled' -import Flexbox from '../atoms/Flexbox' +import Button from '../../../design/components/atoms/Button' +import styled from '../../../design/lib/styled' import { useEffectOnce } from 'react-use' -import useSuggestions from '../../../shared/lib/hooks/useSuggestions' +import useSuggestions from '../../../design/lib/hooks/useSuggestions' import { SerializedUser } from '../../interfaces/db/user' -import UserIcon from '../atoms/UserIcon' +import UserIcon from '../UserIcon' import { makeMentionElement, fromNode, @@ -14,6 +13,7 @@ import { } from '../../lib/comments' import { lngKeys } from '../../lib/i18n/types' import { useI18n } from '../../lib/hooks/useI18n' +import Flexbox from '../../../design/components/atoms/Flexbox' interface CommentInputProps { onSubmit: (comment: string) => any diff --git a/src/cloud/components/molecules/CommentList.tsx b/src/cloud/components/Comments/CommentList.tsx similarity index 96% rename from src/cloud/components/molecules/CommentList.tsx rename to src/cloud/components/Comments/CommentList.tsx index 54ef9b931e..038ff11334 100644 --- a/src/cloud/components/molecules/CommentList.tsx +++ b/src/cloud/components/Comments/CommentList.tsx @@ -1,15 +1,15 @@ import React, { useState, useCallback, useMemo } from 'react' import { Comment } from '../../interfaces/db/comments' -import styled from '../../../shared/lib/styled' -import UserIcon from '../atoms/UserIcon' +import styled from '../../../design/lib/styled' +import UserIcon from '../UserIcon' import { format } from 'date-fns' -import Icon from '../../../shared/components/atoms/Icon' +import Icon from '../../../design/components/atoms/Icon' import { mdiDotsVertical, mdiClose } from '@mdi/js' import { SerializedUser } from '../../interfaces/db/user' import { useContextMenu, MenuTypes, -} from '../../../shared/lib/stores/contextMenu' +} from '../../../design/lib/stores/contextMenu' import CommentInput from './CommentInput' import sortBy from 'ramda/es/sortBy' import prop from 'ramda/es/prop' diff --git a/src/cloud/components/organisms/CommentManager.tsx b/src/cloud/components/Comments/CommentManager.tsx similarity index 93% rename from src/cloud/components/organisms/CommentManager.tsx rename to src/cloud/components/Comments/CommentManager.tsx index 1766e935f1..2f5e3c2c56 100644 --- a/src/cloud/components/organisms/CommentManager.tsx +++ b/src/cloud/components/Comments/CommentManager.tsx @@ -1,20 +1,20 @@ import React, { useMemo, useState } from 'react' import { Thread, Comment } from '../../interfaces/db/comments' -import Spinner from '../../../shared/components/atoms/Spinner' +import Spinner from '../../../design/components/atoms/Spinner' import { mdiPlusBoxOutline, mdiArrowLeft } from '@mdi/js' -import Icon from '../../../shared/components/atoms/Icon' -import CommentList from '../molecules/CommentList' -import styled from '../../../shared/lib/styled' -import CommentInput from '../molecules/CommentInput' -import ThreadActionButton from '../molecules/ThreadActionButton' -import Button from '../../../shared/components/atoms/Button' +import Icon from '../../../design/components/atoms/Icon' +import CommentList from './CommentList' +import styled from '../../../design/lib/styled' +import CommentInput from './CommentInput' +import ThreadActionButton from './ThreadActionButton' +import Button from '../../../design/components/atoms/Button' import { CreateThreadRequestBody } from '../../api/comments/thread' import { SerializedUser } from '../../interfaces/db/user' -import ThreadList from '../molecules/ThreadList' +import ThreadList from './ThreadList' import ThreadStatusFilterControl, { StatusFilter, -} from '../atoms/ThreadStatusFilterControl' -import { partitionOnStatus } from '../../../shared/lib/utils/comments' +} from '../ThreadStatusFilterControl' +import { partitionOnStatus } from '../../../design/lib/utils/comments' import { useI18n } from '../../lib/hooks/useI18n' import { lngKeys } from '../../lib/i18n/types' diff --git a/src/cloud/components/molecules/ThreadActionButton.tsx b/src/cloud/components/Comments/ThreadActionButton.tsx similarity index 87% rename from src/cloud/components/molecules/ThreadActionButton.tsx rename to src/cloud/components/Comments/ThreadActionButton.tsx index 081d6f848e..9c4925853d 100644 --- a/src/cloud/components/molecules/ThreadActionButton.tsx +++ b/src/cloud/components/Comments/ThreadActionButton.tsx @@ -5,13 +5,13 @@ import { mdiAlertCircleOutline, mdiAlertCircleCheckOutline, } from '@mdi/js' -import Icon from '../../../shared/components/atoms/Icon' +import Icon from '../../../design/components/atoms/Icon' import { capitalize } from '../../lib/utils/string' -import { useContextMenu } from '../../../shared/lib/stores/contextMenu' -import Flexbox from '../atoms/Flexbox' +import { useContextMenu } from '../../../design/lib/stores/contextMenu' import useThreadActions from '../../lib/hooks/useThreadMenuActions' -import { RoundButton } from '../../../shared/components/atoms/Button' +import { RoundButton } from '../../../design/components/atoms/Button' import { useI18n } from '../../lib/hooks/useI18n' +import Flexbox from '../../../design/components/atoms/Flexbox' interface ThreadActionButtonProps { thread: Thread diff --git a/src/cloud/components/molecules/ThreadItem.tsx b/src/cloud/components/Comments/ThreadItem.tsx similarity index 95% rename from src/cloud/components/molecules/ThreadItem.tsx rename to src/cloud/components/Comments/ThreadItem.tsx index 86fbafb663..10089be334 100644 --- a/src/cloud/components/molecules/ThreadItem.tsx +++ b/src/cloud/components/Comments/ThreadItem.tsx @@ -6,13 +6,13 @@ import { mdiDotsVertical, mdiAlertCircleCheckOutline, } from '@mdi/js' -import UserIcon from '../atoms/UserIcon' -import Icon from '../../../shared/components/atoms/Icon' -import styled from '../../../shared/lib/styled' +import UserIcon from '../UserIcon' +import Icon from '../../../design/components/atoms/Icon' +import styled from '../../../design/lib/styled' import useThreadActions, { ThreadActionProps, } from '../../lib/hooks/useThreadMenuActions' -import { useContextMenu } from '../../../shared/lib/stores/contextMenu' +import { useContextMenu } from '../../../design/lib/stores/contextMenu' import { lngKeys } from '../../lib/i18n/types' import { useI18n } from '../../lib/hooks/useI18n' diff --git a/src/cloud/components/molecules/ThreadList.tsx b/src/cloud/components/Comments/ThreadList.tsx similarity index 87% rename from src/cloud/components/molecules/ThreadList.tsx rename to src/cloud/components/Comments/ThreadList.tsx index db9d3d3d5f..350ba89a27 100644 --- a/src/cloud/components/molecules/ThreadList.tsx +++ b/src/cloud/components/Comments/ThreadList.tsx @@ -1,12 +1,12 @@ import React, { useMemo } from 'react' -import ThreadItem, { ThreadListItemProps } from '../molecules/ThreadItem' +import ThreadItem, { ThreadListItemProps } from './ThreadItem' import { Thread } from '../../interfaces/db/comments' import { sortBy } from 'ramda' import { highlightComment, unhighlightComment, -} from '../../../shared/lib/utils/comments' -import styled from '../../../shared/lib/styled' +} from '../../../design/lib/utils/comments' +import styled from '../../../design/lib/styled' interface ThreadListProps extends Omit { threads: Thread[] diff --git a/src/cloud/components/molecules/ContentManager/Actions/ContentManagerArchivesBulkActions.tsx b/src/cloud/components/ContentManager/Actions/ContentManagerArchivesBulkActions.tsx similarity index 90% rename from src/cloud/components/molecules/ContentManager/Actions/ContentManagerArchivesBulkActions.tsx rename to src/cloud/components/ContentManager/Actions/ContentManagerArchivesBulkActions.tsx index 5def11ae57..c8c4664e33 100644 --- a/src/cloud/components/molecules/ContentManager/Actions/ContentManagerArchivesBulkActions.tsx +++ b/src/cloud/components/ContentManager/Actions/ContentManagerArchivesBulkActions.tsx @@ -1,17 +1,17 @@ import React, { useState, useCallback, useMemo } from 'react' -import Flexbox from '../../../atoms/Flexbox' import HeaderAction from './HeaderAction' import { mdiFileUndoOutline, mdiTrashCanOutline } from '@mdi/js' import { useDialog, DialogIconTypes, -} from '../../../../../shared/lib/stores/dialog' -import { useNav } from '../../../../lib/stores/nav' -import { destroyDoc, updateDocStatus } from '../../../../api/teams/docs' -import { SerializedTeam } from '../../../../interfaces/db/team' +} from '../../../../design/lib/stores/dialog' +import { useNav } from '../../../lib/stores/nav' +import { destroyDoc, updateDocStatus } from '../../../api/teams/docs' +import { SerializedTeam } from '../../../interfaces/db/team' import { difference } from 'ramda' -import { getDocIdFromString } from '../../../../lib/utils/patterns' -import { SerializedDocWithBookmark } from '../../../../interfaces/db/doc' +import { getDocIdFromString } from '../../../lib/utils/patterns' +import { SerializedDocWithBookmark } from '../../../interfaces/db/doc' +import Flexbox from '../../../../design/components/atoms/Flexbox' interface ContentManagerArchivesBulkActionsProps { team: SerializedTeam diff --git a/src/cloud/components/molecules/ContentManager/Actions/DocOnlyContentManagerBulkActions.tsx b/src/cloud/components/ContentManager/Actions/DocOnlyContentManagerBulkActions.tsx similarity index 89% rename from src/cloud/components/molecules/ContentManager/Actions/DocOnlyContentManagerBulkActions.tsx rename to src/cloud/components/ContentManager/Actions/DocOnlyContentManagerBulkActions.tsx index 20f01abe2e..7fee8fa135 100644 --- a/src/cloud/components/molecules/ContentManager/Actions/DocOnlyContentManagerBulkActions.tsx +++ b/src/cloud/components/ContentManager/Actions/DocOnlyContentManagerBulkActions.tsx @@ -1,20 +1,20 @@ import React, { useState, useCallback, useMemo } from 'react' -import Flexbox from '../../../atoms/Flexbox' import HeaderAction from './HeaderAction' import { mdiFolderMoveOutline, mdiTrashCanOutline } from '@mdi/js' -import { SerializedDocWithBookmark } from '../../../../interfaces/db/doc' -import { SerializedTeam } from '../../../../interfaces/db/team' -import { useNav } from '../../../../lib/stores/nav' +import { SerializedDocWithBookmark } from '../../../interfaces/db/doc' +import { SerializedTeam } from '../../../interfaces/db/team' +import { useNav } from '../../../lib/stores/nav' import { difference } from 'ramda' -import { destroyDoc } from '../../../../api/teams/docs' -import { getDocIdFromString } from '../../../../lib/utils/patterns' +import { destroyDoc } from '../../../api/teams/docs' +import { getDocIdFromString } from '../../../lib/utils/patterns' import { useDialog, DialogIconTypes, -} from '../../../../../shared/lib/stores/dialog' -import { SerializedWorkspace } from '../../../../interfaces/db/workspace' -import MoveItemModal from '../../../organisms/Modal/contents/Forms/MoveItemModal' -import { useModal } from '../../../../../shared/lib/stores/modal' +} from '../../../../design/lib/stores/dialog' +import { SerializedWorkspace } from '../../../interfaces/db/workspace' +import MoveItemModal from '../../Modal/contents/Forms/MoveItemModal' +import { useModal } from '../../../../design/lib/stores/modal' +import Flexbox from '../../../../design/components/atoms/Flexbox' interface DocOnlyContentManagerBulkActionsProps { team: SerializedTeam diff --git a/src/cloud/components/ContentManager/Actions/HeaderAction.tsx b/src/cloud/components/ContentManager/Actions/HeaderAction.tsx new file mode 100644 index 0000000000..8f1d1ce17a --- /dev/null +++ b/src/cloud/components/ContentManager/Actions/HeaderAction.tsx @@ -0,0 +1,51 @@ +import React from 'react' +import { LoadingButton } from '../../../../design/components/atoms/Button' +import WithTooltip from '../../../../design/components/atoms/WithTooltip' + +type ContentManagerHeaderAction = { + iconPath: string + tooltip?: string + onClick: () => void +} + +interface HeaderActionProps { + action: ContentManagerHeaderAction + sending?: boolean + disabled?: boolean +} + +const HeaderAction = ({ + action, + disabled, + sending = false, +}: HeaderActionProps) => { + if (action.tooltip != null) { + return ( + + + + ) + } + + return ( + + ) +} + +export default HeaderAction diff --git a/src/cloud/components/ContentManager/Actions/RowAction.tsx b/src/cloud/components/ContentManager/Actions/RowAction.tsx new file mode 100644 index 0000000000..436a1ef08e --- /dev/null +++ b/src/cloud/components/ContentManager/Actions/RowAction.tsx @@ -0,0 +1,58 @@ +import React from 'react' +import { LoadingButton } from '../../../../design/components/atoms/Button' +import WithTooltip from '../../../../design/components/atoms/WithTooltip' +import { SerializedDocWithBookmark } from '../../../interfaces/db/doc' +import { SerializedFolderWithBookmark } from '../../../interfaces/db/folder' + +export type UnsignedItem = + | SerializedDocWithBookmark + | SerializedFolderWithBookmark + +export type ContentManagerRowAction = { + iconPath: string + tooltip?: string + id: number + onClick: (item: T) => void +} + +interface RowActionProps { + action: ContentManagerRowAction + item: T + sending?: boolean + disabled?: boolean +} + +const RowAction = ({ + action, + item, + disabled, + sending = false, +}: RowActionProps) => { + if (action.tooltip != null) { + return ( + + action.onClick(item)} + disabled={disabled} + /> + + ) + } + + return ( + action.onClick(item)} + disabled={disabled} + /> + ) +} + +export default RowAction diff --git a/src/cloud/components/molecules/ContentManager/ContentManagerCell.tsx b/src/cloud/components/ContentManager/ContentManagerCell.tsx similarity index 89% rename from src/cloud/components/molecules/ContentManager/ContentManagerCell.tsx rename to src/cloud/components/ContentManager/ContentManagerCell.tsx index 4991213088..20ade02f58 100644 --- a/src/cloud/components/molecules/ContentManager/ContentManagerCell.tsx +++ b/src/cloud/components/ContentManager/ContentManagerCell.tsx @@ -1,6 +1,6 @@ import React from 'react' -import styled from '../../../../shared/lib/styled' -import { AppComponent } from '../../../../shared/lib/types' +import styled from '../../../design/lib/styled' +import { AppComponent } from '../../../design/lib/types' import cc from 'classcat' interface ContentManagerCellProps { diff --git a/src/cloud/components/molecules/ContentManager/ContentManagerStatusFilter.tsx b/src/cloud/components/ContentManager/ContentManagerStatusFilter.tsx similarity index 87% rename from src/cloud/components/molecules/ContentManager/ContentManagerStatusFilter.tsx rename to src/cloud/components/ContentManager/ContentManagerStatusFilter.tsx index d0150f0629..3e638520f3 100644 --- a/src/cloud/components/molecules/ContentManager/ContentManagerStatusFilter.tsx +++ b/src/cloud/components/ContentManager/ContentManagerStatusFilter.tsx @@ -1,12 +1,12 @@ import { mdiFilterMenuOutline } from '@mdi/js' import React, { useCallback, useEffect, useRef, useState } from 'react' -import Button from '../../../../shared/components/atoms/Button' -import { isChildNode } from '../../../../shared/lib/dom' -import styled from '../../../../shared/lib/styled' -import { DocStatus } from '../../../interfaces/db/doc' -import { usePreferences } from '../../../lib/stores/preferences' -import Checkbox from '../../atoms/Checkbox' -import DocStatusIcon from '../../atoms/DocStatusIcon' +import Button from '../../../design/components/atoms/Button' +import { CheckboxWithLabel } from '../../../design/components/molecules/Form/atoms/FormCheckbox' +import { isChildNode } from '../../../design/lib/dom' +import styled from '../../../design/lib/styled' +import { DocStatus } from '../../interfaces/db/doc' +import { usePreferences } from '../../lib/stores/preferences' +import DocStatusIcon from '../DocStatusIcon' interface ContentManagerStatusFilterProps { statusFilterSet: Set @@ -77,10 +77,10 @@ const ContentManagerStatusFilter = ({ tabIndex={-1} >
- toggleStatusFilter('in_progress')} + toggle={() => toggleStatusFilter('in_progress')} label={
- toggleStatusFilter('paused')} + toggle={() => toggleStatusFilter('paused')} label={
- toggleStatusFilter('completed')} + toggle={() => toggleStatusFilter('completed')} label={
- toggleStatusFilter('archived')} + toggle={() => toggleStatusFilter('archived')} label={
void diff --git a/src/cloud/components/molecules/ContentManager/Rows/ContentManagerDocRow.tsx b/src/cloud/components/ContentManager/Rows/ContentManagerDocRow.tsx similarity index 85% rename from src/cloud/components/molecules/ContentManager/Rows/ContentManagerDocRow.tsx rename to src/cloud/components/ContentManager/Rows/ContentManagerDocRow.tsx index c7287bfa96..4ab0e745d3 100644 --- a/src/cloud/components/molecules/ContentManager/Rows/ContentManagerDocRow.tsx +++ b/src/cloud/components/ContentManager/Rows/ContentManagerDocRow.tsx @@ -2,26 +2,26 @@ import React, { useMemo, useCallback } from 'react' import { DocStatus, SerializedDocWithBookmark, -} from '../../../../interfaces/db/doc' -import { SerializedTeam } from '../../../../interfaces/db/team' +} from '../../../interfaces/db/doc' +import { SerializedTeam } from '../../../interfaces/db/team' import ContentManagerRow from './ContentManagerRow' -import { getDocTitle } from '../../../../lib/utils/patterns' +import { getDocTitle } from '../../../lib/utils/patterns' import { mdiFileDocumentOutline } from '@mdi/js' -import { getDocLinkHref } from '../../../atoms/Link/DocLink' -import { SerializedWorkspace } from '../../../../interfaces/db/workspace' -import { usePage } from '../../../../lib/stores/pageStore' -import { SerializedUser } from '../../../../interfaces/db/user' -import { useRouter } from '../../../../lib/router' -import styled from '../../../../../shared/lib/styled' -import { overflowEllipsis } from '../../../../../shared/lib/styled/styleFunctions' -import DocTagsListItem from '../../../atoms/DocTagsListItem' +import { getDocLinkHref } from '../../Link/DocLink' +import { SerializedWorkspace } from '../../../interfaces/db/workspace' +import { usePage } from '../../../lib/stores/pageStore' +import { SerializedUser } from '../../../interfaces/db/user' +import { useRouter } from '../../../lib/router' +import styled from '../../../../design/lib/styled' +import { overflowEllipsis } from '../../../../design/lib/styled/styleFunctions' +import DocTagsListItem from '../../DocTagsListItem' import ContentManagerCell from '../ContentManagerCell' -import { getFormattedBoosthubDateTime } from '../../../../lib/date' -import EditorsIcons from '../../../atoms/EditorsIcons' -import DocAssigneeSelect from '../../../organisms/DocProperties/DocAssigneeSelect' -import { useCloudApi } from '../../../../lib/hooks/useCloudApi' -import DocStatusSelect from '../../../organisms/DocProperties/DocStatusSelect' -import DocDueDateSelect from '../../../organisms/DocProperties/DocDueDateSelect' +import { getFormattedBoosthubDateTime } from '../../../lib/date' +import EditorsIcons from '../../EditorsIcons' +import DocAssigneeSelect from '../../DocProperties/DocAssigneeSelect' +import { useCloudApi } from '../../../lib/hooks/useCloudApi' +import DocStatusSelect from '../../DocProperties/DocStatusSelect' +import DocDueDateSelect from '../../DocProperties/DocDueDateSelect' interface ContentManagerDocRowProps { team: SerializedTeam diff --git a/src/cloud/components/molecules/ContentManager/Rows/ContentManagerFolderRow.tsx b/src/cloud/components/ContentManager/Rows/ContentManagerFolderRow.tsx similarity index 85% rename from src/cloud/components/molecules/ContentManager/Rows/ContentManagerFolderRow.tsx rename to src/cloud/components/ContentManager/Rows/ContentManagerFolderRow.tsx index eaf1def624..c0e20d6874 100644 --- a/src/cloud/components/molecules/ContentManager/Rows/ContentManagerFolderRow.tsx +++ b/src/cloud/components/ContentManager/Rows/ContentManagerFolderRow.tsx @@ -1,14 +1,13 @@ import React, { useMemo } from 'react' -import { SerializedFolderWithBookmark } from '../../../../interfaces/db/folder' -import { SerializedTeam } from '../../../../interfaces/db/team' +import { SerializedFolderWithBookmark } from '../../../interfaces/db/folder' +import { SerializedTeam } from '../../../interfaces/db/team' import ContentManagerRow from './ContentManagerRow' -import { getFolderHref } from '../../../atoms/Link/FolderLink' +import { getFolderHref } from '../../Link/FolderLink' import ContentManagerCell from '../ContentManagerCell' -import { useNav } from '../../../../lib/stores/nav' +import { useNav } from '../../../lib/stores/nav' import { useTranslation } from 'react-i18next' -import { lngKeys } from '../../../../lib/i18n/types' -import { useRouter } from '../../../../lib/router' - +import { lngKeys } from '../../../lib/i18n/types' +import { useRouter } from '../../../lib/router' interface ContentManagerFolderRowProps { team: SerializedTeam folder: SerializedFolderWithBookmark diff --git a/src/cloud/components/molecules/ContentManager/Rows/ContentManagerRow.tsx b/src/cloud/components/ContentManager/Rows/ContentManagerRow.tsx similarity index 94% rename from src/cloud/components/molecules/ContentManager/Rows/ContentManagerRow.tsx rename to src/cloud/components/ContentManager/Rows/ContentManagerRow.tsx index a3391d2ce1..fad25cd6d2 100644 --- a/src/cloud/components/molecules/ContentManager/Rows/ContentManagerRow.tsx +++ b/src/cloud/components/ContentManager/Rows/ContentManagerRow.tsx @@ -1,10 +1,10 @@ import React, { useCallback, useRef, useState } from 'react' import cc from 'classcat' -import Checkbox from '../../../atoms/Checkbox' -import styled from '../../../../../shared/lib/styled' -import { AppComponent } from '../../../../../shared/lib/types' -import EmojiIcon from '../../../atoms/EmojiIcon' import { onDragLeaveCb } from '../../../../../shared/lib/dnd' +import styled from '../../../../design/lib/styled' +import { AppComponent } from '../../../../design/lib/types' +import EmojiIcon from '../../EmojiIcon' +import Checkbox from '../../../../design/components/molecules/Form/atoms/FormCheckbox' interface ContentManagerRowProps { type?: 'header' | 'row' @@ -97,7 +97,7 @@ const ContentManagerRow: AppComponent = ({ onSelect(!checked)} /> )} - Latest Updated ), + icon: ( + + ), value: 'Latest Updated', - data: 'Latest Updated', }, { label: ( - Title A-Z ), + icon: ( + + ), value: 'Title A-Z', - data: 'Title A-Z', }, { label: ( - Title Z-A ), + icon: ( + + ), value: 'Title Z-A', - data: 'Title Z-A', }, ] interface SortingOptionProps { - value: typeof sortingOrders[number]['data'] - onChange: (value: CustomSelectOption) => void + value: typeof sortingOrders[number]['value'] + onChange: (value: FormSelectOption) => void } const SortingOption = ({ value, onChange }: SortingOptionProps) => { + const val = sortingOrders.find((ORDER) => ORDER.value === value) return ( - ORDER.data === value)} + value={val != null ? { label: val.icon, value: val.value } : undefined} onChange={onChange} className='rc-select' - classNamePrefix='select' isSearchable={false} isMulti={false} /> @@ -80,9 +98,9 @@ const SortingOption = ({ value, onChange }: SortingOptionProps) => { const StyledSortingOption = styled.div` margin-left: ${({ theme }) => theme.sizes.spaces.sm}px; - - .select__control { + .form__select__control { flex-wrap: inherit; + min-width: 32px !important; width: 32px; min-height: 32px; height: 34px; @@ -90,51 +108,42 @@ const StyledSortingOption = styled.div` box-shadow: none !important; background-color: transparent; cursor: pointer; - - .select__single-value, - .select__dropdown-indicator { + .form__select__single-value, + .form__select__dropdown-indicator { color: ${({ theme }) => theme.colors.text.subtle} !important; transition: color 150ms; - - .select__option__icon { + .form__select__option__icon { width: 20px !important; height: 20px !important; } - - .select__option__label { + .form__select__option__label { display: none; } } - - .select__value-container, - .select__dropdown-indicator { + .form__select__value-container, + .form__select__dropdown-indicator { padding: 2px; - svg { margin-right: 0; } } - &:hover { - .select__single-value, - .select__dropdown-indicator { + .form__select__single-value, + .form__select__dropdown-indicator { color: ${({ theme }) => theme.colors.text.secondary} !important; } } } - - .select__menu { + .form__select__menu { right: 0; width: 180px; background-color: ${({ theme }) => theme.colors.background.primary}; box-shadow: ${({ theme }) => theme.colors.shadow}; } - - .select__indicators { + .form__select__indicators { display: none; } - - .select__option { + .form__select__option { display: flex; align-items: center; justify-content: space-between; @@ -148,7 +157,6 @@ const StyledSortingOption = styled.div` font-size: ${({ theme }) => theme.sizes.fonts.sm}px; text-align: left; transition: 200ms color; - &:hover { background-color: ${({ theme }) => theme.colors.background.quaternary}; color: ${({ theme }) => theme.colors.text.primary}; @@ -168,8 +176,7 @@ const StyledSortingOption = styled.div` } } } - - .select__option__icon { + .form__select__option__icon { margin-right: ${({ theme }) => theme.sizes.spaces.xsm}px; } ` diff --git a/src/cloud/components/molecules/ContentManager/index.tsx b/src/cloud/components/ContentManager/index.tsx similarity index 91% rename from src/cloud/components/molecules/ContentManager/index.tsx rename to src/cloud/components/ContentManager/index.tsx index b75e861f6b..5b59ed8396 100644 --- a/src/cloud/components/molecules/ContentManager/index.tsx +++ b/src/cloud/components/ContentManager/index.tsx @@ -17,29 +17,36 @@ import { getFolderId, } from '../../../lib/utils/patterns' import { SerializedWorkspace } from '../../../interfaces/db/workspace' +import React, { useState, useMemo, useCallback, useEffect, useRef } from 'react' +import { SerializedDocWithBookmark, DocStatus } from '../../interfaces/db/doc' +import { SerializedFolderWithBookmark } from '../../interfaces/db/folder' +import { useSet } from 'react-use' +import { sortByAttributeAsc, sortByAttributeDesc } from '../../lib/utils/array' +import { getDocTitle, getDocId, getFolderId } from '../../lib/utils/patterns' +import { SerializedWorkspace } from '../../interfaces/db/workspace' import { StyledContentManagerList } from './styled' -import Checkbox from '../../atoms/Checkbox' -import { SerializedTeam } from '../../../interfaces/db/team' -import { CustomSelectOption } from '../../atoms/Select/CustomSelect' +import { SerializedTeam } from '../../interfaces/db/team' import SortingOption, { sortingOrders } from './SortingOption' import ContentManagerDocRow from './Rows/ContentManagerDocRow' import ContentmanagerFolderRow from './Rows/ContentManagerFolderRow' import { difference } from 'ramda' import ContentManagerToolbar from './ContentManagerToolbar' -import Button from '../../../../shared/components/atoms/Button' -import styled from '../../../../shared/lib/styled' -import { usePreferences } from '../../../lib/stores/preferences' +import Button from '../../../design/components/atoms/Button' +import styled from '../../../design/lib/styled' +import { usePreferences } from '../../lib/stores/preferences' import EmptyRow from './Rows/EmptyRow' import cc from 'classcat' import ContentManagerRow from './Rows/ContentManagerRow' -import { lngKeys } from '../../../lib/i18n/types' -import { useI18n } from '../../../lib/hooks/useI18n' +import { lngKeys } from '../../lib/i18n/types' +import { useI18n } from '../../lib/hooks/useI18n' import ContentManagerCell from './ContentManagerCell' -import Flexbox from '../../../../shared/components/atoms/Flexbox' +import Flexbox from '../../../design/components/atoms/Flexbox' import ContentManagerStatusFilter from './ContentManagerStatusFilter' -import VerticalScroller from '../../../../shared/components/atoms/VerticalScroller' import { useCloudDnd } from '../../../lib/hooks/sidebar/useCloudDnd' import { DraggedTo } from '../../../../shared/lib/dnd' +import VerticalScroller from '../../../design/components/atoms/VerticalScroller' +import { FormSelectOption } from '../../../design/components/molecules/Form/atoms/FormSelect' +import Checkbox from '../../../design/components/molecules/Form/atoms/FormCheckbox' export type ContentManagerParent = | { type: 'folder'; item: SerializedFolderWithBookmark } @@ -68,7 +75,7 @@ const ContentManager = ({ }: ContentManagerProps) => { const { preferences, setPreferences } = usePreferences() const [contentTab, setContentTab] = useState('all') - const [order, setOrder] = useState( + const [order, setOrder] = useState( preferences.folderSortingOrder ) const { translate } = useI18n() @@ -210,9 +217,9 @@ const ContentManager = ({ }, [resetDocs, resetFolders]) const onChangeOrder = useCallback( - (val: CustomSelectOption) => { - setOrder(val.data) - setPreferences({ folderSortingOrder: val.data }) + (val: FormSelectOption) => { + setOrder(val.value) + setPreferences({ folderSortingOrder: val.value as any }) }, [setPreferences] ) @@ -279,9 +286,7 @@ const ContentManager = ({ 'header__left__checkbox', selectingAllItems && 'header__left__checkbox--checked', ])} - onChange={ - selectingAllItems ? unselectAllItems : selectAllItems - } + toggle={selectingAllItems ? unselectAllItems : selectAllItems} /> )} diff --git a/src/cloud/components/ContentManager/styled.ts b/src/cloud/components/ContentManager/styled.ts new file mode 100644 index 0000000000..f387620b90 --- /dev/null +++ b/src/cloud/components/ContentManager/styled.ts @@ -0,0 +1,14 @@ +import { rightSideTopBarHeight } from '../../../design/components/organisms/Topbar' +import styled from '../../../design/lib/styled' + +export const StyledContentManager = styled.div` + display: block; + width: 100%; +` + +export const StyledContentManagerList = styled.div` + display: flex; + flex-direction: column; + width: 100%; + max-height: calc(100vh - ${rightSideTopBarHeight}px); +` diff --git a/src/cloud/components/organisms/EditorLayout/molecules/BackLinksList.tsx b/src/cloud/components/DocPage/BackLinksList.tsx similarity index 75% rename from src/cloud/components/organisms/EditorLayout/molecules/BackLinksList.tsx rename to src/cloud/components/DocPage/BackLinksList.tsx index a61088fb62..6230a05e61 100644 --- a/src/cloud/components/organisms/EditorLayout/molecules/BackLinksList.tsx +++ b/src/cloud/components/DocPage/BackLinksList.tsx @@ -1,14 +1,14 @@ import { mdiArrowBottomLeftBoldOutline, mdiTextBox } from '@mdi/js' import plur from 'plur' import React from 'react' -import Icon from '../../../../../shared/components/atoms/Icon' -import MetadataContainerRow from '../../../../../shared/components/organisms/MetadataContainer/molecules/MetadataContainerRow' -import styled from '../../../../../shared/lib/styled' -import { overflowEllipsis } from '../../../../../shared/lib/styled/styleFunctions' -import { SerializedDoc } from '../../../../interfaces/db/doc' -import { SerializedTeam } from '../../../../interfaces/db/team' -import { getDocTitle } from '../../../../lib/utils/patterns' -import DocLink from '../../../atoms/Link/DocLink' +import Icon from '../../../design/components/atoms/Icon' +import MetadataContainerRow from '../../../design/components/organisms/MetadataContainer/molecules/MetadataContainerRow' +import styled from '../../../design/lib/styled' +import { overflowEllipsis } from '../../../design/lib/styled/styleFunctions' +import { SerializedDoc } from '../../interfaces/db/doc' +import { SerializedTeam } from '../../interfaces/db/team' +import { getDocTitle } from '../../lib/utils/patterns' +import DocLink from '../Link/DocLink' interface BackLinksListProps { team: SerializedTeam diff --git a/src/cloud/components/organisms/EditorLayout/molecules/DocContextMenuActions.tsx b/src/cloud/components/DocPage/DocContextMenuActions.tsx similarity index 83% rename from src/cloud/components/organisms/EditorLayout/molecules/DocContextMenuActions.tsx rename to src/cloud/components/DocPage/DocContextMenuActions.tsx index e46305ebeb..59f904bcfe 100644 --- a/src/cloud/components/organisms/EditorLayout/molecules/DocContextMenuActions.tsx +++ b/src/cloud/components/DocPage/DocContextMenuActions.tsx @@ -12,49 +12,49 @@ import { mdiStar, mdiHistory, } from '@mdi/js' -import { SerializedDocWithBookmark } from '../../../../interfaces/db/doc' +import { SerializedDocWithBookmark } from '../../interfaces/db/doc' import copy from 'copy-to-clipboard' -import { SerializedTeam } from '../../../../interfaces/db/team' -import { getDocLinkHref } from '../../../atoms/Link/DocLink' -import { boostHubBaseUrl } from '../../../../lib/consts' +import { SerializedTeam } from '../../interfaces/db/team' +import { getDocLinkHref } from '../Link/DocLink' +import { boostHubBaseUrl } from '../../lib/consts' import { usingElectron, sendToHost, useElectron, -} from '../../../../lib/stores/electron' -import { useToast } from '../../../../../shared/lib/stores/toast' -import { useSettings } from '../../../../lib/stores/settings' -import { trackEvent } from '../../../../api/track' -import { MixpanelActionTrackTypes } from '../../../../interfaces/analytics/mixpanel' -import { defaultPreviewStyle } from '../../../atoms/MarkdownView/styles' +} from '../../lib/stores/electron' +import { useToast } from '../../../design/lib/stores/toast' +import { useSettings } from '../../lib/stores/settings' +import { trackEvent } from '../../api/track' +import { MixpanelActionTrackTypes } from '../../interfaces/analytics/mixpanel' +import { defaultPreviewStyle } from '../MarkdownView/styles' import { CreateDocTemplateResponseBody, saveDocAsTemplate, -} from '../../../../api/teams/docs/templates' +} from '../../api/teams/docs/templates' import { exportAsMarkdownFile, exportAsHtmlFile, convertMarkdownToPdfExportableHtml, filenamifyTitle, -} from '../../../../lib/export' -import { downloadBlob, printIframe } from '../../../../lib/download' -import { useNav } from '../../../../lib/stores/nav' -import MoveItemModal from '../../Modal/contents/Forms/MoveItemModal' -import { useModal } from '../../../../../shared/lib/stores/modal' -import { selectV2Theme } from '../../../../../shared/lib/styled/styleFunctions' -import { useI18n } from '../../../../lib/hooks/useI18n' -import { lngKeys } from '../../../../lib/i18n/types' -import MetadataContainerRow from '../../../../../shared/components/organisms/MetadataContainer/molecules/MetadataContainerRow' -import { useCloudApi } from '../../../../lib/hooks/useCloudApi' -import { useCloudResourceModals } from '../../../../lib/hooks/useCloudResourceModals' -import RevisionsModal from '../../Modal/contents/Doc/RevisionsModal' -import { SerializedRevision } from '../../../../interfaces/db/revision' -import MetadataContainerBreak from '../../../../../shared/components/organisms/MetadataContainer/atoms/MetadataContainerBreak' -import { usePage } from '../../../../lib/stores/pageStore' -import { revisionHistoryStandardDays } from '../../../../lib/subscription' -import UpgradeIntroButton from '../../../UpgradeIntroButton' +} from '../../lib/export' +import { downloadBlob, printIframe } from '../../lib/download' +import { useNav } from '../../lib/stores/nav' +import MoveItemModal from '../Modal/contents/Forms/MoveItemModal' +import { useModal } from '../../../design/lib/stores/modal' +import { selectV2Theme } from '../../../design/lib/styled/styleFunctions' +import { useI18n } from '../../lib/hooks/useI18n' +import { lngKeys } from '../../lib/i18n/types' +import MetadataContainerRow from '../../../design/components/organisms/MetadataContainer/molecules/MetadataContainerRow' +import { useCloudApi } from '../../lib/hooks/useCloudApi' +import { useCloudResourceModals } from '../../lib/hooks/useCloudResourceModals' +import RevisionsModal from '../Modal/contents/Doc/RevisionsModal' +import { SerializedRevision } from '../../interfaces/db/revision' +import MetadataContainerBreak from '../../../design/components/organisms/MetadataContainer/atoms/MetadataContainerBreak' +import { usePage } from '../../lib/stores/pageStore' +import { revisionHistoryStandardDays } from '../../lib/subscription' +import UpgradeIntroButton from '../UpgradeIntroButton' export interface DocContextMenuActionsProps { team: SerializedTeam diff --git a/src/cloud/components/organisms/EditorLayout/DocPageHeader.tsx b/src/cloud/components/DocPage/DocPageHeader.tsx similarity index 89% rename from src/cloud/components/organisms/EditorLayout/DocPageHeader.tsx rename to src/cloud/components/DocPage/DocPageHeader.tsx index cc98a54d47..03aba68b3c 100644 --- a/src/cloud/components/organisms/EditorLayout/DocPageHeader.tsx +++ b/src/cloud/components/DocPage/DocPageHeader.tsx @@ -1,30 +1,28 @@ import React, { useCallback, useState } from 'react' -import styled from '../../../../shared/lib/styled' -import { - DocStatus, - SerializedDocWithBookmark, -} from '../../../interfaces/db/doc' +import styled from '../../../design/lib/styled' +import { DocStatus, SerializedDocWithBookmark } from '../../interfaces/db/doc' import cc from 'classcat' -import { useCloudResourceModals } from '../../../lib/hooks/useCloudResourceModals' -import Button from '../../../../shared/components/atoms/Button' -import Icon from '../../../../shared/components/atoms/Icon' +import { useCloudResourceModals } from '../../lib/hooks/useCloudResourceModals' +import Button from '../../../design/components/atoms/Button' +import Icon from '../../../design/components/atoms/Icon' import { mdiCommentTextOutline, mdiPencil } from '@mdi/js' -import { usePage } from '../../../lib/stores/pageStore' -import { useNav } from '../../../lib/stores/nav' +import { usePage } from '../../lib/stores/pageStore' +import { useNav } from '../../lib/stores/nav' import { updateDocAssignees, updateDocDueDate, updateDocStatus, -} from '../../../api/teams/docs' +} from '../../api/teams/docs' import { format as formatDate } from 'date-fns' -import { useToast } from '../../../../shared/lib/stores/toast' +import { useToast } from '../../../design/lib/stores/toast' import DocAssigneeSelect from '../DocProperties/DocAssigneeSelect' -import DocTagsList from './molecules/DocTagsList' -import { SerializedTeam } from '../../../interfaces/db/team' +import DocTagsList from './DocTagsList' +import { SerializedTeam } from '../../interfaces/db/team' import DocStatusSelect from '../DocProperties/DocStatusSelect' import DocDueDateSelect from '../DocProperties/DocDueDateSelect' -import { usePreferences } from '../../../lib/stores/preferences' -import { overflowEllipsis } from '../../../../shared/lib/styled/styleFunctions' +import { usePreferences } from '../../lib/stores/preferences' +import { overflowEllipsis } from '../../../design/lib/styled/styleFunctions' +import { getDocTitle } from '../../lib/utils/patterns' interface DocPageHeaderProps { docIsEditable?: boolean @@ -132,7 +130,9 @@ const DocPageHeader = ({ ])} onClick={() => openRenameDocForm(doc)} > - {doc.title} + + {getDocTitle(doc, 'Untitled')} + ) : ( @@ -232,7 +232,7 @@ const Container = styled.div` font-size: ${({ theme }) => theme.sizes.fonts.xl}px; color: ${({ theme }) => theme.colors.text.primary}; width: fit-content; - max-width: 100%; + width: 100%; .button__label { max-width: 100%; diff --git a/src/cloud/components/molecules/DocShare.tsx b/src/cloud/components/DocPage/DocShare.tsx similarity index 95% rename from src/cloud/components/molecules/DocShare.tsx rename to src/cloud/components/DocPage/DocShare.tsx index 141848f4a2..b6de386dfc 100644 --- a/src/cloud/components/molecules/DocShare.tsx +++ b/src/cloud/components/DocPage/DocShare.tsx @@ -12,27 +12,27 @@ import { mdiClipboardCheckOutline, mdiEarth, } from '@mdi/js' -import Icon from '../atoms/Icon' import copy from 'copy-to-clipboard' -import Flexbox from '../atoms/Flexbox' import { isArray } from 'util' import 'react-datepicker/dist/react-datepicker.css' import { boostHubBaseUrl } from '../../lib/consts' import { SerializedTeam } from '../../interfaces/db/team' -import { useToast } from '../../../shared/lib/stores/toast' -import Button, { LoadingButton } from '../../../shared/components/atoms/Button' -import Switch from '../../../shared/components/atoms/Switch' +import { useToast } from '../../../design/lib/stores/toast' +import Button, { LoadingButton } from '../../../design/components/atoms/Button' +import Switch from '../../../design/components/atoms/Switch' import UpgradeIntroButton from '../UpgradeIntroButton' import { useI18n } from '../../lib/hooks/useI18n' import { lngKeys } from '../../lib/i18n/types' import { capitalize } from '../../lib/utils/string' -import Banner from '../../../shared/components/atoms/Banner' -import styled from '../../../shared/lib/styled' -import FormInput from '../../../shared/components/molecules/Form/atoms/FormInput' +import Banner from '../../../design/components/atoms/Banner' +import styled from '../../../design/lib/styled' +import FormInput from '../../../design/components/molecules/Form/atoms/FormInput' import cc from 'classcat' -import Form from '../../../shared/components/molecules/Form' -import FormDatePicker from '../../../shared/components/molecules/Form/atoms/FormDatePicker' -import Portal from '../../../shared/components/atoms/Portal' +import Form from '../../../design/components/molecules/Form' +import FormDatePicker from '../../../design/components/molecules/Form/atoms/FormDatePicker' +import Portal from '../../../design/components/atoms/Portal' +import Flexbox from '../../../design/components/atoms/Flexbox' +import Icon from '../../../design/components/atoms/Icon' type SendingState = | 'idle' @@ -298,7 +298,7 @@ const DocShare = ({ currentDoc, team }: DocShareProps) => { <>
- + { id='tag__add__btn' onClick={activateAndFocus} > - + ) ) : ( diff --git a/src/cloud/components/organisms/EditorLayout/molecules/DocTagsList/index.tsx b/src/cloud/components/DocPage/DocTagsList/index.tsx similarity index 87% rename from src/cloud/components/organisms/EditorLayout/molecules/DocTagsList/index.tsx rename to src/cloud/components/DocPage/DocTagsList/index.tsx index 67dfa1452a..1949fce5f6 100644 --- a/src/cloud/components/organisms/EditorLayout/molecules/DocTagsList/index.tsx +++ b/src/cloud/components/DocPage/DocTagsList/index.tsx @@ -1,16 +1,16 @@ import React, { useState, useCallback, useMemo } from 'react' -import { SerializedDocWithBookmark } from '../../../../../interfaces/db/doc' -import { SerializedTeam } from '../../../../../interfaces/db/team' +import { SerializedDocWithBookmark } from '../../../interfaces/db/doc' +import { SerializedTeam } from '../../../interfaces/db/team' import TagsAutoCompleteInput from './TagsAutoCompleteInput' -import { deleteTagFromDoc } from '../../../../../api/teams/docs/tags' -import { useNav } from '../../../../../lib/stores/nav' -import DocTagsListItem from '../../../../atoms/DocTagsListItem' -import { SerializedTag } from '../../../../../interfaces/db/tag' +import { deleteTagFromDoc } from '../../../api/teams/docs/tags' +import { useNav } from '../../../lib/stores/nav' +import DocTagsListItem from '../../DocTagsListItem' +import { SerializedTag } from '../../../interfaces/db/tag' import { mdiChevronRight, mdiChevronDown, mdiLabelOutline } from '@mdi/js' -import { useToast } from '../../../../../../shared/lib/stores/toast' +import { useToast } from '../../../../design/lib/stores/toast' import cc from 'classcat' -import styled from '../../../../../../shared/lib/styled' -import Icon from '../../../../../../shared/components/atoms/Icon' +import styled from '../../../../design/lib/styled' +import Icon from '../../../../design/components/atoms/Icon' interface DocTagsListProps { doc: SerializedDocWithBookmark diff --git a/src/cloud/components/organisms/DocPage/Edit.tsx b/src/cloud/components/DocPage/Edit.tsx similarity index 71% rename from src/cloud/components/organisms/DocPage/Edit.tsx rename to src/cloud/components/DocPage/Edit.tsx index 3001f4a710..5c7bf1c408 100644 --- a/src/cloud/components/organisms/DocPage/Edit.tsx +++ b/src/cloud/components/DocPage/Edit.tsx @@ -2,13 +2,13 @@ import React from 'react' import { SerializedDocWithBookmark, SerializedDoc, -} from '../../../interfaces/db/doc' -import Editor from '../../molecules/Editor' -import { SerializedTeam } from '../../../interfaces/db/team' -import { SerializedUser } from '../../../interfaces/db/user' -import styled from '../../../lib/styled' -import { rightSideTopBarHeight } from '../RightSideTopBar/styled' -import { SerializedRevision } from '../../../interfaces/db/revision' +} from '../../interfaces/db/doc' +import Editor from '../Editor' +import { SerializedTeam } from '../../interfaces/db/team' +import { SerializedUser } from '../../interfaces/db/user' +import { SerializedRevision } from '../../interfaces/db/revision' +import styled from '../../../design/lib/styled' +import { rightSideTopBarHeight } from '../../../design/components/organisms/Topbar' interface EditPageProps { doc: SerializedDocWithBookmark diff --git a/src/cloud/components/organisms/EditorLayout/index.tsx b/src/cloud/components/DocPage/EditorLayout.tsx similarity index 88% rename from src/cloud/components/organisms/EditorLayout/index.tsx rename to src/cloud/components/DocPage/EditorLayout.tsx index 019a499c5a..738f9327c6 100644 --- a/src/cloud/components/organisms/EditorLayout/index.tsx +++ b/src/cloud/components/DocPage/EditorLayout.tsx @@ -1,10 +1,10 @@ import React, { PropsWithChildren } from 'react' -import styled from '../../../../shared/lib/styled' -import { SerializedDocWithBookmark } from '../../../interfaces/db/doc' +import styled from '../../../design/lib/styled' +import { SerializedDocWithBookmark } from '../../interfaces/db/doc' import DocPageHeader from './DocPageHeader' import cc from 'classcat' -import { SerializedTeam } from '../../../interfaces/db/team' -import VerticalScroller from '../../../../shared/components/atoms/VerticalScroller' +import { SerializedTeam } from '../../interfaces/db/team' +import VerticalScroller from '../../../design/components/atoms/VerticalScroller' interface EditorLayoutProps { docIsEditable: boolean diff --git a/src/cloud/components/organisms/EditorLayout/NewDocContextMenu.tsx b/src/cloud/components/DocPage/NewDocContextMenu.tsx similarity index 76% rename from src/cloud/components/organisms/EditorLayout/NewDocContextMenu.tsx rename to src/cloud/components/DocPage/NewDocContextMenu.tsx index ab8e771924..ce6ef4533a 100644 --- a/src/cloud/components/organisms/EditorLayout/NewDocContextMenu.tsx +++ b/src/cloud/components/DocPage/NewDocContextMenu.tsx @@ -5,26 +5,26 @@ import { mdiContentSaveOutline, } from '@mdi/js' import React, { useMemo, useState } from 'react' -import Flexbox from '../../../../shared/components/atoms/Flexbox' -import MetadataContainer from '../../../../shared/components/organisms/MetadataContainer' -import MetadataContainerBreak from '../../../../shared/components/organisms/MetadataContainer/atoms/MetadataContainerBreak' -import MetadataContainerRow from '../../../../shared/components/organisms/MetadataContainer/molecules/MetadataContainerRow' +import Button from '../../../design/components/atoms/Button' +import Flexbox from '../../../design/components/atoms/Flexbox' +import MetadataContainer from '../../../design/components/organisms/MetadataContainer' +import MetadataContainerBreak from '../../../design/components/organisms/MetadataContainer/atoms/MetadataContainerBreak' +import MetadataContainerRow from '../../../design/components/organisms/MetadataContainer/molecules/MetadataContainerRow' import { SerializedDoc, SerializedDocWithBookmark, -} from '../../../interfaces/db/doc' -import { SerializedRevision } from '../../../interfaces/db/revision' -import { SerializedTeam } from '../../../interfaces/db/team' -import { SerializedUser } from '../../../interfaces/db/user' -import { SerializedUserTeamPermissions } from '../../../interfaces/db/userTeamPermissions' -import { getFormattedDateTime } from '../../../lib/date' -import { useI18n } from '../../../lib/hooks/useI18n' -import { lngKeys } from '../../../lib/i18n/types' -import { useNav } from '../../../lib/stores/nav' -import SmallButton from '../../atoms/SmallButton' -import UserIcon from '../../atoms/UserIcon' -import BackLinksList from './molecules/BackLinksList' -import DocContextMenuActions from './molecules/DocContextMenuActions' +} from '../../interfaces/db/doc' +import { SerializedRevision } from '../../interfaces/db/revision' +import { SerializedTeam } from '../../interfaces/db/team' +import { SerializedUser } from '../../interfaces/db/user' +import { SerializedUserTeamPermissions } from '../../interfaces/db/userTeamPermissions' +import { getFormattedDateTime } from '../../lib/date' +import { useI18n } from '../../lib/hooks/useI18n' +import { lngKeys } from '../../lib/i18n/types' +import { useNav } from '../../lib/stores/nav' +import UserIcon from '../UserIcon' +import BackLinksList from './BackLinksList' +import DocContextMenuActions from './DocContextMenuActions' interface DocContextMenuProps { currentDoc: SerializedDocWithBookmark @@ -190,15 +190,19 @@ const DocContextMenu = ({ /> ))} - {contributors.length > 5 && ( - setSliceContributors((prev) => !prev)} - > - {contributorsState.sliced > 0 - ? `+${contributorsState.sliced}` - : '-'} - + {contributors.length > 0 && ( + <> +
+ + )} ), diff --git a/src/cloud/components/organisms/DocPage/SharedDocPage.tsx b/src/cloud/components/DocPage/SharedDocPage.tsx similarity index 81% rename from src/cloud/components/organisms/DocPage/SharedDocPage.tsx rename to src/cloud/components/DocPage/SharedDocPage.tsx index cad2583249..af8e2ef4b6 100644 --- a/src/cloud/components/organisms/DocPage/SharedDocPage.tsx +++ b/src/cloud/components/DocPage/SharedDocPage.tsx @@ -1,15 +1,15 @@ import React, { useState, useEffect, useRef, useCallback } from 'react' -import useRealtime from '../../../lib/editor/hooks/useRealtime' -import { getRandomColor } from '../../../lib/utils/string' -import { StyledDocPage } from '../../../components/organisms/DocPage/styles' -import styled from '../../../../shared/lib/styled' -import SyncStatus from '../../../components/organisms/Topbar/SyncStatus' -import PresenceIcons from '../../../components/organisms/Topbar/PresenceIcons' -import Spinner from '../../../components/atoms/CustomSpinner' -import ColoredBlock from '../../../components/atoms/ColoredBlock' -import SharePageTopbar from '../../../components/organisms/SharePageTopBar' -import { SerializedDoc } from '../../../interfaces/db/doc' -import MarkdownView from '../../atoms/MarkdownView' +import useRealtime from '../../lib/editor/hooks/useRealtime' +import { getRandomColor } from '../../lib/utils/string' +import { StyledDocPage } from './styles' +import styled from '../../../design/lib/styled' +import SyncStatus from '../Topbar/SyncStatus' +import PresenceIcons from '../Topbar/PresenceIcons' +import SharePageTopbar from '../SharePageTopBar' +import { SerializedDoc } from '../../interfaces/db/doc' +import MarkdownView from '../MarkdownView' +import Spinner from '../../../design/components/atoms/Spinner' +import ColoredBlock from '../../../design/components/atoms/ColoredBlock' interface SharedDocPageProps { doc: SerializedDoc diff --git a/src/cloud/components/organisms/DocPage/View.tsx b/src/cloud/components/DocPage/View.tsx similarity index 86% rename from src/cloud/components/organisms/DocPage/View.tsx rename to src/cloud/components/DocPage/View.tsx index 830a2f13c2..a4f1899c6a 100644 --- a/src/cloud/components/organisms/DocPage/View.tsx +++ b/src/cloud/components/DocPage/View.tsx @@ -2,52 +2,54 @@ import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react' import { SerializedDocWithBookmark, SerializedDoc, -} from '../../../interfaces/db/doc' -import styled from '../../../lib/styled' -import { useNav } from '../../../lib/stores/nav' -import { SerializedTeam } from '../../../interfaces/db/team' -import { usePage } from '../../../lib/stores/pageStore' -import { usePreferences } from '../../../lib/stores/preferences' -import Application from '../../Application' -import { rightSideTopBarHeight } from '../RightSideTopBar/styled' -import { rightSidePageLayout } from '../../../lib/styled/styleFunctions' -import { SerializedUser } from '../../../interfaces/db/user' -import MarkdownView, { SelectionContext } from '../../atoms/MarkdownView' -import { useRouter } from '../../../lib/router' -import { LoadingButton } from '../../../../shared/components/atoms/Button' +} from '../../interfaces/db/doc' +import { useNav } from '../../lib/stores/nav' +import { SerializedTeam } from '../../interfaces/db/team' +import { usePage } from '../../lib/stores/pageStore' +import { usePreferences } from '../../lib/stores/preferences' +import Application from '../Application' +import { SerializedUser } from '../../interfaces/db/user' +import MarkdownView, { SelectionContext } from '../MarkdownView' +import { useRouter } from '../../lib/router' +import { LoadingButton } from '../../../design/components/atoms/Button' import { mdiCommentTextOutline, mdiDotsHorizontal, mdiStar, mdiStarOutline, } from '@mdi/js' -import { useCloudApi } from '../../../lib/hooks/useCloudApi' -import { useCloudResourceModals } from '../../../lib/hooks/useCloudResourceModals' -import { mapTopbarBreadcrumbs } from '../../../lib/mappers/topbarBreadcrumbs' -import useRealtime from '../../../lib/editor/hooks/useRealtime' -import { buildIconUrl } from '../../../api/files' -import { getColorFromString } from '../../../lib/utils/string' +import { useCloudApi } from '../../lib/hooks/useCloudApi' +import { useCloudResourceModals } from '../../lib/hooks/useCloudResourceModals' +import { mapTopbarBreadcrumbs } from '../../lib/mappers/topbarBreadcrumbs' +import useRealtime from '../../lib/editor/hooks/useRealtime' +import { buildIconUrl } from '../../api/files' +import { getColorFromString } from '../../lib/utils/string' import { createAbsolutePositionFromRelativePosition, createRelativePositionFromTypeIndex, } from 'yjs' -import useCommentManagerState from '../../../lib/hooks/useCommentManagerState' -import { HighlightRange } from '../../../lib/rehypeHighlight' -import Spinner from '../../../../shared/components/atoms/Spinner' -import Icon from '../../atoms/Icon' +import useCommentManagerState from '../../lib/hooks/useCommentManagerState' +import { HighlightRange } from '../../lib/rehypeHighlight' +import Spinner from '../../../design/components/atoms/Spinner' import PresenceIcons from '../Topbar/PresenceIcons' -import CommentManager from '../CommentManager' -import { SerializedRevision } from '../../../interfaces/db/revision' -import { TopbarControlProps } from '../../../../shared/components/organisms/Topbar' -import { getDocLinkHref } from '../../atoms/Link/DocLink' -import { useI18n } from '../../../lib/hooks/useI18n' -import { lngKeys } from '../../../lib/i18n/types' +import CommentManager from '../Comments/CommentManager' +import { SerializedRevision } from '../../interfaces/db/revision' +import { + rightSideTopBarHeight, + TopbarControlProps, +} from '../../../design/components/organisms/Topbar' +import { getDocLinkHref } from '../Link/DocLink' +import { useI18n } from '../../lib/hooks/useI18n' +import { lngKeys } from '../../lib/i18n/types' import { parse } from 'querystring' -import DocShare from '../../molecules/DocShare' -import { useModal } from '../../../../shared/lib/stores/modal' -import NewDocContextMenu from '../EditorLayout/NewDocContextMenu' -import PreferencesContextMenuWrapper from '../../molecules/PreferencesContextMenuWrapper' -import InviteCTAButton from '../../molecules/InviteCTAButton' +import DocShare from './DocShare' +import { useModal } from '../../../design/lib/stores/modal' +import NewDocContextMenu from './NewDocContextMenu' +import PreferencesContextMenuWrapper from '../PreferencesContextMenuWrapper' +import InviteCTAButton from '../Buttons/InviteCTAButton' +import styled from '../../../design/lib/styled' +import { rightSidePageLayout } from '../../../design/lib/styled/styleFunctions' +import Icon from '../../../design/components/atoms/Icon' interface ViewPageProps { team: SerializedTeam @@ -492,7 +494,7 @@ const ViewPage = ({ SelectionMenu={({ selection }) => (
newRangeThread(selection)}> - +
)} @@ -539,7 +541,7 @@ const StyledSelectionMenu = styled.div` ` const StyledPlaceholderContent = styled.div` - color: ${({ theme }) => theme.subtleTextColor}; + color: ${({ theme }) => theme.colors.text.subtle}; ` const Container = styled.div` @@ -565,17 +567,17 @@ const Container = styled.div` height: auto; min-height: calc( 100vh - ${rightSideTopBarHeight}px - - ${({ theme }) => theme.space.xlarge}px + ${({ theme }) => theme.sizes.spaces.xl}px ); font-size: 15px; ${rightSidePageLayout} margin: auto; - padding: 0 ${({ theme }) => theme.space.xlarge}px; + padding: 0 ${({ theme }) => theme.sizes.spaces.xl}px; } .view__content { height: 100%; - padding-top: ${({ theme }) => theme.space.small}px; + padding-top: ${({ theme }) => theme.sizes.spaces.sm}px; margin: 0 auto; width: 100%; diff --git a/src/cloud/components/organisms/DocPage/index.tsx b/src/cloud/components/DocPage/index.tsx similarity index 78% rename from src/cloud/components/organisms/DocPage/index.tsx rename to src/cloud/components/DocPage/index.tsx index 065ec70f43..0a7323727b 100644 --- a/src/cloud/components/organisms/DocPage/index.tsx +++ b/src/cloud/components/DocPage/index.tsx @@ -1,8 +1,7 @@ import React, { useEffect, useMemo } from 'react' -import { usePage } from '../../../lib/stores/pageStore' -import { getDocTitle } from '../../../lib/utils/patterns' -import { useNav } from '../../../lib/stores/nav' -import ColoredBlock from '../../atoms/ColoredBlock' +import { usePage } from '../../lib/stores/pageStore' +import { getDocTitle } from '../../lib/utils/patterns' +import { useNav } from '../../lib/stores/nav' import EditPage from './Edit' import ViewPage from './View' import { useTitle } from 'react-use' @@ -10,18 +9,19 @@ import { useGlobalKeyDownHandler, isSingleKeyEventOutsideOfInput, preventKeyboardEventPropagation, -} from '../../../lib/keyboard' -import { getDocLinkHref } from '../../atoms/Link/DocLink' -import { shortcuts, isDocDeleteShortcut } from '../../../lib/shortcuts' -import { useGlobalData } from '../../../lib/stores/globalData' +} from '../../lib/keyboard' +import { getDocLinkHref } from '../Link/DocLink' +import { shortcuts, isDocDeleteShortcut } from '../../lib/shortcuts' +import { useGlobalData } from '../../lib/stores/globalData' import { SerializedDocWithBookmark, SerializedDoc, -} from '../../../interfaces/db/doc' -import Application from '../../Application' -import { SerializedUser } from '../../../interfaces/db/user' -import { SerializedRevision } from '../../../interfaces/db/revision' -import { useRouter } from '../../../lib/router' +} from '../../interfaces/db/doc' +import Application from '../Application' +import { SerializedUser } from '../../interfaces/db/user' +import { SerializedRevision } from '../../interfaces/db/revision' +import { useRouter } from '../../lib/router' +import ColoredBlock from '../../../design/components/atoms/ColoredBlock' interface DocPageProps { doc: SerializedDocWithBookmark @@ -140,7 +140,15 @@ const DocPage = ({ if (currentDoc == null || team == null) { return ( - +

Oops...

The document has been deleted.

@@ -151,7 +159,15 @@ const DocPage = ({ if (currentUser == null) { return ( - +

Oops...

You need to be connected to access this document.

diff --git a/src/cloud/components/DocPage/styles.ts b/src/cloud/components/DocPage/styles.ts new file mode 100644 index 0000000000..5c27fb31cb --- /dev/null +++ b/src/cloud/components/DocPage/styles.ts @@ -0,0 +1,23 @@ +import { rightSideTopBarHeight } from '../../../design/components/organisms/Topbar' +import styled from '../../../design/lib/styled' +import { rightSidePageLayout } from '../../../design/lib/styled/styleFunctions' + +export const StyledDocPage = styled.div` + ${rightSidePageLayout} + margin: 0 auto; + padding-top: calc( + ${rightSideTopBarHeight}px + ${({ theme }) => theme.sizes.spaces.l}px + ); + padding-left: ${({ theme }) => theme.sizes.spaces.l}px; + padding-right: ${({ theme }) => theme.sizes.spaces.l}px; + min-height: calc(100vh - ${rightSideTopBarHeight}px); + height: auto; + display: flex; + flex-direction: column; + align-items: center; +` + +export const StyledDocPageButtons = styled.div` + display: flex; + align-items: center; +` diff --git a/src/cloud/components/DocProperties/DocAssigneeSelect.tsx b/src/cloud/components/DocProperties/DocAssigneeSelect.tsx new file mode 100644 index 0000000000..0d10c0545e --- /dev/null +++ b/src/cloud/components/DocProperties/DocAssigneeSelect.tsx @@ -0,0 +1,176 @@ +import React, { useCallback, useState, useMemo } from 'react' +import { usePage } from '../../lib/stores/pageStore' +import styled from '../../../design/lib/styled' +import UserIcon from '../UserIcon' +import { useI18n } from '../../lib/hooks/useI18n' +import { lngKeys } from '../../lib/i18n/types' +import DocPropertyValueButton from './DocPropertyValueButton' +import { mdiAccountCircleOutline } from '@mdi/js' +import { useModal } from '../../../design/lib/stores/modal' +import SearchableList, { + SearchableListOption, +} from '../../../design/components/molecules/SearchableList' + +interface DocAssigneeSelectProps { + disabled?: boolean + defaultValue: string[] + update: (value: string[]) => void + isLoading: boolean + readOnly: boolean + popupAlignment?: 'bottom-left' | 'top-left' +} + +const DocAssigneeSelect = ({ + disabled = false, + defaultValue, + isLoading, + readOnly, + update, + popupAlignment = 'bottom-left', +}: DocAssigneeSelectProps) => { + const { translate } = useI18n() + const { openContextModal, closeAllModals } = useModal() + const { permissions = [] } = usePage() + + const updateAssignees = useCallback( + (selectedUserIds: string[]) => { + update(selectedUserIds) + closeAllModals() + }, + [update, closeAllModals] + ) + + const selectedUsers = useMemo(() => { + if (defaultValue.length === 0) { + return null + } + + return ( +
+ {permissions + .filter((p) => defaultValue.includes(p.userId) && p.user != null) + .map((p) => ( + + ))} +
+ ) + }, [defaultValue, permissions]) + + return ( + + + openContextModal( + e, + , + { + alignment: popupAlignment, + width: 300, + } + ) + } + > + {defaultValue.length !== 0 + ? selectedUsers + : translate(lngKeys.Unassigned)} + + + ) +} + +const Container = styled.div` + .doc__assignees__wrapper { + display: flex; + width: auto; + align-items: center; + } + + .doc__assignee { + display: inline-flex; + width: 22px; + height: 22px; + line-height: 19px; + margin-right: 0; + } +` + +const DocAssigneeModal = ({ + selectedUsers, + submitUpdate, + closeModal, +}: { + selectedUsers: string[] + submitUpdate: (val: string[]) => void + closeModal: () => void +}) => { + const { permissions = [] } = usePage() + const [value, setValue] = useState(selectedUsers) + const [query, setQuery] = useState('') + + const toggleUser = useCallback((userId: string) => { + setValue((prev) => { + const newValue = prev.slice() + if (newValue.includes(userId)) { + return newValue.filter((id) => id !== userId) + } else { + newValue.push(userId) + return newValue + } + }) + }, []) + + const matchedUsers = useMemo(() => { + const trimmed = query.trim().toLocaleLowerCase() + if (trimmed === '') { + return permissions.map((p) => p.user) + } + + return permissions + .filter((p) => p.user.displayName.toLocaleLowerCase().includes(trimmed)) + .map((p) => p.user) + }, [permissions, query]) + + const availableOptions: SearchableListOption[] = useMemo(() => { + return matchedUsers.map((user) => { + return { + onClick: () => toggleUser(user.id), + label: user.displayName, + checked: value.includes(user.id), + icon: , + } + }) + }, [matchedUsers, toggleUser, value]) + + return ( + + submitUpdate(value)} + onCancel={closeModal} + /> + + ) +} + +const ModalContainer = styled.div` + .assignee__item__icon { + width: 24px; + height: 24px; + margin-right: ${({ theme }) => theme.sizes.spaces.sm}px; + } +` + +export default DocAssigneeSelect diff --git a/src/cloud/components/organisms/DocProperties/DocDueDateSelect.tsx b/src/cloud/components/DocProperties/DocDueDateSelect.tsx similarity index 91% rename from src/cloud/components/organisms/DocProperties/DocDueDateSelect.tsx rename to src/cloud/components/DocProperties/DocDueDateSelect.tsx index a2650fc5a3..38d0a9d62b 100644 --- a/src/cloud/components/organisms/DocProperties/DocDueDateSelect.tsx +++ b/src/cloud/components/DocProperties/DocDueDateSelect.tsx @@ -2,11 +2,11 @@ import React, { useState, useEffect } from 'react' import DatePicker from 'react-datepicker' import DocPropertyValueButton from './DocPropertyValueButton' import { format as formatDate } from 'date-fns' -import styled from '../../../../shared/lib/styled' -import Button from '../../../../shared/components/atoms/Button' +import styled from '../../../design/lib/styled' +import Button from '../../../design/components/atoms/Button' import { mdiCalendarMonthOutline, mdiClose } from '@mdi/js' -import { useI18n } from '../../../lib/hooks/useI18n' -import { lngKeys } from '../../../lib/i18n/types' +import { useI18n } from '../../lib/hooks/useI18n' +import { lngKeys } from '../../lib/i18n/types' interface DocDueDateSelectProps { className?: string diff --git a/src/cloud/components/DocProperties/DocLabelSelectionModal.tsx b/src/cloud/components/DocProperties/DocLabelSelectionModal.tsx new file mode 100644 index 0000000000..d446c0a154 --- /dev/null +++ b/src/cloud/components/DocProperties/DocLabelSelectionModal.tsx @@ -0,0 +1,196 @@ +import React, { useCallback, useMemo, useState } from 'react' +import SearchableList, { + SearchableListOption, +} from '../../../design/components/molecules/SearchableList' +import styled from '../../../design/lib/styled' +import { overflowEllipsis } from '../../../design/lib/styled/styleFunctions' +import { + getMapValues, + sortByAttributeAsc, +} from '../../../design/lib/utils/array' +import { useNav } from '../../lib/stores/nav' + +interface DocLabelSelectionModalProps { + selectedTags: string[] + sendTags: (tags: string[]) => void +} + +interface SelectionTag { + isNew?: boolean + text: string +} + +const DocLabelSelectionModal = ({ + selectedTags, + sendTags, +}: DocLabelSelectionModalProps) => { + const { tagsMap } = useNav() + const [query, setQuery] = useState('') + const [selected, setSelected] = useState( + selectedTags.map((tag) => { + return { text: tag } + }) + ) + + const availableTags = useMemo(() => { + return getMapValues(tagsMap) + }, [tagsMap]) + + const searchedTagIsNew = useMemo(() => { + const trimmed = query.trim() + if (trimmed === '') return + return ( + availableTags.find((tag) => tag.text === trimmed) == null && + selected.find((t) => t.text === trimmed) == null + ) + }, [availableTags, query, selected]) + + const matchedTags = useMemo(() => { + const trimmed = query.trim().toLocaleLowerCase() + if (trimmed === '') return sortByAttributeAsc('text', availableTags) + return sortByAttributeAsc( + 'text', + availableTags.filter((tag) => + tag.text.toLocaleLowerCase().startsWith(trimmed) + ) + ) + }, [availableTags, query]) + + const toggleTagSelection = useCallback( + (tag: string, isNew?: boolean) => { + if (selected.find((t) => t.text === tag) != null) { + return setSelected((prev) => { + const newSelection = prev.slice().filter((t) => t.text !== tag) + return newSelection + }) + } else { + return setSelected((prev) => { + return [...prev.slice(), { isNew, text: tag }] + }) + } + }, + [selected] + ) + + const availableOptions: SearchableListOption[] = useMemo(() => { + const options: SearchableListOption[] = [] + + if (searchedTagIsNew) { + options.push({ + label: `Create "${query.trim()}"`, + onClick: () => toggleTagSelection(query.trim(), true), + }) + } + + selected + .filter((selection) => selection.isNew) + .forEach((tag) => { + options.push({ + label: tag.text, + checked: selected.find((t) => t.text === tag.text) != null, + onClick: () => toggleTagSelection(tag.text), + }) + }) + + matchedTags.forEach((tag) => { + options.push({ + label: tag.text, + checked: selected.find((t) => t.text === tag.text) != null, + onClick: () => toggleTagSelection(tag.text), + }) + }) + + return options + }, [matchedTags, query, selected, searchedTagIsNew, toggleTagSelection]) + + return ( + + { + return sendTags(selected.map((tag) => tag.text)) + }} + /> + + ) +} + +const Container = styled.div` + #labels__selection__input { + margin-bottom: ${({ theme }) => theme.sizes.spaces.sm}px; + } + + .labels__selection__break { + display: block; + height: 1px; + width: 100%; + background: ${({ theme }) => theme.colors.border.second}; + flex: 0 0 auto; + margin-bottom: ${({ theme }) => theme.sizes.spaces.sm}px; + } + .labels__selection__submit { + display: flex; + width: 100%; + } + + .labels__selection__wrapper { + min-height: 30px; + max-height: 250px; + } + + .selection__checkbox { + flex: 0 0 auto; + } + + .selection__item__wrapper { + display: flex; + flex: 1 1 auto; + align-items: center; + width: 100%; + height: 30px; + cursor: pointer; + background: none; + transition: background 200ms; + color: ${({ theme }) => theme.colors.text.primary}; + justify-content: space-between; + text-align: left; + border-radius: ${({ theme }) => theme.borders.radius}px; + padding: ${({ theme }) => theme.sizes.spaces.xsm}px + ${({ theme }) => theme.sizes.spaces.sm}px; + + &:focus { + background: ${({ theme }) => theme.colors.background.tertiary}; + } + + &:hover { + background: ${({ theme }) => theme.colors.background.secondary}; + } + + .selection__label { + flex: 1 1 auto; + ${overflowEllipsis} + } + + .selection__item__icon { + margin-right: ${({ theme }) => theme.sizes.spaces.df}px; + width: 22px; + height: 22px; + line-height: 19px; + } + + .selection__checkbox { + margin-left: ${({ theme }) => theme.sizes.spaces.df}px; + pointer-events: none; + } + + .selection__item__icon, + .selection__checkbox { + flex: 0 0 auto; + flex-shrink: 0; + } + } +` + +export default React.memo(DocLabelSelectionModal) diff --git a/src/cloud/components/organisms/DocProperties/DocPropertyValueButton.tsx b/src/cloud/components/DocProperties/DocPropertyValueButton.tsx similarity index 91% rename from src/cloud/components/organisms/DocProperties/DocPropertyValueButton.tsx rename to src/cloud/components/DocProperties/DocPropertyValueButton.tsx index 887a1c3866..8a4bbe87c3 100644 --- a/src/cloud/components/organisms/DocProperties/DocPropertyValueButton.tsx +++ b/src/cloud/components/DocProperties/DocPropertyValueButton.tsx @@ -1,9 +1,9 @@ import React, { forwardRef } from 'react' -import styled from '../../../../shared/lib/styled' -import Spinner from '../../../../shared/components/atoms/Spinner' -import { contextMenuFormItem } from '../../../../shared/lib/styled/styleFunctions' +import styled from '../../../design/lib/styled' +import Spinner from '../../../design/components/atoms/Spinner' +import { contextMenuFormItem } from '../../../design/lib/styled/styleFunctions' import cc from 'classcat' -import Icon from '../../../../shared/components/atoms/Icon' +import Icon from '../../../design/components/atoms/Icon' interface DocPropertyValueButtonProps { children: React.ReactNode diff --git a/src/cloud/components/organisms/DocProperties/DocStatusSelect.tsx b/src/cloud/components/DocProperties/DocStatusSelect.tsx similarity index 86% rename from src/cloud/components/organisms/DocProperties/DocStatusSelect.tsx rename to src/cloud/components/DocProperties/DocStatusSelect.tsx index 518603ebb4..cd5b150828 100644 --- a/src/cloud/components/organisms/DocProperties/DocStatusSelect.tsx +++ b/src/cloud/components/DocProperties/DocStatusSelect.tsx @@ -3,8 +3,8 @@ import { useContextMenu, MenuTypes, MenuItem, -} from '../../../../shared/lib/stores/contextMenu' -import Icon from '../../../../shared/components/atoms/Icon' +} from '../../../design/lib/stores/contextMenu' +import Icon from '../../../design/components/atoms/Icon' import { mdiPlayCircleOutline, mdiPauseCircleOutline, @@ -13,11 +13,11 @@ import { mdiCheckCircleOutline, mdiListStatus, } from '@mdi/js' -import styled from '../../../lib/styled' -import { DocStatus } from '../../../interfaces/db/doc' +import { DocStatus } from '../../interfaces/db/doc' import DocPropertyValueButton from './DocPropertyValueButton' -import { useI18n } from '../../../lib/hooks/useI18n' -import { lngKeys } from '../../../lib/i18n/types' +import { useI18n } from '../../lib/hooks/useI18n' +import { lngKeys } from '../../lib/i18n/types' +import styled from '../../../design/lib/styled' interface DocStatusSelectProps { sending?: boolean @@ -143,16 +143,16 @@ const Container = styled.div` margin-right: 5px; } .status_icon--in-progress { - color: ${({ theme }) => theme.infoTextColor}; + color: ${({ theme }) => theme.colors.variants.info.base}; } .status_icon--paused { - color: ${({ theme }) => theme.secondaryTextColor}; + color: ${({ theme }) => theme.colors.variants.secondary.base}; } .status_icon--completed { - color: ${({ theme }) => theme.successTextColor}; + color: ${({ theme }) => theme.colors.variants.success.base}; } .status_icon--archived { - color: ${({ theme }) => theme.warningTextColor}; + color: ${({ theme }) => theme.colors.variants.warning.base}; } ` @@ -160,16 +160,16 @@ const ContextMenuItemContainer = styled.div` display: flex; align-items: center; .status_icon--in-progress { - color: ${({ theme }) => theme.infoTextColor}; + color: ${({ theme }) => theme.colors.variants.info.base}; } .status_icon--paused { - color: ${({ theme }) => theme.secondaryTextColor}; + color: ${({ theme }) => theme.colors.variants.secondary.base}; } .status_icon--completed { - color: ${({ theme }) => theme.successTextColor}; + color: ${({ theme }) => theme.colors.variants.success.base}; } .status_icon--archived { - color: ${({ theme }) => theme.warningTextColor}; + color: ${({ theme }) => theme.colors.variants.warning.base}; } ` diff --git a/src/cloud/components/atoms/DocStatusIcon.tsx b/src/cloud/components/DocStatusIcon.tsx similarity index 77% rename from src/cloud/components/atoms/DocStatusIcon.tsx rename to src/cloud/components/DocStatusIcon.tsx index 0172c8ac2e..124986b166 100644 --- a/src/cloud/components/atoms/DocStatusIcon.tsx +++ b/src/cloud/components/DocStatusIcon.tsx @@ -1,7 +1,6 @@ import React from 'react' -import { DocStatus } from '../../interfaces/db/doc' -import Icon, { IconSize } from '../../../shared/components/atoms/Icon' -import styled from '../../lib/styled' +import { DocStatus } from '../interfaces/db/doc' +import Icon, { IconSize } from '../../design/components/atoms/Icon' import cc from 'classcat' import { mdiPlayCircleOutline, @@ -9,6 +8,7 @@ import { mdiCheckCircleOutline, mdiArchiveOutline, } from '@mdi/js' +import styled from '../../design/lib/styled' interface DocStatusIconProps { status: DocStatus @@ -34,16 +34,16 @@ export default DocStatusIcon const WrappedIcon = styled(Icon)` &.doc-status-icon--in-progress { - color: ${({ theme }) => theme.infoTextColor}; + color: ${({ theme }) => theme.colors.variants.info.base}; } &.doc-status-icon--paused { - color: ${({ theme }) => theme.secondaryTextColor}; + color: ${({ theme }) => theme.colors.variants.secondary.base}; } &.doc-status-icon--completed { - color: ${({ theme }) => theme.successTextColor}; + color: ${({ theme }) => theme.colors.variants.success.base}; } &.doc-status-icon--archived { - color: ${({ theme }) => theme.warningTextColor}; + color: ${({ theme }) => theme.colors.variants.warning.base}; } ` diff --git a/src/cloud/components/atoms/DocTagsListItem.tsx b/src/cloud/components/DocTagsListItem.tsx similarity index 92% rename from src/cloud/components/atoms/DocTagsListItem.tsx rename to src/cloud/components/DocTagsListItem.tsx index 7f6ecc9f6e..3062ea6ef4 100644 --- a/src/cloud/components/atoms/DocTagsListItem.tsx +++ b/src/cloud/components/DocTagsListItem.tsx @@ -1,11 +1,11 @@ import React from 'react' -import { SerializedTeam } from '../../interfaces/db/team' +import { SerializedTeam } from '../interfaces/db/team' import { mdiClose } from '@mdi/js' import cc from 'classcat' import TagLink from './Link/TagLink' -import { SerializedTag } from '../../interfaces/db/tag' -import styled from '../../../shared/lib/styled' -import { LoadingButton } from '../../../shared/components/atoms/Button' +import { SerializedTag } from '../interfaces/db/tag' +import styled from '../../design/lib/styled' +import { LoadingButton } from '../../design/components/atoms/Button' interface DocTagsListItemProps { tag: SerializedTag diff --git a/src/cloud/components/molecules/Editor/EditorAdmonitionTool.tsx b/src/cloud/components/Editor/EditorAdmonitionTool.tsx similarity index 82% rename from src/cloud/components/molecules/Editor/EditorAdmonitionTool.tsx rename to src/cloud/components/Editor/EditorAdmonitionTool.tsx index 17a7885102..1819b1e8ae 100644 --- a/src/cloud/components/molecules/Editor/EditorAdmonitionTool.tsx +++ b/src/cloud/components/Editor/EditorAdmonitionTool.tsx @@ -1,12 +1,12 @@ import React, { useState } from 'react' -import IconMdi from '../../atoms/IconMdi' -import Tooltip from '../../atoms/Tooltip' import { StyledEditorToolButtonContainer, StyledEditorToolButton, } from './styled' import { FormattingTool } from './types' import EditorAdmonitionToolDropdown from './EditorAdmonitionToolDropdown' +import WithTooltip from '../../../design/components/atoms/WithTooltip' +import Icon from '../../../design/components/atoms/Icon' interface EditorAdmonitionToolProps { tooltip?: string @@ -25,14 +25,14 @@ const EditorAdmonitionTool = ({ return ( - + setOpenDropdown((prev) => !prev)} style={style} > - + - + {openDropdown && ( void diff --git a/src/cloud/components/molecules/Editor/EditorHeaderTool.tsx b/src/cloud/components/Editor/EditorHeaderTool.tsx similarity index 81% rename from src/cloud/components/molecules/Editor/EditorHeaderTool.tsx rename to src/cloud/components/Editor/EditorHeaderTool.tsx index 3fc11f02c2..708fbf8664 100644 --- a/src/cloud/components/molecules/Editor/EditorHeaderTool.tsx +++ b/src/cloud/components/Editor/EditorHeaderTool.tsx @@ -1,12 +1,12 @@ import React, { useState } from 'react' -import IconMdi from '../../atoms/IconMdi' -import Tooltip from '../../atoms/Tooltip' import { StyledEditorToolButtonContainer, StyledEditorToolButton, } from './styled' import { FormattingTool } from './types' import EditorHeaderToolDropdown from './EditorHeaderToolDropdown' +import WithTooltip from '../../../design/components/atoms/WithTooltip' +import Icon from '../../../design/components/atoms/Icon' interface EditorHeaderToolProps { tooltip?: string @@ -25,14 +25,14 @@ const EditorHeaderTool = ({ return ( - + setOpenDropdown((prev) => !prev)} style={style} > - + - + {openDropdown && ( void @@ -86,7 +86,7 @@ const EditorHeaderToolDropdown = ({ label={ - + {option.label} @@ -111,6 +111,6 @@ const StyledMenuItem = styled.div` const StyledIcon = styled.div` display: flex; align-items: center; - padding-right: ${({ theme }) => theme.space.small}px; + padding-right: ${({ theme }) => theme.sizes.spaces.sm}px; font-size: 21px; ` diff --git a/src/cloud/components/Editor/EditorIndentationStatus.tsx b/src/cloud/components/Editor/EditorIndentationStatus.tsx new file mode 100644 index 0000000000..73bcebdb8a --- /dev/null +++ b/src/cloud/components/Editor/EditorIndentationStatus.tsx @@ -0,0 +1,198 @@ +import React, { + useCallback, + MouseEventHandler, + useState, + useRef, + useEffect, + FocusEventHandler, +} from 'react' +import { capitalize } from '../../lib/utils/string' +import BottomBarButton from '../BottomBarButton' +import { + useSettings, + GeneralEditorIndentType, + GeneralEditorIndentSize, +} from '../../lib/stores/settings' +import { isChildNode } from '../../lib/dom' +import { trackEvent } from '../../api/track' +import { MixpanelActionTrackTypes } from '../../interfaces/analytics/mixpanel' +import { useI18n } from '../../lib/hooks/useI18n' +import { lngKeys } from '../../lib/i18n/types' +import styled from '../../../design/lib/styled' +import FormSelect, { + FormSelectOption, + SimpleFormSelect, +} from '../../../design/components/molecules/Form/atoms/FormSelect' +import FormRow from '../../../design/components/molecules/Form/templates/FormRow' +import Form from '../../../design/components/molecules/Form' +import FormRowItem from '../../../design/components/molecules/Form/templates/FormRowItem' + +const EditorIndentationStatus = () => { + const { settings, setSettings } = useSettings() + const currentIndentType = settings['general.editorIndentType'] + const currentIndentSize = settings['general.editorIndentSize'] + const [showingIndentMenu, setShowingIndentMenu] = useState(false) + const menuRef = useRef(null) + const { translate } = useI18n() + + const showIndentMenu: MouseEventHandler = useCallback(() => { + setShowingIndentMenu(true) + }, []) + + useEffect(() => { + if (showingIndentMenu && menuRef.current != null) { + menuRef.current.focus() + } + }, [showingIndentMenu]) + + const handleMenuBlur: FocusEventHandler = useCallback( + (event) => { + if (menuRef.current == null) { + return + } + if (isChildNode(menuRef.current, event.relatedTarget as Node)) { + return + } + setShowingIndentMenu(false) + }, + [] + ) + + const selectIndentType = useCallback( + (option: FormSelectOption) => { + setSettings({ + 'general.editorIndentType': option.value as GeneralEditorIndentType, + }) + trackEvent(MixpanelActionTrackTypes.ThemeChangeIndentType, { + theme: option.value, + }) + }, + [setSettings] + ) + + const selectIndentSize = useCallback( + (val: string) => { + setSettings({ + 'general.editorIndentSize': parseInt( + val, + 10 + ) as GeneralEditorIndentSize, + }) + trackEvent(MixpanelActionTrackTypes.ThemeChangeIndentSize, { + theme: val, + }) + }, + [setSettings] + ) + + return ( + + + {capitalize( + currentIndentType === 'spaces' + ? translate(lngKeys.GeneralSpaces) + : translate(lngKeys.GeneralTabs) + )} + : {currentIndentSize} + + {showingIndentMenu && ( +
+
+ + {translate(lngKeys.SettingsIndentType)} + + ), + }} + > + + + + + + {translate(lngKeys.SettingsIndentSize)} + + ), + }} + > + + + + +
+
+ )} +
+ ) +} + +export default EditorIndentationStatus + +const StyledContainer = styled.div` + display: flex; + justify-content: center; + align-items: center; + position: relative; + + .menu { + position: absolute; + border-radius: 5px; + bottom: 30px; + width: 200px; + padding: 5px; + border: solid 1px ${({ theme }) => theme.colors.border.main}; + background: ${({ theme }) => theme.colors.background.primary}; + right: 5px; + z-index: 2; + } + + .menu__item__label { + overflow: nowrap; + display: block; + margin-bottom: 0; + } +` diff --git a/src/cloud/components/molecules/Editor/EditorIntegrationToolButton.tsx b/src/cloud/components/Editor/EditorIntegrationToolButton.tsx similarity index 73% rename from src/cloud/components/molecules/Editor/EditorIntegrationToolButton.tsx rename to src/cloud/components/Editor/EditorIntegrationToolButton.tsx index 873de1ea9e..08527fb403 100644 --- a/src/cloud/components/molecules/Editor/EditorIntegrationToolButton.tsx +++ b/src/cloud/components/Editor/EditorIntegrationToolButton.tsx @@ -1,13 +1,13 @@ import React, { useCallback } from 'react' -import IconMdi from '../../atoms/IconMdi' -import Tooltip from '../../atoms/Tooltip' import { StyledEditorToolButtonContainer, StyledEditorToolButton, } from './styled' -import { useSettings } from '../../../lib/stores/settings' +import { useSettings } from '../../lib/stores/settings' import cc from 'classcat' import { mdiFlash } from '@mdi/js' +import WithTooltip from '../../../design/components/atoms/WithTooltip' +import Icon from '../../../design/components/atoms/Icon' const EditorIntegrationToolButton = () => { const { openSettingsTab } = useSettings() @@ -20,14 +20,14 @@ const EditorIntegrationToolButton = () => { - - + - + ) } diff --git a/src/cloud/components/molecules/Editor/EditorKeyMapSelect.tsx b/src/cloud/components/Editor/EditorKeyMapSelect.tsx similarity index 50% rename from src/cloud/components/molecules/Editor/EditorKeyMapSelect.tsx rename to src/cloud/components/Editor/EditorKeyMapSelect.tsx index faa21ef14c..b325bd8fb2 100644 --- a/src/cloud/components/molecules/Editor/EditorKeyMapSelect.tsx +++ b/src/cloud/components/Editor/EditorKeyMapSelect.tsx @@ -1,16 +1,17 @@ import React, { useCallback, useState, useRef, useEffect } from 'react' import { mdiKeyboard } from '@mdi/js' -import Icon from '../../atoms/Icon' -import { CodeMirrorKeyMap, useSettings } from '../../../lib/stores/settings' -import BottomBarButton from '../../atoms/BottomBarButton' -import styled from '../../../lib/styled' -import { isChildNode } from '../../../lib/dom' -import { SelectChangeEventHandler } from '../../../lib/utils/events' -import { selectStyle } from '../../../lib/styled/styleFunctions' -import { trackEvent } from '../../../api/track' -import { MixpanelActionTrackTypes } from '../../../interfaces/analytics/mixpanel' -import { useI18n } from '../../../lib/hooks/useI18n' -import { lngKeys } from '../../../lib/i18n/types' +import { CodeMirrorKeyMap, useSettings } from '../../lib/stores/settings' +import BottomBarButton from '../BottomBarButton' +import { isChildNode } from '../../lib/dom' +import { trackEvent } from '../../api/track' +import { MixpanelActionTrackTypes } from '../../interfaces/analytics/mixpanel' +import { useI18n } from '../../lib/hooks/useI18n' +import { lngKeys } from '../../lib/i18n/types' +import styled from '../../../design/lib/styled' +import { SimpleFormSelect } from '../../../design/components/molecules/Form/atoms/FormSelect' +import Icon from '../../../design/components/atoms/Icon' +import FormRow from '../../../design/components/molecules/Form/templates/FormRow' +import FormRowItem from '../../../design/components/molecules/Form/templates/FormRowItem' const EditorKeyMapSelect = () => { const { setSettings, settings } = useSettings() @@ -42,13 +43,13 @@ const EditorKeyMapSelect = () => { [] ) - const selectIndentType: SelectChangeEventHandler = useCallback( - (event) => { + const selectIndentType = useCallback( + (val: string) => { setSettings({ - 'general.editorKeyMap': event.target.value as CodeMirrorKeyMap, + 'general.editorKeyMap': val as CodeMirrorKeyMap, }) trackEvent(MixpanelActionTrackTypes.ThemeChangeKeymap, { - theme: event.target.value, + theme: val, }) }, [setSettings] @@ -66,21 +67,30 @@ const EditorKeyMapSelect = () => { ref={menuRef} onBlur={handleMenuBlur} > -
- - -
+ + {translate(lngKeys.SettingsEditorKeyMap)} + + ), + }} + > + + + +
)} @@ -97,23 +107,15 @@ const StyledContainer = styled.div` border-radius: 5px; bottom: 30px; padding: 5px; - border: solid 1px ${({ theme }) => theme.baseBorderColor}; - background: ${({ theme }) => theme.baseBackgroundColor}; + border: solid 1px ${({ theme }) => theme.colors.border.main}; + background: ${({ theme }) => theme.colors.background.primary}; right: 5px; } .menu__item__label { overflow: nowrap; display: block; - font-size: ${({ theme }) => theme.fontSizes.small}px; margin-bottom: 0; } - .menu__item__select { - width: 100%; - display: block; - ${selectStyle} - padding: 5px; - border-radius: 5px; - } ` export default EditorKeyMapSelect diff --git a/src/cloud/components/molecules/Editor/EditorSelectionStatus.tsx b/src/cloud/components/Editor/EditorSelectionStatus.tsx similarity index 80% rename from src/cloud/components/molecules/Editor/EditorSelectionStatus.tsx rename to src/cloud/components/Editor/EditorSelectionStatus.tsx index 2dc04299e5..e3a44b9eec 100644 --- a/src/cloud/components/molecules/Editor/EditorSelectionStatus.tsx +++ b/src/cloud/components/Editor/EditorSelectionStatus.tsx @@ -1,6 +1,6 @@ import React from 'react' -import { EditorPosition } from '../../../lib/editor/CodeMirror' -import styled from '../../../lib/styled' +import styled from '../../../design/lib/styled' +import { EditorPosition } from '../../lib/editor/CodeMirror' interface EditorSelectionStatusProps { cursor: EditorPosition @@ -45,7 +45,10 @@ export default EditorSelectionStatus const Container = styled.div` padding: 0 5px; height: 24px; - font-size: 14px; - color: ${({ theme }) => theme.baseTextColor}; user-select: none; + + display: flex; + align-items: center; + font-size: ${({ theme }) => theme.sizes.fonts.sm}px; + color: ${({ theme }) => theme.colors.text.subtle}; ` diff --git a/src/cloud/components/molecules/Editor/EditorTemplateButton.tsx b/src/cloud/components/Editor/EditorTemplateButton.tsx similarity index 58% rename from src/cloud/components/molecules/Editor/EditorTemplateButton.tsx rename to src/cloud/components/Editor/EditorTemplateButton.tsx index 25fe4a7c81..df64121ced 100644 --- a/src/cloud/components/molecules/Editor/EditorTemplateButton.tsx +++ b/src/cloud/components/Editor/EditorTemplateButton.tsx @@ -1,11 +1,10 @@ import React, { useCallback } from 'react' -import CustomButton from '../../atoms/buttons/CustomButton' -import TemplatesModal from '../../organisms/Modal/contents/TemplatesModal' +import TemplatesModal from '../Modal/contents/TemplatesModal' import { mdiPalette } from '@mdi/js' -import IconMdi from '../../atoms/IconMdi' -import styled from '../../../lib/styled' -import { SerializedTemplate } from '../../../interfaces/db/template' -import { useModal } from '../../../../shared/lib/stores/modal' +import { SerializedTemplate } from '../../interfaces/db/template' +import { useModal } from '../../../design/lib/stores/modal' +import Button from '../../../design/components/atoms/Button' +import styled from '../../../design/lib/styled' interface EditorTemplateButtonProps { onTemplatePickCallback: (template: SerializedTemplate) => void @@ -31,22 +30,25 @@ const EditorTemplateButton = ({ left: 35, }} > - - Use a Template - + ) } -const StyledEditorTemplateButton = styled.div`` +const StyledEditorTemplateButton = styled.div` + .use-button { + padding: 0px 4px; + display: flex; + align-items: center; + } +` export default EditorTemplateButton diff --git a/src/cloud/components/Editor/EditorThemeSelect.tsx b/src/cloud/components/Editor/EditorThemeSelect.tsx new file mode 100644 index 0000000000..e9cc36de08 --- /dev/null +++ b/src/cloud/components/Editor/EditorThemeSelect.tsx @@ -0,0 +1,169 @@ +import React, { + useCallback, + FocusEventHandler, + useState, + useRef, + MouseEventHandler, + useEffect, +} from 'react' +import BottomBarButton from '../BottomBarButton' +import { mdiPaletteOutline } from '@mdi/js' +import { + codeMirrorEditorThemes, + useSettings, + CodeMirrorEditorTheme, +} from '../../lib/stores/settings' +import { isChildNode } from '../../lib/dom' +import { trackEvent } from '../../api/track' +import { MixpanelActionTrackTypes } from '../../interfaces/analytics/mixpanel' +import { lngKeys } from '../../lib/i18n/types' +import { useI18n } from '../../lib/hooks/useI18n' +import { SimpleFormSelect } from '../../../design/components/molecules/Form/atoms/FormSelect' +import styled from '../../../design/lib/styled' +import Icon from '../../../design/components/atoms/Icon' +import FormRow from '../../../design/components/molecules/Form/templates/FormRow' +import FormRowItem from '../../../design/components/molecules/Form/templates/FormRowItem' +import Form from '../../../design/components/molecules/Form' + +const EditorThemeSelect = () => { + const { settings, setSettings } = useSettings() + const editorTheme = settings['general.editorTheme'] + const codeBlockTheme = settings['general.codeBlockTheme'] + + const { translate } = useI18n() + + const [showingMenu, setShowingMenu] = useState(false) + const menuRef = useRef(null) + + const showIndentMenu: MouseEventHandler = useCallback(() => { + setShowingMenu(true) + }, []) + + useEffect(() => { + if (showingMenu && menuRef.current != null) { + menuRef.current.focus() + } + }, [showingMenu]) + + const handleMenuBlur: FocusEventHandler = useCallback( + (event) => { + if (menuRef.current == null) { + return + } + if (isChildNode(menuRef.current, event.relatedTarget as Node)) { + return + } + setShowingMenu(false) + }, + [] + ) + + const selectIndentType = useCallback( + (val: string) => { + setSettings({ + 'general.editorTheme': val as CodeMirrorEditorTheme, + }) + trackEvent(MixpanelActionTrackTypes.ThemeChangeEditor, { + theme: val, + }) + }, + [setSettings] + ) + + const selectIndentSize = useCallback( + (val: string) => { + setSettings({ + 'general.codeBlockTheme': val as CodeMirrorEditorTheme, + }) + trackEvent(MixpanelActionTrackTypes.ThemeChangeCodeblock, { + theme: val, + }) + }, + [setSettings] + ) + + return ( + + + + + {showingMenu && ( +
+
+ + {translate(lngKeys.SettingsEditorTheme)} + + ), + }} + > + + + + + + {translate(lngKeys.SettingsCodeBlockTheme)} + + ), + }} + > + + + + +
+
+ )} +
+ ) +} + +export default EditorThemeSelect + +const StyledContainer = styled.div` + display: flex; + justify-content: center; + align-items: center; + height: 100%; + .menu { + position: absolute; + border-radius: 5px; + bottom: 30px; + padding: 5px; + border: solid 1px ${({ theme }) => theme.colors.border.main}; + background: ${({ theme }) => theme.colors.background.primary}; + z-index: 2; + right: 5px; + } + .menu__item__label { + overflow: nowrap; + display: block; + margin-bottom: 0; + } +` diff --git a/src/cloud/components/molecules/Editor/EditorToolButton.tsx b/src/cloud/components/Editor/EditorToolButton.tsx similarity index 72% rename from src/cloud/components/molecules/Editor/EditorToolButton.tsx rename to src/cloud/components/Editor/EditorToolButton.tsx index 209f3a97e6..23b3013f90 100644 --- a/src/cloud/components/molecules/Editor/EditorToolButton.tsx +++ b/src/cloud/components/Editor/EditorToolButton.tsx @@ -1,6 +1,6 @@ import React from 'react' -import IconMdi from '../../atoms/IconMdi' -import Tooltip from '../../atoms/Tooltip' +import Icon from '../../../design/components/atoms/Icon' +import WithTooltip from '../../../design/components/atoms/WithTooltip' import { StyledEditorToolButtonContainer, StyledEditorToolButton, @@ -13,7 +13,6 @@ interface EditorToolButtonProps { dropdown?: React.ReactNode onClick?: () => void className?: string - position?: 'bottom' | 'bottom-right' } const EditorToolButton = ({ @@ -22,14 +21,13 @@ const EditorToolButton = ({ style, onClick, className, - position = 'bottom', }: EditorToolButtonProps) => ( - + - + - + ) diff --git a/src/cloud/components/molecules/Editor/EditorToolbar.tsx b/src/cloud/components/Editor/EditorToolbar.tsx similarity index 99% rename from src/cloud/components/molecules/Editor/EditorToolbar.tsx rename to src/cloud/components/Editor/EditorToolbar.tsx index 6d73f17ad4..7a887c3f4f 100644 --- a/src/cloud/components/molecules/Editor/EditorToolbar.tsx +++ b/src/cloud/components/Editor/EditorToolbar.tsx @@ -21,9 +21,9 @@ import { FormattingTool } from './types' import { applyBoldStyleEventEmitter, applyItalicStyleEventEmitter, -} from '../../../lib/utils/events' -import { useI18n } from '../../../lib/hooks/useI18n' -import { lngKeys } from '../../../lib/i18n/types' +} from '../../lib/utils/events' +import { useI18n } from '../../lib/hooks/useI18n' +import { lngKeys } from '../../lib/i18n/types' interface EditorToolbarProps { editorRef?: React.MutableRefObject diff --git a/src/cloud/components/molecules/Editor/EditorToolbarUpload.tsx b/src/cloud/components/Editor/EditorToolbarUpload.tsx similarity index 95% rename from src/cloud/components/molecules/Editor/EditorToolbarUpload.tsx rename to src/cloud/components/Editor/EditorToolbarUpload.tsx index 5fd80e2e85..b8ec1ca9b9 100644 --- a/src/cloud/components/molecules/Editor/EditorToolbarUpload.tsx +++ b/src/cloud/components/Editor/EditorToolbarUpload.tsx @@ -5,9 +5,9 @@ import { stringifyFileNode, buildDefaultUploadWidget, OnFileCallback, -} from '../../../lib/editor/plugins/fileHandler' -import { useI18n } from '../../../lib/hooks/useI18n' -import { lngKeys } from '../../../lib/i18n/types' +} from '../../lib/editor/plugins/fileHandler' +import { useI18n } from '../../lib/hooks/useI18n' +import { lngKeys } from '../../lib/i18n/types' interface EditorToolbarUploadProps { editorRef: React.MutableRefObject diff --git a/src/cloud/components/molecules/Editor/index.tsx b/src/cloud/components/Editor/index.tsx similarity index 87% rename from src/cloud/components/molecules/Editor/index.tsx rename to src/cloud/components/Editor/index.tsx index 01e04d6dcf..2365c2b41c 100644 --- a/src/cloud/components/molecules/Editor/index.tsx +++ b/src/cloud/components/Editor/index.tsx @@ -1,17 +1,15 @@ import React, { useState, useCallback, useRef, useEffect, useMemo } from 'react' -import { getColorFromString } from '../../../lib/utils/string' -import styled from '../../../lib/styled' +import { getColorFromString } from '../../lib/utils/string' import { SerializedDoc, SerializedDocWithBookmark, -} from '../../../interfaces/db/doc' -import { useSettings, CodeMirrorKeyMap } from '../../../lib/stores/settings' -import useRealtime from '../../../lib/editor/hooks/useRealtime' -import Spinner from '../../atoms/CustomSpinner' +} from '../../interfaces/db/doc' +import { useSettings, CodeMirrorKeyMap } from '../../lib/stores/settings' +import useRealtime from '../../lib/editor/hooks/useRealtime' import attachFileHandlerToCodeMirrorEditor, { OnFileCallback, -} from '../../../lib/editor/plugins/fileHandler' -import { uploadFile, buildTeamFileUrl } from '../../../api/teams/files' +} from '../../lib/editor/plugins/fileHandler' +import { uploadFile, buildTeamFileUrl } from '../../api/teams/files' import { createRelativePositionFromTypeIndex, createAbsolutePositionFromRelativePosition, @@ -19,24 +17,23 @@ import { import { useGlobalKeyDownHandler, preventKeyboardEventPropagation, -} from '../../../lib/keyboard' -import { SerializedTeam } from '../../../interfaces/db/team' -import { isEditSessionSaveShortcut } from '../../../lib/shortcuts' -import { getDocTitle } from '../../../lib/utils/patterns' -import { SerializedUser } from '../../../interfaces/db/user' +} from '../../lib/keyboard' +import { SerializedTeam } from '../../interfaces/db/team' +import { isEditSessionSaveShortcut } from '../../lib/shortcuts' +import { getDocTitle } from '../../lib/utils/patterns' +import { SerializedUser } from '../../interfaces/db/user' import EditorToolbar from './EditorToolbar' -import { usePreferences } from '../../../lib/stores/preferences' -import { rightSidePageLayout } from '../../../lib/styled/styleFunctions' -import { useRouter } from '../../../lib/router' +import { usePreferences } from '../../lib/stores/preferences' +import { useRouter } from '../../lib/router' import { pasteFormatPlugin, PositionRange, Callback, -} from '../../../lib/editor/plugins/pasteFormatPlugin' -import { buildIconUrl } from '../../../api/files' -import { SerializedRevision } from '../../../interfaces/db/revision' +} from '../../lib/editor/plugins/pasteFormatPlugin' +import { buildIconUrl } from '../../api/files' +import { SerializedRevision } from '../../interfaces/db/revision' import EditorTemplateButton from './EditorTemplateButton' -import Application from '../../Application' +import Application from '../Application' import { mdiRepeat, mdiRepeatOff, @@ -52,50 +49,53 @@ import { import EditorToolButton from './EditorToolButton' import { not } from 'ramda' import EditorToolbarUpload from './EditorToolbarUpload' -import { useNav } from '../../../lib/stores/nav' +import { useNav } from '../../lib/stores/nav' import { Hint } from 'codemirror' -import { SerializedTemplate } from '../../../interfaces/db/template' -import TemplatesModal from '../../organisms/Modal/contents/TemplatesModal' +import { SerializedTemplate } from '../../interfaces/db/template' +import TemplatesModal from '../Modal/contents/TemplatesModal' import EditorSelectionStatus from './EditorSelectionStatus' import EditorIndentationStatus from './EditorIndentationStatus' import EditorKeyMapSelect from './EditorKeyMapSelect' import EditorThemeSelect from './EditorThemeSelect' -import DocContextMenu from '../../organisms/EditorLayout/NewDocContextMenu' +import DocContextMenu from '../DocPage/NewDocContextMenu' import { focusTitleEventEmitter, focusEditorEventEmitter, toggleSplitEditModeEventEmitter, togglePreviewModeEventEmitter, focusEditorHeadingEventEmitter, -} from '../../../lib/utils/events' -import { ScrollSync, scrollSyncer } from '../../../lib/editor/scrollSync' -import CodeMirrorEditor from '../../../lib/editor/components/CodeMirrorEditor' -import MarkdownView, { SelectionContext } from '../../atoms/MarkdownView' -import { usePage } from '../../../lib/stores/pageStore' -import { useToast } from '../../../../shared/lib/stores/toast' -import { LoadingButton } from '../../../../shared/components/atoms/Button' -import { trackEvent } from '../../../api/track' -import { MixpanelActionTrackTypes } from '../../../interfaces/analytics/mixpanel' -import { useCloudApi } from '../../../lib/hooks/useCloudApi' -import { useCloudResourceModals } from '../../../lib/hooks/useCloudResourceModals' -import { mapTopbarBreadcrumbs } from '../../../lib/mappers/topbarBreadcrumbs' -import { useModal } from '../../../../shared/lib/stores/modal' -import PresenceIcons from '../../organisms/Topbar/PresenceIcons' -import { TopbarControlProps } from '../../../../shared/components/organisms/Topbar' -import Icon from '../../atoms/Icon' -import CommentManager from '../../organisms/CommentManager' -import useCommentManagerState from '../../../lib/hooks/useCommentManagerState' -import { HighlightRange } from '../../../lib/rehypeHighlight' -import { getDocLinkHref } from '../../atoms/Link/DocLink' +} from '../../lib/utils/events' +import { ScrollSync, scrollSyncer } from '../../lib/editor/scrollSync' +import CodeMirrorEditor from '../../lib/editor/components/CodeMirrorEditor' +import MarkdownView, { SelectionContext } from '../MarkdownView' +import { usePage } from '../../lib/stores/pageStore' +import { useToast } from '../../../design/lib/stores/toast' +import { LoadingButton } from '../../../design/components/atoms/Button' +import { trackEvent } from '../../api/track' +import { MixpanelActionTrackTypes } from '../../interfaces/analytics/mixpanel' +import { useCloudApi } from '../../lib/hooks/useCloudApi' +import { useCloudResourceModals } from '../../lib/hooks/useCloudResourceModals' +import { mapTopbarBreadcrumbs } from '../../lib/mappers/topbarBreadcrumbs' +import { useModal } from '../../../design/lib/stores/modal' +import PresenceIcons from '../Topbar/PresenceIcons' +import { TopbarControlProps } from '../../../design/components/organisms/Topbar' +import CommentManager from '../Comments/CommentManager' +import useCommentManagerState from '../../lib/hooks/useCommentManagerState' +import { HighlightRange } from '../../lib/rehypeHighlight' +import { getDocLinkHref } from '../Link/DocLink' import throttle from 'lodash.throttle' -import { useI18n } from '../../../lib/hooks/useI18n' -import { lngKeys } from '../../../lib/i18n/types' +import { useI18n } from '../../lib/hooks/useI18n' +import { lngKeys } from '../../lib/i18n/types' import { parse } from 'querystring' -import DocShare from '../DocShare' -import EditorLayout from '../../organisms/EditorLayout' -import PreferencesContextMenuWrapper from '../../molecules/PreferencesContextMenuWrapper' -import InviteCTAButton from '../InviteCTAButton' -import { BaseTheme } from '../../../../shared/lib/styled/types' +import DocShare from '../DocPage/DocShare' +import EditorLayout from '../DocPage/EditorLayout' +import PreferencesContextMenuWrapper from '../PreferencesContextMenuWrapper' +import InviteCTAButton from '../Buttons/InviteCTAButton' +import { BaseTheme } from '../../../design/lib/styled/types' +import Spinner from '../../../design/components/atoms/Spinner' +import styled from '../../../design/lib/styled' +import { rightSidePageLayout } from '../../../design/lib/styled/styleFunctions' +import Icon from '../../../design/components/atoms/Icon' type LayoutMode = 'split' | 'preview' | 'editor' @@ -1057,7 +1057,6 @@ const Editor = ({ doc, team, user, contributors, backLinks }: EditorProps) => { { SelectionMenu={({ selection }) => (
newRangeThread(selection)}> - +
)} @@ -1172,9 +1171,9 @@ const StyledBottomBar = styled.div` display: flex; position: relative; flex: 0 0 auto; - border-top: solid 1px ${({ theme }) => theme.baseBorderColor}; + border-top: solid 1px ${({ theme }) => theme.colors.border.main}; height: 24px; - background-color: ${({ theme }) => theme.baseBackgroundColor}; + background-color: ${({ theme }) => theme.colors.background.primary}; box-sizing: content-box; & > :first-child { flex: 1; @@ -1182,19 +1181,19 @@ const StyledBottomBar = styled.div` ` const StyledShortcodeConvertMenu = styled.div` - margin-top: ${({ theme }) => theme.space.xsmall}px; + margin-top: ${({ theme }) => theme.sizes.spaces.xsm}px; border-radius: 5px; - box-shadow: ${({ theme }) => theme.baseShadowColor}; + box-shadow: ${({ theme }) => theme.colors.shadow}; button { display: block; width: 200px; line-height: 25px; - padding: ${({ theme }) => theme.space.xsmall}px - ${({ theme }) => theme.space.small}px; - background-color: ${({ theme }) => theme.contextMenuColor}; - color: ${({ theme }) => theme.baseTextColor}; - font-size: ${({ theme }) => theme.fontSizes.small}px; + padding: ${({ theme }) => theme.sizes.spaces.xsm}px + ${({ theme }) => theme.sizes.spaces.sm}px; + background-color: ${({ theme }) => theme.colors.background.secondary}; + color: ${({ theme }) => theme.colors.text.primary}; + font-size: ${({ theme }) => theme.sizes.fonts.sm}px; text-align: left; &:first-child { @@ -1207,8 +1206,8 @@ const StyledShortcodeConvertMenu = styled.div` &:hover, &:focus { - background-color: ${({ theme }) => theme.subtleBackgroundColor}; - color: ${({ theme }) => theme.emphasizedTextColor}; + background-color: ${({ theme }) => theme.colors.background.tertiary}; + opacity: 0.8; cursor: pointer; } } @@ -1240,13 +1239,14 @@ const ToolbarRow = styled.div` display: flex; flex-wrap: nowrap; position: absolute; - bottom: ${({ theme }) => theme.space.large}px; - left: 50%; - transform: translateX(-50%); + bottom: ${({ theme }) => theme.sizes.spaces.l}px; + right: 0; + left: 0; + margin: auto; z-index: 1; width: fit-content; - background-color: ${({ theme }) => theme.boldBackgroundColor}; - border: solid 1px ${({ theme }) => theme.divideBorderColor}; + background-color: ${({ theme }) => theme.colors.background.secondary}; + border: solid 1px ${({ theme }) => theme.colors.border.second}; border-radius: 5px; ` interface FontOptionsProps { @@ -1280,11 +1280,11 @@ const StyledPreview = styled.div` .scroller { height: 100%; overflow: auto; - border-left: 1px solid ${({ theme }) => theme.baseBorderColor}; + border-left: 1px solid ${({ theme }) => theme.colors.border.main}; } } &.layout-preview { - padding-top: ${({ theme }) => theme.space.small}px; + padding-top: ${({ theme }) => theme.sizes.spaces.sm}px; margin: 0 auto; width: 100%; } @@ -1340,9 +1340,9 @@ const StyledEditor = styled.div` margin: 0; padding: 0; border-radius: 3px; - border: 1px solid ${({ theme }) => theme.baseBorderColor}; - background: ${({ theme }) => theme.baseBackgroundColor}; - color: ${({ theme }) => theme.baseTextColor}; + border: 1px solid ${({ theme }) => theme.colors.border.main}; + background: ${({ theme }) => theme.colors.background.primary}; + color: ${({ theme }) => theme.colors.text.primary}; font-size: 90%; font-family: monospace; list-style: none; @@ -1350,24 +1350,24 @@ const StyledEditor = styled.div` .CodeMirror-hint { position: relative; margin: 0; - padding: ${({ theme }) => theme.space.xxsmall}px - ${({ theme }) => theme.space.small}px; + padding: ${({ theme }) => theme.sizes.spaces.xsm}px + ${({ theme }) => theme.sizes.spaces.sm}px; white-space: pre; - color: ${({ theme }) => theme.baseTextColor}; + color: ${({ theme }) => theme.colors.text.primary}; cursor: pointer; - font-size: ${({ theme }) => theme.fontSizes.xsmall}px; + font-size: ${({ theme }) => theme.sizes.fonts.xsm}px; } li.CodeMirror-hint-active { - color: ${({ theme }) => theme.primaryTextColor}; + color: ${({ theme }) => theme.colors.variants.primary.base}; &:before { content: ''; display: block; position: absolute; top: 3px; - left: ${({ theme }) => theme.space.xsmall}px; + left: ${({ theme }) => theme.sizes.spaces.xsm}px; width: 3px; height: 22px; - background-color: ${({ theme }) => theme.primaryBackgroundColor}; + background-color: ${({ theme }) => theme.colors.variants.primary.base}; } } & .remote-caret { @@ -1385,9 +1385,9 @@ const StyledEditor = styled.div` height: 100%; top: 0; transform: translate3d(0, -100%, 0); - font-size: ${({ theme }) => theme.fontSizes.xxsmall}px; - height: ${({ theme }) => theme.fontSizes.xxsmall + 4}px; - line-height: ${({ theme }) => theme.fontSizes.xxsmall + 4}px; + font-size: ${({ theme }) => theme.sizes.fonts.xsm}px; + height: ${({ theme }) => theme.sizes.fonts.xsm + 4}px; + line-height: ${({ theme }) => theme.sizes.fonts.xsm + 4}px; vertical-align: middle; background-color: rgb(250, 129, 0); user-select: none; @@ -1407,7 +1407,7 @@ const StyledEditor = styled.div` } .CodeMirror-code, .CodeMirror-gutters { - padding-bottom: ${({ theme }) => theme.space.xxxlarge}px; + padding-bottom: 32px; } & .file-loading-widget { transform: translate3d(0, -100%, 0); diff --git a/src/cloud/components/molecules/Editor/styled.ts b/src/cloud/components/Editor/styled.ts similarity index 52% rename from src/cloud/components/molecules/Editor/styled.ts rename to src/cloud/components/Editor/styled.ts index dadf3c8ca9..2d5d75c172 100644 --- a/src/cloud/components/molecules/Editor/styled.ts +++ b/src/cloud/components/Editor/styled.ts @@ -1,11 +1,11 @@ -import styled from '../../../lib/styled' +import styled from '../../../design/lib/styled' export const StyledEditorToolButtonContainer = styled.div` margin: 0 5px; position: relative; &.editor-tool-integrations { - margin-right: ${({ theme }) => theme.space.default}px; + margin-right: ${({ theme }) => theme.sizes.spaces.df}px; .top { transform: translateX(-10%); @@ -14,19 +14,11 @@ export const StyledEditorToolButtonContainer = styled.div` button { &:hover, &:focus { - color: ${({ theme }) => theme.primaryTextColor}; + color: ${({ theme }) => theme.colors.text.link}; } } } - &.tour-component { - width: 20px; - height: 20px; - border-radius: 50%; - box-shadow: 0px 4px 0px 12px ${({ theme }) => theme.baseBackgroundColor}; - background: ${({ theme }) => theme.baseBackgroundColor}; - } - &.scroll-sync .bottom { left: 100%; transform: translateX(-20%); @@ -36,13 +28,13 @@ export const StyledEditorToolButtonContainer = styled.div` export const StyledEditorToolButton = styled.button` display: flex; background: none; - color: ${({ theme }) => theme.subtleTextColor}; - padding: ${({ theme }) => theme.space.xxsmall}px 0; - font-size: ${({ theme }) => theme.fontSizes.xxlarge}px; + color: ${({ theme }) => theme.colors.text.subtle}; + padding: ${({ theme }) => theme.sizes.spaces.xsm}px 0; + font-size: ${({ theme }) => theme.sizes.fonts.xl}px; &:hover, &:focus { - color: ${({ theme }) => theme.emphasizedTextColor}; + color: ${({ theme }) => theme.colors.text.primary}; } ` @@ -54,7 +46,7 @@ export const StyledEditorToolList = styled.div` export const StyledEditorToolDropdownContainer = styled.div` z-index: 9000; position: absolute; - padding: ${({ theme }) => theme.space.xsmall}px 0; + padding: ${({ theme }) => theme.sizes.spaces.xsm}px 0; width: 110px; height: auto; min-width: 100%; @@ -66,6 +58,6 @@ export const StyledEditorToolDropdownContainer = styled.div` border: none; left: 0; bottom: 100%; - background-color: ${({ theme }) => theme.baseBackgroundColor}; - box-shadow: ${({ theme }) => theme.baseShadowColor}; + background-color: ${({ theme }) => theme.colors.background.primary}; + box-shadow: ${({ theme }) => theme.colors.shadow}; ` diff --git a/src/cloud/components/molecules/Editor/types.ts b/src/cloud/components/Editor/types.ts similarity index 100% rename from src/cloud/components/molecules/Editor/types.ts rename to src/cloud/components/Editor/types.ts diff --git a/src/cloud/components/atoms/EditorsIcons.tsx b/src/cloud/components/EditorsIcons.tsx similarity index 72% rename from src/cloud/components/atoms/EditorsIcons.tsx rename to src/cloud/components/EditorsIcons.tsx index 3a72d2d467..4335775c95 100644 --- a/src/cloud/components/atoms/EditorsIcons.tsx +++ b/src/cloud/components/EditorsIcons.tsx @@ -1,10 +1,10 @@ import React from 'react' -import { SerializedUser } from '../../interfaces/db/user' -import styled from '../../lib/styled' -import { buildIconUrl } from '../../api/files' -import { getColorFromString } from '../../lib/utils/string' -import Flexbox from './Flexbox' -import { userIconStyle } from '../../lib/styled/styleFunctions' +import { SerializedUser } from '../interfaces/db/user' +import { buildIconUrl } from '../api/files' +import { getColorFromString } from '../lib/utils/string' +import Flexbox from '../../design/components/atoms/Flexbox' +import styled from '../../design/lib/styled' +import { userIconStyle } from '../../design/lib/styled/styleFunctions' interface EditorsIconsProps { editors: SerializedUser[] @@ -48,17 +48,17 @@ const StyledUsersList = styled.ul` flex: 0 0 auto; align-items: center; list-style: none; - margin: 0 ${({ theme }) => theme.space.xxsmall}px 0 0; + margin: 0 ${({ theme }) => theme.sizes.spaces.xsm}px 0 0; padding: 0; - color: ${({ theme }) => theme.subtleTextColor}; + color: ${({ theme }) => theme.colors.text.subtle}; font-size: inherit; - margin-left: ${({ theme }) => theme.space.xxsmall}px; + margin-left: ${({ theme }) => theme.sizes.spaces.xsm}px; z-index: initial; line-height: 24px; ` const StyledCropped = styled.span` - padding-left: ${({ theme }) => theme.space.xxsmall}px; + padding-left: ${({ theme }) => theme.sizes.spaces.xsm}px; ` const StyledUsersListItem = styled.div` diff --git a/src/cloud/components/EmojiIcon.tsx b/src/cloud/components/EmojiIcon.tsx new file mode 100644 index 0000000000..2cbc2637fa --- /dev/null +++ b/src/cloud/components/EmojiIcon.tsx @@ -0,0 +1,49 @@ +import React from 'react' +import { Emoji } from 'emoji-mart' +import cc from 'classcat' +import Flexbox from '../../design/components/atoms/Flexbox' +import WithTooltip from '../../design/components/atoms/WithTooltip' +import Icon, { IconSize } from '../../design/components/atoms/Icon' + +interface EmojiIconProps { + emoji?: string + defaultIcon?: string + className?: string + style?: React.CSSProperties + onClick?: (event: React.MouseEvent) => void + size?: IconSize + tooltip?: React.ReactNode +} + +const EmojiIcon = ({ + emoji, + defaultIcon, + className, + style, + size = 34, + tooltip, + onClick, +}: EmojiIconProps) => { + if (emoji == null && defaultIcon == null) { + return null + } + + return ( + + + {emoji != null ? ( + + ) : ( + + )} + + + ) +} + +export default EmojiIcon diff --git a/src/cloud/components/atoms/ErrorBlock.tsx b/src/cloud/components/ErrorBlock.tsx similarity index 92% rename from src/cloud/components/atoms/ErrorBlock.tsx rename to src/cloud/components/ErrorBlock.tsx index 063fa73f43..34cdf57b6a 100644 --- a/src/cloud/components/atoms/ErrorBlock.tsx +++ b/src/cloud/components/ErrorBlock.tsx @@ -1,7 +1,7 @@ import React, { useEffect, useState } from 'react' -import ColoredBlock from './ColoredBlock' -import { nodeEnv } from '../../lib/consts' +import { nodeEnv } from '../lib/consts' import ky from 'ky' +import ColoredBlock from '../../design/components/atoms/ColoredBlock' interface ErrorAlertProps { error: unknown diff --git a/src/cloud/components/organisms/EventSource.tsx b/src/cloud/components/EventSource.tsx similarity index 93% rename from src/cloud/components/organisms/EventSource.tsx rename to src/cloud/components/EventSource.tsx index 9dabf3c00c..8ad4598fe3 100644 --- a/src/cloud/components/organisms/EventSource.tsx +++ b/src/cloud/components/EventSource.tsx @@ -1,25 +1,25 @@ import { useCallback, useEffect, useRef } from 'react' import { EventSourcePolyfill } from 'event-source-polyfill' -import { sseUrl } from '../../lib/consts' +import { sseUrl } from '../lib/consts' import { useNumber } from 'react-use' import { ResourcesIdSortedByWorkspaceIds, SerializedAppEvent, -} from '../../interfaces/db/appEvents' -import { getMapFromEntityArray } from '../../../shared/lib/utils/array' -import { getResources } from '../../api/teams/resources' -import { SerializedWorkspace } from '../../interfaces/db/workspace' -import { SerializedTag } from '../../interfaces/db/tag' -import { SerializedUserTeamPermissions } from '../../interfaces/db/userTeamPermissions' -import { useGlobalData } from '../../lib/stores/globalData' -import { useNav } from '../../lib/stores/nav' -import { usePage } from '../../lib/stores/pageStore' -import { SerializedTeam } from '../../interfaces/db/team' -import { getTemplate } from '../../api/teams/docs/templates' -import { getUniqueFolderAndDocIdsFromResourcesIds } from '../../lib/utils/patterns' -import { getAccessToken, useElectron } from '../../lib/stores/electron' -import { useNotifications } from '../../../shared/lib/stores/notifications' -import { useComments } from '../../lib/stores/comments' +} from '../interfaces/db/appEvents' +import { getMapFromEntityArray } from '../../design/lib/utils/array' +import { getResources } from '../api/teams/resources' +import { SerializedWorkspace } from '../interfaces/db/workspace' +import { SerializedTag } from '../interfaces/db/tag' +import { SerializedUserTeamPermissions } from '../interfaces/db/userTeamPermissions' +import { useGlobalData } from '../lib/stores/globalData' +import { useNav } from '../lib/stores/nav' +import { usePage } from '../lib/stores/pageStore' +import { SerializedTeam } from '../interfaces/db/team' +import { getTemplate } from '../api/teams/docs/templates' +import { getUniqueFolderAndDocIdsFromResourcesIds } from '../lib/utils/patterns' +import { getAccessToken, useElectron } from '../lib/stores/electron' +import { useNotifications } from '../../design/lib/stores/notifications' +import { useComments } from '../lib/stores/comments' interface EventSourceProps { teamId: string diff --git a/src/cloud/components/FeedbackForm/ExpandingRow.tsx b/src/cloud/components/FeedbackForm/ExpandingRow.tsx new file mode 100644 index 0000000000..6c2006de27 --- /dev/null +++ b/src/cloud/components/FeedbackForm/ExpandingRow.tsx @@ -0,0 +1,81 @@ +import React, { useCallback } from 'react' +import FormRow from '../../../design/components/molecules/Form/templates/FormRow' +import FormRowItem from '../../../design/components/molecules/Form/templates/FormRowItem' +import Flexbox from '../../../design/components/atoms/Flexbox' +import Checkbox from '../../../design/components/molecules/Form/atoms/FormCheckbox' + +interface ExpandingRowProps { + label: string + isChecked: boolean + expandedLabel: string + expandedValue?: string + toggleCheckBoxValue: () => void + onChangeExpandedValue: (val: string) => void +} + +const ExpandingRow = ({ + label, + isChecked, + toggleCheckBoxValue, + expandedValue = '', + expandedLabel, + onChangeExpandedValue, +}: ExpandingRowProps) => { + const onCheckboxChangeHandler = useCallback(() => { + toggleCheckBoxValue() + }, [toggleCheckBoxValue]) + + const onTextAreaChangeHandler = useCallback( + (event: React.ChangeEvent) => { + onChangeExpandedValue(event.target.value) + }, + [onChangeExpandedValue] + ) + + return ( + <> + + + + +
+ ), + }} + /> + + {isChecked && ( + + )} + + ) +} + +export default ExpandingRow diff --git a/src/cloud/components/organisms/FeedbackForm/index.tsx b/src/cloud/components/FeedbackForm/index.tsx similarity index 69% rename from src/cloud/components/organisms/FeedbackForm/index.tsx rename to src/cloud/components/FeedbackForm/index.tsx index c453975f8b..31696e85bf 100644 --- a/src/cloud/components/organisms/FeedbackForm/index.tsx +++ b/src/cloud/components/FeedbackForm/index.tsx @@ -1,6 +1,5 @@ import React, { useCallback } from 'react' -import styled from '../../../lib/styled' -import { inputStyle } from '../../../lib/styled/styleFunctions' +import Form from '../../../design/components/molecules/Form' import ExpandingRow from './ExpandingRow' import { UserFeedbackFormData } from './types' @@ -32,7 +31,7 @@ const FeedbackForm = ({ feedback, onChangeFeedback }: FeedbackFormProps) => { ) return ( - +
{ expandedValue={feedback.price} onChangeExpandedValue={(val) => textAreaChangeHandler('price', val)} /> - +
+ ) } -const StyledFeedbackForm = styled.form` - max-width: 100%; - margin: ${({ theme }) => theme.space.medium}px auto; - text-align: left; - - .flex { - align-items: center; - margin-bottom: ${({ theme }) => theme.space.small}px; - - input[type=checkbox], - label { - &:hover { - cursor: pointer; - } - } - - input[type=checkbox] { - width: 22px; - height: 22px; - } - - label { - padding-left: ${({ theme }) => theme.space.xsmall}px; - margin-bottom: 0; - } - } - - .row { - display: block; - position: relative; - - input { - position: relative; - width: 100%; - height: 50px; - ${inputStyle} - padding-left: ${({ theme }) => theme.space.small}px; - } - } -` - export default FeedbackForm diff --git a/src/cloud/components/organisms/FeedbackForm/types.ts b/src/cloud/components/FeedbackForm/types.ts similarity index 100% rename from src/cloud/components/organisms/FeedbackForm/types.ts rename to src/cloud/components/FeedbackForm/types.ts diff --git a/src/cloud/components/atoms/FileListItem.tsx b/src/cloud/components/FileListItem.tsx similarity index 69% rename from src/cloud/components/atoms/FileListItem.tsx rename to src/cloud/components/FileListItem.tsx index ccb9c5bd35..80d5e5780f 100644 --- a/src/cloud/components/atoms/FileListItem.tsx +++ b/src/cloud/components/FileListItem.tsx @@ -1,11 +1,11 @@ import React from 'react' -import { SerializedTeam } from '../../interfaces/db/team' -import { buildTeamFileUrl } from '../../api/teams/files' +import { SerializedTeam } from '../interfaces/db/team' +import { buildTeamFileUrl } from '../api/teams/files' import { mdiClose } from '@mdi/js' -import IconMdi from './IconMdi' -import { getFormattedBoosthubDate } from '../../lib/date' +import { getFormattedBoosthubDate } from '../lib/date' import cc from 'classcat' -import { SerializedFileInfo } from '../../interfaces/db/storage' +import { SerializedFileInfo } from '../interfaces/db/storage' +import Button from '../../design/components/atoms/Button' interface FileListItemProps { file: SerializedFileInfo @@ -23,12 +23,13 @@ const FileListItem = ({ return (
{onDeleteHandler != null && ( -
onDeleteHandler(team, file)} - > - -
+ /> )}
diff --git a/src/cloud/components/FolderPage/NewFolderContextMenu.tsx b/src/cloud/components/FolderPage/NewFolderContextMenu.tsx new file mode 100644 index 0000000000..f7ec2b2297 --- /dev/null +++ b/src/cloud/components/FolderPage/NewFolderContextMenu.tsx @@ -0,0 +1,258 @@ +import React, { useCallback, useMemo, useState } from 'react' +import { SerializedFolderWithBookmark } from '../../interfaces/db/folder' +import { + mdiStar, + mdiTrashCan, + mdiStarOutline, + mdiPencil, + mdiContentSaveOutline, + mdiClockOutline, + mdiContentCopy, + mdiOpenInNew, + mdiArrowRight, + mdiFolderMultipleOutline, +} from '@mdi/js' +import { useCloudResourceModals } from '../../lib/hooks/useCloudResourceModals' +import { useI18n } from '../../lib/hooks/useI18n' +import { lngKeys } from '../../lib/i18n/types' +import MetadataContainer from '../../../design/components/organisms/MetadataContainer' +import MetadataContainerRow from '../../../design/components/organisms/MetadataContainer/molecules/MetadataContainerRow' +import { useCloudApi } from '../../lib/hooks/useCloudApi' +import { useModal } from '../../../design/lib/stores/modal' +import { useNav } from '../../lib/stores/nav' +import { getFormattedDateTime } from '../../lib/date' +import MetadataContainerBreak from '../../../design/components/organisms/MetadataContainer/atoms/MetadataContainerBreak' +import { boostHubBaseUrl } from '../../lib/consts' +import { getFolderHref } from '../Link/FolderLink' +import { usePage } from '../../lib/stores/pageStore' +import copy from 'copy-to-clipboard' +import { sendToHost, usingElectron } from '../../lib/stores/electron' +import MoveItemModal from '../Modal/contents/Forms/MoveItemModal' +import { getMapValues } from '../../../design/lib/utils/array' + +interface FolderContextMenuProps { + currentFolder: SerializedFolderWithBookmark + currentUserIsCoreMember: boolean +} + +const FolderContextMenu = ({ + currentFolder: folder, + currentUserIsCoreMember, +}: FolderContextMenuProps) => { + const { toggleFolderBookmark, sendingMap, updateFolder } = useCloudApi() + const { deleteFolder, openRenameFolderForm } = useCloudResourceModals() + const { closeAllModals, openModal } = useModal() + const { translate } = useI18n() + const { foldersMap, docsMap } = useNav() + const [copied, setCopied] = useState(false) + const { team } = usePage() + + const currentFolder = useMemo(() => { + return foldersMap.get(folder.id) + }, [foldersMap, folder.id]) + + const folderUrl = useMemo(() => { + if (currentFolder == null || team == null) { + return '' + } + return boostHubBaseUrl + getFolderHref(currentFolder, team, 'index') + }, [team, currentFolder]) + + const children = useMemo(() => { + if (currentFolder == null) { + return { docs: 0, folders: 0 } + } + + const docs = getMapValues(docsMap).reduce((acc, val) => { + if (val.parentFolderId === currentFolder.id) { + return acc + 1 + } + return acc + }, 0) + + const folders = getMapValues(foldersMap).reduce((acc, val) => { + if (val.parentFolderId === currentFolder.id) { + return acc + 1 + } + return acc + }, 0) + + return { + docs, + folders, + } + }, [foldersMap, currentFolder, docsMap]) + + const copyButtonHandler = useCallback(() => { + copy(folderUrl) + setCopied(true) + setTimeout(() => { + setCopied(false) + }, 200) + }, [folderUrl]) + + if (currentFolder == null) { + return ( + + + + ) + } + + return ( + + + + + + + toggleFolderBookmark( + currentFolder.teamId, + currentFolder.id, + currentFolder.bookmarked + ), + }, + }} + /> + + {usingElectron && ( + { + sendToHost('open-external-url', folderUrl) + }, + }, + }} + /> + )} + {currentUserIsCoreMember && ( + <> + + openRenameFolderForm(currentFolder), + }, + }} + /> + + { + return openModal( + + updateFolder(currentFolder, { + workspaceId, + parentFolderId, + }) + } + /> + ) + }, + }, + }} + /> + { + closeAllModals() + deleteFolder(currentFolder) + }, + }, + }} + /> + + )} + + ) +} + +export default FolderContextMenu diff --git a/src/cloud/components/organisms/FolderPage/index.tsx b/src/cloud/components/FolderPage/index.tsx similarity index 84% rename from src/cloud/components/organisms/FolderPage/index.tsx rename to src/cloud/components/FolderPage/index.tsx index 8dc40991c1..e1d2612fac 100644 --- a/src/cloud/components/organisms/FolderPage/index.tsx +++ b/src/cloud/components/FolderPage/index.tsx @@ -1,17 +1,17 @@ import React, { useMemo, useEffect } from 'react' -import { usePage } from '../../../lib/stores/pageStore' -import { useNav } from '../../../lib/stores/nav' +import { usePage } from '../../lib/stores/pageStore' +import { useNav } from '../../lib/stores/nav' import { useTitle } from 'react-use' import { useGlobalKeyDownHandler, preventKeyboardEventPropagation, -} from '../../../lib/keyboard' +} from '../../lib/keyboard' import { isFolderBookmarkShortcut, isFolderDeleteShortcut, isFolderEditShortcut, -} from '../../../lib/shortcuts' -import { SerializedDocWithBookmark } from '../../../interfaces/db/doc' +} from '../../lib/shortcuts' +import { SerializedDocWithBookmark } from '../../interfaces/db/doc' import { mdiStarOutline, mdiStar, @@ -20,24 +20,25 @@ import { mdiTextBoxPlus, mdiFolderPlusOutline, } from '@mdi/js' -import { SerializedFolderWithBookmark } from '../../../interfaces/db/folder' -import ContentManager from '../../molecules/ContentManager' -import { SerializedWorkspace } from '../../../interfaces/db/workspace' -import Application from '../../Application' -import ErrorLayout from '../../../../shared/components/templates/ErrorLayout' -import { useRouter } from '../../../lib/router' -import { LoadingButton } from '../../../../shared/components/atoms/Button' +import { SerializedFolderWithBookmark } from '../../interfaces/db/folder' +import ContentManager from '../ContentManager' +import { SerializedWorkspace } from '../../interfaces/db/workspace' +import Application from '../Application' +import ErrorLayout from '../../../design/components/templates/ErrorLayout' +import { useRouter } from '../../lib/router' +import { LoadingButton } from '../../../design/components/atoms/Button' import FolderContextMenu from './NewFolderContextMenu' -import { useCloudResourceModals } from '../../../lib/hooks/useCloudResourceModals' -import { useCloudApi } from '../../../lib/hooks/useCloudApi' -import { mapTopbarBreadcrumbs } from '../../../lib/mappers/topbarBreadcrumbs' -import { useI18n } from '../../../lib/hooks/useI18n' -import InviteCTAButton from '../../molecules/InviteCTAButton' -import { useModal } from '../../../../shared/lib/stores/modal' -import MetadataContainer from '../../../../shared/components/organisms/MetadataContainer' -import MetadataContainerRow from '../../../../shared/components/organisms/MetadataContainer/molecules/MetadataContainerRow' -import { lngKeys } from '../../../lib/i18n/types' -import { TopbarControlProps } from '../../../../shared/components/organisms/Topbar' +import { useCloudResourceModals } from '../../lib/hooks/useCloudResourceModals' +import { useCloudApi } from '../../lib/hooks/useCloudApi' +import { mapTopbarBreadcrumbs } from '../../lib/mappers/topbarBreadcrumbs' +import { useI18n } from '../../lib/hooks/useI18n' +import InviteCTAButton from '../Buttons/InviteCTAButton' +import { useModal } from '../../../design/lib/stores/modal' +import MetadataContainer from '../../../design/components/organisms/MetadataContainer' +import MetadataContainerRow from '../../../design/components/organisms/MetadataContainer/molecules/MetadataContainerRow' +import { lngKeys } from '../../lib/i18n/types' +import { TopbarControlProps } from '../../../design/components/organisms/Topbar' +import FolderPageInviteSection from '../Onboarding/FolderPageInviteSection' const FolderPage = () => { const { pageFolder, team, currentUserIsCoreMember } = usePage() @@ -275,7 +276,7 @@ const FolderPage = () => { { hideBackground: true, removePadding: true, - width: 200, + width: 300, alignment: 'bottom-right', } ), @@ -294,9 +295,9 @@ const FolderPage = () => { currentUserIsCoreMember={currentUserIsCoreMember} />, { - width: 200, - hideBackground: true, + alignment: 'bottom-right', removePadding: true, + hideBackground: true, } ), }) @@ -362,6 +363,7 @@ const FolderPage = () => { }, }} > + {
- + {translate(lngKeys.FreeTrialModalCTA)} + + )} + + {scrollbarStyle === 'native' ? ( + + ) : ( + + + + )} + + ) +} + +const Container = styled.div` + height: 100%; + display: flex; + flex-direction: column; + + .revision__detail__header { + flex: 0 0 auto; + padding-bottom: ${({ theme }) => theme.sizes.spaces.sm}px; + border-bottom: 1px solid ${({ theme }) => theme.colors.border.second}; + } + + .revision__detail__title { + padding-left: ${({ theme }) => theme.sizes.spaces.df}px; + + h3 { + margin: 0; + font-size: ${({ theme }) => theme.sizes.fonts.df}px; + } + span { + font-size: ${({ theme }) => theme.sizes.fonts.sm}px; + color: ${({ theme }) => theme.colors.text.subtle}; + } + } + + &.revision__modal__scroll--transparent { + .codemirror__scroller { + flex: 1 1 auto; + } + + .CodeMirror { + height: fit-content; + } + + .CodeMirror-vscrollbar { + display: none; + } + } + + &.revision__modal__scroll--native { + .CodeMirrorWrapper { + flex: 1 1 auto; + display: flex; + flex-direction: column; + } + + .CodeMirror { + flex: 1 1 auto; + } + } +` + +export default RevisionModalDetail diff --git a/src/cloud/components/Modal/contents/Doc/RevisionsModal/RevisionModalNavigator.tsx b/src/cloud/components/Modal/contents/Doc/RevisionsModal/RevisionModalNavigator.tsx new file mode 100644 index 0000000000..61649a868d --- /dev/null +++ b/src/cloud/components/Modal/contents/Doc/RevisionsModal/RevisionModalNavigator.tsx @@ -0,0 +1,171 @@ +import React, { useMemo } from 'react' +import { SerializedSubscription } from '../../../../../interfaces/db/subscription' +import { SerializedRevision } from '../../../../../interfaces/db/revision' +import { SerializedUserTeamPermissions } from '../../../../../interfaces/db/userTeamPermissions' +import styled from '../../../../../../design/lib/styled' +import { isFocusLeftSideShortcut } from '../../../../../../design/lib/shortcuts' +import { + preventKeyboardEventPropagation, + useGlobalKeyDownHandler, + useUpDownNavigationListener, +} from '../../../../../../design/lib/keyboard' +import { focusFirstChildFromElement } from '../../../../../../design/lib/dom' +import Spinner from '../../../../../../design/components/atoms/Spinner' +import plur from 'plur' +import VerticalScroller from '../../../../../../design/components/atoms/VerticalScroller' +import NavigationItem from '../../../../../../design/components/molecules/Navigation/NavigationItem' +import Flexbox from '../../../../../../design/components/atoms/Flexbox' +import { format } from 'date-fns' +import UserIcon from '../../../../UserIcon' +import Button from '../../../../../../design/components/atoms/Button' + +interface RevisionModalNavigatorProps { + revisions: SerializedRevision[] + revisionIndex?: number + fetching: boolean + currentUserPermissions?: SerializedUserTeamPermissions + menuRef: React.RefObject + setRevisionIndex: (index: number) => void + subscription?: SerializedSubscription + currentPage: number + totalPages: number + fetchRevisions: (page: number) => void +} + +const RevisionModalNavigator = React.forwardRef< + HTMLButtonElement, + RevisionModalNavigatorProps +>( + ({ + menuRef, + fetching, + revisions, + currentPage, + totalPages, + setRevisionIndex, + revisionIndex, + fetchRevisions, + }) => { + const keydownHandler = useMemo(() => { + return (event: KeyboardEvent) => { + if (isFocusLeftSideShortcut(event)) { + preventKeyboardEventPropagation(event) + focusFirstChildFromElement(menuRef.current) + return + } + } + }, [menuRef]) + useGlobalKeyDownHandler(keydownHandler) + useUpDownNavigationListener(menuRef) + + return ( + +
+

Revision History

+
+ {fetching ? ( + + ) : ( + + {`${revisions.length}${ + currentPage !== totalPages ? '+ ' : ' ' + }`} + {plur('version', revisions.length)} + + )} +
+
+ + + {revisions.map((rev) => ( + setRevisionIndex(rev.id)} + label={format(new Date(rev.created), 'HH:mm, dd MMMM u')} + borderRadius={true} + icon={{ + type: 'node', + icon: ( + + {rev.creators.map((user) => ( + + ))} + + ), + }} + /> + ))} + + {currentPage < totalPages && ( + + )} +
+ ) + } +) + +const Container = styled.div` + width: 200px; + height: 100%; + border-right: 1px solid ${({ theme }) => theme.colors.border.main}; + display: flex; + flex-direction: column; + overflow: hidden; + + header, + .revisions__scroller { + padding-right: ${({ theme }) => theme.sizes.spaces.df}px; + } + + header { + display: block; + text-align: center; + flex: 0 0 auto; + + h2 { + margin: 0; + font-size: ${({ theme }) => theme.sizes.fonts.md}px; + } + + .revision__navigator__description { + font-size: ${({ theme }) => theme.sizes.fonts.sm}px; + color: ${({ theme }) => theme.colors.text.subtle}; + margin-bottom: ${({ theme }) => theme.sizes.spaces.sm}px; + } + } + + #revision__navigator__load { + display: block; + margin: ${({ theme }) => theme.sizes.spaces.sm}px auto; + } + + .user__icon { + width: 18px; + height: 18px; + font-size: ${({ theme }) => theme.sizes.fonts.sm}px; + line-height: 15px; + } + + .navigation__item__label__ellipsis { + margin-left: ${({ theme }) => theme.sizes.spaces.sm}px; + } + + .revisions__scroller { + flex: 1 1 auto; + } +` + +export default RevisionModalNavigator diff --git a/src/cloud/components/organisms/Modal/contents/Doc/RevisionsModal/index.tsx b/src/cloud/components/Modal/contents/Doc/RevisionsModal/index.tsx similarity index 73% rename from src/cloud/components/organisms/Modal/contents/Doc/RevisionsModal/index.tsx rename to src/cloud/components/Modal/contents/Doc/RevisionsModal/index.tsx index 4fa89dc61e..71f25c3a01 100644 --- a/src/cloud/components/organisms/Modal/contents/Doc/RevisionsModal/index.tsx +++ b/src/cloud/components/Modal/contents/Doc/RevisionsModal/index.tsx @@ -1,39 +1,35 @@ import React, { useState, useMemo, useCallback, useEffect, useRef } from 'react' -import { ModalContainer } from '../../styled' import { useEffectOnce } from 'react-use' -import { SerializedDocWithBookmark } from '../../../../../../interfaces/db/doc' +import { SerializedDocWithBookmark } from '../../../../../interfaces/db/doc' import { isFocusLeftSideShortcut, isFocusRightSideShortcut, -} from '../../../../../../lib/shortcuts' +} from '../../../../../lib/shortcuts' import { preventKeyboardEventPropagation, useCapturingGlobalKeyDownHandler, -} from '../../../../../../lib/keyboard' -import { focusFirstChildFromElement } from '../../../../../../lib/dom' -import { SerializedRevision } from '../../../../../../interfaces/db/revision' -import { getAllRevisionsFromDoc } from '../../../../../../api/teams/docs/revisions' -import { usePage } from '../../../../../../lib/stores/pageStore' -import IconMdi from '../../../../../atoms/IconMdi' +} from '../../../../../lib/keyboard' +import { focusFirstChildFromElement } from '../../../../../lib/dom' +import { SerializedRevision } from '../../../../../interfaces/db/revision' +import { getAllRevisionsFromDoc } from '../../../../../api/teams/docs/revisions' +import { usePage } from '../../../../../lib/stores/pageStore' import { mdiBackupRestore } from '@mdi/js' -import { useSettings } from '../../../../../../lib/stores/settings' +import { useSettings } from '../../../../../lib/stores/settings' import { useDialog, DialogIconTypes, -} from '../../../../../../../shared/lib/stores/dialog' +} from '../../../../../../design/lib/stores/dialog' import RevisionModalDetail from './RevisionModalDetail' -import { - StyledNoSubContent, - StyledContent, - StyledRevisionsModal, -} from './styled' import RevisionModalNavigator from './RevisionModalNavigator' -import { compareDateString } from '../../../../../../lib/date' -import { trackEvent } from '../../../../../../api/track' -import { MixpanelActionTrackTypes } from '../../../../../../interfaces/analytics/mixpanel' -import { useModal } from '../../../../../../../shared/lib/stores/modal' -import Button from '../../../../../../../shared/components/atoms/Button' -import useApi from '../../../../../../../shared/lib/hooks/useApi' +import { compareDateString } from '../../../../../lib/date' +import { trackEvent } from '../../../../../api/track' +import { MixpanelActionTrackTypes } from '../../../../../interfaces/analytics/mixpanel' +import { useModal } from '../../../../../../design/lib/stores/modal' +import Button from '../../../../../../design/components/atoms/Button' +import useApi from '../../../../../../design/lib/hooks/useApi' +import Icon from '../../../../../../design/components/atoms/Icon' +import styled from '../../../../../../design/lib/styled' +import DoublePane from '../../../../../../design/components/atoms/DoublePane' interface RevisionsModalProps { currentDoc: SerializedDocWithBookmark @@ -168,12 +164,8 @@ const RevisionsModal = ({ const rightSideContent = useMemo(() => { if (subscription == null && currentUserPermissions != null) { return ( - - +
+

Let's upgrade to the Pro plan now and protect your shared documents with a password. @@ -188,11 +180,11 @@ const RevisionsModal = ({ > Start Free Trial - +

) } - return {preview} + return preview }, [ currentUserPermissions, subscription, @@ -218,8 +210,17 @@ const RevisionsModal = ({ }, [orderedRevisions, menuRef]) return ( - - + + + {rightSideContent} +
+ } + > -
- {rightSideContent} -
- - + + ) } +const RevisionModalContainer = styled.div` + height: 80vh; + + .revision__modal__panes, + .right { + height: 100%; + } + + .content--unsubscribed { + display: flex; + flex-direction: column; + text-align: center; + width: 80%; + margin: auto; + height: 100%; + justify-content: center; + align-items: center; + + p { + text-align: center; + } + + svg { + color: ${({ theme }) => theme.colors.icon.default}; + } + } +` + export default RevisionsModal diff --git a/src/cloud/components/organisms/Modal/contents/FeedbackModal.tsx b/src/cloud/components/Modal/contents/FeedbackModal.tsx similarity index 64% rename from src/cloud/components/organisms/Modal/contents/FeedbackModal.tsx rename to src/cloud/components/Modal/contents/FeedbackModal.tsx index 45d8da226f..36c718951d 100644 --- a/src/cloud/components/organisms/Modal/contents/FeedbackModal.tsx +++ b/src/cloud/components/Modal/contents/FeedbackModal.tsx @@ -1,5 +1,5 @@ import React from 'react' -import AppFeedbackForm from '../../../molecules/AppFeedbackForm' +import AppFeedbackForm from '../../AppFeedbackForm' const FeedbackModal = () => { return diff --git a/src/cloud/components/organisms/Modal/contents/Forms/MoveItemModal.tsx b/src/cloud/components/Modal/contents/Forms/MoveItemModal.tsx similarity index 79% rename from src/cloud/components/organisms/Modal/contents/Forms/MoveItemModal.tsx rename to src/cloud/components/Modal/contents/Forms/MoveItemModal.tsx index cdadfa5f9a..f43c8c7dec 100644 --- a/src/cloud/components/organisms/Modal/contents/Forms/MoveItemModal.tsx +++ b/src/cloud/components/Modal/contents/Forms/MoveItemModal.tsx @@ -1,15 +1,14 @@ import React, { useState, useCallback, useMemo } from 'react' -import { ModalContainer } from '../styled' -import styled from '../../../../../lib/styled' -import Flexbox from '../../../../atoms/Flexbox' -import WorkspaceExplorer from '../../../../molecules/WorkspaceExplorer' -import { useNav } from '../../../../../lib/stores/nav' -import { SerializedWorkspace } from '../../../../../interfaces/db/workspace' -import { sortByAttributeAsc } from '../../../../../lib/utils/array' -import { useModal } from '../../../../../../shared/lib/stores/modal' -import Button from '../../../../../../shared/components/atoms/Button' -import { useI18n } from '../../../../../lib/hooks/useI18n' -import { lngKeys } from '../../../../../lib/i18n/types' +import WorkspaceExplorer from '../../../WorkspaceExplorer' +import { useNav } from '../../../../lib/stores/nav' +import { SerializedWorkspace } from '../../../../interfaces/db/workspace' +import { sortByAttributeAsc } from '../../../../lib/utils/array' +import { useModal } from '../../../../../design/lib/stores/modal' +import Button from '../../../../../design/components/atoms/Button' +import { useI18n } from '../../../../lib/hooks/useI18n' +import { lngKeys } from '../../../../lib/i18n/types' +import styled from '../../../../../design/lib/styled' +import Flexbox from '../../../../../design/components/atoms/Flexbox' interface MoveItemModalProps { onSubmit: (workspaceId: string, parentFolderId?: string) => void @@ -68,7 +67,7 @@ const MoveItemModal = ({ onSubmit }: MoveItemModalProps) => { ) return ( - +
{ - +
) } @@ -117,5 +116,5 @@ const StyledModalForm = styled.form` margin: 2px 0; border-top: 1px solid transparent; border-bottom: 1px solid transparent; - margin-bottom: ${({ theme }) => theme.space.small}px; + margin-bottom: ${({ theme }) => theme.sizes.spaces.sm}px; ` diff --git a/src/cloud/components/organisms/Modal/contents/SmartFolder/CreateSmartFolderModal.tsx b/src/cloud/components/Modal/contents/SmartFolder/CreateSmartFolderModal.tsx similarity index 77% rename from src/cloud/components/organisms/Modal/contents/SmartFolder/CreateSmartFolderModal.tsx rename to src/cloud/components/Modal/contents/SmartFolder/CreateSmartFolderModal.tsx index 4799e2c122..2936c0ecb3 100644 --- a/src/cloud/components/organisms/Modal/contents/SmartFolder/CreateSmartFolderModal.tsx +++ b/src/cloud/components/Modal/contents/SmartFolder/CreateSmartFolderModal.tsx @@ -1,14 +1,14 @@ import React, { useState, useCallback } from 'react' -import { useModal } from '../../../../../../shared/lib/stores/modal' +import { useModal } from '../../../../../design/lib/stores/modal' import { createSmartFolder, CreateSmartFolderRequestBody, -} from '../../../../../api/teams/smart-folder' -import { usePage } from '../../../../../lib/stores/pageStore' -import { useNav } from '../../../../../lib/stores/nav' -import { useToast } from '../../../../../../shared/lib/stores/toast' -import { getSmartFolderHref } from '../../../../../lib/href' -import { useRouter } from '../../../../../lib/router' +} from '../../../../api/teams/smart-folder' +import { usePage } from '../../../../lib/stores/pageStore' +import { useNav } from '../../../../lib/stores/nav' +import { useToast } from '../../../../../design/lib/stores/toast' +import { getSmartFolderHref } from '../../../../lib/href' +import { useRouter } from '../../../../lib/router' import SmartFolderForm from './SmartFolderForm' const CreateSmartFolderModal = () => { diff --git a/src/cloud/components/organisms/Modal/contents/SmartFolder/DateConditionValueTypeSelect.tsx b/src/cloud/components/Modal/contents/SmartFolder/DateConditionValueTypeSelect.tsx similarity index 93% rename from src/cloud/components/organisms/Modal/contents/SmartFolder/DateConditionValueTypeSelect.tsx rename to src/cloud/components/Modal/contents/SmartFolder/DateConditionValueTypeSelect.tsx index 23bd291073..9a7cc21d07 100644 --- a/src/cloud/components/organisms/Modal/contents/SmartFolder/DateConditionValueTypeSelect.tsx +++ b/src/cloud/components/Modal/contents/SmartFolder/DateConditionValueTypeSelect.tsx @@ -1,6 +1,6 @@ import React from 'react' -import { DateConditionValueType } from '../../../../../interfaces/db/smartFolder' -import FormSelect from '../../../../../../shared/components/molecules/Form/atoms/FormSelect' +import { DateConditionValueType } from '../../../../interfaces/db/smartFolder' +import FormSelect from '../../../../../design/components/molecules/Form/atoms/FormSelect' import { EditibleDateConditionValue } from './interfaces' interface DateValueTypeSelectProps { diff --git a/src/cloud/components/organisms/Modal/contents/SmartFolder/DocAssigneeSelect.tsx b/src/cloud/components/Modal/contents/SmartFolder/DocAssigneeSelect.tsx similarity index 87% rename from src/cloud/components/organisms/Modal/contents/SmartFolder/DocAssigneeSelect.tsx rename to src/cloud/components/Modal/contents/SmartFolder/DocAssigneeSelect.tsx index 32ceeedbc4..d23539cd8b 100644 --- a/src/cloud/components/organisms/Modal/contents/SmartFolder/DocAssigneeSelect.tsx +++ b/src/cloud/components/Modal/contents/SmartFolder/DocAssigneeSelect.tsx @@ -1,11 +1,11 @@ import React, { useMemo, useCallback } from 'react' -import { usePage } from '../../../../../lib/stores/pageStore' -import { SerializedUser } from '../../../../../interfaces/db/user' +import { usePage } from '../../../../lib/stores/pageStore' +import { SerializedUser } from '../../../../interfaces/db/user' import FormSelect, { FormSelectOption, -} from '../../../../../../shared/components/molecules/Form/atoms/FormSelect' -import styled from '../../../../../../shared/lib/styled' -import UserIcon from '../../../../atoms/UserIcon' +} from '../../../../../design/components/molecules/Form/atoms/FormSelect' +import styled from '../../../../../design/lib/styled' +import UserIcon from '../../../UserIcon' interface DocAssigneeSelectProps { value: string[] diff --git a/src/cloud/components/organisms/Modal/contents/SmartFolder/DocDateSelect.tsx b/src/cloud/components/Modal/contents/SmartFolder/DocDateSelect.tsx similarity index 96% rename from src/cloud/components/organisms/Modal/contents/SmartFolder/DocDateSelect.tsx rename to src/cloud/components/Modal/contents/SmartFolder/DocDateSelect.tsx index 0bd4343fd1..d772eb9202 100644 --- a/src/cloud/components/organisms/Modal/contents/SmartFolder/DocDateSelect.tsx +++ b/src/cloud/components/Modal/contents/SmartFolder/DocDateSelect.tsx @@ -1,11 +1,11 @@ import React, { forwardRef, useMemo } from 'react' -import { DateConditionValue } from '../../../../../interfaces/db/smartFolder' +import { DateConditionValue } from '../../../../interfaces/db/smartFolder' import DateConditionValueTypeSelect from './DateConditionValueTypeSelect' import DatePicker from 'react-datepicker' import { format as formatDate } from 'date-fns' import { mdiCalendar, mdiCalendarStart, mdiCalendarEnd } from '@mdi/js' -import Icon from '../../../../../../shared/components/atoms/Icon' -import styled from '../../../../../../shared/lib/styled' +import Icon from '../../../../../design/components/atoms/Icon' +import styled from '../../../../../design/lib/styled' import { EditibleDateConditionValue, EditibleBetweenDateConditionValue, diff --git a/src/cloud/components/organisms/Modal/contents/SmartFolder/DocLabelSelect.tsx b/src/cloud/components/Modal/contents/SmartFolder/DocLabelSelect.tsx similarity index 85% rename from src/cloud/components/organisms/Modal/contents/SmartFolder/DocLabelSelect.tsx rename to src/cloud/components/Modal/contents/SmartFolder/DocLabelSelect.tsx index 7b125bdaf4..8ddee693d9 100644 --- a/src/cloud/components/organisms/Modal/contents/SmartFolder/DocLabelSelect.tsx +++ b/src/cloud/components/Modal/contents/SmartFolder/DocLabelSelect.tsx @@ -1,9 +1,9 @@ import React, { useMemo, useCallback } from 'react' -import { useNav } from '../../../../../lib/stores/nav' -import { SerializedTag } from '../../../../../interfaces/db/tag' +import { useNav } from '../../../../lib/stores/nav' +import { SerializedTag } from '../../../../interfaces/db/tag' import FormSelect, { FormSelectOption, -} from '../../../../../../shared/components/molecules/Form/atoms/FormSelect' +} from '../../../../../design/components/molecules/Form/atoms/FormSelect' interface DocLabelSelect { value: string[] diff --git a/src/cloud/components/organisms/Modal/contents/SmartFolder/DocStatusSelect.tsx b/src/cloud/components/Modal/contents/SmartFolder/DocStatusSelect.tsx similarity index 88% rename from src/cloud/components/organisms/Modal/contents/SmartFolder/DocStatusSelect.tsx rename to src/cloud/components/Modal/contents/SmartFolder/DocStatusSelect.tsx index 0920783cdf..44e8a29df0 100644 --- a/src/cloud/components/organisms/Modal/contents/SmartFolder/DocStatusSelect.tsx +++ b/src/cloud/components/Modal/contents/SmartFolder/DocStatusSelect.tsx @@ -1,16 +1,16 @@ import React from 'react' -import { DocStatus } from '../../../../../interfaces/db/doc' +import { DocStatus } from '../../../../interfaces/db/doc' import FormSelect, { FormSelectOption, -} from '../../../../../../shared/components/molecules/Form/atoms/FormSelect' -import Icon from '../../../../../../shared/components/atoms/Icon' +} from '../../../../../design/components/molecules/Form/atoms/FormSelect' +import Icon from '../../../../../design/components/atoms/Icon' import { mdiPlayCircleOutline, mdiPauseCircleOutline, mdiCheckCircleOutline, mdiArchiveOutline, } from '@mdi/js' -import styled from '../../../../../../shared/lib/styled' +import styled from '../../../../../design/lib/styled' interface DocStatusSelectProps { value: DocStatus | null diff --git a/src/cloud/components/organisms/Modal/contents/SmartFolder/SecondaryConditionItem.tsx b/src/cloud/components/Modal/contents/SmartFolder/SecondaryConditionItem.tsx similarity index 90% rename from src/cloud/components/organisms/Modal/contents/SmartFolder/SecondaryConditionItem.tsx rename to src/cloud/components/Modal/contents/SmartFolder/SecondaryConditionItem.tsx index 885df0157e..f4c5205f78 100644 --- a/src/cloud/components/organisms/Modal/contents/SmartFolder/SecondaryConditionItem.tsx +++ b/src/cloud/components/Modal/contents/SmartFolder/SecondaryConditionItem.tsx @@ -4,7 +4,7 @@ import { StatusCondition, LabelsCondition, AssigneesCondition, -} from '../../../../../interfaces/db/smartFolder' +} from '../../../../interfaces/db/smartFolder' import { EditibleSecondaryCondition, EditibleDueDateCondition, @@ -13,12 +13,12 @@ import { EditibleSecondaryConditionType, } from './interfaces' import SecondaryConditionValueControl from './SecondaryConditionValueControl' -import Button from '../../../../../../shared/components/atoms/Button' -import FormRow from '../../../../../../shared/components/molecules/Form/templates/FormRow' -import FormRowItem from '../../../../../../shared/components/molecules/Form/templates/FormRowItem' +import Button from '../../../../../design/components/atoms/Button' +import FormRow from '../../../../../design/components/molecules/Form/templates/FormRow' +import FormRowItem from '../../../../../design/components/molecules/Form/templates/FormRowItem' import { TFunction } from 'i18next' -import { useI18n } from '../../../../../lib/hooks/useI18n' -import { lngKeys } from '../../../../../lib/i18n/types' +import { useI18n } from '../../../../lib/hooks/useI18n' +import { lngKeys } from '../../../../lib/i18n/types' interface SecondaryConditionItemProps { condition: EditibleSecondaryCondition diff --git a/src/cloud/components/organisms/Modal/contents/SmartFolder/SecondaryConditionValueControl.tsx b/src/cloud/components/Modal/contents/SmartFolder/SecondaryConditionValueControl.tsx similarity index 93% rename from src/cloud/components/organisms/Modal/contents/SmartFolder/SecondaryConditionValueControl.tsx rename to src/cloud/components/Modal/contents/SmartFolder/SecondaryConditionValueControl.tsx index c673936e18..8053965c89 100644 --- a/src/cloud/components/organisms/Modal/contents/SmartFolder/SecondaryConditionValueControl.tsx +++ b/src/cloud/components/Modal/contents/SmartFolder/SecondaryConditionValueControl.tsx @@ -4,11 +4,11 @@ import { EditibleDateConditionValue, } from './interfaces' import DocStatusSelect from './DocStatusSelect' -import { DocStatus } from '../../../../../interfaces/db/doc' +import { DocStatus } from '../../../../interfaces/db/doc' import DocLabelSelect from './DocLabelSelect' import DocAssigneeSelect from './DocAssigneeSelect' import DocDateSelect from './DocDateSelect' -import FormRowItem from '../../../../../../shared/components/molecules/Form/templates/FormRowItem' +import FormRowItem from '../../../../../design/components/molecules/Form/templates/FormRowItem' interface SecondaryConditionValueControlProps { condition: EditibleSecondaryCondition diff --git a/src/cloud/components/organisms/Modal/contents/SmartFolder/SmartFolderForm.tsx b/src/cloud/components/Modal/contents/SmartFolder/SmartFolderForm.tsx similarity index 88% rename from src/cloud/components/organisms/Modal/contents/SmartFolder/SmartFolderForm.tsx rename to src/cloud/components/Modal/contents/SmartFolder/SmartFolderForm.tsx index ab83eee049..be23cf0f5d 100644 --- a/src/cloud/components/organisms/Modal/contents/SmartFolder/SmartFolderForm.tsx +++ b/src/cloud/components/Modal/contents/SmartFolder/SmartFolderForm.tsx @@ -1,23 +1,23 @@ import { mdiPlus } from '@mdi/js' import { TFunction } from 'i18next' import React, { useCallback, useState } from 'react' +import BorderSeparator from '../../../../../design/components/atoms/BorderSeparator' import Button, { LoadingButton, -} from '../../../../../../shared/components/atoms/Button' -import ButtonGroup from '../../../../../../shared/components/atoms/ButtonGroup' -import Switch from '../../../../../../shared/components/atoms/Switch' -import Form from '../../../../../../shared/components/molecules/Form' -import { FormSelectOption } from '../../../../../../shared/components/molecules/Form/atoms/FormSelect' -import FormRow from '../../../../../../shared/components/molecules/Form/templates/FormRow' -import FormRowItem from '../../../../../../shared/components/molecules/Form/templates/FormRowItem' -import styled from '../../../../../../shared/lib/styled' +} from '../../../../../design/components/atoms/Button' +import ButtonGroup from '../../../../../design/components/atoms/ButtonGroup' +import Switch from '../../../../../design/components/atoms/Switch' +import Form from '../../../../../design/components/molecules/Form' +import { FormSelectOption } from '../../../../../design/components/molecules/Form/atoms/FormSelect' +import FormRow from '../../../../../design/components/molecules/Form/templates/FormRow' +import FormRowItem from '../../../../../design/components/molecules/Form/templates/FormRowItem' +import styled from '../../../../../design/lib/styled' import { UpdateSmartFolderRequestBody, CreateSmartFolderRequestBody, -} from '../../../../../api/teams/smart-folder' -import { useI18n } from '../../../../../lib/hooks/useI18n' -import { lngKeys } from '../../../../../lib/i18n/types' -import { StyledModalSeparator } from '../Forms/styled' +} from '../../../../api/teams/smart-folder' +import { useI18n } from '../../../../lib/hooks/useI18n' +import { lngKeys } from '../../../../lib/i18n/types' import { EditibleSecondaryCondition } from './interfaces' import SecondaryConditionItem from './SecondaryConditionItem' @@ -120,7 +120,7 @@ const SmartFolderForm = ({ }], + items: [{ type: 'node', element: }], }} /> @@ -189,7 +189,7 @@ const SmartFolderForm = ({ }], + items: [{ type: 'node', element: }], }} /> diff --git a/src/cloud/components/organisms/Modal/contents/SmartFolder/UpdateSmartFolderModal.tsx b/src/cloud/components/Modal/contents/SmartFolder/UpdateSmartFolderModal.tsx similarity index 86% rename from src/cloud/components/organisms/Modal/contents/SmartFolder/UpdateSmartFolderModal.tsx rename to src/cloud/components/Modal/contents/SmartFolder/UpdateSmartFolderModal.tsx index 0b405f89cd..7a07f03db5 100644 --- a/src/cloud/components/organisms/Modal/contents/SmartFolder/UpdateSmartFolderModal.tsx +++ b/src/cloud/components/Modal/contents/SmartFolder/UpdateSmartFolderModal.tsx @@ -1,15 +1,15 @@ import React, { useState, useCallback } from 'react' -import { useModal } from '../../../../../../shared/lib/stores/modal' +import { useModal } from '../../../../../design/lib/stores/modal' import { updateSmartFolder, UpdateSmartFolderRequestBody, -} from '../../../../../api/teams/smart-folder' -import { usePage } from '../../../../../lib/stores/pageStore' -import { useNav } from '../../../../../lib/stores/nav' -import { useToast } from '../../../../../../shared/lib/stores/toast' -import { getSmartFolderHref } from '../../../../../lib/href' -import { useRouter } from '../../../../../lib/router' -import { SerializedSmartFolder } from '../../../../../interfaces/db/smartFolder' +} from '../../../../api/teams/smart-folder' +import { usePage } from '../../../../lib/stores/pageStore' +import { useNav } from '../../../../lib/stores/nav' +import { useToast } from '../../../../../design/lib/stores/toast' +import { getSmartFolderHref } from '../../../../lib/href' +import { useRouter } from '../../../../lib/router' +import { SerializedSmartFolder } from '../../../../interfaces/db/smartFolder' import SmartFolderForm from './SmartFolderForm' interface UpdateSmartFolderModalProps { diff --git a/src/cloud/components/organisms/Modal/contents/SmartFolder/interfaces.ts b/src/cloud/components/Modal/contents/SmartFolder/interfaces.ts similarity index 96% rename from src/cloud/components/organisms/Modal/contents/SmartFolder/interfaces.ts rename to src/cloud/components/Modal/contents/SmartFolder/interfaces.ts index 373e3b51b3..5201730f84 100644 --- a/src/cloud/components/organisms/Modal/contents/SmartFolder/interfaces.ts +++ b/src/cloud/components/Modal/contents/SmartFolder/interfaces.ts @@ -5,7 +5,7 @@ import { TodayDateConditionValue, InWeekDateConditionValue, InMonthDateConditionValue, -} from '../../../../../interfaces/db/smartFolder' +} from '../../../../interfaces/db/smartFolder' export type EditibleBetweenDateConditionValue = { type: 'between' diff --git a/src/cloud/components/organisms/Modal/contents/TemplatesModal/index.tsx b/src/cloud/components/Modal/contents/TemplatesModal/index.tsx similarity index 52% rename from src/cloud/components/organisms/Modal/contents/TemplatesModal/index.tsx rename to src/cloud/components/Modal/contents/TemplatesModal/index.tsx index 699e7e825a..d7aa60bd6c 100644 --- a/src/cloud/components/organisms/Modal/contents/TemplatesModal/index.tsx +++ b/src/cloud/components/Modal/contents/TemplatesModal/index.tsx @@ -1,56 +1,56 @@ import React, { useState, useMemo, useCallback, useEffect, useRef } from 'react' -import { ModalContainer } from '../styled' -import { useNav } from '../../../../../lib/stores/nav' -import { usePage } from '../../../../../lib/stores/pageStore' +import { useNav } from '../../../../lib/stores/nav' +import { usePage } from '../../../../lib/stores/pageStore' import { isFocusLeftSideShortcut, isFocusRightSideShortcut, -} from '../../../../../lib/shortcuts' +} from '../../../../lib/shortcuts' import { preventKeyboardEventPropagation, useCapturingGlobalKeyDownHandler, - useUpDownNavigationListener, -} from '../../../../../lib/keyboard' -import { focusFirstChildFromElement } from '../../../../../lib/dom' -import { capitalize, getHexFromUUID } from '../../../../../lib/utils/string' -import { trackEvent } from '../../../../../api/track' -import { MixpanelActionTrackTypes } from '../../../../../interfaces/analytics/mixpanel' -import { SerializedTemplate } from '../../../../../interfaces/db/template' -import Flexbox from '../../../../atoms/Flexbox' -import ClickableListItem from '../../../../molecules/ClickableListItem' -import EditableInput from '../../../../atoms/EditableInput' +} from '../../../../lib/keyboard' +import { focusFirstChildFromElement } from '../../../../lib/dom' +import { capitalize, getHexFromUUID } from '../../../../lib/utils/string' +import { trackEvent } from '../../../../api/track' +import { MixpanelActionTrackTypes } from '../../../../interfaces/analytics/mixpanel' +import { SerializedTemplate } from '../../../../interfaces/db/template' import { useDialog, DialogIconTypes, -} from '../../../../../../shared/lib/stores/dialog' +} from '../../../../../design/lib/stores/dialog' import { destroyDocTemplate, updateTemplate, -} from '../../../../../api/teams/docs/templates' +} from '../../../../api/teams/docs/templates' import { mdiTrashCanOutline, mdiFileDocumentOutline, mdiClose, mdiContentSaveOutline, } from '@mdi/js' -import Icon from '../../../../atoms/Icon' -import EmojiIcon from '../../../../atoms/EmojiIcon' -import { useSettings } from '../../../../../lib/stores/settings' +import EmojiIcon from '../../../EmojiIcon' +import { useSettings } from '../../../../lib/stores/settings' import cc from 'classcat' -import Tooltip from '../../../../atoms/Tooltip' -import CodeMirrorEditor from '../../../../../lib/editor/components/CodeMirrorEditor' -import MarkdownView from '../../../../atoms/MarkdownView' -import { useToast } from '../../../../../../shared/lib/stores/toast' -import { useModal } from '../../../../../../shared/lib/stores/modal' -import Switch from '../../../../../../shared/components/atoms/Switch' -import { useEmoji } from '../../../../../../shared/lib/stores/emoji' -import { useI18n } from '../../../../../lib/hooks/useI18n' -import { lngKeys } from '../../../../../lib/i18n/types' +import CodeMirrorEditor from '../../../../lib/editor/components/CodeMirrorEditor' +import MarkdownView from '../../../MarkdownView' +import { useToast } from '../../../../../design/lib/stores/toast' +import { useModal } from '../../../../../design/lib/stores/modal' +import Switch from '../../../../../design/components/atoms/Switch' +import { useEmoji } from '../../../../../design/lib/stores/emoji' +import { useI18n } from '../../../../lib/hooks/useI18n' +import { lngKeys } from '../../../../lib/i18n/types' import Button, { LoadingButton, -} from '../../../../../../shared/components/atoms/Button' -import FormInput from '../../../../../../shared/components/molecules/Form/atoms/FormInput' -import styled from '../../../../../../shared/lib/styled' +} from '../../../../../design/components/atoms/Button' +import FormInput from '../../../../../design/components/molecules/Form/atoms/FormInput' +import styled from '../../../../../design/lib/styled' +import WithTooltip from '../../../../../design/components/atoms/WithTooltip' +import Flexbox from '../../../../../design/components/atoms/Flexbox' +import NavigationItem from '../../../../../design/components/molecules/Navigation/NavigationItem' +import UpDownList from '../../../../../design/components/atoms/UpDownList' +import DoublePane from '../../../../../design/components/atoms/DoublePane' +import plur from 'plur' +import EditableInput from '../../../../../design/components/atoms/EditableInput' interface TemplatesModalProps { callback?: (template: SerializedTemplate) => void @@ -161,7 +161,6 @@ const TemplatesModal = ({ callback }: TemplatesModalProps) => { } }, [menuRef, contentSideRef]) useCapturingGlobalKeyDownHandler(keydownHandler) - useUpDownNavigationListener(menuRef, { inactive: closed }) const filteredTemplates = useMemo(() => { const templates = [...templatesMap.values()] @@ -305,206 +304,227 @@ const TemplatesModal = ({ callback }: TemplatesModalProps) => { selectedTemplate.emoji !== emoji) if (team == null) { - return You need to select a valid team. + return
You need to select a valid team.
} return ( - - -
-
{capitalize(translate(lngKeys.GeneralTemplates))}
- - {filteredTemplates.length > 0 ? ( - filteredTemplates.map((template) => ( - - + + {selectedTemplate == null ? ( + +
+ +
-
- {selectedTemplate == null ? ( - -
- -
-
-
-

{translate(lngKeys.ModalsTemplatesSelectTemplate)}

-
-
- ) : ( - -
- - - +
+

{translate(lngKeys.ModalsTemplatesSelectTemplate)}

+
+
+
+ ) : ( + +
+ + + + + - - - - - {' '} - deleteTemplate(selectedTemplate)} - /> -
- {changesAreUnsaved ? ( + + + {' '} - - - - {translate(lngKeys.GeneralSaveVerb)} + onClick={() => deleteTemplate(selectedTemplate)} + /> +
+ {changesAreUnsaved ? ( + + {translate(lngKeys.GeneralSaveVerb)} + + ) : callback == null ? ( + + {translate(lngKeys.GeneralUse)} + + ) : ( + + )} + variant='icon' + iconPath={mdiClose} + className='smallButton' + onClick={closeModal} + /> + +
+
+
+ +
+ {!inPreview && ( + )} -
-
-
-
- {!inPreview && ( - - )} + + )} +
+ } + > + +
+
+

{capitalize(translate(lngKeys.GeneralTemplates))}

+
+ {templatesMap.size} {plur('template', templatesMap.size)}
- - )} -
- - + + + {filteredTemplates.length > 0 ? ( + filteredTemplates.map((template) => { + return ( + selectTemplate(template)} + id={`template-${getHexFromUUID(template.id)}`} + className={ + selectedTemplateId === template.id ? 'active' : '' + } + /> + ) + }) + ) : ( + {translate(lngKeys.ModalsTemplatesSearchEmpty)} + )} +
+ + + ) } -const StyledTemplatesModal = styled.div` - display: flex; - width: 100%; - height: 100%; +const TemplatesModalContainer = styled.div` + height: 80vh; + + .two__pane__left > *, + .templates__navigator { + height: 100%; + } + + .templates__navigator__header { + display: block; + text-align: center; + flex: 0 0 auto; + + h2 { + margin: 0; + font-size: ${({ theme }) => theme.sizes.fonts.md}px; + } + + .templates__navigator__description { + font-size: ${({ theme }) => theme.sizes.fonts.sm}px; + color: ${({ theme }) => theme.colors.text.subtle}; + margin-bottom: ${({ theme }) => theme.sizes.spaces.sm}px; + } + } + h5 { margin-top: 0; font-size: ${({ theme }) => theme.sizes.fonts.md}px; } - .list { - width: 250px; - height: 100%; - padding: ${({ theme }) => theme.sizes.spaces.df}px; + .templates__navigator { + width: 200px; + padding-right: ${({ theme }) => theme.sizes.spaces.df}px; border: 0; border-right: 1px solid ${({ theme }) => theme.colors.border.main}; input { margin-bottom: ${({ theme }) => theme.sizes.spaces.sm}px; + width: 100%; } - - .sideNavItemStyle { - padding-left: ${({ theme }) => theme.sizes.spaces.xsm}px; - .emoji-mart-emoji { - display: flex !important; - } - } - - h3 { - margin: 0; - } - } - - .separator { - width: 1px; - height: 30px; - background: ${({ theme }) => theme.colors.border.second}; - margin: 0 ${({ theme }) => theme.sizes.spaces.xsm}px; } .content { diff --git a/src/cloud/components/organisms/Modal/contents/Workspace/WorkspaceAccess.tsx b/src/cloud/components/Modal/contents/Workspace/WorkspaceAccess.tsx similarity index 80% rename from src/cloud/components/organisms/Modal/contents/Workspace/WorkspaceAccess.tsx rename to src/cloud/components/Modal/contents/Workspace/WorkspaceAccess.tsx index bdfdd08dde..c405d6faa7 100644 --- a/src/cloud/components/organisms/Modal/contents/Workspace/WorkspaceAccess.tsx +++ b/src/cloud/components/Modal/contents/Workspace/WorkspaceAccess.tsx @@ -1,19 +1,17 @@ import React, { useCallback, useState, useMemo } from 'react' -import { SerializedUser } from '../../../../../interfaces/db/user' -import { SerializedUserTeamPermissions } from '../../../../../interfaces/db/userTeamPermissions' -import styled from '../../../../../lib/styled' -import Flexbox from '../../../../atoms/Flexbox' -import Checkbox from '../../../../atoms/Checkbox' -import IconMdi from '../../../../atoms/IconMdi' +import { SerializedUser } from '../../../../interfaces/db/user' +import { SerializedUserTeamPermissions } from '../../../../interfaces/db/userTeamPermissions' +import Flexbox from '../../../../../design/components/atoms/Flexbox' import { mdiClose } from '@mdi/js' import { useSet } from 'react-use' -import UserIcon from '../../../../atoms/UserIcon' +import UserIcon from '../../../UserIcon' import cc from 'classcat' -import { linkText } from '../../../../../lib/styled/styleFunctions' -import FormRow from '../../../../../../shared/components/molecules/Form/templates/FormRow' -import Button from '../../../../../../shared/components/atoms/Button' -import { useI18n } from '../../../../../lib/hooks/useI18n' -import { lngKeys } from '../../../../../lib/i18n/types' +import FormRow from '../../../../../design/components/molecules/Form/templates/FormRow' +import Button from '../../../../../design/components/atoms/Button' +import { useI18n } from '../../../../lib/hooks/useI18n' +import { lngKeys } from '../../../../lib/i18n/types' +import styled from '../../../../../design/lib/styled' +import { CheckboxWithLabel } from '../../../../../design/components/molecules/Form/atoms/FormCheckbox' interface WorkspaceAccessProps { selectedPermissions: SerializedUserTeamPermissions[] @@ -122,9 +120,9 @@ const WorkspaceAccess = ({ className='workspace__access__row' > {ownerOrUserNode} - +
{selectedPermissions.map((p) => { return ( @@ -138,15 +136,15 @@ const WorkspaceAccess = ({ {p.user.displayName} {currentUserIsOwner && ( - setSelectedPermissions((prev) => prev.filter((permission) => permission.id !== p.id) ) } - > - - + /> )} ) @@ -167,7 +165,7 @@ const WorkspaceAccess = ({ ) : ( - {leftoverPermissions.length !== 0 && leftoverPermissions.map((p) => ( - toggle(p.id)} + toggle={() => toggle(p.id)} label={ theme.space.xsmall}px; + margin-bottom: ${({ theme }) => theme.sizes.spaces.xsm}px; ` const StyledSelector = styled.div` display: flex; flex-direction: column; width: 100%; - border: 1px solid ${({ theme }) => theme.subtleBackgroundColor}; - padding: ${({ theme }) => theme.space.xsmall}px - ${({ theme }) => theme.space.small}px; + border: 1px solid ${({ theme }) => theme.colors.border.second}; + padding: ${({ theme }) => theme.sizes.spaces.xsm}px + ${({ theme }) => theme.sizes.spaces.sm}px; border-radius: 2px; ` -const StyledRemoveAccessButton = styled.button` - background: none; - border: 0; - outline: none; - margin-top: 0 !important; - color: inherit; - svg { - font-size: ${({ theme }) => theme.fontSizes.default}px; - ${linkText} - } -` - export default WorkspaceAccess diff --git a/src/cloud/components/organisms/Modal/contents/Workspace/WorkspaceModalForm.tsx b/src/cloud/components/Modal/contents/Workspace/WorkspaceModalForm.tsx similarity index 80% rename from src/cloud/components/organisms/Modal/contents/Workspace/WorkspaceModalForm.tsx rename to src/cloud/components/Modal/contents/Workspace/WorkspaceModalForm.tsx index 102ab1d346..ca54f08cb9 100644 --- a/src/cloud/components/organisms/Modal/contents/Workspace/WorkspaceModalForm.tsx +++ b/src/cloud/components/Modal/contents/Workspace/WorkspaceModalForm.tsx @@ -1,28 +1,29 @@ import React, { useState, useCallback, useMemo, useRef } from 'react' -import { usePage } from '../../../../../lib/stores/pageStore' -import ErrorBlock from '../../../../atoms/ErrorBlock' -import { SerializedWorkspace } from '../../../../../interfaces/db/workspace' -import { useGlobalData } from '../../../../../lib/stores/globalData' -import { SerializedUserTeamPermissions } from '../../../../../interfaces/db/userTeamPermissions' +import { usePage } from '../../../../lib/stores/pageStore' +import ErrorBlock from '../../../ErrorBlock' +import { SerializedWorkspace } from '../../../../interfaces/db/workspace' +import { useGlobalData } from '../../../../lib/stores/globalData' +import { SerializedUserTeamPermissions } from '../../../../interfaces/db/userTeamPermissions' import { CreateWorkspaceRequestBody, createWorkspace, UpdateWorkspaceRequestBody, updateWorkspace, -} from '../../../../../api/teams/workspaces' -import { SerializedTeam } from '../../../../../interfaces/db/team' -import { useNav } from '../../../../../lib/stores/nav' +} from '../../../../api/teams/workspaces' +import { SerializedTeam } from '../../../../interfaces/db/team' +import { useNav } from '../../../../lib/stores/nav' import WorkspaceAccess from './WorkspaceAccess' -import { useToast } from '../../../../../../shared/lib/stores/toast' -import { useModal } from '../../../../../../shared/lib/stores/modal' +import { useToast } from '../../../../../design/lib/stores/toast' +import { useModal } from '../../../../../design/lib/stores/modal' import Button, { LoadingButton, -} from '../../../../../../shared/components/atoms/Button' -import Form from '../../../../../../shared/components/molecules/Form' -import { useI18n } from '../../../../../lib/hooks/useI18n' -import { lngKeys } from '../../../../../lib/i18n/types' -import FormRow from '../../../../../../shared/components/molecules/Form/templates/FormRow' +} from '../../../../../design/components/atoms/Button' +import Form from '../../../../../design/components/molecules/Form' +import { useI18n } from '../../../../lib/hooks/useI18n' +import { lngKeys } from '../../../../lib/i18n/types' +import FormRow from '../../../../../design/components/molecules/Form/templates/FormRow' import { useEffectOnce } from 'react-use' +import ButtonGroup from '../../../../../design/components/atoms/ButtonGroup' interface WorkspaceModalFormProps { workspace?: SerializedWorkspace @@ -255,13 +256,13 @@ const WorkspaceModalForm = ({ workspace }: WorkspaceModalFormProps) => { )} {!isOwner && ( -
+ {translate(lngKeys.ModalsWorkspacesNonOwnerDisclaimer)} -
+ )} {!isPublic && ( -
+ { setSelectedPermissions={setSelectedPermissions} currentUser={currentUser} /> -
+ )} {error != null && ( -
+ -
+ )} -
- - - {workspace != null - ? translate(lngKeys.GeneralUpdateVerb) - : translate(lngKeys.GeneralCreate)} - -
+ + + + + {workspace != null + ? translate(lngKeys.GeneralUpdateVerb) + : translate(lngKeys.GeneralCreate)} + + + ) } diff --git a/src/cloud/components/organisms/Onboarding/molecules/BulkInvitesForm.tsx b/src/cloud/components/Onboarding/BulkInvitesForm.tsx similarity index 86% rename from src/cloud/components/organisms/Onboarding/molecules/BulkInvitesForm.tsx rename to src/cloud/components/Onboarding/BulkInvitesForm.tsx index 9dbd3a977e..24b05cea18 100644 --- a/src/cloud/components/organisms/Onboarding/molecules/BulkInvitesForm.tsx +++ b/src/cloud/components/Onboarding/BulkInvitesForm.tsx @@ -1,17 +1,15 @@ import React, { useCallback, useState } from 'react' -import styled from '../../../../../shared/lib/styled' -import { AppComponent } from '../../../../../shared/lib/types' +import styled from '../../../design/lib/styled' +import { AppComponent } from '../../../design/lib/types' import cc from 'classcat' -import Form from '../../../../../shared/components/molecules/Form' -import FormRow from '../../../../../shared/components/molecules/Form/templates/FormRow' -import FormRowItem from '../../../../../shared/components/molecules/Form/templates/FormRowItem' +import Form from '../../../design/components/molecules/Form' +import FormRow from '../../../design/components/molecules/Form/templates/FormRow' +import FormRowItem from '../../../design/components/molecules/Form/templates/FormRowItem' import copy from 'copy-to-clipboard' -import Button, { - LoadingButton, -} from '../../../../../shared/components/atoms/Button' -import { isEmailValid } from '../../../../lib/utils/string' -import { useToast } from '../../../../../shared/lib/stores/toast' -import { createTeamInvitesInBulk } from '../../../../api/teams/invites' +import Button, { LoadingButton } from '../../../design/components/atoms/Button' +import { isEmailValid } from '../../lib/utils/string' +import { useToast } from '../../../design/lib/stores/toast' +import { createTeamInvitesInBulk } from '../../api/teams/invites' interface BulkInvitesFormProps { openInviteLink: string diff --git a/src/cloud/components/organisms/Onboarding/molecules/CreateTeamForm.tsx b/src/cloud/components/Onboarding/CreateTeamForm.tsx similarity index 83% rename from src/cloud/components/organisms/Onboarding/molecules/CreateTeamForm.tsx rename to src/cloud/components/Onboarding/CreateTeamForm.tsx index 5e293d91e2..e6608912bb 100644 --- a/src/cloud/components/organisms/Onboarding/molecules/CreateTeamForm.tsx +++ b/src/cloud/components/Onboarding/CreateTeamForm.tsx @@ -1,21 +1,19 @@ import React, { useMemo, FormEvent } from 'react' import slugify from 'slugify' import cc from 'classcat' -import IconMdi from '../../../atoms/IconMdi' import { mdiChevronRight, mdiDomain } from '@mdi/js' -import { boostHubBaseUrl } from '../../../../lib/consts' -import Form from '../../../../../shared/components/molecules/Form' -import FormRow from '../../../../../shared/components/molecules/Form/templates/FormRow' -import FormRowItem from '../../../../../shared/components/molecules/Form/templates/FormRowItem' -import Button, { - LoadingButton, -} from '../../../../../shared/components/atoms/Button' -import ButtonGroup from '../../../../../shared/components/atoms/ButtonGroup' -import FormImage from '../../../../../shared/components/molecules/Form/atoms/FormImage' -import styled from '../../../../../shared/lib/styled' -import { useI18n } from '../../../../lib/hooks/useI18n' -import { lngKeys } from '../../../../lib/i18n/types' +import { boostHubBaseUrl } from '../../lib/consts' +import Form from '../../../design/components/molecules/Form' +import FormRow from '../../../design/components/molecules/Form/templates/FormRow' +import FormRowItem from '../../../design/components/molecules/Form/templates/FormRowItem' +import Button, { LoadingButton } from '../../../design/components/atoms/Button' +import ButtonGroup from '../../../design/components/atoms/ButtonGroup' +import FormImage from '../../../design/components/molecules/Form/atoms/FormImage' +import styled from '../../../design/lib/styled' +import { useI18n } from '../../lib/hooks/useI18n' +import { lngKeys } from '../../lib/i18n/types' import UsageFormRow, { SpaceUsageIntent } from './UsageFormRow' +import Icon from '../../../design/components/atoms/Icon' interface CreateTeamFormProps { name: string @@ -157,8 +155,7 @@ const CreateTeamForm = ({ type='button' onClick={goBack} > - {' '} - {translate(lngKeys.GeneralBack)} + {translate(lngKeys.GeneralBack)} )} diff --git a/src/cloud/components/Onboarding/FolderPageInviteSection.tsx b/src/cloud/components/Onboarding/FolderPageInviteSection.tsx new file mode 100644 index 0000000000..a285e6ad4a --- /dev/null +++ b/src/cloud/components/Onboarding/FolderPageInviteSection.tsx @@ -0,0 +1,172 @@ +import { mdiClose } from '@mdi/js' +import copy from 'copy-to-clipboard' +import React, { useCallback, useEffect, useState } from 'react' +import Button from '../../../design/components/atoms/Button' +import ColoredBlock from '../../../design/components/atoms/ColoredBlock' +import Flexbox from '../../../design/components/atoms/Flexbox' +import Form from '../../../design/components/molecules/Form' +import { FormSelectOption } from '../../../design/components/molecules/Form/atoms/FormSelect' +import FormRow from '../../../design/components/molecules/Form/templates/FormRow' +import FormRowItem from '../../../design/components/molecules/Form/templates/FormRowItem' +import styled from '../../../design/lib/styled' +import { SerializedOpenInvite } from '../../interfaces/db/openInvite' +import { SerializedTeam } from '../../interfaces/db/team' +import { boostHubBaseUrl } from '../../lib/consts' +import { useI18n } from '../../lib/hooks/useI18n' +import { lngKeys } from '../../lib/i18n/types' +import { + OpenInvitesProvider, + useOpenInvites, +} from '../../lib/stores/openInvites' +import { usePage } from '../../lib/stores/pageStore' +import { useTeamPreferences } from '../../lib/stores/teamPreferences' +import { getOpenInviteURL, getTeamURL } from '../../lib/utils/patterns' + +const InviteSection = ({ team }: { team: SerializedTeam }) => { + const { teamPreferences, toggleItem } = useTeamPreferences() + const { translate, getRoleLabel } = useI18n() + const store = useOpenInvites() + const [selectedInvite, setSelectedInvite] = useState() + const [copyButtonLabel, setCopyButtonLabel] = useState( + translate(lngKeys.GeneralCopyVerb) + ) + + const onButtonClick = useCallback(() => { + if (selectedInvite == null) { + return + } + + copy( + `${boostHubBaseUrl}${getTeamURL(team)}${getOpenInviteURL(selectedInvite)}` + ) + setCopyButtonLabel(`✓ ${translate(lngKeys.GeneralCopied)}`) + setTimeout(() => { + setCopyButtonLabel(translate(lngKeys.GeneralCopyVerb)) + }, 600) + }, [selectedInvite, team, translate]) + + useEffect(() => { + if (store.state === 'loaded' && store.openInvites.length > 0) { + setSelectedInvite(store.openInvites[0]) + } + }, [store]) + + if ( + teamPreferences['hide-onboarding-invite'] || + store.state === 'loading' || + selectedInvite == null + ) { + return null + } + + const inviteLink = `${boostHubBaseUrl}${getTeamURL(team)}${getOpenInviteURL( + selectedInvite + )}` + + return ( + + + +
{translate(lngKeys.OnboardingFolderSectionTitle)}
+ ) } diff --git a/src/cloud/components/molecules/SettingsTeamForm.tsx b/src/cloud/components/SettingsTeamForm.tsx similarity index 87% rename from src/cloud/components/molecules/SettingsTeamForm.tsx rename to src/cloud/components/SettingsTeamForm.tsx index cd7b383483..169e8c321b 100644 --- a/src/cloud/components/molecules/SettingsTeamForm.tsx +++ b/src/cloud/components/SettingsTeamForm.tsx @@ -1,15 +1,15 @@ import { mdiDomain } from '@mdi/js' import React, { useCallback, useState } from 'react' -import { buildIconUrl } from '../../api/files' -import { updateTeam, updateTeamIcon } from '../../api/teams' -import { SerializedTeam } from '../../interfaces/db/team' -import { useElectron } from '../../lib/stores/electron' -import { useGlobalData } from '../../lib/stores/globalData' -import { usePage } from '../../lib/stores/pageStore' -import { useRouter } from '../../lib/router' -import { getTeamURL } from '../../lib/utils/patterns' -import { useToast } from '../../../shared/lib/stores/toast' -import Form from '../../../shared/components/molecules/Form' +import { buildIconUrl } from '../api/files' +import { updateTeam, updateTeamIcon } from '../api/teams' +import { SerializedTeam } from '../interfaces/db/team' +import { useElectron } from '../lib/stores/electron' +import { useGlobalData } from '../lib/stores/globalData' +import { usePage } from '../lib/stores/pageStore' +import { useRouter } from '../lib/router' +import { getTeamURL } from '../lib/utils/patterns' +import { useToast } from '../../design/lib/stores/toast' +import Form from '../../design/components/molecules/Form' import { useTranslation } from 'react-i18next' import { lngKeys } from '../../lib/i18n/types' import { allowedUploadSizeInMb } from '../../lib/upload' diff --git a/src/cloud/components/SharePageTopBar/index.tsx b/src/cloud/components/SharePageTopBar/index.tsx new file mode 100644 index 0000000000..35cb574ed8 --- /dev/null +++ b/src/cloud/components/SharePageTopBar/index.tsx @@ -0,0 +1,54 @@ +import React from 'react' +import styled from '../../../design/lib/styled' + +const SharePageTopbar = ({ children }: React.PropsWithChildren<{}>) => ( + + + + + Boost Note + + + {children} + + +) + +const StyledLogo = styled.div` + margin-right: ${({ theme }) => theme.sizes.spaces.sm}px; + img { + height: 30px; + vertical-align: middle; + } +` + +const StyledTopbar = styled.div` + display: flex; + align-items: center; + justify-content: center; + position: fixed; + top: 0; + z-index: 1; + width: 100%; + height: 40px; + padding: ${({ theme }) => theme.sizes.spaces.xsm}px; + background-color: ${({ theme }) => theme.colors.background.primary}; + border-bottom: 1px solid ${({ theme }) => theme.colors.border.main}; + font-size: ${({ theme }) => theme.sizes.fonts.xsm}px; + + &:not(.alignedLeft) { + right: 0; + } +` + +const StyledTopbarContainer = styled.div` + display: flex; + justify-content: space-between; + width: 100%; + max-width: 75vw; +` + +export default SharePageTopbar diff --git a/src/cloud/components/molecules/SignInForm/EmailForm.tsx b/src/cloud/components/SignInForm/EmailForm.tsx similarity index 87% rename from src/cloud/components/molecules/SignInForm/EmailForm.tsx rename to src/cloud/components/SignInForm/EmailForm.tsx index 61b72cbbf6..c7ddf1cb07 100644 --- a/src/cloud/components/molecules/SignInForm/EmailForm.tsx +++ b/src/cloud/components/SignInForm/EmailForm.tsx @@ -1,11 +1,10 @@ import React, { useState, useCallback, FormEventHandler } from 'react' -import styled from '../../../../shared/lib/styled' -import { Spinner } from '../../atoms/Spinner' +import styled from '../../../design/lib/styled' import { stringify } from 'querystring' import cc from 'classcat' -import { createLoginEmailRequest } from '../../../api/auth/email' -import { boostHubBaseUrl } from '../../../lib/consts' -import Button from '../../../../shared/components/atoms/Button' +import { createLoginEmailRequest } from '../../api/auth/email' +import { boostHubBaseUrl } from '../../lib/consts' +import { LoadingButton } from '../../../design/components/atoms/Button' interface EmailFormProps { query?: any @@ -85,7 +84,7 @@ const EmailForm = ({ placeholder='Paste signin code' onChange={codeChangeHandler} /> - + Continue with signin code + ) } @@ -119,15 +115,16 @@ const EmailForm = ({ placeholder='Email...' onChange={emailChangeHandler} /> - + Continue with email + ) } diff --git a/src/cloud/components/molecules/SignInForm/index.tsx b/src/cloud/components/SignInForm/index.tsx similarity index 88% rename from src/cloud/components/molecules/SignInForm/index.tsx rename to src/cloud/components/SignInForm/index.tsx index a39330dadb..353750f701 100644 --- a/src/cloud/components/molecules/SignInForm/index.tsx +++ b/src/cloud/components/SignInForm/index.tsx @@ -1,10 +1,10 @@ import React, { useState, useMemo } from 'react' -import GoogleLoginButton from '../../atoms/buttons/login/GoogleLoginButton' -import GithubLoginButton from '../../atoms/buttons/login/GithubLoginButton' -import styled from '../../../../shared/lib/styled' -import ErrorBlock from '../../atoms/ErrorBlock' +import GoogleLoginButton from '../Buttons/login/GoogleLoginButton' +import GithubLoginButton from '../Buttons/login/GithubLoginButton' +import styled from '../../../design/lib/styled' +import ErrorBlock from '../ErrorBlock' import EmailForm from './EmailForm' -import { useRouter } from '../../../lib/router' +import { useRouter } from '../../lib/router' interface SignInFormProps { isSignup?: boolean diff --git a/src/cloud/components/organisms/SmartFolderContextMenu.tsx b/src/cloud/components/SmartFolderContextMenu.tsx similarity index 88% rename from src/cloud/components/organisms/SmartFolderContextMenu.tsx rename to src/cloud/components/SmartFolderContextMenu.tsx index 0083655047..021fe67c4c 100644 --- a/src/cloud/components/organisms/SmartFolderContextMenu.tsx +++ b/src/cloud/components/SmartFolderContextMenu.tsx @@ -13,35 +13,35 @@ import { mdiTrashCanOutline, } from '@mdi/js' import React, { useCallback, useMemo, useState } from 'react' -import Flexbox from '../../../shared/components/atoms/Flexbox' -import MetadataContainer from '../../../shared/components/organisms/MetadataContainer' -import MetadataContainerBreak from '../../../shared/components/organisms/MetadataContainer/atoms/MetadataContainerBreak' -import MetadataContainerRow from '../../../shared/components/organisms/MetadataContainer/molecules/MetadataContainerRow' -import { getMapValues } from '../../../shared/lib/utils/array' -import { SerializedSmartFolder } from '../../interfaces/db/smartFolder' -import { SerializedTeam } from '../../interfaces/db/team' -import { SerializedUser } from '../../interfaces/db/user' -import { boostHubBaseUrl } from '../../lib/consts' -import { getFormattedDateTime } from '../../lib/date' -import { useI18n } from '../../lib/hooks/useI18n' -import { getSmartFolderHref } from '../../lib/href' -import { lngKeys } from '../../lib/i18n/types' -import { usePage } from '../../lib/stores/pageStore' -import UserIcon from '../atoms/UserIcon' +import Flexbox from '../../design/components/atoms/Flexbox' +import MetadataContainer from '../../design/components/organisms/MetadataContainer' +import MetadataContainerBreak from '../../design/components/organisms/MetadataContainer/atoms/MetadataContainerBreak' +import MetadataContainerRow from '../../design/components/organisms/MetadataContainer/molecules/MetadataContainerRow' +import { getMapValues } from '../../design/lib/utils/array' +import { SerializedSmartFolder } from '../interfaces/db/smartFolder' +import { SerializedTeam } from '../interfaces/db/team' +import { SerializedUser } from '../interfaces/db/user' +import { boostHubBaseUrl } from '../lib/consts' +import { getFormattedDateTime } from '../lib/date' +import { useI18n } from '../lib/hooks/useI18n' +import { getSmartFolderHref } from '../lib/href' +import { lngKeys } from '../lib/i18n/types' +import { usePage } from '../lib/stores/pageStore' +import UserIcon from './UserIcon' import copy from 'copy-to-clipboard' -import { usingElectron, sendToHost } from '../../lib/stores/electron' +import { usingElectron, sendToHost } from '../lib/stores/electron' import UpdateSmartFolderModal from './Modal/contents/SmartFolder/UpdateSmartFolderModal' -import { useModal } from '../../../shared/lib/stores/modal' -import { useCloudApi } from '../../lib/hooks/useCloudApi' -import { useDialog } from '../../../shared/lib/stores/dialog' +import { useModal } from '../../design/lib/stores/modal' +import { useCloudApi } from '../lib/hooks/useCloudApi' +import { useDialog } from '../../design/lib/stores/dialog' import { format } from 'date-fns' import { capitalize } from 'lodash' import DocAssigneeSelect from './DocProperties/DocAssigneeSelect' import DocStatusSelect from './DocProperties/DocStatusSelect' -import styled from '../../../shared/lib/styled' -import DocTagsListItem from '../atoms/DocTagsListItem' -import { useNav } from '../../lib/stores/nav' -import { SerializedTag } from '../../interfaces/db/tag' +import styled from '../../design/lib/styled' +import DocTagsListItem from './DocTagsListItem' +import { useNav } from '../lib/stores/nav' +import { SerializedTag } from '../interfaces/db/tag' interface SmartFolderContextMenuProps { smartFolder: SerializedSmartFolder diff --git a/src/cloud/components/organisms/Subscription/PlanTables.tsx b/src/cloud/components/Subscription/PlanTables.tsx similarity index 96% rename from src/cloud/components/organisms/Subscription/PlanTables.tsx rename to src/cloud/components/Subscription/PlanTables.tsx index 9b648d55d8..b6e9cb08d6 100644 --- a/src/cloud/components/organisms/Subscription/PlanTables.tsx +++ b/src/cloud/components/Subscription/PlanTables.tsx @@ -1,25 +1,25 @@ import { formatDistanceToNow } from 'date-fns' import React, { useMemo } from 'react' import { useMediaQuery } from 'react-responsive' -import { SerializedSubscription } from '../../../interfaces/db/subscription' -import { SerializedTeam } from '../../../interfaces/db/team' +import { SerializedSubscription } from '../../interfaces/db/subscription' +import { SerializedTeam } from '../../interfaces/db/team' import { discountPlans, stripeProPlanUnit, stripeStandardPlanUnit, UpgradePlans, -} from '../../../lib/stripe' +} from '../../lib/stripe' import { freePlanStorageMb, proPlanStorageMb, revisionHistoryStandardDays, standardPlanStorageMb, -} from '../../../lib/subscription' +} from '../../lib/subscription' import cc from 'classcat' -import Button from '../../../../shared/components/atoms/Button' -import styled from '../../../../shared/lib/styled' -import { useI18n } from '../../../lib/hooks/useI18n' -import { lngKeys } from '../../../lib/i18n/types' +import Button from '../../../design/components/atoms/Button' +import styled from '../../../design/lib/styled' +import { useI18n } from '../../lib/hooks/useI18n' +import { lngKeys } from '../../lib/i18n/types' interface PlanTablesProps { team: SerializedTeam diff --git a/src/cloud/components/organisms/Subscription/SubscriptionCostSummary.tsx b/src/cloud/components/Subscription/SubscriptionCostSummary.tsx similarity index 95% rename from src/cloud/components/organisms/Subscription/SubscriptionCostSummary.tsx rename to src/cloud/components/Subscription/SubscriptionCostSummary.tsx index 47c728f288..357bb14174 100644 --- a/src/cloud/components/organisms/Subscription/SubscriptionCostSummary.tsx +++ b/src/cloud/components/Subscription/SubscriptionCostSummary.tsx @@ -1,7 +1,7 @@ import React, { useMemo } from 'react' -import styled from '../../../../shared/lib/styled' +import styled from '../../../design/lib/styled' import cc from 'classcat' -import { AppComponent } from '../../../../shared/lib/types' +import { AppComponent } from '../../../design/lib/types' import plur from 'plur' import { stripeProJpyPlanUnit, @@ -10,11 +10,11 @@ import { stripeStandardPlanUnit, UpgradePlans, CloudDiscountParameters, -} from '../../../lib/stripe' -import Icon from '../../../../shared/components/atoms/Icon' +} from '../../lib/stripe' +import Icon from '../../../design/components/atoms/Icon' import { mdiGiftOutline } from '@mdi/js' -import { useI18n } from '../../../lib/hooks/useI18n' -import { lngKeys } from '../../../lib/i18n/types' +import { useI18n } from '../../lib/hooks/useI18n' +import { lngKeys } from '../../lib/i18n/types' import { lowerCase } from 'lodash' interface SubscriptionCostSummaryProps { diff --git a/src/cloud/components/organisms/Subscription/SubscriptionManagement.tsx b/src/cloud/components/Subscription/SubscriptionManagement.tsx similarity index 84% rename from src/cloud/components/organisms/Subscription/SubscriptionManagement.tsx rename to src/cloud/components/Subscription/SubscriptionManagement.tsx index 6c734dc1b2..58ccead7a0 100644 --- a/src/cloud/components/organisms/Subscription/SubscriptionManagement.tsx +++ b/src/cloud/components/Subscription/SubscriptionManagement.tsx @@ -1,32 +1,32 @@ import { mdiGiftOff, mdiOpenInNew } from '@mdi/js' import React, { useCallback, useMemo, useState } from 'react' -import Spinner from '../../../../shared/components/atoms/Spinner' -import { useToast } from '../../../../shared/lib/stores/toast' -import { cancelSubscription } from '../../../api/teams/subscription' -import { getTeamPortalUrl } from '../../../api/teams/subscription/invoices' -import { updateSubPlan } from '../../../api/teams/subscription/update' -import { SerializedSubscription } from '../../../interfaces/db/subscription' -import { SerializedTeam } from '../../../interfaces/db/team' -import { getFormattedDateFromUnixTimestamp } from '../../../lib/date' -import { usePage } from '../../../lib/stores/pageStore' -import { discountPlans, UpgradePlans } from '../../../lib/stripe' -import styled from '../../../lib/styled' -import Flexbox from '../../atoms/Flexbox' -import { SectionIntroduction } from '../settings/styled' +import Spinner from '../../../design/components/atoms/Spinner' +import { useToast } from '../../../design/lib/stores/toast' +import { cancelSubscription } from '../../api/teams/subscription' +import { getTeamPortalUrl } from '../../api/teams/subscription/invoices' +import { updateSubPlan } from '../../api/teams/subscription/update' +import { SerializedSubscription } from '../../interfaces/db/subscription' +import { SerializedTeam } from '../../interfaces/db/team' +import { getFormattedDateFromUnixTimestamp } from '../../lib/date' +import { usePage } from '../../lib/stores/pageStore' +import { discountPlans, UpgradePlans } from '../../lib/stripe' +import Flexbox from '../../../design/components/atoms/Flexbox' +import { SectionIntroduction } from '../Settings/styled' import PlanTables from './PlanTables' -import Alert from '../../../../components/atoms/Alert' +import Alert from '../../../components/atoms/Alert' import SubscriptionCostSummary from './SubscriptionCostSummary' -import Banner from '../../../../shared/components/atoms/Banner' -import Button from '../../../../shared/components/atoms/Button' +import Banner from '../../../design/components/atoms/Banner' +import Button, { LoadingButton } from '../../../design/components/atoms/Button' import { newSpaceCouponId, newUserProCouponId, newUserStandardCouponId, -} from '../../../lib/consts' -import { useElectron } from '../../../lib/stores/electron' -import Icon from '../../../../shared/components/atoms/Icon' -import { lngKeys } from '../../../lib/i18n/types' -import { useI18n } from '../../../lib/hooks/useI18n' +} from '../../lib/consts' +import { useElectron } from '../../lib/stores/electron' +import Icon from '../../../design/components/atoms/Icon' +import { lngKeys } from '../../lib/i18n/types' +import { useI18n } from '../../lib/hooks/useI18n' +import styled from '../../../design/lib/styled' interface SubscriptionManagementProps { subscription: SerializedSubscription @@ -378,19 +378,16 @@ const SubscriptionManagement = ({ direction='column' className='button__group' > - + subscriptionPlanChange +
diff --git a/src/cloud/components/atoms/ThreadStatusFilterControl.tsx b/src/cloud/components/ThreadStatusFilterControl.tsx similarity index 87% rename from src/cloud/components/atoms/ThreadStatusFilterControl.tsx rename to src/cloud/components/ThreadStatusFilterControl.tsx index 6203b5693e..6ca09d66be 100644 --- a/src/cloud/components/atoms/ThreadStatusFilterControl.tsx +++ b/src/cloud/components/ThreadStatusFilterControl.tsx @@ -1,22 +1,22 @@ import React, { useCallback } from 'react' import { mdiChevronDown, mdiAlertCircleOutline } from '@mdi/js' -import { capitalize } from '../../lib/utils/string' +import { capitalize } from '../lib/utils/string' import { useContextMenu, MenuTypes, MenuItem, -} from '../../../shared/lib/stores/contextMenu' -import { Thread } from '../../interfaces/db/comments' +} from '../../design/lib/stores/contextMenu' +import { Thread } from '../interfaces/db/comments' import Icon, { SuccessIcon, PrimaryIcon, WarningIcon, -} from '../../../shared/components/atoms/Icon' -import { RoundButton } from '../../../shared/components/atoms/Button' -import styled from '../../../shared/lib/styled' -import { useI18n } from '../../lib/hooks/useI18n' +} from '../../design/components/atoms/Icon' +import { RoundButton } from '../../design/components/atoms/Button' +import styled from '../../design/lib/styled' +import { useI18n } from '../lib/hooks/useI18n' import { TFunction } from 'i18next' -import { lngKeys } from '../../lib/i18n/types' +import { lngKeys } from '../lib/i18n/types' export type StatusFilter = Thread['status']['type'] | 'all' diff --git a/src/cloud/components/atoms/TitleComponent.tsx b/src/cloud/components/TitleComponent.tsx similarity index 75% rename from src/cloud/components/atoms/TitleComponent.tsx rename to src/cloud/components/TitleComponent.tsx index 8d4a9e1709..a740656796 100644 --- a/src/cloud/components/atoms/TitleComponent.tsx +++ b/src/cloud/components/TitleComponent.tsx @@ -1,5 +1,5 @@ import React from 'react' -import styled from '../../lib/styled' +import styled from '../../design/lib/styled' const TitleComponent = () => ( @@ -12,7 +12,7 @@ const TitleComponent = () => ( export default TitleComponent const StyledTitle = styled.div` - padding-top: ${({ theme }) => theme.space.small}px; + padding-top: ${({ theme }) => theme.sizes.spaces.sm}px; img { height: 50px; diff --git a/src/cloud/components/molecules/TokenControl.tsx b/src/cloud/components/TokenControl.tsx similarity index 53% rename from src/cloud/components/molecules/TokenControl.tsx rename to src/cloud/components/TokenControl.tsx index 5a820bb63a..2b367a769c 100644 --- a/src/cloud/components/molecules/TokenControl.tsx +++ b/src/cloud/components/TokenControl.tsx @@ -5,8 +5,7 @@ import React, { useRef, useEffect, } from 'react' -import { SerializedApiToken } from '../../interfaces/db/apiTokens' -import IconMdi from '../atoms/IconMdi' +import { SerializedApiToken } from '../interfaces/db/apiTokens' import { mdiDeleteOutline, mdiPencil, @@ -14,19 +13,14 @@ import { mdiContentCopy, mdiCheck, } from '@mdi/js' -import Flexbox from '../atoms/Flexbox' -import styled from '../../lib/styled' -import SmallButton from '../atoms/SmallButton' -import { - inputStyle, - borderedInputStyle, - baseIconStyle, -} from '../../lib/styled/styleFunctions' import copy from 'copy-to-clipboard' -import CustomButton from '../atoms/buttons/CustomButton' -import Tooltip from '../atoms/Tooltip' -import { useI18n } from '../../lib/hooks/useI18n' -import { lngKeys } from '../../lib/i18n/types' +import { useI18n } from '../lib/hooks/useI18n' +import { lngKeys } from '../lib/i18n/types' +import Button from '../../design/components/atoms/Button' +import styled from '../../design/lib/styled' +import FormInput from '../../design/components/molecules/Form/atoms/FormInput' +import WithTooltip from '../../design/components/atoms/WithTooltip' +import Flexbox from '../../design/components/atoms/Flexbox' interface TokenControlProps { token: SerializedApiToken @@ -38,7 +32,7 @@ const TokenControl = ({ token, onUpdate, onDelete }: TokenControlProps) => { const [name, setName] = useState(token.name) const [hide, setHide] = useState(true) const [edit, setEdit] = useState(false) - const inputRef = useRef() + const inputRef = useRef(null) const [clipIcon, setClipIcon] = useState(mdiContentCopy) const { translate } = useI18n() @@ -68,7 +62,7 @@ const TokenControl = ({ token, onUpdate, onDelete }: TokenControlProps) => { {edit ? ( <> - ) => @@ -76,27 +70,36 @@ const TokenControl = ({ token, onUpdate, onDelete }: TokenControlProps) => { } />
- setEdit(false)}> - - - +
) : ( <>

{name}

- setEdit(true)}> - - - setEdit(true)} + iconPath={mdiPencil} + iconSize={16} + /> +
)} @@ -110,32 +113,27 @@ const TokenControl = ({ token, onUpdate, onDelete }: TokenControlProps) => { {translate(lngKeys.GeneralToken)}: - - - + + ) @@ -146,30 +144,15 @@ export default TokenControl const StyledTokenControl = styled.div` width: 100%; - & > div:first-child { - margin-bottom: ${({ theme }) => theme.space.xsmall}px; + .control-button { + lineheight: normal; + padding: 0 8px; + height: 100%; + width: 70px; + flex: 0 0 auto; } -` -const StyleNameInput = styled.input` - ${inputStyle} -` - -const StyledReadOnlyInput = styled.input` - ${borderedInputStyle} - padding: 0 4px; - flex: 1 1 auto; - font-size: ${({ theme }) => theme.fontSizes.small}px; - height: 100%; -` - -const StyledClipboardButton = styled.button` - flex: 0 0 auto; - background: none; - ${baseIconStyle} - border-top-right-radius: 3px; - border-bottom-right-radius: 3px; - height: 100%; - font-size: inherit; - line-height: inherit; + & > div:first-child { + margin-bottom: ${({ theme }) => theme.sizes.spaces.xsm}px; + } ` diff --git a/src/cloud/components/organisms/Topbar/Controls/ControlsContextMenu/ControlsContextMenuBackground.tsx b/src/cloud/components/Topbar/Controls/ControlsContextMenu/ControlsContextMenuBackground.tsx similarity index 100% rename from src/cloud/components/organisms/Topbar/Controls/ControlsContextMenu/ControlsContextMenuBackground.tsx rename to src/cloud/components/Topbar/Controls/ControlsContextMenu/ControlsContextMenuBackground.tsx diff --git a/src/cloud/components/organisms/Topbar/Controls/ControlsContextMenu/ControlsContextMenuItem.tsx b/src/cloud/components/Topbar/Controls/ControlsContextMenu/ControlsContextMenuItem.tsx similarity index 94% rename from src/cloud/components/organisms/Topbar/Controls/ControlsContextMenu/ControlsContextMenuItem.tsx rename to src/cloud/components/Topbar/Controls/ControlsContextMenu/ControlsContextMenuItem.tsx index da5665d1a9..fed6379326 100644 --- a/src/cloud/components/organisms/Topbar/Controls/ControlsContextMenu/ControlsContextMenuItem.tsx +++ b/src/cloud/components/Topbar/Controls/ControlsContextMenu/ControlsContextMenuItem.tsx @@ -1,6 +1,6 @@ import React from 'react' -import { menuHeight } from '../../../../../../shared/lib/stores/contextMenu' -import styled from '../../../../../../shared/lib/styled' +import { menuHeight } from '../../../../../design/lib/stores/contextMenu' +import styled from '../../../../../design/lib/styled' interface ContextMenuItemProps { label: string | React.ReactNode diff --git a/src/cloud/components/organisms/Topbar/Controls/ControlsContextMenu/FolderContextMenu.tsx b/src/cloud/components/Topbar/Controls/ControlsContextMenu/FolderContextMenu.tsx similarity index 83% rename from src/cloud/components/organisms/Topbar/Controls/ControlsContextMenu/FolderContextMenu.tsx rename to src/cloud/components/Topbar/Controls/ControlsContextMenu/FolderContextMenu.tsx index 206a4462de..1c62ee62a9 100644 --- a/src/cloud/components/organisms/Topbar/Controls/ControlsContextMenu/FolderContextMenu.tsx +++ b/src/cloud/components/Topbar/Controls/ControlsContextMenu/FolderContextMenu.tsx @@ -1,12 +1,12 @@ import React, { useState, useCallback, useMemo, useRef } from 'react' -import { usePage } from '../../../../../lib/stores/pageStore' -import { useNav } from '../../../../../lib/stores/nav' +import { usePage } from '../../../../lib/stores/pageStore' +import { useNav } from '../../../../lib/stores/nav' import { destroyFolderBookmark, createFolderBookmark, CreateFolderBookmarkResponseBody, DestroyFolderBookmarkResponseBody, -} from '../../../../../api/teams/folders/bookmarks' +} from '../../../../api/teams/folders/bookmarks' import ContextMenuItem from './ControlsContextMenuItem' import { StyledContextMenuContainer, @@ -14,21 +14,21 @@ import { StyledMenuItem, } from './styled' import ControlsContextMenuBackground from './ControlsContextMenuBackground' -import { SerializedFolderWithBookmark } from '../../../../../interfaces/db/folder' +import { SerializedFolderWithBookmark } from '../../../../interfaces/db/folder' import { useEffectOnce } from 'react-use' import { useGlobalKeyDownHandler, isSingleKeyEventOutsideOfInput, preventKeyboardEventPropagation, useContextMenuKeydownHandler, -} from '../../../../../lib/keyboard' -import { MetaKeyText } from '../../../../../lib/keyboard' -import IconMdi from '../../../../atoms/IconMdi' +} from '../../../../lib/keyboard' +import { MetaKeyText } from '../../../../lib/keyboard' import { mdiStar, mdiTrashCan, mdiStarOutline, mdiPencil } from '@mdi/js' -import { useToast } from '../../../../../../shared/lib/stores/toast' -import { useCloudResourceModals } from '../../../../../lib/hooks/useCloudResourceModals' -import { useI18n } from '../../../../../lib/hooks/useI18n' -import { lngKeys } from '../../../../../lib/i18n/types' +import { useToast } from '../../../../../design/lib/stores/toast' +import { useCloudResourceModals } from '../../../../lib/hooks/useCloudResourceModals' +import { useI18n } from '../../../../lib/hooks/useI18n' +import { lngKeys } from '../../../../lib/i18n/types' +import Icon from '../../../../../design/components/atoms/Icon' interface FolderContextMenuProps { currentFolder: SerializedFolderWithBookmark @@ -125,7 +125,7 @@ const FolderContextMenu = ({ label={
- + {translate(lngKeys.GeneralRenameVerb)}
@@ -146,14 +146,14 @@ const FolderContextMenu = ({ ) : currentFolder.bookmarked ? (
- + {translate(lngKeys.GeneralUnbookmarkVerb)}
) : (
- + {translate(lngKeys.GeneralBookmarkVerb)}
@@ -169,7 +169,7 @@ const FolderContextMenu = ({ label={
- + {translate(lngKeys.GeneralDelete)}
diff --git a/src/cloud/components/organisms/Topbar/Controls/ControlsContextMenu/styled.ts b/src/cloud/components/Topbar/Controls/ControlsContextMenu/styled.ts similarity index 93% rename from src/cloud/components/organisms/Topbar/Controls/ControlsContextMenu/styled.ts rename to src/cloud/components/Topbar/Controls/ControlsContextMenu/styled.ts index 9bfe71253f..255b0fd59c 100644 --- a/src/cloud/components/organisms/Topbar/Controls/ControlsContextMenu/styled.ts +++ b/src/cloud/components/Topbar/Controls/ControlsContextMenu/styled.ts @@ -1,8 +1,8 @@ import { menuVerticalPadding, menuZIndex, -} from '../../../../../../shared/lib/stores/contextMenu' -import styled from '../../../../../../shared/lib/styled' +} from '../../../../../design/lib/stores/contextMenu' +import styled from '../../../../../design/lib/styled' export const zIndexModalsBackground = 8002 diff --git a/src/cloud/components/organisms/Topbar/PresenceIcons.tsx b/src/cloud/components/Topbar/PresenceIcons.tsx similarity index 83% rename from src/cloud/components/organisms/Topbar/PresenceIcons.tsx rename to src/cloud/components/Topbar/PresenceIcons.tsx index 7f07329dd3..91956a584b 100644 --- a/src/cloud/components/organisms/Topbar/PresenceIcons.tsx +++ b/src/cloud/components/Topbar/PresenceIcons.tsx @@ -1,8 +1,8 @@ import React, { useMemo } from 'react' -import styled from '../../../lib/styled' -import { UserPresenceInfo } from '../../../interfaces/presence' -import Tooltip from '../../atoms/Tooltip' -import { userIconStyle } from '../../../lib/styled/styleFunctions' +import WithTooltip from '../../../design/components/atoms/WithTooltip' +import styled from '../../../design/lib/styled' +import { userIconStyle } from '../../../design/lib/styled/styleFunctions' +import { UserPresenceInfo } from '../../interfaces/presence' interface PresenceListProps { users: UserPresenceInfo[] @@ -69,9 +69,9 @@ const PresenceIcons = ({ users, user, withTooltip }: PresenceIconProps) => { if (withTooltip) { return ( - + - + ) } @@ -83,9 +83,9 @@ const StyledPresenceList = styled.ul` flex-direction: row-reverse; align-items: center; list-style: none; - margin: 0 ${({ theme }) => theme.space.xxsmall}px 0 0; + margin: 0 ${({ theme }) => theme.sizes.spaces.xsm}px 0 0; padding: 0; - font-size: ${({ theme }) => theme.fontSizes.small}px; + font-size: ${({ theme }) => theme.sizes.fonts.sm}px; ` const StyledPresenceListItem = styled.div` diff --git a/src/cloud/components/organisms/Topbar/SyncStatus.tsx b/src/cloud/components/Topbar/SyncStatus.tsx similarity index 55% rename from src/cloud/components/organisms/Topbar/SyncStatus.tsx rename to src/cloud/components/Topbar/SyncStatus.tsx index d4fd712828..2f499219cf 100644 --- a/src/cloud/components/organisms/Topbar/SyncStatus.tsx +++ b/src/cloud/components/Topbar/SyncStatus.tsx @@ -1,10 +1,10 @@ import React, { useCallback, useMemo } from 'react' -import styled from '../../../lib/styled' -import Tooltip from '../../atoms/Tooltip' -import Spinner from '../../atoms/CustomSpinner' import { WebsocketProvider } from 'y-websocket' -import { ConnectionState } from '../../../lib/editor/hooks/useRealtime' -import { warningButtonStyle } from '../../../lib/styled/styleFunctions' +import { ConnectionState } from '../../lib/editor/hooks/useRealtime' +import Button from '../../../design/components/atoms/Button' +import Spinner from '../../../design/components/atoms/Spinner' +import styled from '../../../design/lib/styled' +import WithTooltip from '../../../design/components/atoms/WithTooltip' interface SyncStatusProps { provider: WebsocketProvider @@ -36,19 +36,19 @@ const SyncStatus = ({ provider, connState }: SyncStatusProps) => { switch (connState) { case 'reconnecting': return ( - + Connecting.. - + ) case 'disconnected': return ( - - + + + ) default: return undefined @@ -62,20 +62,12 @@ const StyledSyncTextContainer = styled.div` span { display: flex; align-items: center; - font-size: ${({ theme }) => theme.fontSizes.small}px; - color: ${({ theme }) => theme.dangerTextColor}; + font-size: ${({ theme }) => theme.sizes.fonts.sm}px; + color: ${({ theme }) => theme.colors.variants.danger.text}; > div { - margin-left: ${({ theme }) => theme.space.xsmall}px; + margin-left: ${({ theme }) => theme.sizes.spaces.xsm}px; } } ` -const StyledButton = styled.button` - ${warningButtonStyle} - font-size: ${({ theme }) => theme.fontSizes.small}px; - padding: ${({ theme }) => theme.space.xxsmall}px - ${({ theme }) => theme.space.small}px; - border: 1px solid ${({ theme }) => theme.subtleBorderColor}; - border-radius: 3px; -` export default SyncStatus diff --git a/src/cloud/components/UpgradeButton.tsx b/src/cloud/components/UpgradeButton.tsx index 86391a1756..bc8dceb7bd 100644 --- a/src/cloud/components/UpgradeButton.tsx +++ b/src/cloud/components/UpgradeButton.tsx @@ -5,7 +5,7 @@ import { MixpanelFrontEvent, } from '../interfaces/analytics/mixpanel' import { trackEvent } from '../api/track' -import Button, { ButtonVariant } from '../../shared/components/atoms/Button' +import Button, { ButtonVariant } from '../../design/components/atoms/Button' interface UpgradeBadgeProps { origin: 'share.password' | 'share.expire' | 'revision' | 'limit' diff --git a/src/cloud/components/UpgradeIntroButton.tsx b/src/cloud/components/UpgradeIntroButton.tsx index 92e10439ff..a2113c7fcf 100644 --- a/src/cloud/components/UpgradeIntroButton.tsx +++ b/src/cloud/components/UpgradeIntroButton.tsx @@ -4,9 +4,9 @@ import { MixpanelFrontEvent, } from '../interfaces/analytics/mixpanel' import { trackEvent } from '../api/track' -import { useModal } from '../../shared/lib/stores/modal' -import Button, { ButtonVariant } from '../../shared/components/atoms/Button' -import IntroPopup, { IntroPopupVariant } from './organisms/IntroPopup' +import { useModal } from '../../design/lib/stores/modal' +import Button, { ButtonVariant } from '../../design/components/atoms/Button' +import IntroPopup, { IntroPopupVariant } from './IntroducePlansPopup' interface UpgradeIntroButtonProps { origin: 'share.password' | 'share.expire' | 'revision' | 'guest' | 'limit' diff --git a/src/cloud/components/atoms/UserIcon.tsx b/src/cloud/components/UserIcon.tsx similarity index 68% rename from src/cloud/components/atoms/UserIcon.tsx rename to src/cloud/components/UserIcon.tsx index b5933a3f57..046f8f7327 100644 --- a/src/cloud/components/atoms/UserIcon.tsx +++ b/src/cloud/components/UserIcon.tsx @@ -1,11 +1,8 @@ import React from 'react' -import styled from '../../lib/styled' -import { SerializedUser } from '../../interfaces/db/user' -import { buildIconUrl } from '../../api/files' -import { - subtleBorderColor, - userIconStyle, -} from '../../lib/styled/styleFunctions' +import { SerializedUser } from '../interfaces/db/user' +import { buildIconUrl } from '../api/files' +import styled from '../../design/lib/styled' +import { userIconStyle } from '../../design/lib/styled/styleFunctions' interface UserIconProps { user: SerializedUser @@ -34,6 +31,6 @@ const StyledUserIcon = styled.div` border: 2px solid currentColor; &.subtle { - ${subtleBorderColor} + border: 1px solid ${({ theme }) => theme.colors.border.second}; } ` diff --git a/src/cloud/components/molecules/ViewerDisclaimer.tsx b/src/cloud/components/ViewerDisclaimer.tsx similarity index 80% rename from src/cloud/components/molecules/ViewerDisclaimer.tsx rename to src/cloud/components/ViewerDisclaimer.tsx index 6e54c09e17..01016ee87b 100644 --- a/src/cloud/components/molecules/ViewerDisclaimer.tsx +++ b/src/cloud/components/ViewerDisclaimer.tsx @@ -1,11 +1,11 @@ import { mdiOpenInNew } from '@mdi/js' import React from 'react' -import Icon from '../../../shared/components/atoms/Icon' -import { ExternalLink } from '../../../shared/components/atoms/Link' -import styled from '../../../shared/lib/styled' -import { useI18n } from '../../lib/hooks/useI18n' -import { lngKeys } from '../../lib/i18n/types' -import { usePage } from '../../lib/stores/pageStore' +import Icon from '../../design/components/atoms/Icon' +import { ExternalLink } from '../../design/components/atoms/Link' +import styled from '../../design/lib/styled' +import { useI18n } from '../lib/hooks/useI18n' +import { lngKeys } from '../lib/i18n/types' +import { usePage } from '../lib/stores/pageStore' const ViewerDisclaimer = () => { const { currentUserIsCoreMember } = usePage() diff --git a/src/cloud/components/molecules/ViewerRestrictedWrapper.tsx b/src/cloud/components/ViewerRestrictedWrapper.tsx similarity index 77% rename from src/cloud/components/molecules/ViewerRestrictedWrapper.tsx rename to src/cloud/components/ViewerRestrictedWrapper.tsx index 8a8d8e0d10..6c6f581b02 100644 --- a/src/cloud/components/molecules/ViewerRestrictedWrapper.tsx +++ b/src/cloud/components/ViewerRestrictedWrapper.tsx @@ -1,7 +1,7 @@ import React from 'react' -import Banner from '../../../shared/components/atoms/Banner' -import { AppComponent } from '../../../shared/lib/types' -import { usePage } from '../../lib/stores/pageStore' +import Banner from '../../design/components/atoms/Banner' +import { AppComponent } from '../../design/lib/types' +import { usePage } from '../lib/stores/pageStore' interface ViewerRestrictedWrapperProps { showBanner?: boolean diff --git a/src/cloud/components/molecules/WorkspaceExplorer/ExplorerListItem.tsx b/src/cloud/components/WorkspaceExplorer/ExplorerListItem.tsx similarity index 85% rename from src/cloud/components/molecules/WorkspaceExplorer/ExplorerListItem.tsx rename to src/cloud/components/WorkspaceExplorer/ExplorerListItem.tsx index 4f738d5ac8..c9a12e0352 100644 --- a/src/cloud/components/molecules/WorkspaceExplorer/ExplorerListItem.tsx +++ b/src/cloud/components/WorkspaceExplorer/ExplorerListItem.tsx @@ -1,10 +1,10 @@ import React from 'react' import cc from 'classcat' -import IconMdi from '../../atoms/IconMdi' import { StyledExplorerListItemIcon, StyledExplorerListItem } from './styled' -import Flexbox from '../../atoms/Flexbox' import { mdiMenuRight } from '@mdi/js' -import EmojiIcon from '../../atoms/EmojiIcon' +import EmojiIcon from '../EmojiIcon' +import Flexbox from '../../../design/components/atoms/Flexbox' +import Icon from '../../../design/components/atoms/Icon' interface ExplorerListItemProps { emoji?: string @@ -35,7 +35,7 @@ const ExplorerListItem = ({ {iconPath != null && ( - + )} {label} @@ -47,7 +47,7 @@ const ExplorerListItem = ({ (isInCurrentTree || isLastChildInCurrentTree) && 'emphasized', ])} > - + )} diff --git a/src/cloud/components/molecules/WorkspaceExplorer/FolderExplorer.tsx b/src/cloud/components/WorkspaceExplorer/FolderExplorer.tsx similarity index 97% rename from src/cloud/components/molecules/WorkspaceExplorer/FolderExplorer.tsx rename to src/cloud/components/WorkspaceExplorer/FolderExplorer.tsx index b6977c0774..7feb46ac88 100644 --- a/src/cloud/components/molecules/WorkspaceExplorer/FolderExplorer.tsx +++ b/src/cloud/components/WorkspaceExplorer/FolderExplorer.tsx @@ -1,5 +1,5 @@ import React, { useCallback, useMemo } from 'react' -import { SerializedFolderWithBookmark } from '../../../interfaces/db/folder' +import { SerializedFolderWithBookmark } from '../../interfaces/db/folder' import { mdiFolderOutline } from '@mdi/js' import { StyledExplorerDepth } from './styled' import ExplorerListItem from './ExplorerListItem' diff --git a/src/cloud/components/molecules/WorkspaceExplorer/index.tsx b/src/cloud/components/WorkspaceExplorer/index.tsx similarity index 95% rename from src/cloud/components/molecules/WorkspaceExplorer/index.tsx rename to src/cloud/components/WorkspaceExplorer/index.tsx index 25f3722721..c1a76ef3f7 100644 --- a/src/cloud/components/molecules/WorkspaceExplorer/index.tsx +++ b/src/cloud/components/WorkspaceExplorer/index.tsx @@ -1,6 +1,6 @@ import React, { useMemo, useCallback, useState } from 'react' -import { SerializedWorkspace } from '../../../interfaces/db/workspace' -import { SerializedFolderWithBookmark } from '../../../interfaces/db/folder' +import { SerializedWorkspace } from '../../interfaces/db/workspace' +import { SerializedFolderWithBookmark } from '../../interfaces/db/folder' import { StyledWorkspaceExplorerWrapper, StyledExplorerDepth, diff --git a/src/cloud/components/molecules/WorkspaceExplorer/styled.ts b/src/cloud/components/WorkspaceExplorer/styled.ts similarity index 95% rename from src/cloud/components/molecules/WorkspaceExplorer/styled.ts rename to src/cloud/components/WorkspaceExplorer/styled.ts index b0dd7ef03e..3b139fef04 100644 --- a/src/cloud/components/molecules/WorkspaceExplorer/styled.ts +++ b/src/cloud/components/WorkspaceExplorer/styled.ts @@ -1,4 +1,4 @@ -import styled from '../../../../shared/lib/styled' +import styled from '../../../design/lib/styled' export const StyledWorkspaceExplorer = styled.div` width: 100%; @@ -35,6 +35,7 @@ export const StyledExplorerListItem = styled.div` ${({ theme }) => theme.sizes.spaces.sm}px; position: relative; cursor: pointer; + height: 30px; span { flex: 1 1 auto; diff --git a/src/cloud/components/WorkspacePage/WorkspaceContextMenu.tsx b/src/cloud/components/WorkspacePage/WorkspaceContextMenu.tsx new file mode 100644 index 0000000000..4ff03b77ab --- /dev/null +++ b/src/cloud/components/WorkspacePage/WorkspaceContextMenu.tsx @@ -0,0 +1,240 @@ +import React, { useCallback, useMemo, useState } from 'react' +import { + mdiTrashCan, + mdiContentSaveOutline, + mdiClockOutline, + mdiContentCopy, + mdiOpenInNew, + mdiFolderMultipleOutline, + mdiArrowRight, + mdiStarOutline, + mdiApplicationCog, +} from '@mdi/js' +import { useCloudResourceModals } from '../../lib/hooks/useCloudResourceModals' +import { useI18n } from '../../lib/hooks/useI18n' +import { lngKeys } from '../../lib/i18n/types' +import MetadataContainer from '../../../design/components/organisms/MetadataContainer' +import MetadataContainerRow from '../../../design/components/organisms/MetadataContainer/molecules/MetadataContainerRow' +import { useCloudApi } from '../../lib/hooks/useCloudApi' +import { useModal } from '../../../design/lib/stores/modal' +import { useNav } from '../../lib/stores/nav' +import { getFormattedDateTime } from '../../lib/date' +import MetadataContainerBreak from '../../../design/components/organisms/MetadataContainer/atoms/MetadataContainerBreak' +import { boostHubBaseUrl } from '../../lib/consts' +import { usePage } from '../../lib/stores/pageStore' +import copy from 'copy-to-clipboard' +import { sendToHost, usingElectron } from '../../lib/stores/electron' +import { getMapValues } from '../../../design/lib/utils/array' +import { SerializedWorkspace } from '../../interfaces/db/workspace' +import { getWorkspaceHref } from '../Link/WorkspaceLink' + +interface WorkspaceContextMenuProps { + currentWorkspace: SerializedWorkspace + currentUserIsCoreMember: boolean +} + +const WorkspaceContextMenu = ({ + currentWorkspace: workspace, + currentUserIsCoreMember, +}: WorkspaceContextMenuProps) => { + const { sendingMap } = useCloudApi() + const { openWorkspaceEditForm, deleteWorkspace } = useCloudResourceModals() + const { closeAllModals } = useModal() + const { translate } = useI18n() + const { foldersMap, docsMap, workspacesMap } = useNav() + const [copied, setCopied] = useState(false) + const { team } = usePage() + + const currentWorkspace = useMemo(() => { + return workspacesMap.get(workspace.id) + }, [workspacesMap, workspace]) + + const workspaceUrl = useMemo(() => { + if (currentWorkspace == null || team == null) { + return '' + } + return boostHubBaseUrl + getWorkspaceHref(currentWorkspace, team, 'index') + }, [team, currentWorkspace]) + + const children = useMemo(() => { + if (currentWorkspace == null) { + return { docs: 0, folders: 0 } + } + + const docs = getMapValues(docsMap).reduce((acc, val) => { + if ( + val.workspaceId === currentWorkspace.id && + val.parentFolderId == null + ) { + return acc + 1 + } + return acc + }, 0) + + const folders = getMapValues(foldersMap).reduce((acc, val) => { + if ( + val.workspaceId === currentWorkspace.id && + val.parentFolderId == null + ) { + return acc + 1 + } + return acc + }, 0) + + return { + docs, + folders, + } + }, [foldersMap, currentWorkspace, docsMap]) + + const copyButtonHandler = useCallback(() => { + copy(workspaceUrl) + setCopied(true) + setTimeout(() => { + setCopied(false) + }, 200) + }, [workspaceUrl]) + + if (currentWorkspace == null) { + return ( + + + + ) + } + + return ( + + + + + + + + {usingElectron && ( + { + sendToHost('open-external-url', workspaceUrl) + }, + }, + }} + /> + )} + {currentUserIsCoreMember && ( + <> + + openWorkspaceEditForm(currentWorkspace), + }, + }} + /> + + { + closeAllModals() + deleteWorkspace(currentWorkspace) + }, + }, + }} + /> + + )} + + ) +} + +export default WorkspaceContextMenu diff --git a/src/cloud/components/WorkspacePage/index.tsx b/src/cloud/components/WorkspacePage/index.tsx new file mode 100644 index 0000000000..d2dfa7adfc --- /dev/null +++ b/src/cloud/components/WorkspacePage/index.tsx @@ -0,0 +1,224 @@ +import React, { useMemo } from 'react' +import { usePage } from '../../lib/stores/pageStore' +import { SerializedWorkspace } from '../../interfaces/db/workspace' +import { useNav } from '../../lib/stores/nav' +import ContentManager from '../ContentManager' +import Application from '../Application' +import { useRouter } from '../../lib/router' +import { useCloudResourceModals } from '../../lib/hooks/useCloudResourceModals' +import { mapWorkspaceBreadcrumb } from '../../lib/mappers/topbarBreadcrumbs' +import { useI18n } from '../../lib/hooks/useI18n' +import InviteCTAButton from '../Buttons/InviteCTAButton' +import MetadataContainerRow from '../../../design/components/organisms/MetadataContainer/molecules/MetadataContainerRow' +import { useCloudApi } from '../../lib/hooks/useCloudApi' +import { + mdiDotsHorizontal, + mdiFolderPlusOutline, + mdiPlus, + mdiTextBoxPlus, +} from '@mdi/js' +import MetadataContainer from '../../../design/components/organisms/MetadataContainer' +import { lngKeys } from '../../lib/i18n/types' +import { useModal } from '../../../design/lib/stores/modal' +import FolderPageInviteSection from '../Onboarding/FolderPageInviteSection' +import { TopbarControlProps } from '../../../design/components/organisms/Topbar' +import WorkspaceContextMenu from './WorkspaceContextMenu' + +interface WorkspacePage { + workspace: SerializedWorkspace +} + +const WorkspacePage = ({ workspace }: WorkspacePage) => { + const { team, currentUserIsCoreMember } = usePage() + const { docsMap, foldersMap } = useNav() + const { push } = useRouter() + const { + openNewFolderForm, + openNewDocForm, + openWorkspaceEditForm, + deleteWorkspace, + } = useCloudResourceModals() + const { sendingMap } = useCloudApi() + const { translate } = useI18n() + const { openContextModal } = useModal() + + const topbarBreadcrumbs = useMemo(() => { + if (team == null) { + return [] + } + + if (!currentUserIsCoreMember) { + return [mapWorkspaceBreadcrumb(translate, team, workspace, push)] + } + + return [ + mapWorkspaceBreadcrumb( + translate, + team, + workspace, + push, + openNewDocForm, + openNewFolderForm, + openWorkspaceEditForm, + deleteWorkspace + ), + ] + }, [ + translate, + team, + workspace, + push, + openNewFolderForm, + openNewDocForm, + openWorkspaceEditForm, + deleteWorkspace, + currentUserIsCoreMember, + ]) + + const childFolders = useMemo(() => { + if (workspace == null) { + return [] + } + return [...foldersMap.values()].filter( + (folder) => + folder.workspaceId === workspace.id && folder.parentFolderId == null + ) + }, [foldersMap, workspace]) + + const childDocs = useMemo(() => { + if (workspace == null) { + return [] + } + return [...docsMap.values()].filter( + (doc) => doc.workspaceId === workspace.id && doc.parentFolderId == null + ) + }, [docsMap, workspace]) + + const workspaceMap = useMemo(() => { + const map = new Map() + map.set(workspace.id, workspace) + return map + }, [workspace]) + + const topbarControls = useMemo(() => { + if (team == null) { + return undefined + } + + const controls: TopbarControlProps[] = [ + { + type: 'node', + element: , + }, + ] + + if (currentUserIsCoreMember) { + controls.push({ + type: 'button', + variant: 'icon', + iconPath: mdiPlus, + onClick: (event) => + openContextModal( + event, + + + openNewDocForm({ + team, + workspaceId: workspace.id, + }), + }, + }} + /> + + openNewFolderForm({ + team, + workspaceId: workspace.id, + }), + }, + }} + /> + , + { + hideBackground: true, + removePadding: true, + width: 300, + alignment: 'bottom-right', + } + ), + }) + } + + controls.push({ + type: 'button', + variant: 'icon', + iconPath: mdiDotsHorizontal, + onClick: (event) => + openContextModal( + event, + , + { + alignment: 'bottom-right', + removePadding: true, + hideBackground: true, + } + ), + }) + + return controls + }, [ + workspace, + currentUserIsCoreMember, + openContextModal, + openNewDocForm, + openNewFolderForm, + sendingMap, + translate, + team, + ]) + + if (team == null) { + return + } + + return ( + + + + + ) +} + +export default WorkspacePage diff --git a/src/cloud/components/atoms/Badge.tsx b/src/cloud/components/atoms/Badge.tsx deleted file mode 100644 index 4bf3503a7b..0000000000 --- a/src/cloud/components/atoms/Badge.tsx +++ /dev/null @@ -1,42 +0,0 @@ -import React from 'react' -import styled from '../../lib/styled' -import cc from 'classcat' - -interface BadgeProps { - label: React.ReactNode - variant?: 'danger' | 'warning' | 'info' - className?: string -} - -const Badge = ({ label, variant, className }: BadgeProps) => ( - - {label} - -) - -const StyledBadge = styled.div` - display: inline-block; - text-decoration: none; - position: relative; - padding: ${({ theme }) => theme.space.xxsmall}px - ${({ theme }) => theme.space.xsmall}px; - border-radius: 3px; - font-size: ${({ theme }) => theme.fontSizes.small}px; - - &.badge-danger { - background-color: ${({ theme }) => theme.dangerBackgroundColor}; - color: ${({ theme }) => theme.whiteTextColor}; - } - - &.badge-warning { - background-color: ${({ theme }) => theme.warningBackgroundColor}; - color: ${({ theme }) => theme.whiteTextColor}; - } - - &.badge-info { - background-color: ${({ theme }) => theme.infoBackgroundColor}; - color: ${({ theme }) => theme.whiteTextColor}; - } -` - -export default Badge diff --git a/src/cloud/components/atoms/Button.tsx b/src/cloud/components/atoms/Button.tsx deleted file mode 100644 index 55d7102406..0000000000 --- a/src/cloud/components/atoms/Button.tsx +++ /dev/null @@ -1,342 +0,0 @@ -import React, { - MouseEventHandler, - FocusEventHandler, - DragEventHandler, - PropsWithChildren, -} from 'react' -import styled from '../../lib/styled' -import cc from 'classcat' -import Icon from './Icon' -import { - UnroundedParamTypes, - createUnroundedStyle, -} from '../../lib/styled/unrounded' - -const { getUnroundedClassNames, unroundedStyle } = createUnroundedStyle( - 'button' -) - -export interface ButtonProps { - variant?: - | 'primary' - | 'secondary' - | 'danger' - | 'warning' - | 'info' - | 'link' - | 'transparent' - | 'nav' - | 'outline-primary' - | 'outline-secondary' - size?: 'sm' | 'md' | 'lg' - block?: boolean - iconPath?: string - unrounded?: UnroundedParamTypes - - type?: string - className?: string - style?: React.CSSProperties - disabled?: boolean - title?: string - align?: 'left' | 'center' | 'right' - tabIndex?: number - id?: string - - onClick?: MouseEventHandler - onMouseUp?: MouseEventHandler - onMouseDown?: MouseEventHandler - onMouseMove?: MouseEventHandler - onMouseOver?: MouseEventHandler - onMouseOut?: MouseEventHandler - onMouseEnter?: MouseEventHandler - onMouseLeave?: MouseEventHandler - onDoubleClick?: MouseEventHandler - onContextMenu?: MouseEventHandler - onFocus?: FocusEventHandler - onDrag?: DragEventHandler - onDragStart?: DragEventHandler - onDragEnd?: DragEventHandler - onDrop?: DragEventHandler -} - -const Button = React.forwardRef< - HTMLButtonElement, - PropsWithChildren ->( - ( - { - children, - variant = 'primary', - size = 'md', - block, - iconPath, - unrounded = false, - type, - title, - disabled, - className, - style, - tabIndex, - align = 'center', - id, - onClick, - onMouseUp, - onMouseDown, - onMouseMove, - onMouseOver, - onMouseOut, - onMouseEnter, - onMouseLeave, - onDoubleClick, - onContextMenu, - onFocus, - onDrag, - onDragStart, - onDragEnd, - onDrop, - }, - ref - ) => { - return ( - - {iconPath != null && } - {children != null &&
{children}
} -
- ) - } -) - -export default Button - -const StyledButton = styled.button` - padding: 0 10px; - border-radius: 2px; - cursor: pointer; - font-size: ${({ theme }) => theme.fontSizes.small}px; - color: ${({ theme }) => theme.whiteTextColor}; - height: 36px; - outline: none; - border-radius: 4px; - border-color: transparent; - border-width: 1px; - border-style: solid; - display: inline-flex; - align-items: center; - justify-content: center; - font-family: Arial; - box-sizing: border-box; - - &.button--align-left { - justify-content: left; - } - &.button--align-right { - justify-content: right; - } - - & + * { - margin-left: 5px; - &.block { - margin-left: 0; - } - } - - & > .button__icon + .button__label { - margin-left: 4px; - } - - &:disabled { - cursor: not-allowed; - opacity: 0.5; - } - ${unroundedStyle} - - &.button--variant-nav { - color: ${({ theme }) => theme.baseTextColor}; - background-color: transparent; - &:hover:not(:disabled), - &:active:not(:disabled), - &:focus:not(:disabled), - &.active:not(:disabled) { - color: ${({ theme }) => theme.whiteTextColor}; - } - &:focus { - box-shadow: none; - } - &:focus-visible { - box-shadow: 0 0 0 0.2rem ${({ theme }) => theme.focusShadowColor}; - } - } - - &.button--variant-transparent { - background-color: transparent; - &:hover:not(:disabled), - &:active:not(:disabled), - &:focus:not(:disabled), - &.active:not(:disabled) { - color: ${({ theme }) => theme.primaryTextColor}; - } - &:focus { - box-shadow: none; - } - &:focus-visible { - box-shadow: 0 0 0 0.2rem ${({ theme }) => theme.focusShadowColor}; - } - } - - &.button--variant-outline-primary { - background-color: transparent; - border-color: ${({ theme }) => theme.primaryBackgroundColor}; - color: ${({ theme }) => theme.primaryTextColor}; - - &:hover:not(:disabled), - &:active:not(:disabled), - &:focus:not(:disabled), - &.active:not(:disabled) { - background-color: ${({ theme }) => theme.darkerPrimaryBackgroundColor}; - color: ${({ theme }) => theme.whiteTextColor}; - } - } - - &.button--variant-outline-secondary { - background-color: transparent; - border-color: ${({ theme }) => theme.secondaryBackgroundColor}; - color: ${({ theme }) => theme.whiteTextColor}; - - &:hover:not(:disabled), - &:active:not(:disabled), - &:focus:not(:disabled), - &.active:not(:disabled) { - background-color: ${({ theme }) => theme.darkerSecondaryBackgroundColor}; - color: ${({ theme }) => theme.whiteTextColor}; - } - } - - &.button--variant-primary { - background-color: ${({ theme }) => theme.primaryBackgroundColor}; - color: ${({ theme }) => theme.whiteTextColor}; - - &:hover:not(:disabled), - &:active:not(:disabled), - &:focus:not(:disabled), - &.active:not(:disabled) { - background-color: ${({ theme }) => theme.darkerPrimaryBackgroundColor}; - } - } - - &.button--variant-secondary { - background-color: ${({ theme }) => theme.secondaryBackgroundColor}; - color: ${({ theme }) => theme.whiteTextColor}; - - &:hover:not(:disabled), - &:active:not(:disabled), - &:focus:not(:disabled), - &.active:not(:disabled) { - background-color: ${({ theme }) => theme.darkerSecondaryBackgroundColor}; - } - } - - &.button--variant-danger { - background-color: ${({ theme }) => theme.dangerBackgroundColor}; - color: ${({ theme }) => theme.whiteTextColor}; - &:hover:not(:disabled), - &:active:not(:disabled), - &:focus:not(:disabled), - &.active:not(:disabled) { - background-color: ${({ theme }) => theme.darkerDangerBackgroundColor}; - } - } - - &.button--variant-warning { - background-color: ${({ theme }) => theme.warningBackgroundColor}; - color: ${({ theme }) => theme.whiteTextColor}; - &:hover:not(:disabled), - &:active:not(:disabled), - &:focus:not(:disabled), - &.active:not(:disabled) { - background-color: ${({ theme }) => theme.darkerWarningBackgroundColor}; - } - } - - &.button--variant-info { - background-color: ${({ theme }) => theme.infoBackgroundColor}; - color: ${({ theme }) => theme.whiteTextColor}; - &:hover:not(:disabled), - &:active:not(:disabled), - &:focus:not(:disabled), - &.active:not(:disabled) { - background-color: ${({ theme }) => theme.darkerInfoBackgroundColor}; - } - } - - &.button--variant-link { - color: ${({ theme }) => theme.primaryBackgroundColor}; - background-color: transparent; - &:hover:not(:disabled), - &:active:not(:disabled), - &:focus:not(:disabled), - &.active:not(:disabled) { - color: ${({ theme }) => theme.darkerPrimaryBackgroundColor}; - } - } - - &.button--variant-transparent { - color: ${({ theme }) => theme.secondaryBackgroundColor}; - background-color: transparent; - &:hover:not(:disabled), - &:active:not(:disabled), - &:focus:not(:disabled), - &.active:not(:disabled) { - color: ${({ theme }) => theme.darkerSecondaryBackgroundColor}; - } - } - - &.button--size-lg { - height: 44px; - padding: 0 14px; - } - - &.button--size-sm { - height: 28px; - padding: 0 6px; - } - - &.block { - display: flex; - width: 100%; - } - - &:focus { - box-shadow: 0 0 0 0.2rem ${({ theme }) => theme.focusShadowColor}; - } -` diff --git a/src/cloud/components/atoms/ButtonLink.tsx b/src/cloud/components/atoms/ButtonLink.tsx deleted file mode 100644 index 924c7b7b69..0000000000 --- a/src/cloud/components/atoms/ButtonLink.tsx +++ /dev/null @@ -1,337 +0,0 @@ -import React, { - FC, - MouseEventHandler, - FocusEventHandler, - DragEventHandler, - useCallback, -} from 'react' -import styled from '../../lib/styled' -import cc from 'classcat' -import Icon from './Icon' -import { - UnroundedParamTypes, - createUnroundedStyle, -} from '../../lib/styled/unrounded' -import { useRouter } from '../../lib/router' - -const { getUnroundedClassNames, unroundedStyle } = createUnroundedStyle( - 'button' -) -export interface ButtonLinkProps { - variant?: - | 'primary' - | 'secondary' - | 'danger' - | 'warning' - | 'info' - | 'link' - | 'transparent' - | 'nav' - | 'outline-primary' - | 'outline-secondary' - size?: 'sm' | 'md' | 'lg' - block?: boolean - iconPath?: string - unrounded?: UnroundedParamTypes - newTab?: boolean - - href?: string - className?: string - style?: React.CSSProperties - disabled?: boolean - title?: string - align?: 'left' | 'center' | 'right' - - onClick?: MouseEventHandler - onMouseUp?: MouseEventHandler - onMouseDown?: MouseEventHandler - onMouseMove?: MouseEventHandler - onMouseOver?: MouseEventHandler - onMouseOut?: MouseEventHandler - onMouseEnter?: MouseEventHandler - onMouseLeave?: MouseEventHandler - onDoubleClick?: MouseEventHandler - onContextMenu?: MouseEventHandler - onFocus?: FocusEventHandler - onDrag?: DragEventHandler - onDragStart?: DragEventHandler - onDragEnd?: DragEventHandler - onDrop?: DragEventHandler -} - -const ButtonLink: FC = React.forwardRef( - ( - { - children, - variant = 'primary', - size = 'md', - block, - iconPath, - unrounded = false, - newTab = false, - href, - title, - disabled, - className, - style, - align = 'center', - onClick, - onMouseUp, - onMouseDown, - onMouseMove, - onMouseOver, - onMouseOut, - onMouseEnter, - onMouseLeave, - onDoubleClick, - onContextMenu, - onFocus, - onDrag, - onDragStart, - onDragEnd, - onDrop, - }, - ref - ) => { - const { push } = useRouter() - const navigateToHref = useCallback( - (event: MouseEvent) => { - if (href == null) { - return - } - event.preventDefault() - push(href) - }, - [push, href] - ) - return ( - - {iconPath != null && } - {children != null &&
{children}
} -
- ) - } -) - -export default ButtonLink - -const StyledButton = styled.a` - padding: 0 10px; - cursor: pointer; - font-size: ${({ theme }) => theme.fontSizes.small}px; - color: ${({ theme }) => theme.whiteTextColor}; - height: 36px; - outline: none; - border-radius: 4px; - border-color: transparent; - border-width: 1px; - border-style: solid; - display: inline-flex; - align-items: center; - justify-content: center; - font-family: Arial; - box-sizing: border-box; - - &.button--align-left { - justify-content: left; - } - &.button--align-right { - justify-content: right; - } - - & + * { - margin-left: 5px; - &.block { - margin-left: 0; - } - } - - text-decoration: none; - &:hover { - text-decoration: none; - } - - &:disabled { - cursor: not-allowed; - opacity: 0.5; - } - - ${unroundedStyle} - - &.button-variant-nav { - color: ${({ theme }) => theme.baseTextColor}; - background-color: transparent; - &:hover:not(:disabled), - &:active:not(:disabled), - &:focus:not(:disabled), - &.active:not(:disabled) { - color: ${({ theme }) => theme.whiteTextColor}; - } - &:focus { - box-shadow: none; - } - &:focus-visible { - box-shadow: 0 0 0 0.2rem ${({ theme }) => theme.focusShadowColor}; - } - } - - &.button-variant-transparent { - background-color: transparent; - &:hover:not(:disabled), - &:active:not(:disabled), - &:focus:not(:disabled), - &.active:not(:disabled) { - color: ${({ theme }) => theme.primaryTextColor}; - } - &:focus { - box-shadow: none; - } - &:focus-visible { - box-shadow: 0 0 0 0.2rem ${({ theme }) => theme.focusShadowColor}; - } - } - - &.button-variant-outline-primary { - border-color: ${({ theme }) => theme.primaryBackgroundColor}; - color: ${({ theme }) => theme.primaryTextColor}; - - &:hover:not(:disabled), - &:active:not(:disabled), - &:focus:not(:disabled), - &.active:not(:disabled) { - background-color: ${({ theme }) => theme.darkerPrimaryBackgroundColor}; - color: ${({ theme }) => theme.whiteTextColor}; - } - } - - &.button-variant-outline-secondary { - border-color: ${({ theme }) => theme.whiteTextColor}; - color: ${({ theme }) => theme.whiteTextColor}; - - &:hover:not(:disabled), - &:active:not(:disabled), - &:focus:not(:disabled), - &.active:not(:disabled) { - background-color: ${({ theme }) => theme.darkerSecondaryBackgroundColor}; - color: ${({ theme }) => theme.whiteTextColor}; - } - } - - &.button-variant-primary { - background-color: ${({ theme }) => theme.primaryBackgroundColor}; - color: ${({ theme }) => theme.whiteTextColor}; - - &:hover:not(:disabled), - &:active:not(:disabled), - &:focus:not(:disabled), - &.active:not(:disabled) { - background-color: ${({ theme }) => theme.darkerPrimaryBackgroundColor}; - } - } - - &.button-variant-secondary { - background-color: ${({ theme }) => theme.secondaryBackgroundColor}; - color: ${({ theme }) => theme.whiteTextColor}; - - &:hover:not(:disabled), - &:active:not(:disabled), - &:focus:not(:disabled), - &.active:not(:disabled) { - background-color: ${({ theme }) => theme.darkerSecondaryBackgroundColor}; - } - } - - &.button-variant-danger { - background-color: ${({ theme }) => theme.dangerBackgroundColor}; - color: ${({ theme }) => theme.whiteTextColor}; - &:hover:not(:disabled), - &:active:not(:disabled), - &:focus:not(:disabled), - &.active:not(:disabled) { - background-color: ${({ theme }) => theme.darkerDangerBackgroundColor}; - } - } - - &.button-variant-warning { - background-color: ${({ theme }) => theme.warningBackgroundColor}; - color: ${({ theme }) => theme.whiteTextColor}; - &:hover:not(:disabled), - &:active:not(:disabled), - &:focus:not(:disabled), - &.active:not(:disabled) { - background-color: ${({ theme }) => theme.darkerWarningBackgroundColor}; - } - } - - &.button-variant-info { - background-color: ${({ theme }) => theme.infoBackgroundColor}; - color: ${({ theme }) => theme.whiteTextColor}; - &:hover:not(:disabled), - &:active:not(:disabled), - &:focus:not(:disabled), - &.active:not(:disabled) { - background-color: ${({ theme }) => theme.darkerInfoBackgroundColor}; - } - } - - &.button-variant-link { - color: ${({ theme }) => theme.primaryBackgroundColor}; - background-color: transparent; - &:hover:not(:disabled), - &:active:not(:disabled), - &:focus:not(:disabled), - &.active:not(:disabled) { - color: ${({ theme }) => theme.darkerPrimaryBackgroundColor}; - } - } - - &.button-size-lg { - height: 40px; - padding: 0 ${({ theme }) => theme.space.default}px; - } - - &.button-size-sm { - height: 28px; - padding: 0 ${({ theme }) => theme.space.xsmall}px; - } - - &.block { - display: flex; - width: 100%; - } - - &:focus { - box-shadow: 0 0 0 0.2rem ${({ theme }) => theme.focusShadowColor}; - } -` diff --git a/src/cloud/components/atoms/Card.tsx b/src/cloud/components/atoms/Card.tsx deleted file mode 100644 index 22f65101db..0000000000 --- a/src/cloud/components/atoms/Card.tsx +++ /dev/null @@ -1,21 +0,0 @@ -import styled from '../../lib/styled' -import { StyledProps } from '../../lib/styled/styleFunctions' - -const Card = styled.div` - width: 100%; - max-width: 600px; - max-height: 90vh; - overflow-y: auto; - padding: ${({ theme }: StyledProps) => theme.space.xxlarge}px - ${({ theme }) => theme.space.large}px; - background: ${({ theme }: StyledProps) => theme.secondaryBackgroundColor}; - box-shadow: 0 5px 10px 0 rgba(0, 0, 0, 0.1); - border-radius: 5px; - text-align: center; - - p { - color: ${({ theme }) => theme.baseTextColor}; - } -` - -export default Card diff --git a/src/cloud/components/atoms/Checkbox.tsx b/src/cloud/components/atoms/Checkbox.tsx deleted file mode 100644 index 771061d2bf..0000000000 --- a/src/cloud/components/atoms/Checkbox.tsx +++ /dev/null @@ -1,159 +0,0 @@ -import React, { useCallback, useMemo } from 'react' -import styled from '../../lib/styled' -import cc from 'classcat' -import Flexbox from './Flexbox' - -interface CheckboxProps { - checked?: boolean - label?: React.ReactNode - className?: string - disabled?: boolean - style?: React.CSSProperties - onChange?: (val: boolean) => void -} - -const Checkbox = ({ - onChange, - checked = false, - disabled, - label, - className, - style, -}: CheckboxProps) => { - const onClick = useCallback(() => { - if (onChange == null || disabled) { - return - } - - onChange(!checked) - }, [onChange, checked, disabled]) - - const checkboxStyle: React.CSSProperties = useMemo(() => { - const size = 15 - if ((className || '').includes('reducer') && !checked) { - const fontSize = size * 1.3 - return { - width: size, - height: size, - fontSize: fontSize, - lineHeight: `${fontSize * 0.6}px`, - } - } - - return { - width: size, - height: size, - fontSize: size * 1.2, - lineHeight: `${size * 0.8}px`, - } - }, [className, checked]) - - const labelNode = useMemo(() => { - if (label == null) { - return null - } - - if (typeof label === 'string') { - return {label} - } - - return
{label}
- }, [label]) - - return ( - - - - {labelNode} - - - ) -} - -const StyledCheckbox = styled.div` - display: inline-block; - border: 2px solid ${({ theme }) => theme.subtleIconColor}; - border-radius: 2px; - transition: 0.3s; - cursor: pointer; - position: relative; - - &.disabled { - cursor: not-allowed; - } - - &::after { - position: relative; - left: -2px; - color: transparent; - content: '✓' !important; - font-size: inherit !important; - pointer-events: none; - } - - &.checked { - &::after { - color: ${({ theme }) => theme.subtleIconColor}; - } - - &:hover::after { - color: ${({ theme }) => theme.emphasizedIconColor}; - } - } -` - -const StyledLabel = styled.label` - display: flex; - align-items: center; - color: ${({ theme }) => theme.subtleTextColor}; - margin-bottom: 0; - cursor: pointer; - vertical-align: middle; - font-size: inherit; - line-height: 0; - - &.disabled { - opacity: 0.8; - cursor: not-allowed; - } - - > span, - > .margin-left { - margin-left: 4px; - } - - span { - color: ${({ theme }) => theme.baseTextColor}; - } - - &:hover:not(.disabled) { - color: ${({ theme }) => theme.emphasizedIconColor}; - .checkbox { - border-color: ${({ theme }) => theme.emphasizedIconColor}; - - &::after { - color: ${({ theme }) => theme.emphasizedIconColor}; - } - } - } - - &.reducer { - .checkbox:not(.checked)::after { - content: '-'; - left: 2px; - } - } -` - -export default Checkbox diff --git a/src/cloud/components/atoms/ClickInput.tsx b/src/cloud/components/atoms/ClickInput.tsx deleted file mode 100644 index 2589232c7d..0000000000 --- a/src/cloud/components/atoms/ClickInput.tsx +++ /dev/null @@ -1,62 +0,0 @@ -import React, { HTMLProps, useState, useRef, useEffect, useMemo } from 'react' -import styled from '../../lib/styled' - -interface ClickInputProps extends HTMLProps { - value?: string - initalFocus?: boolean - format?: (str: string) => string -} - -const ClickInput = ({ - value, - placeholder, - format, - initalFocus = false, - ...props -}: ClickInputProps) => { - const [open, setOpen] = useState(initalFocus) - const inputRef = useRef(null) - - const onBlur: React.FocusEventHandler = (e) => { - setOpen(false) - if (props.onBlur != null) { - props.onBlur(e) - } - } - - useEffect(() => { - if (open && inputRef.current != null) { - inputRef.current.focus() - } - }, [open]) - - const displayValue = useMemo(() => { - const withDefault = orDefault(value, placeholder || '') - return format != null ? format(withDefault) : withDefault - }, [value, placeholder, format]) - - return open ? ( - - ) : ( - setOpen(true)}> - {displayValue} - - ) -} - -export default ClickInput - -const StyledValueDisplay = styled.span` - display: inline-block; - cursor: pointer; -` - -function orDefault(str: string | null | undefined, defaultStr: string) { - return str != null && str !== '' ? str : defaultStr -} diff --git a/src/cloud/components/atoms/Collapsible.tsx b/src/cloud/components/atoms/Collapsible.tsx deleted file mode 100644 index bb3ca57f81..0000000000 --- a/src/cloud/components/atoms/Collapsible.tsx +++ /dev/null @@ -1,48 +0,0 @@ -import React, { useState, useCallback } from 'react' -import IconMdi from './IconMdi' -import { mdiChevronRight, mdiChevronDown } from '@mdi/js' -import styled from '../../lib/styled' - -interface CollapsibleProps { - header: React.ReactElement - content: React.ReactElement - defaultState?: boolean -} - -const Collapsible = ({ - header, - content, - defaultState = false, -}: CollapsibleProps) => { - const [isOpen, setIsOpen] = useState(defaultState) - - const toggle = useCallback(() => { - setIsOpen((state) => !state) - }, []) - - return ( - <> - - - {header} - - {isOpen && content} - - ) -} - -const StyledCollapsibleHeader = styled.div` - display: flex; - width: 100%; - cursor: pointer; - - svg { - align-self: center; - } -` - -const StyledCollapsibleContent = styled.div` - margin-left: 24px; -` - -export default Collapsible diff --git a/src/cloud/components/atoms/ColoredBlock.tsx b/src/cloud/components/atoms/ColoredBlock.tsx deleted file mode 100644 index 7d619a17b6..0000000000 --- a/src/cloud/components/atoms/ColoredBlock.tsx +++ /dev/null @@ -1,85 +0,0 @@ -import React, { CSSProperties, PropsWithChildren } from 'react' -import cc from 'classcat' -import styled from '../../lib/styled' - -interface ColoredBlockProps { - className?: string - variant: 'danger' | 'warning' | 'success' | 'info' - style?: CSSProperties -} - -const ColoredBlock = ({ - className, - variant, - style, - children, -}: PropsWithChildren) => ( - - {children} - -) - -const StyledColoredBlock = styled.div` - position: relative; - width: 100%; - padding: ${({ theme }) => theme.space.xsmall}px - ${({ theme }) => theme.space.default}px; - border-radius: 3px; - color: ${({ theme }) => theme.whiteTextColor}; - - &.info, - &.danger, - &.warning, - &.success { - > ul, - > ol, - > p { - margin: 0; - } - - button { - margin-left: ${({ theme }) => theme.space.small}px; - padding: 0 ${({ theme }) => theme.space.small}px; - background-color: transparent; - border: 1px solid ${({ theme }) => theme.whiteBorderColor}; - color: ${({ theme }) => theme.whiteTextColor}; - line-height: 32px; - - &:hover:not(:disabled), - &:focus:not(:disabled), - &:active:not(:disabled) { - background-color: rgba(255, 255, 255, 0.2); - border-color: ${({ theme }) => theme.whiteBorderColor}; - box-shadow: none; - } - } - } - - &.info { - background-color: ${({ theme }) => theme.infoBackgroundColor}; - } - - &.danger { - background-color: ${({ theme }) => theme.dangerBackgroundColor}; - } - - &.warning { - background-color: ${({ theme }) => theme.warningBackgroundColor}; - } - - &.success { - background-color: ${({ theme }) => theme.successBackgroundColor}; - } - - &.float-on-top { - display: flex; - align-items: center; - justify-content: center; - position: absolute; - top: 0; - left: 0; - border-radius: 0; - } -` - -export default ColoredBlock diff --git a/src/cloud/components/atoms/CustomSpinner.ts b/src/cloud/components/atoms/CustomSpinner.ts deleted file mode 100644 index e993e00474..0000000000 --- a/src/cloud/components/atoms/CustomSpinner.ts +++ /dev/null @@ -1,29 +0,0 @@ -import { keyframes } from 'styled-components' -import styled from '../../lib/styled' - -const rotate = keyframes` - from { - transform: rotate(0deg); - } - to { - transform: rotate(360deg); - } - -` -const Spinner = styled.div` - border-style: solid; - border-color: ${({ theme }) => theme.primaryBackgroundColor}; - border-right-color: transparent; - border-width: 2px; - width: 1em; - height: 1em; - display: inline-block; - border-radius: 50%; - animation: ${rotate} 0.75s linear infinite; - - &.emphasized { - border-color: ${({ theme }) => theme.emphasizedBackgroundColor}; - border-right-color: transparent; - } -` -export default Spinner diff --git a/src/cloud/components/atoms/EmojiIcon.tsx b/src/cloud/components/atoms/EmojiIcon.tsx deleted file mode 100644 index 5eda986290..0000000000 --- a/src/cloud/components/atoms/EmojiIcon.tsx +++ /dev/null @@ -1,68 +0,0 @@ -import React from 'react' -import { Emoji } from 'emoji-mart' -import IconMdi from './IconMdi' -import Flexbox from './Flexbox' -import cc from 'classcat' -import Tooltip from './Tooltip' - -interface EmojiIconProps { - emoji?: string - defaultIcon?: string - className?: string - style?: React.CSSProperties - onClick?: (event: React.MouseEvent) => void - size?: number - tooltip?: React.ReactNode -} - -const EmojiIcon = ({ - emoji, - defaultIcon, - className, - style, - size = 32, - tooltip, - onClick, -}: EmojiIconProps) => { - if (emoji == null && defaultIcon == null) { - return null - } - - if (tooltip != null) { - return ( - - - {emoji != null ? ( - - ) : ( - - )} - - - ) - } - - return ( - - {emoji != null ? ( - - ) : ( - - )} - - ) -} - -export default EmojiIcon diff --git a/src/cloud/components/atoms/Flexbox.tsx b/src/cloud/components/atoms/Flexbox.tsx deleted file mode 100644 index 9420d10bdb..0000000000 --- a/src/cloud/components/atoms/Flexbox.tsx +++ /dev/null @@ -1,176 +0,0 @@ -import React, { PropsWithChildren } from 'react' -import cc from 'classcat' -import styled from '../../lib/styled' - -interface FlexboxProps { - flex?: string - shrink?: number - grow?: number - basis?: string - wrap?: 'nowrap' | 'wrap' | 'wrap-reverse' | 'inherit' | 'initial' - justifyContent?: - | 'center' - | 'flex-start' - | 'flex-end' - | 'space-between' - | 'space-around' - | 'inherit' - | 'initial' - alignItems?: - | 'center' - | 'start' - | 'end' - | 'flex-start' - | 'flex-end' - | 'baseline' - | 'inherit' - | 'initial' - direction?: - | 'column' - | 'column-reverse' - | 'row' - | 'row-reverse' - | 'unset' - | 'inherit' - | 'initial' - style?: React.CSSProperties - className?: string - onClick?: any -} - -const Flexbox = ({ - children, - justifyContent = 'flex-start', - alignItems = 'center', - direction = 'row', - flex, - grow = 1, - shrink = 1, - basis = 'auto', - wrap = 'nowrap', - style, - className, - onClick, -}: PropsWithChildren) => ( - - {children} - -) - -const StyledFlexbox = styled.div` - min-width: 0; - display: flex; - - &.direction-unset { - flex-direction: unset; - } - &.direction-initial { - flex-direction: initial; - } - &.direction-inherit { - flex-direction: inherit; - } - &.direction-row-reverse { - flex-direction: row-reverse; - } - &.direction-column-reverse { - flex-direction: column-reverse; - } - &.direction-column { - flex-direction: column; - } - &.direction-row { - flex-direction: row; - } - &.align-center { - align-items: center; - } - &.align-start { - align-items: start; - } - &.align-end { - align-items: end; - } - &.align-flex-start { - align-items: flex-start; - } - &.align-flex-end { - align-items: flex-end; - } - &.align-baseline { - align-items: baseline; - } - &.align-inherit { - align-items: inherit; - } - &.align-initial { - align-items: initial; - } - &.justify-flex-start { - justify-content: flex-start; - } - &.justify-flex-end { - justify-content: flex-end; - } - &.justify-center { - justify-content: center; - } - &.justify-space-between { - justify-content: space-between; - } - &.justify-space-around { - justify-content: space-around; - } - &.justify-initial { - justify-content: initial; - } - &.justify-inherit { - justify-content: inherit; - } - &.wrap-nowrap { - flex-wrap: nowrap; - } - &.wrap-wrap { - flex-wrap: wrap; - } - &.wrap-wrap-reverse { - flex-wrap: wrap-reverse; - } - &.wrap-initial { - flex-wrap: initial; - } - &.wrap-inherit { - flex-wrap: inherit; - } - - &.button { - cursor: pointer; - &:hover { - color: ${({ theme }) => theme.subtleTextColor}; - } - } -` - -export default Flexbox diff --git a/src/cloud/components/atoms/HighlightedCode.tsx b/src/cloud/components/atoms/HighlightedCode.tsx deleted file mode 100644 index c9daf71c9d..0000000000 --- a/src/cloud/components/atoms/HighlightedCode.tsx +++ /dev/null @@ -1,24 +0,0 @@ -import React, { useEffect, useRef } from 'react' -import CodeMirror from '../../../cloud/lib/editor/CodeMirror' - -interface HighlightedCodeProps { - value: string -} - -const HighlightedCode = ({ value }: HighlightedCodeProps) => { - const editorRootRef = useRef(null) - useEffect(() => { - if (editorRootRef.current == null) { - return - } - CodeMirror.runMode(value, 'application/javascript', editorRootRef.current) - }, [value]) - return ( -
-  )
-}
-
-export default HighlightedCode
diff --git a/src/cloud/components/atoms/Icon.tsx b/src/cloud/components/atoms/Icon.tsx
deleted file mode 100644
index 13d39fc3ee..0000000000
--- a/src/cloud/components/atoms/Icon.tsx
+++ /dev/null
@@ -1,38 +0,0 @@
-import React from 'react'
-import { Icon as MdiIcon } from '@mdi/react'
-
-interface IconProps {
-  path: string
-  color?: string
-  size?: number
-  className?: string
-  spin?: boolean
-}
-
-const Icon = ({
-  path,
-  color = 'currentColor',
-  size,
-  className,
-  spin,
-}: IconProps) => (
-  
-)
-
-export default Icon
diff --git a/src/cloud/components/atoms/IconMdi.tsx b/src/cloud/components/atoms/IconMdi.tsx
deleted file mode 100644
index ba2fcdcffe..0000000000
--- a/src/cloud/components/atoms/IconMdi.tsx
+++ /dev/null
@@ -1,24 +0,0 @@
-import React from 'react'
-import Icon from '@mdi/react'
-
-interface IconProps {
-  path: string
-  size?: number | string
-  style?: React.CSSProperties
-  className?: string
-}
-
-const IconMdi = ({ path, style, size, className }: IconProps) => (
-  
-)
-
-export default IconMdi
diff --git a/src/cloud/components/atoms/Image.tsx b/src/cloud/components/atoms/Image.tsx
deleted file mode 100644
index be814357c5..0000000000
--- a/src/cloud/components/atoms/Image.tsx
+++ /dev/null
@@ -1,14 +0,0 @@
-import React, { CSSProperties } from 'react'
-
-interface ImageProps {
-  src: string
-  className?: string
-  style?: CSSProperties
-  alt?: string
-}
-
-const Image = ({ src, className, style, alt }: ImageProps) => {
-  return {alt}
-}
-
-export default Image
diff --git a/src/cloud/components/atoms/IntersectionAction.tsx b/src/cloud/components/atoms/IntersectionAction.tsx
deleted file mode 100644
index e15fd83237..0000000000
--- a/src/cloud/components/atoms/IntersectionAction.tsx
+++ /dev/null
@@ -1,45 +0,0 @@
-import React, { useRef, useEffect, useState } from 'react'
-import { useIntersection } from 'react-use'
-
-interface IntersectionActionProps {
-  root?: Element
-  rootMargin?: string
-  threshold?: number
-  ratio?: number
-  callback: () => void
-}
-
-const IntersectionAction = ({
-  root,
-  rootMargin,
-  threshold,
-  ratio = 1,
-  callback,
-}: IntersectionActionProps) => {
-  const ref = useRef(null)
-  const intersection = useIntersection(ref, {
-    root,
-    rootMargin,
-    threshold,
-  })
-  const [entered, setEntered] = useState(false)
-
-  useEffect(() => {
-    if (intersection == null) {
-      return
-    }
-
-    if (intersection.intersectionRatio >= ratio && !entered) {
-      setEntered(true)
-      callback()
-    }
-
-    if (intersection.intersectionRatio < ratio) {
-      setEntered(false)
-    }
-  }, [intersection, callback, ratio, entered])
-
-  return 
-} - -export default IntersectionAction diff --git a/src/cloud/components/atoms/Link/CustomLink.tsx b/src/cloud/components/atoms/Link/CustomLink.tsx deleted file mode 100644 index 359046fc9b..0000000000 --- a/src/cloud/components/atoms/Link/CustomLink.tsx +++ /dev/null @@ -1,124 +0,0 @@ -import React, { useState, MouseEvent, useCallback } from 'react' -import cc from 'classcat' -import { ParsedUrlQuery } from 'querystring' -import styled from '../../../lib/styled' -import { - primaryButtonStyle, - baseButtonStyle, -} from '../../../lib/styled/styleFunctions' -import { stringifyUrl } from '../../../lib/utils/string' -import { useRouter } from '../../../lib/router' - -export interface UrlLike { - pathname: string - query?: ParsedUrlQuery -} - -type CustomLinkProps = { - className?: string - style?: React.CSSProperties - hoverStyle?: React.CSSProperties - children: React.ReactNode - active?: boolean - block?: boolean - variant?: 'link' | 'primary' - disabled?: boolean - external?: boolean - decoration?: boolean - isReactLink?: boolean - target?: string - rel?: string - href: string | UrlLike - id?: string - onClick?: (event: MouseEvent) => void -} - -const CustomLink = (props: CustomLinkProps) => { - const [hovered, toggleHover] = useState(false) - const { push } = useRouter() - - const { - external = false, - className, - href, - disabled, - active, - children, - block, - variant = 'link', - decoration = false, - style, - id, - rel, - target, - onClick, - } = props - - const navigate = useCallback( - (event: MouseEvent) => { - event.preventDefault() - push(href) - }, - [push, href] - ) - - return ( - toggleHover} - onMouseLeave={() => toggleHover} - id={id} - onClick={onClick != null ? onClick : external ? undefined : navigate} - > - {children} - - ) -} - -export default CustomLink - -const StyledInternalLink = styled.a` - &.type-link { - text-decoration: none; - transition: 200ms color; - color: ${({ theme }) => theme.primaryTextColor}; - - &:hover, - &:focus, - &:active, - &.active { - color: ${({ theme }) => theme.darkerPrimaryBackgroundColor}; - } - } - - &.btn { - margin: ${({ theme }) => theme.space.xsmall}px 0; - padding: 0 ${({ theme }) => theme.space.default}px; - border-radius: 2px; - cursor: pointer; - font-size: ${({ theme }) => theme.fontSizes.default}px; - line-height: 40px; - text-decoration: none; - } - - &.type-primary { - ${baseButtonStyle} - ${primaryButtonStyle} - } - - &.d-block { - display: inline-block; - } -` diff --git a/src/cloud/components/atoms/PageTitle.tsx b/src/cloud/components/atoms/PageTitle.tsx deleted file mode 100644 index 8d167167a3..0000000000 --- a/src/cloud/components/atoms/PageTitle.tsx +++ /dev/null @@ -1,12 +0,0 @@ -import styled from '../../lib/styled' - -const PageTitle = styled.h1` - display: flex; - align-items: center; - max-width: 500px; - font-size: ${({ theme }) => theme.fontSizes.xxxlarge}px; - font-weight: 400; - margin: 0; -` - -export default PageTitle diff --git a/src/cloud/components/atoms/Select/CustomSelect.tsx b/src/cloud/components/atoms/Select/CustomSelect.tsx deleted file mode 100644 index aac6f4929d..0000000000 --- a/src/cloud/components/atoms/Select/CustomSelect.tsx +++ /dev/null @@ -1,173 +0,0 @@ -import React, { useMemo } from 'react' -import Select from 'react-select' -import { useSettings } from '../../../lib/stores/settings' -import cc from 'classcat' -import styled, { selectTheme } from '../../../lib/styled' - -export interface CustomSelectOption { - label: string | React.ReactNode - value: string - data: any -} - -interface ReactSelectStates { - isDisabled: boolean - isFocused: boolean - isSelected: boolean -} - -interface StyledSelectProps { - options: CustomSelectOption[] - value?: CustomSelectOption | CustomSelectOption[] - onChange: (val: any) => void - closeMenuOnSelect?: boolean - className?: string - classNamePrefix?: string - isDisabled?: boolean - isLoading?: boolean - isMulti?: boolean - isSearchable?: boolean - name?: string - style?: React.CSSProperties - filterOption?: (option: CustomSelectOption, rawInput: string) => boolean - onMenuOpen?: () => void -} - -const CustomSelect = ({ - options, - value, - onChange, - closeMenuOnSelect = true, - className, - classNamePrefix = 'select', - isDisabled = false, - isLoading = false, - isMulti = false, - isSearchable = false, - name, - style, - filterOption, - onMenuOpen, -}: StyledSelectProps) => { - const { settings } = useSettings() - - const customSelectStyle = useMemo(() => { - const appTheme = selectTheme(settings['general.theme']) - return { - control: (styles: any, { isFocused }: ReactSelectStates) => ({ - ...styles, - width: '100%', - height: '40px', - backgroundColor: appTheme.subtleBackgroundColor, - color: appTheme.subtleTextColor, - border: 'none', - boxShadow: isFocused - ? `0 0 0 2px ${appTheme.primaryShadowColor};` - : null, - }), - singleValue: (styles: any) => ({ - ...styles, - color: appTheme.subtleTextColor, - }), - input: (styles: any, { isDisabled }: ReactSelectStates) => ({ - ...styles, - opacity: isDisabled ? 0.6 : 'inherit', - color: appTheme.emphasizedTextColor, - }), - multiValue: (styles: any) => ({ - ...styles, - backgroundColor: appTheme.subtleBackgroundColor, - }), - multiValueLabel: (styles: any) => ({ - ...styles, - color: appTheme.subtleTextColor, - }), - multiValueRemove: (styles: any) => ({ - ...styles, - color: appTheme.subtleTextColor, - ':hover': { - color: appTheme.primaryBackgroundColor, - backgroundColor: appTheme.emphasizedBackgroundColor, - }, - }), - valueContainer: (styles: any) => ({ - ...styles, - color: appTheme.subtleTextColor, - }), - dropdownIndicator: (styles: any) => ({ - ...styles, - color: `${appTheme.subtleTextColor} !important`, - }), - menu: (styles: any) => ({ - ...styles, - background: appTheme.baseBackgroundColor, - boxShadow: appTheme.baseShadowColor, - }), - option: ( - styles: any, - { isDisabled, isFocused, isSelected }: ReactSelectStates - ) => { - return { - ...styles, - transition: isFocused ? '0.2s' : null, - backgroundColor: isDisabled - ? null - : isSelected - ? null - : isFocused - ? appTheme.subtleBackgroundColor - : null, - color: isDisabled - ? appTheme.subtleTextColor - : isFocused - ? appTheme.emphasizedTextColor - : appTheme.subtleTextColor, - cursor: isDisabled ? 'not-allowed' : 'default', - ':active': { - ...styles[':active'], - backgroundColor: !isDisabled && appTheme.emphasizedBackgroundColor, - }, - ':hover': { - ...styles[':hover'], - backgroundColor: appTheme.subtleBackgroundColor, - transition: '0.2s', - }, - } - }, - } - }, [settings]) - - return ( - - onChange(event.target.value as T)} - value={value} - id={elementId} - > - {options.map((option) => ( - - ))} - - - ) -} - -export const StyledSimpleSelect = styled.div` - label { - margin: 0; - font-size: ${({ theme }) => theme.fontSizes.small}px; - } - display: flex; - justify-content: flex-start; - margin-right: ${({ theme }) => theme.space.xsmall}px; - color: ${({ theme }) => theme.subtleTextColor}; - align-items: center; - select { - background: none; - color: ${({ theme }) => theme.subtleTextColor}; - font-size: ${({ theme }) => theme.fontSizes.small}px; - height: auto; - border: 0; - cursor: pointer; - transition: 0.2s; - &:hover, - &.active { - color: ${({ theme }) => theme.emphasizedTextColor}; - } - &:focus { - background-color: ${({ theme }) => theme.subtleBackgroundColor}; - } - } -` - -export default SimpleSelect diff --git a/src/cloud/components/atoms/SmallButton.tsx b/src/cloud/components/atoms/SmallButton.tsx deleted file mode 100644 index 3e3da1d0f7..0000000000 --- a/src/cloud/components/atoms/SmallButton.tsx +++ /dev/null @@ -1,20 +0,0 @@ -import React, { CSSProperties } from 'react' -import CustomButton from './buttons/CustomButton' - -const SmallButtonStyle: CSSProperties = { - lineHeight: 'normal', - padding: '0 8px', -} - -const SmallButton = ({ - children, - ...rest -}: Parameters[0]) => { - return ( - - {children} - - ) -} - -export default SmallButton diff --git a/src/cloud/components/atoms/Spinner.tsx b/src/cloud/components/atoms/Spinner.tsx deleted file mode 100644 index 94aa1df0db..0000000000 --- a/src/cloud/components/atoms/Spinner.tsx +++ /dev/null @@ -1,79 +0,0 @@ -import React from 'react' -import cc from 'classcat' -import styled, { rotateKeyframe } from '../../lib/styled' -import { baseIconStyle } from '../../lib/styled/styleFunctions' - -interface CustomIconProps { - viewbox?: string - color?: string - size?: string | number - width?: string | number - height?: string | number - className?: string - style?: React.CSSProperties -} - -export const Spinner = (props: CustomIconProps) => ( - - - - - -) - -const StyledCustomIcon = styled.div` - display: inline-block; - color: currentColor; - background-color: transparent; - border: none; - vertical-align: middle; - - svg { - vertical-align: sub; - - &.icon { - ${baseIconStyle} - position: absolute; - top: ${({ theme }) => theme.space.xxsmall}px; - left: ${({ theme }) => theme.space.xxsmall}px; - font-size: ${({ theme }) => theme.fontSizes.default}px; - z-index: 0; - pointer-events: none; - color: ${({ theme }) => theme.subtleIconColor}; - opacity: 0.4; - } - - &.rotate { - -webkit-transition: all 1s ease; - -moz-transition: all 1s ease; - -o-transition: all 1s ease; - -ms-transition: all 1s ease; - transition: all 1s ease; - transform-box: fill-box; - transform-origin: center; - animation: ${rotateKeyframe} 4s linear infinite; - } - - &.relative { - position: relative; - top: 0; - bottom: 0; - vertical-align: middle; - } - } -` diff --git a/src/cloud/components/atoms/TextInput.tsx b/src/cloud/components/atoms/TextInput.tsx deleted file mode 100644 index a3aa0bfcd3..0000000000 --- a/src/cloud/components/atoms/TextInput.tsx +++ /dev/null @@ -1,174 +0,0 @@ -import React, { - FC, - ChangeEventHandler, - MouseEventHandler, - FocusEventHandler, - DragEventHandler, -} from 'react' -import styled from '../../lib/styled' -import cc from 'classcat' -import { - UnroundedParamTypes, - createUnroundedStyle, -} from '../../lib/styled/unrounded' - -const { getUnroundedClassNames, unroundedStyle } = createUnroundedStyle( - 'text-input' -) - -export interface TextInputProps { - size?: 'sm' | 'md' | 'lg' - block?: boolean - unrounded?: UnroundedParamTypes - - type: - | 'text' - | 'number' - | 'email' - | 'datetime-local' - | 'month' - | 'date' - | 'search' - | 'password' - | 'url' - | 'tel' - | 'week' - className?: string - disabled?: boolean - placeholder?: string - title?: string - value?: string - defaultValue?: string - readOnly?: boolean - onChange?: ChangeEventHandler - onClick?: MouseEventHandler - onMouseUp?: MouseEventHandler - onMouseDown?: MouseEventHandler - onMouseMove?: MouseEventHandler - onMouseOver?: MouseEventHandler - onMouseOut?: MouseEventHandler - onMouseEnter?: MouseEventHandler - onMouseLeave?: MouseEventHandler - onDoubleClick?: MouseEventHandler - onContextMenu?: MouseEventHandler - onFocus?: FocusEventHandler - onDrag?: DragEventHandler - onDragStart?: DragEventHandler - onDragEnd?: DragEventHandler - onDrop?: DragEventHandler -} - -const TextInput: FC = ({ - value, - className, - size = 'md', - unrounded, - block, - type, - placeholder, - title, - defaultValue, - readOnly, - onChange, - onClick, - onMouseUp, - onMouseDown, - onMouseMove, - onMouseOver, - onMouseOut, - onMouseEnter, - onMouseLeave, - onDoubleClick, - onContextMenu, - onFocus, - onDrag, - onDragStart, - onDragEnd, - onDrop, -}) => { - return ( - - ) -} - -export default TextInput - -const StyledInput = styled.input` - padding: 0 ${({ theme }) => theme.space.xsmall}px; - border-radius: 2px; - cursor: pointer; - font-size: ${({ theme }) => theme.fontSizes.small}px; - height: 36px; - outline: none; - border-radius: 4px; - border-color: transparent; - border-width: 1px; - border-style: solid; - box-sizing: border-box; - - background: none; - border: 1px solid ${({ theme }) => theme.subtleBorderColor}; - color: ${({ theme }) => theme.emphasizedTextColor}; - - & + * { - margin-left: 5px; - &.block { - margin-left: 0; - } - } - - &:disabled { - cursor: not-allowed; - opacity: 0.5; - } - - ${unroundedStyle} - - &.size-lg { - height: 44px; - padding: 0 ${({ theme }) => theme.space.small}px; - } - - &.size-sm { - height: 28px; - padding: 0 ${({ theme }) => theme.space.xsmall}px; - } - - &.block { - display: flex; - width: 100%; - } - - &:focus { - border-color: ${({ theme }) => theme.primaryBorderColor}; - } -` diff --git a/src/cloud/components/atoms/Tooltip.tsx b/src/cloud/components/atoms/Tooltip.tsx deleted file mode 100644 index 204cfa7bcc..0000000000 --- a/src/cloud/components/atoms/Tooltip.tsx +++ /dev/null @@ -1,98 +0,0 @@ -import React, { useState } from 'react' -import styled from '../../lib/styled' - -interface TooltipProps { - children: React.ReactNode - className?: string - style?: React.CSSProperties - side?: 'top' | 'left' | 'right' | 'bottom' | 'bottom-right' - tooltip: React.ReactNode - tagName?: 'span' | 'div' | 'p' | 'li' -} - -const Tooltip = ({ - children, - tooltip, - style, - className, - tagName = 'div', - side = 'bottom', -}: TooltipProps) => { - const [open, setOpen] = useState(false) - - const Tag = tagName - - return ( - setOpen(true)} - onMouseLeave={() => setOpen(false)} - onClick={() => setOpen(false)} - style={{ position: 'relative', cursor: 'pointer', display: 'flex' }} - className={className} - > - {children} - {open && ( - -
- {tooltip} -
-
- )} -
- ) -} - -export default Tooltip - -const StyledTooltip = styled.div` - position: absolute; - top: 100%; - left: 50%; - transform: translateX(-50%); - z-index: 100; - margin-top: 9px; - width: max-content; - min-width: 40px; - text-align: center; - - &.top { - top: initial; - bottom: 120%; - - &::after { - border-bottom: 0; - border-top: 9px solid ${({ theme }) => theme.subtleIconColor}; - bottom: -9px; - top: initial; - } - } - - &.bottom-right { - left: 100%; - transform: translateX(-5%); - } - - > div { - background-color: ${({ theme }) => theme.subtleBackgroundColor}; - padding: ${({ theme }) => theme.space.xxsmall}px - ${({ theme }) => theme.space.xsmall}px; - border: 1px solid ${({ theme }) => theme.secondaryBorderColor}; - border-radius: 5px; - font-size: ${({ theme }) => theme.fontSizes.xsmall}px; - color: ${({ theme }) => theme.baseTextColor}; - - .tooltip-text { - background-color: none; - padding-right: ${({ theme }) => theme.space.default}px; - } - - .tooltip-command { - display: inline-block; - line-height: 18px; - padding: 0 ${({ theme }) => theme.space.xxsmall}px; - border-radius: 2px; - border: 1px solid ${({ theme }) => theme.secondaryBorderColor}; - color: ${({ theme }) => theme.subtleTextColor}; - } - } -` diff --git a/src/cloud/components/atoms/TopBarSideNavHideButton.tsx b/src/cloud/components/atoms/TopBarSideNavHideButton.tsx deleted file mode 100644 index 844271af7d..0000000000 --- a/src/cloud/components/atoms/TopBarSideNavHideButton.tsx +++ /dev/null @@ -1,36 +0,0 @@ -import React from 'react' -import styled from '../../lib/styled' -import IconMdi from './IconMdi' -import { mdiMenu, mdiChevronDoubleRight } from '@mdi/js' -import { usePreferences } from '../../lib/stores/preferences' -import { defaultTopbarIndex } from '../organisms/RightSideTopBar/styled' -import { topbarIconButtonStyle } from '../../lib/styled/styleFunctions' - -const TopBarSideNavHideButton = () => { - const { - preferences, - toggleHideSidebar, - hoverSidebarOff, - hoverSidebarOn, - } = usePreferences() - - return ( - hoverSidebarOn()} - onMouseLeave={() => hoverSidebarOff()} - > - - - ) -} - -const StyledButton = styled.button` - ${topbarIconButtonStyle} - z-index: ${defaultTopbarIndex + 1}; -` - -export default TopBarSideNavHideButton diff --git a/src/cloud/components/atoms/buttons/ButtonDropdown.tsx b/src/cloud/components/atoms/buttons/ButtonDropdown.tsx deleted file mode 100644 index ab072fa672..0000000000 --- a/src/cloud/components/atoms/buttons/ButtonDropdown.tsx +++ /dev/null @@ -1,73 +0,0 @@ -import React, { useState } from 'react' -import CustomButton, { PrimaryButtonProps } from './CustomButton' -import styled from '../../../lib/styled' -import ButtonGroup from './ButtonGroup' -import { StyledContextMenuContainer } from '../../organisms/Topbar/Controls/ControlsContextMenu/styled' -import ControlsContextMenuBackground from '../../organisms/Topbar/Controls/ControlsContextMenu/ControlsContextMenuBackground' - -interface ButtonDropdownProps extends PrimaryButtonProps { - title: string - children?: React.ReactNode -} - -const ButtonDropdown = ({ - title, - children, - variant, - ...rest -}: ButtonDropdownProps) => { - const [open, setOpen] = useState(false) - return ( - - - - {title} - - setOpen((prev) => !prev)} - > - - - - {open && ( - <> - setOpen(false)} - /> - {children} - - )} - - ) -} - -const StyledButtonDropdown = styled.div` - .btn-trigger { - border-left: 1px solid ${({ theme }) => theme.darkPrimaryBorderColor}; - } -` - -const CaratDown = styled.span` - width: 1px; - height: 1px; - padding: 0; - white-space: nowrap; - border: 0; - - &::after { - display: inline-block; - width: 0; - height: 0; - vertical-align: 0.255em; - content: ''; - border-top: 0.3em solid white; - border-right: 0.3em solid transparent; - border-bottom: 0; - border-left: 0.3em solid transparent; - } -` - -export default ButtonDropdown diff --git a/src/cloud/components/atoms/buttons/ButtonGroup.tsx b/src/cloud/components/atoms/buttons/ButtonGroup.tsx deleted file mode 100644 index 5b69ca67d8..0000000000 --- a/src/cloud/components/atoms/buttons/ButtonGroup.tsx +++ /dev/null @@ -1,31 +0,0 @@ -import React from 'react' -import styled from '../../../lib/styled' - -interface ButtonGroupProps { - children: React.ReactNode -} - -const ButtonGroup = ({ children }: ButtonGroupProps) => { - return {children} -} - -const StyledButtonGroup = styled.div` - display: inline-flex; - position: relative; - - & > button:first-child { - border-top-right-radius: 0; - border-bottom-right-radius: 0; - } - - & > button:last-child { - border-top-left-radius: 0; - border-bottom-left-radius: 0; - } - - & > button:not(:first-child):not(:last-child) { - border-radius: 0; - } -` - -export default ButtonGroup diff --git a/src/cloud/components/atoms/buttons/CustomButton.tsx b/src/cloud/components/atoms/buttons/CustomButton.tsx deleted file mode 100644 index 8d5f9430c2..0000000000 --- a/src/cloud/components/atoms/buttons/CustomButton.tsx +++ /dev/null @@ -1,139 +0,0 @@ -import React, { CSSProperties } from 'react' -import styled from '../../../lib/styled' -import { - primaryButtonStyle, - secondaryButtonStyle, - dangerButtonStyle, - transparentButtonStyle, - baseButtonStyle, - warningButtonStyle, - infoButtonStyle, - lpPrimaryButtonStyle, - blueButtonStyle, - inverseSecondaryButtonStyle, -} from '../../../lib/styled/styleFunctions' -import cc from 'classcat' - -export interface PrimaryButtonProps { - disabled?: boolean - active?: boolean - variant?: - | 'primary' - | 'lp-primary' - | 'secondary' - | 'inverse-secondary' - | 'danger' - | 'warning' - | 'info' - | 'transparent' - | 'blue' - type?: 'submit' | 'reset' | 'button' - onClick?: (event: React.MouseEvent) => void - className?: string - style?: CSSProperties - tabIndex?: number -} - -const CustomButton = ({ - type = 'button', - variant = 'primary', - active, - onClick, - className, - style, - disabled, - children, - tabIndex = 0, -}: React.PropsWithChildren) => { - return ( - - {children} - - ) -} - -export default CustomButton - -const CustomButtonStyle = styled.button` - display: inline-block; - text-decoration: none; - position: relative; - - &:disabled { - pointer-events: none; - opacity: 0.6; - } - - svg.icon { - position: relative !important; - top: 0 !important; - left: 0 !important; - color: currentColor; - transform: none !important; - line-height: inherit !important; - } - - &.btn-primary { - ${baseButtonStyle} - ${primaryButtonStyle} - } - - &.btn-lp-primary { - ${baseButtonStyle} - ${lpPrimaryButtonStyle} - } - - &.btn-secondary { - ${baseButtonStyle} - ${secondaryButtonStyle} - } - - &.btn-inverse-secondary { - ${baseButtonStyle} - ${inverseSecondaryButtonStyle} - } - - &.btn-danger { - ${baseButtonStyle} - ${dangerButtonStyle} - } - - &.btn-warning { - ${baseButtonStyle} - ${warningButtonStyle} - } - - &.btn-info { - ${baseButtonStyle} - ${infoButtonStyle} - } - - &.btn-transparent { - ${baseButtonStyle} - ${transparentButtonStyle} - } - - &.btn-blue { - ${baseButtonStyle} - ${blueButtonStyle} - } - - &.size-l { - min-width: 130px; - } - - &.rounded { - border-radius: 25px; - } - - &.mr-2 { - margin-right: ${({ theme }) => theme.space.small}px; - } -` diff --git a/src/cloud/components/atoms/buttons/ScrollUpButton.tsx b/src/cloud/components/atoms/buttons/ScrollUpButton.tsx deleted file mode 100644 index 53c4df5a3f..0000000000 --- a/src/cloud/components/atoms/buttons/ScrollUpButton.tsx +++ /dev/null @@ -1,48 +0,0 @@ -import React from 'react' -import { mdiArrowUpBold } from '@mdi/js' -import cc from 'classcat' -import IconMdi from '../IconMdi' -import styled from '../../../lib/styled' -import { - primaryButtonStyle, - baseButtonStyle, -} from '../../../lib/styled/styleFunctions' - -interface ScrollUpButtonProps { - active: boolean -} - -const ScrollUpButton = ({ active }: ScrollUpButtonProps) => { - return ( - { - document.body.scrollTop = 0 - document.documentElement.scrollTop = 0 - }} - > - - - ) -} - -const StyledScrollUpButton = styled.button` - ${baseButtonStyle} - ${primaryButtonStyle} - height: 45px; - width: 45px; - border-radius: 6px; - position: fixed; - right: ${({ theme }) => theme.space.xlarge * -2}px; - bottom: ${({ theme }) => theme.space.default}px; - -webkit-transition: all 0.3s ease-out; - -moz-transition: all 0.3s ease-out; - -o-transition: all 0.3s ease-out; - transition: all 0.3s ease-out; - - &.active { - right: ${({ theme }) => theme.space.default}px; - } -` - -export default ScrollUpButton diff --git a/src/cloud/components/molecules/InviteCTAButton.tsx b/src/cloud/components/buttons/InviteCTAButton.tsx similarity index 93% rename from src/cloud/components/molecules/InviteCTAButton.tsx rename to src/cloud/components/buttons/InviteCTAButton.tsx index c2d37ffa1d..b83f5c1be8 100644 --- a/src/cloud/components/molecules/InviteCTAButton.tsx +++ b/src/cloud/components/buttons/InviteCTAButton.tsx @@ -1,9 +1,9 @@ import React, { useCallback, useState } from 'react' import { useEffectOnce } from 'react-use' -import Button, { LoadingButton } from '../../../shared/components/atoms/Button' -import useApi from '../../../shared/lib/hooks/useApi' -import { useModal } from '../../../shared/lib/stores/modal' -import styled from '../../../shared/lib/styled' +import Button, { LoadingButton } from '../../../design/components/atoms/Button' +import useApi from '../../../design/lib/hooks/useApi' +import { useModal } from '../../../design/lib/stores/modal' +import styled from '../../../design/lib/styled' import { getUserEditRequests, sendEditRequest } from '../../api/editRequests' import { trackEvent } from '../../api/track' import { MixpanelActionTrackTypes } from '../../interfaces/analytics/mixpanel' diff --git a/src/cloud/components/molecules/NewDocButton.tsx b/src/cloud/components/buttons/NewDocButton.tsx similarity index 86% rename from src/cloud/components/molecules/NewDocButton.tsx rename to src/cloud/components/buttons/NewDocButton.tsx index ecb953abb2..efc354b2de 100644 --- a/src/cloud/components/molecules/NewDocButton.tsx +++ b/src/cloud/components/buttons/NewDocButton.tsx @@ -1,14 +1,14 @@ import { mdiPencilBoxMultipleOutline, mdiTextBoxPlus } from '@mdi/js' import React from 'react' -import SidebarButton from '../../../shared/components/organisms/Sidebar/atoms/SidebarButton' -import { MenuTypes } from '../../../shared/lib/stores/contextMenu' -import { useModal } from '../../../shared/lib/stores/modal' +import SidebarButton from '../../../design/components/organisms/Sidebar/atoms/SidebarButton' +import { MenuTypes } from '../../../design/lib/stores/contextMenu' +import { useModal } from '../../../design/lib/stores/modal' import { SerializedTeam } from '../../interfaces/db/team' import { useCloudResourceModals } from '../../lib/hooks/useCloudResourceModals' import { useI18n } from '../../lib/hooks/useI18n' import { lngKeys } from '../../lib/i18n/types' import { useNav } from '../../lib/stores/nav' -import TemplatesModal from '../organisms/Modal/contents/TemplatesModal' +import TemplatesModal from '../Modal/contents/TemplatesModal' const NewDocButton = ({ team }: { team: SerializedTeam }) => { const { diff --git a/src/cloud/components/atoms/buttons/login/GithubLoginButton.tsx b/src/cloud/components/buttons/login/GithubLoginButton.tsx similarity index 83% rename from src/cloud/components/atoms/buttons/login/GithubLoginButton.tsx rename to src/cloud/components/buttons/login/GithubLoginButton.tsx index d8ef9d03e0..e4f2c57716 100644 --- a/src/cloud/components/atoms/buttons/login/GithubLoginButton.tsx +++ b/src/cloud/components/buttons/login/GithubLoginButton.tsx @@ -1,10 +1,10 @@ import React, { useState } from 'react' import cc from 'classcat' -import styled from '../../../../lib/styled' import { stringify } from 'querystring' -import IconMdi from '../../IconMdi' import { mdiGithub } from '@mdi/js' -import { boostHubBaseUrl } from '../../../../lib/consts' +import { boostHubBaseUrl } from '../../../lib/consts' +import styled from '../../../../design/lib/styled' +import Icon from '../../../../design/components/atoms/Icon' interface GithubLoginButtonProps { query?: any @@ -36,7 +36,7 @@ const GithubLoginButton = ({ }} href={loginHref} > - + {sending ? Signing in... : Continue with GitHub} ) @@ -56,7 +56,7 @@ const StyledGithubButton = styled.a` border-radius: 4px; background-color: #24292e; color: #fff; - font-size: ${({ theme }) => theme.fontSizes.small}px; + font-size: ${({ theme }) => theme.sizes.fonts.sm}px; align-items: center; outline: 0; @@ -77,7 +77,7 @@ const StyledGithubButton = styled.a` } svg { font-size: 26px; - margin-right: ${({ theme }) => theme.space.xsmall}px; + margin-right: ${({ theme }) => theme.sizes.spaces.xsm}px; } span { display: inline-block; diff --git a/src/cloud/components/atoms/buttons/login/GoogleLoginButton.tsx b/src/cloud/components/buttons/login/GoogleLoginButton.tsx similarity index 89% rename from src/cloud/components/atoms/buttons/login/GoogleLoginButton.tsx rename to src/cloud/components/buttons/login/GoogleLoginButton.tsx index 025bf88cbb..9b044d77c1 100644 --- a/src/cloud/components/atoms/buttons/login/GoogleLoginButton.tsx +++ b/src/cloud/components/buttons/login/GoogleLoginButton.tsx @@ -1,11 +1,11 @@ import React, { useState, useCallback } from 'react' import cc from 'classcat' -import styled from '../../../../lib/styled' import GoogleLogin from 'react-google-login' -import { postGoogleLoginCallback } from '../../../../api/auth/google' -import { useRouter } from '../../../../lib/router' -import IconMdi from '../../IconMdi' +import { postGoogleLoginCallback } from '../../../api/auth/google' +import { useRouter } from '../../../lib/router' import { mdiGoogle } from '@mdi/js' +import styled from '../../../../design/lib/styled' +import Icon from '../../../../design/components/atoms/Icon' interface GoogleLoginButtonProps { redirectTo?: string @@ -91,7 +91,7 @@ const GoogleLoginButton = ({ style={style} className={cc(['login-google-btn g-signin2', className])} > - + {sending ? ( Signing in... ) : ( @@ -118,7 +118,7 @@ const StyledGoogleButton = styled.button` border-radius: 4px; background-color: #c5544c; color: #fff; - font-size: ${({ theme }) => theme.fontSizes.small}px; + font-size: ${({ theme }) => theme.sizes.fonts.sm}px; outline: none !important; &:disabled { @@ -136,7 +136,7 @@ const StyledGoogleButton = styled.button` } svg { font-size: 24px; - margin-right: ${({ theme }) => theme.space.xsmall}px; + margin-right: ${({ theme }) => theme.sizes.spaces.xsm}px; } span { display: inline-block; diff --git a/src/cloud/components/organisms/error/ErrorPage.tsx b/src/cloud/components/error/ErrorPage.tsx similarity index 75% rename from src/cloud/components/organisms/error/ErrorPage.tsx rename to src/cloud/components/error/ErrorPage.tsx index aa88f845ed..f2a69325bb 100644 --- a/src/cloud/components/organisms/error/ErrorPage.tsx +++ b/src/cloud/components/error/ErrorPage.tsx @@ -1,15 +1,16 @@ import React from 'react' -import Page from '../../Page' -import ErrorSection from './ErrorSection' -import styled, { darkTheme } from '../../../lib/styled' -import { useGlobalData } from '../../../lib/stores/globalData' -import { useRouter } from '../../../lib/router' -import ColoredBlock from '../../atoms/ColoredBlock' +import Page from '../Page' +import { useGlobalData } from '../../lib/stores/globalData' +import { useRouter } from '../../lib/router' import { ThemeProvider } from 'styled-components' -import ButtonLink from '../../atoms/ButtonLink' -import SignInForm from '../../molecules/SignInForm' -import { nodeEnv } from '../../../lib/consts' -import { usingElectron } from '../../../lib/stores/electron' +import SignInForm from '../SignInForm' +import { nodeEnv } from '../../lib/consts' +import { usingElectron } from '../../lib/stores/electron' +import { darkTheme } from '../../../design/lib/styled/dark' +import styled from '../../../design/lib/styled' +import ColoredBlock from '../../../design/components/atoms/ColoredBlock' +import Button from '../../../design/components/atoms/Button' +import ErrorSection from './ErrorSection' interface ErrorPageProps { error: Error @@ -52,35 +53,25 @@ const ErrorPage = ({ error }: ErrorPageProps) => { /> {usingElectron || statusCode == null ? ( - { location.reload() }} - style={{ - display: 'flex', - margin: '40px auto 20px', - width: 200, - }} > Reload - + ) : ( - { window.location.href = homeUrl }} - style={{ - display: 'flex', - margin: '40px auto 20px', - width: 200, - }} > {currentUser == null ? 'Go to homepage' : 'Go back to your default space'} - + )} {currentUser == null && statusCode === 401 && (
diff --git a/src/cloud/components/organisms/error/ErrorSection.tsx b/src/cloud/components/error/ErrorSection.tsx similarity index 77% rename from src/cloud/components/organisms/error/ErrorSection.tsx rename to src/cloud/components/error/ErrorSection.tsx index f42005b293..ea9251a88b 100644 --- a/src/cloud/components/organisms/error/ErrorSection.tsx +++ b/src/cloud/components/error/ErrorSection.tsx @@ -1,5 +1,5 @@ import React from 'react' -import styled from '../../../lib/styled' +import styled from '../../../design/lib/styled' interface ErrorSectionProps { statusCode?: number @@ -29,13 +29,13 @@ const StyledErrorSection = styled.div` border: 1px solid red; background: rgba(200, 0, 0, 0.6); color: #fff; - padding: ${({ theme }) => theme.space.xsmall}px 2%; + padding: ${({ theme }) => theme.sizes.spaces.xsm}px 2%; border-radius: 5px; width: 100%; margin-bottom: 15px; h1 { - padding: ${({ theme }) => theme.space.xxsmall}px 0; + padding: ${({ theme }) => theme.sizes.spaces.xsm}px 0; margin: 0; } @@ -45,7 +45,7 @@ const StyledErrorSection = styled.div` pre { overflow: auto; - padding-bottom: ${({ theme }) => theme.space.xsmall}px; + padding-bottom: ${({ theme }) => theme.sizes.spaces.xsm}px; code { } } diff --git a/src/cloud/components/atoms/homepage/IntegrationServiceImage.tsx b/src/cloud/components/homepage/IntegrationServiceImage.tsx similarity index 92% rename from src/cloud/components/atoms/homepage/IntegrationServiceImage.tsx rename to src/cloud/components/homepage/IntegrationServiceImage.tsx index c1ff883542..3961261dbe 100644 --- a/src/cloud/components/atoms/homepage/IntegrationServiceImage.tsx +++ b/src/cloud/components/homepage/IntegrationServiceImage.tsx @@ -1,5 +1,5 @@ import React from 'react' -import styled from '../../../lib/styled' +import styled from '../../../design/lib/styled' interface IntegrationServiceImageProps { src: string diff --git a/src/cloud/components/atoms/homepage/PageContainer.tsx b/src/cloud/components/homepage/PageContainer.tsx similarity index 89% rename from src/cloud/components/atoms/homepage/PageContainer.tsx rename to src/cloud/components/homepage/PageContainer.tsx index eafc874d8e..d0580052ca 100644 --- a/src/cloud/components/atoms/homepage/PageContainer.tsx +++ b/src/cloud/components/homepage/PageContainer.tsx @@ -1,5 +1,5 @@ import React from 'react' -import styled from '../../../lib/styled' +import styled from '../../../design/lib/styled' const PageContainer: React.FC = ({ children }) => { return {children} diff --git a/src/cloud/components/layouts/Contents.tsx b/src/cloud/components/layouts/Contents.tsx deleted file mode 100644 index 32815eaba8..0000000000 --- a/src/cloud/components/layouts/Contents.tsx +++ /dev/null @@ -1,14 +0,0 @@ -import styled from '../../lib/styled' - -const Contents = styled.div` - display: flex; - justify-content: center; - align-items: center; - height: 100vh; - - > div { - width: 100%; - } -` - -export default Contents diff --git a/src/cloud/components/layouts/DefaultLayout.tsx b/src/cloud/components/layouts/DefaultLayout.tsx deleted file mode 100644 index 52876636ee..0000000000 --- a/src/cloud/components/layouts/DefaultLayout.tsx +++ /dev/null @@ -1,9 +0,0 @@ -import React from 'react' - -const DefaultLayout = (props: React.PropsWithChildren<{}>) => ( -
{props.children}
-) - -export const LazyDefaultLayout = DefaultLayout - -export default DefaultLayout diff --git a/src/cloud/components/layouts/DocEditLayout.tsx b/src/cloud/components/layouts/DocEditLayout.tsx deleted file mode 100644 index 77ef2f423d..0000000000 --- a/src/cloud/components/layouts/DocEditLayout.tsx +++ /dev/null @@ -1,115 +0,0 @@ -import React from 'react' -import styled from '../../lib/styled' - -export type LayoutMode = 'split' | 'preview' | 'editor' - -interface DocEditLayoutProps { - title: React.ReactNode - actionBar: React.ReactNode - editor: React.ReactNode - preview: React.ReactNode - before?: React.ReactNode - mode: 'split' | 'preview' | 'editor' -} - -const DocEditLayout = ({ - title, - actionBar, - editor, - mode, - preview, - before, -}: DocEditLayoutProps) => { - return ( - <> - - {title} - {actionBar} - - {before} - - - {editor} - - {(mode === 'preview' || mode === 'split') && ( - {preview} - )} - - - ) -} - -const StyledEditorHead = styled.div` - display: flex; - justify-content: space-between; - align-items: center; - margin: ${({ theme }) => theme.space.small}px 0; -` - -const StyledEditorWrapper = styled.div` - height: auto; - width: 50%; - border-right: 1px solid ${({ theme }) => theme.baseBorderColor}; - margin-right: 5px; - - &.layout-editor { - width: 100%; - } - - &.layout-preview { - display: none; - } -` - -const StyledPreview = styled.div` - height: 100%; - overflow: auto; - width: 50%; - - &.layout-split { - width: 50%; - } - - &.layout-preview { - width: 100%; - } -` - -const StyledEditor = styled.div` - position: relative; - width: 100%; - top: 0; - bottom: 0px; - - display: flex; - min-height: 0; - height: auto; - flex-grow: 1; - - & .CodeMirrorWrapper { - height: 100%; - word-break: break-word; - } - - & .CodeMirror { - width: 100%; - height: 100%; - & .remote-caret { - position: relative; - border: 1px solid; - & > div { - display: none; - } - } - } - - .CodeMirror-scroll { - position: relative; - z-index: 0; - } - - & .file-loading-widget { - transform: translate3d(0, -100%, 0); - } -` -export default DocEditLayout diff --git a/src/cloud/components/layouts/RelativeContainer.tsx b/src/cloud/components/layouts/RelativeContainer.tsx deleted file mode 100644 index 9090cf9452..0000000000 --- a/src/cloud/components/layouts/RelativeContainer.tsx +++ /dev/null @@ -1,8 +0,0 @@ -import styled from '../../lib/styled' - -const RelativeContainer = styled.div` - width: 100%; - margin: 0 auto; -` - -export default RelativeContainer diff --git a/src/cloud/components/molecules/Banner/index.tsx b/src/cloud/components/molecules/Banner/index.tsx deleted file mode 100644 index 47beab4761..0000000000 --- a/src/cloud/components/molecules/Banner/index.tsx +++ /dev/null @@ -1,59 +0,0 @@ -import React, { CSSProperties } from 'react' -import cc from 'classcat' -import styled from '../../../lib/styled' - -interface BannerProps { - children: React.ReactNode | string - variant?: 'danger' | 'info' | 'warning' - className?: string - style?: CSSProperties -} - -const Banner = ({ - children, - className, - style, - variant = 'danger', -}: BannerProps) => { - return ( - - {children} - - ) -} - -const StyledBanner = styled.div` - width: 100%; - position: relative; - border: 1px solid transparent; - border-radius: 0.1rem; - height: auto; - min-height: ${({ theme }) => theme.topHeaderHeight}px; - padding: 5px 10px; - display: flex; - align-items: center; - z-index: 1; - - p { - margin: 0px; - } - - &.center { - justify-content: center; - } - - &.banner-danger { - color: #61050d; - background-color: #f7d9dc; - border-color: #f3c6ca; - button { - background-color: #02a47e !important; - color: #fff !important; - } - } -` - -export default Banner diff --git a/src/cloud/components/molecules/ClickableDocListItem.tsx b/src/cloud/components/molecules/ClickableDocListItem.tsx deleted file mode 100644 index 7ebde62d4a..0000000000 --- a/src/cloud/components/molecules/ClickableDocListItem.tsx +++ /dev/null @@ -1,73 +0,0 @@ -import React, { useState } from 'react' -import { SerializedDocWithBookmark } from '../../interfaces/db/doc' -import { SerializedTeam } from '../../interfaces/db/team' -import { - SideNavItemStyle, - SideNavClickableButtonStyle, - SideNavLabelStyle, -} from '../organisms/Sidebar/SideNavigator/styled' -import cc from 'classcat' -import { mdiCardTextOutline } from '@mdi/js' -import { getDocTitle } from '../../lib/utils/patterns' -import SideNavIcon from '../organisms/Sidebar/SideNavigator/SideNavIcon' - -interface ClickableDocListItemProps { - className?: string - item: SerializedDocWithBookmark - team: SerializedTeam - onClick: () => void - id: string -} - -const ClickableDocListItem = ({ - className, - item, - onClick, - id, -}: ClickableDocListItemProps) => { - const [focused, setFocused] = useState(false) - - const onBlurHandler = (event: any) => { - if ( - document.activeElement == null || - !event.currentTarget.contains(event.relatedTarget) - ) { - setFocused(false) - } - } - - return ( - - - - ) -} - -export default ClickableDocListItem diff --git a/src/cloud/components/molecules/ClickableListItem.tsx b/src/cloud/components/molecules/ClickableListItem.tsx deleted file mode 100644 index 32c51ed766..0000000000 --- a/src/cloud/components/molecules/ClickableListItem.tsx +++ /dev/null @@ -1,62 +0,0 @@ -import React, { useState } from 'react' -import { - SideNavItemStyle, - SideNavClickableButtonStyle, - SideNavLabelStyle, -} from '../organisms/Sidebar/SideNavigator/styled' -import cc from 'classcat' - -interface ClickableListItemProps { - className?: string - label: React.ReactNode - icon?: React.ReactNode - onClick: () => void - id: string -} - -const ClickableListItem = ({ - className, - icon, - label, - onClick, - id, -}: ClickableListItemProps) => { - const [focused, setFocused] = useState(false) - - const onBlurHandler = (event: any) => { - if ( - document.activeElement == null || - !event.currentTarget.contains(event.relatedTarget) - ) { - setFocused(false) - } - } - - return ( - - - - ) -} - -export default ClickableListItem diff --git a/src/cloud/components/molecules/ContentManager/Actions/HeaderAction.tsx b/src/cloud/components/molecules/ContentManager/Actions/HeaderAction.tsx deleted file mode 100644 index 834b72b70d..0000000000 --- a/src/cloud/components/molecules/ContentManager/Actions/HeaderAction.tsx +++ /dev/null @@ -1,59 +0,0 @@ -import React, { useMemo } from 'react' -import Tooltip from '../../../atoms/Tooltip' -import IconMdi from '../../../atoms/IconMdi' -import { Spinner } from '../../../atoms/Spinner' -import { StyledRowActionIcon } from '../styled' - -type ContentManagerHeaderAction = { - iconPath: string - tooltip?: string - onClick: () => void -} - -interface HeaderActionProps { - action: ContentManagerHeaderAction - sending?: boolean - disabled?: boolean -} - -const HeaderAction = ({ - action, - disabled, - sending = false, -}: HeaderActionProps) => { - const icon = useMemo(() => { - if (sending) { - return ( - - ) - } - - return - }, [action.iconPath, sending]) - - if (action.tooltip != null) { - return ( - - - {icon} - - - ) - } - - return ( - - {icon} - - ) -} - -export default HeaderAction diff --git a/src/cloud/components/molecules/ContentManager/Actions/RowAction.tsx b/src/cloud/components/molecules/ContentManager/Actions/RowAction.tsx deleted file mode 100644 index 1b0cdca9ce..0000000000 --- a/src/cloud/components/molecules/ContentManager/Actions/RowAction.tsx +++ /dev/null @@ -1,66 +0,0 @@ -import React, { useMemo } from 'react' -import { SerializedDocWithBookmark } from '../../../../interfaces/db/doc' -import { SerializedFolderWithBookmark } from '../../../../interfaces/db/folder' -import Tooltip from '../../../atoms/Tooltip' -import IconMdi from '../../../atoms/IconMdi' -import { Spinner } from '../../../atoms/Spinner' -import { StyledRowActionIcon } from '../styled' - -export type UnsignedItem = - | SerializedDocWithBookmark - | SerializedFolderWithBookmark - -export type ContentManagerRowAction = { - iconPath: string - tooltip?: string - id: number - onClick: (item: T) => void -} - -interface RowActionProps { - action: ContentManagerRowAction - item: T - sending?: boolean - disabled?: boolean -} - -const RowAction = ({ - action, - item, - disabled, - sending = false, -}: RowActionProps) => { - const icon = useMemo(() => { - if (sending) { - return ( - - ) - } - - return - }, [action.iconPath, sending]) - - if (action.tooltip != null) { - return ( - - action.onClick(item)} - disabled={disabled} - > - {icon} - - - ) - } - - return ( - action.onClick(item)} - disabled={disabled} - > - {icon} - - ) -} - -export default RowAction diff --git a/src/cloud/components/molecules/ContentManager/styled.ts b/src/cloud/components/molecules/ContentManager/styled.ts deleted file mode 100644 index 8376233360..0000000000 --- a/src/cloud/components/molecules/ContentManager/styled.ts +++ /dev/null @@ -1,41 +0,0 @@ -import styled from '../../../lib/styled' - -export const StyledContentManager = styled.div` - display: block; - width: 100%; -` - -export const StyledContentManagerList = styled.div` - display: flex; - flex-direction: column; - width: 100%; - max-height: calc(100vh - ${({ theme }) => theme.topHeaderHeight}px); -` - -export const StyledRowActionIcon = styled.button` - padding: 0; - margin: 0 ${({ theme }) => theme.space.xxsmall}px; - display: inline-block; - background: none; - outline: 0; - border: 0; - color: ${({ theme }) => theme.baseTextColor}; - width: 25px; - - .icon { - color: inherit !important; - } - - &:hover { - color: ${({ theme }) => theme.emphasizedTextColor}; - } - - &:disabled { - color: ${({ theme }) => theme.secondaryTextColor}; - cursor: not-allowed; - } - - &.valign-super { - vertical-align: middle; - } -` diff --git a/src/cloud/components/molecules/DocListItem.tsx b/src/cloud/components/molecules/DocListItem.tsx deleted file mode 100644 index f91b51fccd..0000000000 --- a/src/cloud/components/molecules/DocListItem.tsx +++ /dev/null @@ -1,255 +0,0 @@ -import React, { useMemo, useState } from 'react' -import { SerializedDocWithBookmark } from '../../interfaces/db/doc' -import DocLink from '../atoms/Link/DocLink' -import { SerializedTeam } from '../../interfaces/db/team' -import { - SideNavItemStyle, - SideNavClickableButtonStyle, - SideNavLabelStyle, - SideNavControlStyle, - StyledNavTagsList, -} from '../organisms/Sidebar/SideNavigator/styled' -import cc from 'classcat' -import { mdiTrashCan, mdiStar, mdiStarOutline } from '@mdi/js' -import IconMdi from '../atoms/IconMdi' -import { mdiCardTextOutline } from '@mdi/js' -import { - baseIconStyle, - subtleBackgroundColor, -} from '../../lib/styled/styleFunctions' -import styled from '../../lib/styled' -import { getDocTitle } from '../../lib/utils/patterns' -import { getFormattedBoosthubDate } from '../../lib/date' -import { - useCapturingGlobalKeyDownHandler, - isSingleKeyEventOutsideOfInput, - preventKeyboardEventPropagation, -} from '../../lib/keyboard' -import { shortcuts } from '../../lib/shortcuts' -import SideNavIcon from '../organisms/Sidebar/SideNavigator/SideNavIcon' - -interface DocListItemProps { - className?: string - item: SerializedDocWithBookmark - team: SerializedTeam - showUpdatedDate?: boolean - onDeleteHandler?: () => void - onBookmarkHandler?: () => void - id: string - displayTags?: boolean -} - -const DocListItem = ({ - className, - item, - team, - showUpdatedDate = false, - onDeleteHandler, - onBookmarkHandler, - id, - displayTags = true, -}: DocListItemProps) => { - const [focused, setFocused] = useState(false) - - const onBlurHandler = (event: any) => { - if ( - document.activeElement == null || - !event.currentTarget.contains(event.relatedTarget) - ) { - setFocused(false) - } - } - - const dateLabel = useMemo(() => { - if (item.archivedAt != null) { - return ( -
- Archived {getFormattedBoosthubDate(item.archivedAt, true)} -
- ) - } - - if (!showUpdatedDate) { - return null - } - - return ( -
- Updated {getFormattedBoosthubDate(item.updatedAt, true)} -
- ) - }, [item.archivedAt, showUpdatedDate, item.updatedAt]) - - const keyDownHandler = useMemo(() => { - return (event: KeyboardEvent) => { - if (!focused || onBookmarkHandler == null) { - return - } - - if (isSingleKeyEventOutsideOfInput(event, shortcuts.bookmarkDoc)) { - onBookmarkHandler() - preventKeyboardEventPropagation(event) - } - } - }, [onBookmarkHandler, focused]) - useCapturingGlobalKeyDownHandler(keyDownHandler) - - return ( - -
- - - setFocused(true)} - id={id} - > - - {getDocTitle(item, 'Untitled')} - - {displayTags && item.tags != null && item.tags.length > 0 && ( - -
- {item.tags.slice(0, 3).map((tag) => ( - - {tag.text} - - ))} - {item.tags.length > 3 && ( - - +{item.tags.length - 3} - - )} -
-
- )} -
-
- - {dateLabel} - - {onBookmarkHandler != null && ( - - {item.bookmarked ? ( - - ) : ( - - )} - - )} - {onDeleteHandler != null && ( - - - - )} - - -
-
- ) -} - -const Wrapper = styled.div` - vertical-align: middle; - display: flex; - text-align: right; -` - -const Icon = styled.button` - background: none; - ${baseIconStyle} - font-size: ${({ theme }) => theme.fontSizes.default}px; - padding: 0; - cursor: pointer; - svg { - display: inline-block; - vertical-align: middle; - margin-left: ${({ theme }) => theme.space.xxsmall}px; - transform: 0 !important; - } -` - -const StyledTag = styled.div` - display: flex; - flex-wrap: wrap; - padding: 2px 5px; - ${subtleBackgroundColor} - position: relative; - margin: 0 ${({ theme }) => theme.space.xxsmall}px; - color: ${({ theme }) => theme.baseTextColor}; - font-size: ${({ theme }) => theme.fontSizes.small}px; - border-radius: 3px; - vertical-align: middle; - height: 25px; - line-height: 20px; - - &.toolbar-tag { - align-items: center; - } - - .removeTag { - display: inline-block; - cursor: pointer; - margin-left: ${({ theme }) => theme.space.xxsmall}px; - &:hover, - &:focus { - color: ${({ theme }) => theme.emphasizedTextColor}; - } - - &disabled { - pointer-events: none; - } - } - - .tag-link { - display: inline-block; - max-width: 120px; - overflow: hidden; - white-space: nowrap; - text-overflow: ellipsis; - cursor: pointer; - color: ${({ theme }) => theme.baseTextColor}; - text-decoration: none; - &:hover, - &:focus { - opacity: 0.8; - } - } - - .tag-spinner { - margin-top: -3px; - margin-right: ${({ theme }) => theme.space.xxsmall}px; - } - - &.bg-none { - background: none; - } - - &.mb-0 { - margin-bottom: 0; - } - - &.size-s { - height: 100%; - padding: ${({ theme }) => theme.space.xxsmall}px - ${({ theme }) => theme.space.xsmall}px; - font-size: ${({ theme }) => theme.fontSizes.xsmall}px; - line-height: 1; - } - - &.ml-xsmall { - margin-left: ${({ theme }) => theme.space.xsmall}px; - } -` - -export default DocListItem diff --git a/src/cloud/components/molecules/Editor/EditorIndentationStatus.tsx b/src/cloud/components/molecules/Editor/EditorIndentationStatus.tsx deleted file mode 100644 index 185dd409ff..0000000000 --- a/src/cloud/components/molecules/Editor/EditorIndentationStatus.tsx +++ /dev/null @@ -1,171 +0,0 @@ -import React, { - useCallback, - MouseEventHandler, - useState, - useRef, - useEffect, - FocusEventHandler, -} from 'react' -import { capitalize } from '../../../lib/utils/string' -import BottomBarButton from '../../atoms/BottomBarButton' -import { - useSettings, - GeneralEditorIndentType, - GeneralEditorIndentSize, -} from '../../../lib/stores/settings' -import styled from '../../../lib/styled' -import { SelectChangeEventHandler } from '../../../lib/utils/events' -import { selectStyle } from '../../../lib/styled/styleFunctions' -import { isChildNode } from '../../../lib/dom' -import { trackEvent } from '../../../api/track' -import { MixpanelActionTrackTypes } from '../../../interfaces/analytics/mixpanel' -import { useI18n } from '../../../lib/hooks/useI18n' -import { lngKeys } from '../../../lib/i18n/types' - -const EditorIndentationStatus = () => { - const { settings, setSettings } = useSettings() - const currentIndentType = settings['general.editorIndentType'] - const currentIndentSize = settings['general.editorIndentSize'] - const [showingIndentMenu, setShowingIndentMenu] = useState(false) - const menuRef = useRef(null) - const { translate } = useI18n() - - const showIndentMenu: MouseEventHandler = useCallback(() => { - setShowingIndentMenu(true) - }, []) - - useEffect(() => { - if (showingIndentMenu && menuRef.current != null) { - menuRef.current.focus() - } - }, [showingIndentMenu]) - - const handleMenuBlur: FocusEventHandler = useCallback( - (event) => { - if (menuRef.current == null) { - return - } - if (isChildNode(menuRef.current, event.relatedTarget as Node)) { - return - } - setShowingIndentMenu(false) - }, - [] - ) - - const selectIndentType: SelectChangeEventHandler = useCallback( - (event) => { - setSettings({ - 'general.editorIndentType': event.target - .value as GeneralEditorIndentType, - }) - trackEvent(MixpanelActionTrackTypes.ThemeChangeIndentType, { - theme: event.target.value, - }) - }, - [setSettings] - ) - - const selectIndentSize: SelectChangeEventHandler = useCallback( - (event) => { - setSettings({ - 'general.editorIndentSize': parseInt( - event.target.value, - 10 - ) as GeneralEditorIndentSize, - }) - trackEvent(MixpanelActionTrackTypes.ThemeChangeIndentSize, { - theme: event.target.value, - }) - }, - [setSettings] - ) - - return ( - - - {capitalize( - currentIndentType === 'spaces' - ? translate(lngKeys.GeneralSpaces) - : translate(lngKeys.GeneralTabs) - )} - : {currentIndentSize} - - {showingIndentMenu && ( -
-
- - -
-
- - -
-
- )} -
- ) -} - -export default EditorIndentationStatus - -const StyledContainer = styled.div` - display: flex; - justify-content: center; - align-items: center; - position: relative; - - .menu { - position: absolute; - border-radius: 5px; - bottom: 30px; - width: 150px; - padding: ${({ theme }) => theme.space.xsmall}px; - border: solid 1px ${({ theme }) => theme.baseBorderColor}; - background: ${({ theme }) => theme.baseBackgroundColor}; - right: 5px; - z-index: 2; - } - .menu__item + .menu__item { - margin-top: ${({ theme }) => theme.space.xsmall}px; - } - .menu__item__label { - overflow: nowrap; - display: block; - font-size: ${({ theme }) => theme.fontSizes.small}px; - margin-bottom: 0; - } - .menu__item__select { - width: 100%; - display: block; - ${selectStyle} - padding: 5px; - border-radius: 5px; - } -` diff --git a/src/cloud/components/molecules/Editor/EditorThemeSelect.tsx b/src/cloud/components/molecules/Editor/EditorThemeSelect.tsx deleted file mode 100644 index 7803b152b9..0000000000 --- a/src/cloud/components/molecules/Editor/EditorThemeSelect.tsx +++ /dev/null @@ -1,169 +0,0 @@ -import React, { - useCallback, - FocusEventHandler, - useState, - useRef, - MouseEventHandler, - useEffect, -} from 'react' -import BottomBarButton from '../../atoms/BottomBarButton' -import Icon from '../../atoms/Icon' -import { mdiPaletteOutline } from '@mdi/js' -import { - codeMirrorEditorThemes, - useSettings, - CodeMirrorEditorTheme, -} from '../../../lib/stores/settings' -import { SelectChangeEventHandler } from '../../../lib/utils/events' -import styled from '../../../lib/styled' -import { selectStyle } from '../../../lib/styled/styleFunctions' -import { isChildNode } from '../../../lib/dom' -import { trackEvent } from '../../../api/track' -import { MixpanelActionTrackTypes } from '../../../interfaces/analytics/mixpanel' -import { lngKeys } from '../../../lib/i18n/types' -import { useI18n } from '../../../lib/hooks/useI18n' - -const EditorThemeSelect = () => { - const { settings, setSettings } = useSettings() - const editorTheme = settings['general.editorTheme'] - const codeBlockTheme = settings['general.codeBlockTheme'] - - const { translate } = useI18n() - - const [showingMenu, setShowingMenu] = useState(false) - const menuRef = useRef(null) - - const showIndentMenu: MouseEventHandler = useCallback(() => { - setShowingMenu(true) - }, []) - - useEffect(() => { - if (showingMenu && menuRef.current != null) { - menuRef.current.focus() - } - }, [showingMenu]) - - const handleMenuBlur: FocusEventHandler = useCallback( - (event) => { - if (menuRef.current == null) { - return - } - if (isChildNode(menuRef.current, event.relatedTarget as Node)) { - return - } - setShowingMenu(false) - }, - [] - ) - - const selectIndentType: SelectChangeEventHandler = useCallback( - (event) => { - setSettings({ - 'general.editorTheme': event.target.value as CodeMirrorEditorTheme, - }) - trackEvent(MixpanelActionTrackTypes.ThemeChangeEditor, { - theme: event.target.value, - }) - }, - [setSettings] - ) - - const selectIndentSize: SelectChangeEventHandler = useCallback( - (event) => { - setSettings({ - 'general.codeBlockTheme': event.target.value as CodeMirrorEditorTheme, - }) - trackEvent(MixpanelActionTrackTypes.ThemeChangeCodeblock, { - theme: event.target.value, - }) - }, - [setSettings] - ) - - return ( - - - - - {showingMenu && ( -
-
- - -
-
- - -
-
- )} -
- ) -} - -export default EditorThemeSelect - -const StyledContainer = styled.div` - display: flex; - justify-content: center; - align-items: center; - height: 100%; - .menu { - position: absolute; - border-radius: 5px; - bottom: 30px; - padding: 5px; - border: solid 1px ${({ theme }) => theme.baseBorderColor}; - background: ${({ theme }) => theme.baseBackgroundColor}; - z-index: 2; - right: 5px; - } - .menu__item__label { - overflow: nowrap; - display: block; - font-size: ${({ theme }) => theme.fontSizes.small}px; - margin-bottom: 0; - } - .menu__item__select { - width: 100%; - display: block; - ${selectStyle} - padding: 5px; - border-radius: 5px; - } -` diff --git a/src/cloud/components/molecules/FolderDocList.tsx b/src/cloud/components/molecules/FolderDocList.tsx deleted file mode 100644 index 8a78a72d60..0000000000 --- a/src/cloud/components/molecules/FolderDocList.tsx +++ /dev/null @@ -1,26 +0,0 @@ -import styled from '../../lib/styled' - -const FolderDocList = styled.div` - margin: ${({ theme }) => theme.space.xsmall}px 0; - width: 100%; - - svg { - font-size: ${({ theme }) => theme.fontSizes.xlarge}px; - vertical-align: middle !important; - } - - .controls svg { - transform: translateY(0) !important; - } - - .itemLink { - padding: ${({ theme }) => theme.space.xsmall}px; - } - - .label { - padding-left: ${({ theme }) => theme.space.xsmall}px; - margin-bottom: 0; - } -` - -export default FolderDocList diff --git a/src/cloud/components/molecules/FolderListItem.tsx b/src/cloud/components/molecules/FolderListItem.tsx deleted file mode 100644 index 010a1d94bd..0000000000 --- a/src/cloud/components/molecules/FolderListItem.tsx +++ /dev/null @@ -1,143 +0,0 @@ -import React, { useMemo, useState } from 'react' -import styled from '../../lib/styled' -import { - SideNavItemStyle, - SideNavClickableButtonStyle, - SideNavLabelStyle, - SideNavControlStyle, -} from '../organisms/Sidebar/SideNavigator/styled' -import { mdiTrashCan, mdiStar, mdiStarOutline, mdiFolderOutline } from '@mdi/js' -import IconMdi from '../atoms/IconMdi' -import { SerializedTeam } from '../../interfaces/db/team' -import { baseIconStyle } from '../../lib/styled/styleFunctions' -import cc from 'classcat' -import { SerializedFolderWithBookmark } from '../../interfaces/db/folder' -import FolderLink from '../atoms/Link/FolderLink' -import { getFormattedBoosthubDate } from '../../lib/date' -import { - useCapturingGlobalKeyDownHandler, - isSingleKeyEventOutsideOfInput, - preventKeyboardEventPropagation, -} from '../../lib/keyboard' -import { shortcuts } from '../../lib/shortcuts' -import SideNavIcon from '../organisms/Sidebar/SideNavigator/SideNavIcon' - -interface FolderItemProps { - item: SerializedFolderWithBookmark - team: SerializedTeam - showUpdatedDate?: boolean - onBookmarkHandler?: () => void - onDeleteHandler?: () => void - id: string -} - -const FolderListItem = ({ - item, - team, - showUpdatedDate = false, - onDeleteHandler, - onBookmarkHandler, - id, -}: FolderItemProps) => { - const [focused, setFocused] = useState(false) - - const onBlurHandler = (event: any) => { - if ( - document.activeElement == null || - !event.currentTarget.contains(event.relatedTarget) - ) { - setFocused(false) - } - } - - const updatedLabel = useMemo(() => { - if (!showUpdatedDate) { - return null - } - return ( -
- Updated {getFormattedBoosthubDate(item.updatedAt, true)} -
- ) - }, [showUpdatedDate, item.updatedAt]) - - const keyDownHandler = useMemo(() => { - return (event: KeyboardEvent) => { - if (!focused || onBookmarkHandler == null) { - return - } - - if (isSingleKeyEventOutsideOfInput(event, shortcuts.bookmarkDoc)) { - onBookmarkHandler() - preventKeyboardEventPropagation(event) - } - } - }, [onBookmarkHandler, focused]) - useCapturingGlobalKeyDownHandler(keyDownHandler) - - return ( - -
- - - setFocused(true)} - > - {item.name} - - - - {updatedLabel} - - {onBookmarkHandler != null && ( - - {item.bookmarked ? ( - - ) : ( - - )} - - )} - {onDeleteHandler != null && ( - - - - )} - - -
-
- ) -} - -export default FolderListItem - -const Icon = styled.button` - background: none; - ${baseIconStyle} - font-size: ${({ theme }) => theme.fontSizes.default}px; - padding: 0; - cursor: pointer; - svg { - display: inline-block; - vertical-align: sub; - } -` - -const Wrapper = styled.div` - vertical-align: middle; - display: flex; - text-align: right; -` diff --git a/src/cloud/components/molecules/PageHeader.tsx b/src/cloud/components/molecules/PageHeader.tsx deleted file mode 100644 index 329e10727c..0000000000 --- a/src/cloud/components/molecules/PageHeader.tsx +++ /dev/null @@ -1,51 +0,0 @@ -import React from 'react' -import styled from '../../lib/styled' -import PageTitle from '../atoms/PageTitle' -import { Emoji } from 'emoji-mart' -import IconMdi from '../atoms/IconMdi' - -interface PageHeaderProps { - iconType?: 'emoji' | 'icon' - iconVariant?: string - title: string -} - -const PageHeader = ({ - iconType = 'icon', - iconVariant, - title, -}: PageHeaderProps) => { - return ( - - - {iconVariant != null && ( - - {iconType === 'emoji' ? ( - - ) : ( - - )}{' '} - - )} - {title} - - - ) -} - -export default PageHeader - -const StyledPageHeader = styled.header` - display: flex; - align-items: center; - justify-content: space-between; - - & .icon { - display: flex; - margin-right: 10px; - } - - .emoji-icon { - padding-left: 0 !important; - } -` diff --git a/src/cloud/components/molecules/PositionableModal/index.tsx b/src/cloud/components/molecules/PositionableModal/index.tsx deleted file mode 100644 index 07eb477c9d..0000000000 --- a/src/cloud/components/molecules/PositionableModal/index.tsx +++ /dev/null @@ -1,49 +0,0 @@ -import React, { useCallback } from 'react' -import styled from '../../../lib/styled' - -interface PositionableModalProps { - children?: React.ReactNode - position?: { top: number; left: number } - close: () => void -} - -const PositionableModal = ({ - children, - position, - close, -}: PositionableModalProps) => { - const style = - position != null - ? { top: position.top, left: position.left } - : { top: '50%', left: '50%', transform: 'translate3d(50%, 50%, 0)' } - - const closeCallback = useCallback( - (e: Event) => { - e.preventDefault() - e.stopPropagation() - close() - }, - [close] - ) - - return ( - - {children} - - ) -} - -export default PositionableModal - -const StyledModalFrame = styled.div` - position: fixed; - height: 100vh; - width: 100vw; - top: 0px; - left: 0px; - z-index: 999; -` - -const StyledModalContent = styled.div` - position: absolute; -` diff --git a/src/cloud/components/molecules/RelativeDialog/RelativeDialog.tsx b/src/cloud/components/molecules/RelativeDialog/RelativeDialog.tsx deleted file mode 100644 index 8226c7581d..0000000000 --- a/src/cloud/components/molecules/RelativeDialog/RelativeDialog.tsx +++ /dev/null @@ -1,64 +0,0 @@ -import React, { useEffect, useRef } from 'react' -import { - StyledRelativeDialog, - StyledWrapper, - StyledRelativeWrapper, - StyledFixedBackground, -} from './styled' -import { focusFirstChildFromElement } from '../../../lib/dom' - -interface RelativeDialogProps { - closed: boolean - setClosed: (val: boolean) => void -} - -const RelativeDialog = ({ - children, - closed, - setClosed, -}: React.PropsWithChildren) => { - const dialogRef = useRef(null) - - useEffect(() => { - if (!closed) { - focusFirstChildFromElement(dialogRef.current) - } - }, [closed, dialogRef]) - - const closeDialogIfBlurred = (event: React.FocusEvent) => { - if (isBlurred(event.relatedTarget)) { - setClosed(true) - } - } - - const isBlurred = (relatedTarget: any): boolean => { - if (dialogRef.current == null) return true - let currentTarget: HTMLElement | null | undefined = relatedTarget - while (currentTarget != null) { - if (currentTarget === dialogRef.current) return false - currentTarget = currentTarget.parentElement - } - return true - } - - if (closed) return null - - return ( - <> - - - - - {children} - - - - - ) -} - -export default RelativeDialog diff --git a/src/cloud/components/molecules/RelativeDialog/index.ts b/src/cloud/components/molecules/RelativeDialog/index.ts deleted file mode 100644 index 7e2c17d12b..0000000000 --- a/src/cloud/components/molecules/RelativeDialog/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -import RelativeDialog from './RelativeDialog' - -export default RelativeDialog diff --git a/src/cloud/components/molecules/RelativeDialog/styled.ts b/src/cloud/components/molecules/RelativeDialog/styled.ts deleted file mode 100644 index a1e7a8cb5f..0000000000 --- a/src/cloud/components/molecules/RelativeDialog/styled.ts +++ /dev/null @@ -1,51 +0,0 @@ -import styled from '../../../lib/styled' - -export const StyledFixedBackground = styled.div` - position: fixed; - top: 0; - left: 0; - width: 100vw; - height: 100vh; - pointer-events: none; - z-index: 9998; -` - -export const StyledRelativeDialog = styled.div` - width: 100%; - display: flex; - flex-direction: column; - max-height: 65vh; - position: relative; - left: ${({ theme }) => theme.space.default}px; - bottom: ${({ theme }) => theme.space.xxsmall}px; - background-color: ${({ theme }) => theme.baseBackgroundColor}; - border: 1px solid ${({ theme }) => theme.baseBorderColor}; - font-size: ${({ theme }) => theme.fontSizes.small}px; - box-sizing: border-box; - border-radius: 4px; - outline: none; - border-radius: 3px; - position: relative; - max-width: calc(100vw - 24px); - z-index: 9999; - box-shadow: ${({ theme }) => theme.baseShadowColor}; -` - -export const StyledWrapper = styled.div` - position: absolute; - top: 0; - left: 0; - width: 100%; - height: 100%; - display: flex; - flex-direction: column; - justify-content: flex-start; - align-items: center; - z-index: 9997; -` -export const StyledRelativeWrapper = styled.div` - position: relative; - top: 100%; - pointer-events: auto; - width: 100%; -` diff --git a/src/cloud/components/molecules/RightLayoutHeaderButtons.tsx b/src/cloud/components/molecules/RightLayoutHeaderButtons.tsx deleted file mode 100644 index 882fd1a46d..0000000000 --- a/src/cloud/components/molecules/RightLayoutHeaderButtons.tsx +++ /dev/null @@ -1,86 +0,0 @@ -import React from 'react' -import Flexbox from '../atoms/Flexbox' -import IconMdi from '../atoms/IconMdi' -import styled from '../../lib/styled' -import { Spinner } from '../atoms/Spinner' -import Tooltip from '../atoms/Tooltip' - -interface RightLayoutHeaderButtonsProps { - buttons: { - iconPath: string - sending?: boolean - disabled?: boolean - onClick: () => void - tooltip?: string - }[] -} - -const RightLayoutHeaderButtons = ({ - buttons, -}: RightLayoutHeaderButtonsProps) => ( - - {buttons.map(({ tooltip, disabled, onClick, sending, iconPath }, i) => { - if (tooltip != null) { - return ( - - - {sending ? ( - - ) : ( - - )} - - - ) - } - - return ( - - {sending ? ( - - ) : ( - - )} - - ) - })} - -) - -const StyledHeaderButton = styled.button` - outline: 0; - border: 0; - background: none; - color: ${({ theme }) => theme.emphasizedTextColor}; - line-height: 13px; - - svg { - color: ${({ theme }) => theme.emphasizedTextColor} !important; - } - - .spinner-wrapper { - vertical-align: baseline; - } - &:hover, - &:hover svg { - color: ${({ theme }) => theme.subtleTextColor} !important; - } - &:disabled { - opacity: 0.8; - color: ${({ theme }) => theme.subtleTextColor} !important; - } - - &:disabled svg { - color: ${({ theme }) => theme.subtleTextColor} !important; - } -` - -export default RightLayoutHeaderButtons diff --git a/src/cloud/components/molecules/TabHeaders.tsx b/src/cloud/components/molecules/TabHeaders.tsx deleted file mode 100644 index 8f17ceca8a..0000000000 --- a/src/cloud/components/molecules/TabHeaders.tsx +++ /dev/null @@ -1,70 +0,0 @@ -import React from 'react' -import styled from '../../lib/styled' -import cc from 'classcat' - -interface TabHeadersProps { - titles: T[] - onSelect: (selected: T) => void - active: T -} - -const TabHeaders = ({ - titles, - onSelect, - active, -}: TabHeadersProps) => { - return ( -
- {titles.map((title) => { - return ( - onSelect(title)} - className={cc([active === title && 'active'])} - > - {title} - - ) - })} -
- ) -} - -export const StyledTabButton = styled.button` - padding: ${({ theme }) => theme.space.small}px; - background: none; - cursor: pointer; - color: ${({ theme }) => theme.subtleTextColor}; - font-size: ${({ theme }) => theme.fontSizes.default}px; - transition: 0.2s; - text-transform: capitalize; - - &:hover, - &.active { - color: ${({ theme }) => theme.emphasizedTextColor}; - } - - &:focus { - background-color: ${({ theme }) => theme.subtleBackgroundColor}; - } - - &.active { - position: relative; - - &:after { - position: absolute; - bottom: -1px; - left: 0; - content: ''; - width: 100%; - height: 2px; - background-color: ${({ theme }) => theme.emphasizedBackgroundColor}; - } - } - - + button { - margin-left: ${({ theme }) => theme.space.default}px; - } -` - -export default TabHeaders diff --git a/src/cloud/components/molecules/Timeline/TimelineList.tsx b/src/cloud/components/molecules/Timeline/TimelineList.tsx deleted file mode 100644 index 97fc0beba6..0000000000 --- a/src/cloud/components/molecules/Timeline/TimelineList.tsx +++ /dev/null @@ -1,178 +0,0 @@ -import React, { useMemo, useRef } from 'react' -import { SerializedAppEvent } from '../../../interfaces/db/appEvents' -import { useNav } from '../../../lib/stores/nav' -import { getOriginalDocId } from '../../../lib/utils/patterns' -import { SerializedDocWithBookmark } from '../../../interfaces/db/doc' -import { SerializedTeam } from '../../../interfaces/db/team' -import { useUpDownNavigationListener } from '../../../lib/keyboard' -import styled from '../../../lib/styled' -import { getHexFromUUID } from '../../../lib/utils/string' -import TimelineListItem from './TimelineListItem' -import { TimelineUser } from '../../../pages/[teamId]/timeline' -import { SerializedWorkspace } from '../../../interfaces/db/workspace' - -export interface TimelineListProps { - heading: string - team: SerializedTeam - events: SerializedAppEvent[] - timeFormat?: (date: Date) => string - usersMap: Map - workspacesMap: Map -} - -const TimelineList = ({ - heading, - team, - events, - usersMap, - workspacesMap, -}: TimelineListProps) => { - const { docsMap } = useNav() - const listRef = useRef(null) - useUpDownNavigationListener(listRef) - - const timelineDocs = useMemo(() => { - return events.reduce< - { - doc: SerializedDocWithBookmark - editors: string[] - }[] - >((acc, event) => { - const { resource, editors } = event.data || {} - if (!Array.isArray(editors) || typeof resource !== 'string') { - return acc - } - const doc = docsMap.get(getOriginalDocId(resource)) - if (doc != null) { - acc.push({ doc, editors }) - } - return acc - }, []) - }, [events, docsMap]) - - if (events.length === 0) { - return null - } - - return ( - -

{heading}

- - {timelineDocs.length > 0 ? ( - - {timelineDocs.map((timelineDoc) => { - const childId = `timelinePage-dC${getHexFromUUID( - timelineDoc.doc.id - )}` - - const editors = timelineDoc.editors.reduce( - (acc, editor) => { - const user = usersMap.get(editor) - if (user != null) { - acc.push(user) - } - return acc - }, - [] - ) - - const path = `/${ - workspacesMap.get(timelineDoc.doc.workspaceId)?.name - }${timelineDoc.doc.folderPathname}` - - return ( - - ) - })} - - ) : ( -

No documents or folders have been updated/archived.

- )} -
-
- ) -} - -export default TimelineList - -const StyledTimelineList = styled.div` - svg { - font-size: ${({ theme }) => theme.fontSizes.xlarge}px; - vertical-align: middle !important; - } - - .controls svg { - transform: translateY(0) !important; - } - - .label { - padding-left: ${({ theme }) => theme.space.xsmall}px; - margin-bottom: 0; - } -` - -const StyledTimelineListContentWrapper = styled.div` - width: 100%; - margin: auto; - - p { - color: ${({ theme }) => theme.baseTextColor}; - font-size: ${({ theme }) => theme.fontSizes.small}px; - } -` - -const StyledTimelineListContent = styled.div` - .marginLeft { - margin-left: 0 !important; - } - - .sideNavItemStyle { - border-bottom: 1px solid ${({ theme }) => theme.subtleBorderColor}; - padding: ${({ theme }) => theme.space.xsmall}px 0px; - align-items: flex-start; - justify-content: initial; - flex-direction: column; - height: auto; - - &:not(.non-hover):hover { - background-color: ${({ theme }) => theme.subtleBackgroundColor}; - } - - &:not(.non-hover):focus, - &:not(.non-hover):active, - &:not(.non-hover).active { - background-color: ${({ theme }) => theme.emphasizedBackgroundColor}; - } - - &:not(.non-hover).focused { - background-color: transparent; - } - } - - .sideNavWrapper { - width: 100%; - flex: inherit; - padding: 0 ${({ theme }) => theme.space.xlarge}px; - z-index: initial !important; - } - - .controls { - padding-left: 0; - } - - .itemLink { - padding-right: ${({ theme }) => theme.space.xsmall}px; - - > div { - font-size: ${({ theme }) => theme.fontSizes.default}px; - white-space: inherit; - } - } -` diff --git a/src/cloud/components/molecules/Timeline/TimelineListItem.tsx b/src/cloud/components/molecules/Timeline/TimelineListItem.tsx deleted file mode 100644 index 308c15b9f2..0000000000 --- a/src/cloud/components/molecules/Timeline/TimelineListItem.tsx +++ /dev/null @@ -1,244 +0,0 @@ -import React, { useMemo, useState } from 'react' -import { SerializedDocWithBookmark } from '../../../interfaces/db/doc' -import DocLink from '../../atoms/Link/DocLink' -import { SerializedTeam } from '../../../interfaces/db/team' -import { - SideNavItemStyle, - SideNavClickableButtonStyle, - SideNavLabelStyle, - SideNavControlStyle, - StyledNavTagsList, -} from '../../organisms/Sidebar/SideNavigator/styled' -import cc from 'classcat' -import { mdiFileDocumentOutline } from '@mdi/js' -import { getDocTitle } from '../../../lib/utils/patterns' -import { getFormattedBoosthubDate } from '../../../lib/date' -import SideNavIcon from '../../organisms/Sidebar/SideNavigator/SideNavIcon' -import styled from '../../../lib/styled' -import { TimelineUser } from '../../../pages/[teamId]/timeline' -import Tooltip from '../../atoms/Tooltip' -import { - subtleBackgroundColor, - userIconStyle, -} from '../../../lib/styled/styleFunctions' - -interface TimelineListItemProps { - className?: string - item: SerializedDocWithBookmark - team: SerializedTeam - id: string - editors: TimelineUser[] - path?: string -} - -const TimelineListItem = ({ - className, - item, - team, - id, - editors, - path, -}: TimelineListItemProps) => { - const [focused, setFocused] = useState(false) - - const onBlurHandler = (event: any) => { - if ( - document.activeElement == null || - !event.currentTarget.contains(event.relatedTarget) - ) { - setFocused(false) - } - } - - const dateLabel = useMemo(() => { - if (item.archivedAt != null) { - return ( -
- Archived {getFormattedBoosthubDate(item.archivedAt, true)} -
- ) - } - - return ( -
- Updated {getFormattedBoosthubDate(item.updatedAt, true)} -
- ) - }, [item.archivedAt, item.updatedAt]) - - const ByUsers = useMemo(() => { - if (editors.length === 0) { - return null - } - - return ( - -
  • by
  • - {editors.map(({ user, icon, color }) => { - return ( -
  • - - - {icon} - - -
  • - ) - })} -
    - ) - }, [editors]) - - return ( - -
    - - - setFocused(true)} - id={id} - > - - {path !== null && {path}} - {getDocTitle(item, 'Untitled')} - - {item.tags != null && item.tags.length > 0 && ( - -
    - {item.tags.slice(0, 3).map((tag) => ( - - {tag.text} - - ))} - {item.tags.length > 3 && ( - - +{item.tags.length - 3} - - )} -
    -
    - )} -
    -
    - - {dateLabel} - - {ByUsers} -
    -
    - ) -} -const StyledTag = styled.div` - display: flex; - flex-wrap: wrap; - padding: 2px 5px; - ${subtleBackgroundColor} - position: relative; - margin: 0 ${({ theme }) => theme.space.xxsmall}px; - color: ${({ theme }) => theme.baseTextColor}; - font-size: ${({ theme }) => theme.fontSizes.small}px; - border-radius: 3px; - vertical-align: middle; - height: 25px; - line-height: 20px; - - &.toolbar-tag { - align-items: center; - } - - .removeTag { - display: inline-block; - cursor: pointer; - margin-left: ${({ theme }) => theme.space.xxsmall}px; - &:hover, - &:focus { - color: ${({ theme }) => theme.emphasizedTextColor}; - } - - &disabled { - pointer-events: none; - } - } - - .tag-link { - display: inline-block; - max-width: 120px; - overflow: hidden; - white-space: nowrap; - text-overflow: ellipsis; - cursor: pointer; - color: ${({ theme }) => theme.baseTextColor}; - text-decoration: none; - &:hover, - &:focus { - opacity: 0.8; - } - } - - .tag-spinner { - margin-top: -3px; - margin-right: ${({ theme }) => theme.space.xxsmall}px; - } - - &.bg-none { - background: none; - } - - &.mb-0 { - margin-bottom: 0; - } - - &.size-s { - height: 100%; - padding: ${({ theme }) => theme.space.xxsmall}px - ${({ theme }) => theme.space.xsmall}px; - font-size: ${({ theme }) => theme.fontSizes.xsmall}px; - line-height: 1; - } - - &.ml-xsmall { - margin-left: ${({ theme }) => theme.space.xsmall}px; - } -` - -const StyledUsersList = styled.ul` - display: flex; - flex: 0 0 auto; - align-items: center; - list-style: none; - margin: 0 ${({ theme }) => theme.space.xxsmall}px 0 0; - padding: 0; - color: ${({ theme }) => theme.subtleTextColor}; - font-size: ${({ theme }) => theme.fontSizes.xsmall}px; - margin-left: ${({ theme }) => theme.space.xxsmall}px; - z-index: initial; - line-height: 24px; -` - -const StyledUsersListItem = styled.div` - ${userIconStyle} - width: 24px; - height: 24px; -` - -const PathLabel = styled.span` - display: block; - color: ${({ theme }) => theme.subtleTextColor}; - font-size: ${({ theme }) => theme.fontSizes.default}px; - margin-bottom: ${({ theme }) => theme.space.xxsmall}px; -` - -export default TimelineListItem diff --git a/src/cloud/components/molecules/ToggleSection.tsx b/src/cloud/components/molecules/ToggleSection.tsx deleted file mode 100644 index 93face841b..0000000000 --- a/src/cloud/components/molecules/ToggleSection.tsx +++ /dev/null @@ -1,55 +0,0 @@ -import React, { useState, useEffect, useCallback } from 'react' -import IconMdi from '../atoms/IconMdi' -import { mdiMenu, mdiClose } from '@mdi/js' -import styled from '../../lib/styled' - -interface ToggleSectionProps { - children?: React.ReactNode - open?: boolean - onToggle?: (open: boolean) => boolean -} - -const ToggleSection = ({ - children, - open = false, - onToggle = (prev) => !prev, -}: ToggleSectionProps) => { - const [openInternal, setOpen] = useState(open) - - useEffect(() => { - setOpen(open) - }, [open]) - - const toggle = useCallback(() => { - setOpen((prev) => onToggle(!prev)) - }, [onToggle]) - - return ( - -
    - -
    - {openInternal && children} -
    - ) -} - -export default ToggleSection - -const StyledToggleSection = styled.div` - min-width: 85px; - position: relative; - border-left: solid 1px ${({ theme }) => theme.subtleBorderColor}; - - .toggle { - color: ${({ theme }) => theme.subtleTextColor}; - position: absolute; - top: 25px; - right: 25px; - cursor: pointer; - - &:hover { - color: ${({ theme }) => theme.baseTextColor}; - } - } -` diff --git a/src/cloud/components/organisms/BookmarksList/index.tsx b/src/cloud/components/organisms/BookmarksList/index.tsx deleted file mode 100644 index 283944f7b4..0000000000 --- a/src/cloud/components/organisms/BookmarksList/index.tsx +++ /dev/null @@ -1,171 +0,0 @@ -import React, { useMemo, useCallback, useState } from 'react' -import { usePage } from '../../../lib/stores/pageStore' -import styled from '../../../lib/styled' -import Container from '../../layouts/Container' -import FolderDocList from '../../molecules/FolderDocList' -import { useNav } from '../../../lib/stores/nav' -import { SerializedDocWithBookmark } from '../../../interfaces/db/doc' -import FolderListItem from '../../molecules/FolderListItem' -import { - CreateDocBookmarkResponseBody, - DestroyDocBookmarkResponseBody, - destroyDocBookmark, - createDocBookmark, -} from '../../../api/teams/docs/bookmarks' -import { SerializedFolderWithBookmark } from '../../../interfaces/db/folder' -import { - CreateFolderBookmarkResponseBody, - DestroyFolderBookmarkResponseBody, - destroyFolderBookmark, - createFolderBookmark, -} from '../../../api/teams/folders/bookmarks' -import DocListItem from '../../molecules/DocListItem' -import { getDocTitle } from '../../../lib/utils/patterns' -import { getHexFromUUID } from '../../../lib/utils/string' -import { useToast } from '../../../../shared/lib/stores/toast' - -const BookmarkLists = () => { - const { - foldersMap, - docsMap, - deleteDocHandler, - updateDocsMap, - updateFoldersMap, - deleteFolderHandler, - } = useNav() - const { team } = usePage() - const { pushMessage } = useToast() - const [sendingBookmark, setSendingBookmark] = useState(false) - - const bookmarkedFolders = useMemo(() => { - return [...foldersMap.values()] - .filter((folder) => folder.bookmarked) - .sort((a, b) => { - if (a.pathname < b.pathname) { - return -1 - } else { - return 1 - } - }) - }, [foldersMap]) - - const bookmarkedDocs = useMemo(() => { - return [...docsMap.values()] - .filter((doc) => doc.bookmarked) - .sort((a, b) => { - if (getDocTitle(a) < getDocTitle(b)) { - return -1 - } else { - return 1 - } - }) - }, [docsMap]) - - const toggleDocBookmark = useCallback( - async (doc: SerializedDocWithBookmark) => { - if (sendingBookmark || team == null) { - return - } - setSendingBookmark(true) - try { - let data: CreateDocBookmarkResponseBody | DestroyDocBookmarkResponseBody - if (doc.bookmarked) { - data = await destroyDocBookmark(team.id, doc.id) - } else { - data = await createDocBookmark(team.id, doc.id) - } - updateDocsMap([data.doc.id, data.doc]) - } catch (error) { - pushMessage({ - title: 'Error', - description: 'Could not bookmark this doc', - }) - } - setSendingBookmark(false) - }, - [team, setSendingBookmark, pushMessage, updateDocsMap, sendingBookmark] - ) - - const toggleFolderBookmark = useCallback( - async (folder: SerializedFolderWithBookmark) => { - if (sendingBookmark || team == null) { - return - } - setSendingBookmark(true) - try { - let data: - | CreateFolderBookmarkResponseBody - | DestroyFolderBookmarkResponseBody - - if (folder.bookmarked) { - data = await destroyFolderBookmark(team.id, folder.id) - } else { - data = await createFolderBookmark(team.id, folder.id) - } - updateFoldersMap([data.folder.id, data.folder]) - } catch (error) { - pushMessage({ - title: 'Error', - description: 'Could not bookmark this folder', - }) - } - setSendingBookmark(false) - }, - [team, setSendingBookmark, pushMessage, updateFoldersMap, sendingBookmark] - ) - - if (team == null) { - return null - } - - return ( - - - Bookmarks - - {bookmarkedDocs.length === 0 && bookmarkedFolders.length === 0 && ( - No documents have been bookmarked - )} - {bookmarkedFolders.map((folder) => ( - deleteFolderHandler(folder)} - onBookmarkHandler={() => toggleFolderBookmark(folder)} - id={`expandedBookmarkList-fD${getHexFromUUID(folder.id)}`} - /> - ))} - {bookmarkedDocs.map((doc) => ( - deleteDocHandler(doc)} - onBookmarkHandler={() => toggleDocBookmark(doc)} - id={`expandedBookmarkList-dC${getHexFromUUID(doc.id)}`} - displayTags={false} - /> - ))} - - - - ) -} - -export default BookmarkLists - -const StyledBookmarkHeader = styled.h1` - padding: 0 ${({ theme }) => theme.space.xsmall}px; -` - -const StyledBookmarksList = styled.div`` - -const StyledWarning = styled.div` - width: 100%; - padding: ${({ theme }) => theme.space.small}px - ${({ theme }) => theme.space.xsmall}px; - font-size: ${({ theme }) => theme.fontSizes.default}px; - background: ${({ theme }) => theme.baseBackgroundColor}; - border-radius: 5px; -` diff --git a/src/cloud/components/organisms/DocPage/styles.ts b/src/cloud/components/organisms/DocPage/styles.ts deleted file mode 100644 index 06ce78b7e9..0000000000 --- a/src/cloud/components/organisms/DocPage/styles.ts +++ /dev/null @@ -1,27 +0,0 @@ -import styled from '../../../lib/styled' -import { rightSidePageLayout } from '../../../lib/styled/styleFunctions' -import { rightSideTopBarHeight } from '../RightSideTopBar/styled' - -export const StyledDocPage = styled.div` - ${rightSidePageLayout} - margin: 0 auto; - padding-top: calc( - ${rightSideTopBarHeight}px + ${({ theme }) => theme.space.large}px - ); - padding-left: ${({ theme }) => theme.space.large}px; - padding-right: ${({ theme }) => theme.space.large}px; - min-height: calc(100vh - ${rightSideTopBarHeight}px); - height: auto; - display: flex; - flex-direction: column; - align-items: center; -` - -export const StyledDocPageSearch = styled.div` - padding-bottom: ${({ theme }) => theme.space.small}px; -` - -export const StyledDocPageButtons = styled.div` - display: flex; - align-items: center; -` diff --git a/src/cloud/components/organisms/DocProperties/DocAssigneeSelect.tsx b/src/cloud/components/organisms/DocProperties/DocAssigneeSelect.tsx deleted file mode 100644 index 72bc10dcbb..0000000000 --- a/src/cloud/components/organisms/DocProperties/DocAssigneeSelect.tsx +++ /dev/null @@ -1,297 +0,0 @@ -import React, { useCallback, useState, useMemo, useRef } from 'react' -import { usePage } from '../../../lib/stores/pageStore' -import styled from '../../../../shared/lib/styled' -import UserIcon from '../../atoms/UserIcon' -import { overflowEllipsis } from '../../../../shared/lib/styled/styleFunctions' -import { useI18n } from '../../../lib/hooks/useI18n' -import { lngKeys } from '../../../lib/i18n/types' -import DocPropertyValueButton from './DocPropertyValueButton' -import { mdiAccountCircleOutline } from '@mdi/js' -import { useModal } from '../../../../shared/lib/stores/modal' -import Checkbox from '../../../../shared/components/molecules/Form/atoms/FormCheckbox' -import Form from '../../../../shared/components/molecules/Form' -import UpDownList from '../../../../shared/components/atoms/UpDownList' -import FormInput from '../../../../shared/components/molecules/Form/atoms/FormInput' -import { useEffectOnce } from 'react-use' -import VerticalScroller from '../../../../shared/components/atoms/VerticalScroller' -import Button from '../../../../shared/components/atoms/Button' -import FormRowItem from '../../../../shared/components/molecules/Form/templates/FormRowItem' - -interface DocAssigneeSelectProps { - disabled?: boolean - defaultValue: string[] - update: (value: string[]) => void - isLoading: boolean - readOnly: boolean - popupAlignment?: 'bottom-left' | 'top-left' -} - -const DocAssigneeSelect = ({ - disabled = false, - defaultValue, - isLoading, - readOnly, - update, - popupAlignment = 'bottom-left', -}: DocAssigneeSelectProps) => { - const { translate } = useI18n() - const { openContextModal, closeAllModals } = useModal() - const { permissions = [] } = usePage() - - const updateAssignees = useCallback( - (selectedUserIds: string[]) => { - update(selectedUserIds) - closeAllModals() - }, - [update, closeAllModals] - ) - - const selectedUsers = useMemo(() => { - if (defaultValue.length === 0) { - return null - } - - return ( -
    - {permissions - .filter((p) => defaultValue.includes(p.userId) && p.user != null) - .map((p) => ( - - ))} -
    - ) - }, [defaultValue, permissions]) - - return ( - - - openContextModal( - e, - , - { - alignment: popupAlignment, - width: 300, - } - ) - } - > - {defaultValue.length !== 0 - ? selectedUsers - : translate(lngKeys.Unassigned)} - - - ) -} - -const Container = styled.div` - .doc__assignees__wrapper { - display: flex; - width: auto; - align-items: center; - } - - .doc__assignee { - display: inline-flex; - width: 22px; - height: 22px; - line-height: 19px; - margin-right: 0; - } -` - -const DocAssigneeModal = ({ - selectedUsers, - submitUpdate, - closeModal, -}: { - selectedUsers: string[] - submitUpdate: (val: string[]) => void - closeModal: () => void -}) => { - const { permissions = [] } = usePage() - const [value, setValue] = useState(selectedUsers) - const { translate } = useI18n() - const [query, setQuery] = useState('') - - const toggleUser = useCallback((userId: string) => { - setValue((prev) => { - const newValue = prev.slice() - if (newValue.includes(userId)) { - return newValue.filter((id) => id !== userId) - } else { - newValue.push(userId) - return newValue - } - }) - }, []) - - const matchedUsers = useMemo(() => { - const trimmed = query.trim().toLocaleLowerCase() - if (trimmed === '') { - return permissions.map((p) => p.user) - } - - return permissions - .filter((p) => p.user.displayName.toLocaleLowerCase().includes(trimmed)) - .map((p) => p.user) - }, [permissions, query]) - - const inputRef = useRef(null) - useEffectOnce(() => { - inputRef.current!.focus() - }) - - return ( - -
    submitUpdate(value)} - onCancel={closeModal} - className='assignee__form' - > - - - setQuery(event.target.value)} - placeholder={translate(lngKeys.GeneralSearchVerb)} - id='selection__input' - /> - - - {matchedUsers.map((user) => { - return ( -
    - -
    - ) - })} -
    -
    - - - - - ) -} - -const ModalContainer = styled.div` - .assignee__item__icon { - width: 24px; - height: 24px; - margin-right: ${({ theme }) => theme.sizes.spaces.sm}px; - } - - .selection__item { - margin-bottom: ${({ theme }) => theme.sizes.spaces.sm}px; - } - - #selection__input { - margin-bottom: ${({ theme }) => theme.sizes.spaces.sm}px; - } - - .selection__break { - display: block; - height: 1px; - width: 100%; - background: ${({ theme }) => theme.colors.border.second}; - flex: 0 0 auto; - margin-bottom: ${({ theme }) => theme.sizes.spaces.sm}px; - } - .selection__submit { - display: flex; - width: 100%; - } - - .selection__wrapper { - min-height: 30px; - max-height: 250px; - } - - .selection__checkbox { - flex: 0 0 auto; - } - - .selection__item__wrapper { - display: flex; - flex: 1 1 auto; - align-items: center; - width: 100%; - height: 30px; - cursor: pointer; - background: none; - transition: background 200ms; - color: ${({ theme }) => theme.colors.text.primary}; - justify-content: space-between; - text-align: left; - border-radius: ${({ theme }) => theme.borders.radius}px; - padding: ${({ theme }) => theme.sizes.spaces.xsm}px - ${({ theme }) => theme.sizes.spaces.sm}px; - - &:focus { - background: ${({ theme }) => theme.colors.background.tertiary}; - } - - &:hover { - background: ${({ theme }) => theme.colors.background.secondary}; - } - - .selection__label { - flex: 1 1 auto; - ${overflowEllipsis} - } - - .selection__item__icon { - margin-right: ${({ theme }) => theme.sizes.spaces.df}px; - width: 22px; - height: 22px; - line-height: 19px; - } - - .selection__checkbox { - margin-left: ${({ theme }) => theme.sizes.spaces.df}px; - pointer-events: none; - } - - .selection__item__icon, - .selection__checkbox { - flex: 0 0 auto; - flex-shrink: 0; - } - } -` - -export default DocAssigneeSelect diff --git a/src/cloud/components/organisms/DocProperties/DocLabelSelectionModal.tsx b/src/cloud/components/organisms/DocProperties/DocLabelSelectionModal.tsx deleted file mode 100644 index 296e8dbe16..0000000000 --- a/src/cloud/components/organisms/DocProperties/DocLabelSelectionModal.tsx +++ /dev/null @@ -1,249 +0,0 @@ -import React, { useCallback, useMemo, useRef, useState } from 'react' -import { useEffectOnce } from 'react-use' -import Button from '../../../../shared/components/atoms/Button' -import UpDownList from '../../../../shared/components/atoms/UpDownList' -import VerticalScroller from '../../../../shared/components/atoms/VerticalScroller' -import Form from '../../../../shared/components/molecules/Form' -import Checkbox from '../../../../shared/components/molecules/Form/atoms/FormCheckbox' -import FormInput from '../../../../shared/components/molecules/Form/atoms/FormInput' -import FormRowItem from '../../../../shared/components/molecules/Form/templates/FormRowItem' -import styled from '../../../../shared/lib/styled' -import { overflowEllipsis } from '../../../../shared/lib/styled/styleFunctions' -import { - getMapValues, - sortByAttributeAsc, -} from '../../../../shared/lib/utils/array' -import { useI18n } from '../../../lib/hooks/useI18n' -import { lngKeys } from '../../../lib/i18n/types' -import { useNav } from '../../../lib/stores/nav' - -interface DocLabelSelectionModalProps { - selectedTags: string[] - sendTags: (tags: string[]) => void -} - -interface SelectionTag { - isNew?: boolean - text: string -} - -const DocLabelSelectionModal = ({ - selectedTags, - sendTags, -}: DocLabelSelectionModalProps) => { - const { tagsMap } = useNav() - const [query, setQuery] = useState('') - const [selected, setSelected] = useState( - selectedTags.map((tag) => { - return { text: tag } - }) - ) - - const { translate } = useI18n() - - const availableTags = useMemo(() => { - return getMapValues(tagsMap) - }, [tagsMap]) - - const searchedTagIsNew = useMemo(() => { - const trimmed = query.trim() - if (trimmed === '') return - return ( - availableTags.find((tag) => tag.text === trimmed) == null && - selected.find((t) => t.text === trimmed) == null - ) - }, [availableTags, query, selected]) - - const matchedTags = useMemo(() => { - const trimmed = query.trim().toLocaleLowerCase() - if (trimmed === '') return sortByAttributeAsc('text', availableTags) - return sortByAttributeAsc( - 'text', - availableTags.filter((tag) => - tag.text.toLocaleLowerCase().startsWith(trimmed) - ) - ) - }, [availableTags, query]) - - const toggleTagSelection = useCallback( - (tag: string, isNew?: boolean) => { - if (selected.find((t) => t.text === tag) != null) { - return setSelected((prev) => { - const newSelection = prev.slice().filter((t) => t.text !== tag) - return newSelection - }) - } else { - return setSelected((prev) => { - return [...prev.slice(), { isNew, text: tag }] - }) - } - }, - [selected] - ) - - const inputRef = useRef(null) - useEffectOnce(() => { - inputRef.current!.focus() - }) - - return ( - -
    { - event.preventDefault() - return sendTags(selected.map((tag) => tag.text)) - }} - > - - - setQuery(event.target.value)} - placeholder={translate(lngKeys.GeneralSearchVerb)} - id='labels__selection__input' - /> - - - {searchedTagIsNew && ( -
    - -
    - )} - {selected - .filter((selection) => selection.isNew) - .map((tag) => ( -
    - -
    - ))} - {matchedTags.map((tag) => ( -
    - -
    - ))} -
    -
    - - - - - ) -} - -const Container = styled.div` - #labels__selection__input { - margin-bottom: ${({ theme }) => theme.sizes.spaces.sm}px; - } - - .labels__selection__break { - display: block; - height: 1px; - width: 100%; - background: ${({ theme }) => theme.colors.border.second}; - flex: 0 0 auto; - margin-bottom: ${({ theme }) => theme.sizes.spaces.sm}px; - } - .labels__selection__submit { - display: flex; - width: 100%; - } - - .labels__selection__wrapper { - min-height: 30px; - max-height: 250px; - } - - .selection__checkbox { - flex: 0 0 auto; - } - - .selection__item__wrapper { - display: flex; - flex: 1 1 auto; - align-items: center; - width: 100%; - height: 30px; - cursor: pointer; - background: none; - transition: background 200ms; - color: ${({ theme }) => theme.colors.text.primary}; - justify-content: space-between; - text-align: left; - border-radius: ${({ theme }) => theme.borders.radius}px; - padding: ${({ theme }) => theme.sizes.spaces.xsm}px - ${({ theme }) => theme.sizes.spaces.sm}px; - - &:focus { - background: ${({ theme }) => theme.colors.background.tertiary}; - } - - &:hover { - background: ${({ theme }) => theme.colors.background.secondary}; - } - - .selection__label { - flex: 1 1 auto; - ${overflowEllipsis} - } - - .selection__item__icon { - margin-right: ${({ theme }) => theme.sizes.spaces.df}px; - width: 22px; - height: 22px; - line-height: 19px; - } - - .selection__checkbox { - margin-left: ${({ theme }) => theme.sizes.spaces.df}px; - pointer-events: none; - } - - .selection__item__icon, - .selection__checkbox { - flex: 0 0 auto; - flex-shrink: 0; - } - } -` - -export default React.memo(DocLabelSelectionModal) diff --git a/src/cloud/components/organisms/FeedbackForm/ExpandingRow.tsx b/src/cloud/components/organisms/FeedbackForm/ExpandingRow.tsx deleted file mode 100644 index 87b04245d4..0000000000 --- a/src/cloud/components/organisms/FeedbackForm/ExpandingRow.tsx +++ /dev/null @@ -1,91 +0,0 @@ -import React, { useCallback } from 'react' -import styled from '../../../lib/styled' -import { generateSecret } from '../../../lib/utils/secret' -import { inputStyle } from '../../../lib/styled/styleFunctions' - -interface ExpandingRowProps { - label: string - isChecked: boolean - expandedLabel: string - expandedValue?: string - toggleCheckBoxValue: () => void - onChangeExpandedValue: (val: string) => void -} - -const ExpandingRow = ({ - label, - isChecked, - toggleCheckBoxValue, - expandedValue = '', - expandedLabel, - onChangeExpandedValue, -}: ExpandingRowProps) => { - const rowId = generateSecret() - const onCheckboxChangeHandler = useCallback(() => { - toggleCheckBoxValue() - }, [toggleCheckBoxValue]) - - const onTextAreaChangeHandler = useCallback( - (event: React.ChangeEvent) => { - onChangeExpandedValue(event.target.value) - }, - [onChangeExpandedValue] - ) - - return ( - -
    - - -
    - {isChecked && ( -
    - -