From 0c99bfbc31da8327979c6fa7a8e00b95208360e5 Mon Sep 17 00:00:00 2001 From: nitin <142569587+ehconitin@users.noreply.github.com> Date: Wed, 7 Aug 2024 11:53:05 +0530 Subject: [PATCH] New sidemenu for notes editor (#6527) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @Bonapara @lucasbordeau This PR addresses issue #6489: - Created an entire sidemenu for the block editor. ## Review Request Please review the implementation of the custom sidemenu. ## Outstanding Issues 1. Sidemenu Positioning: - The current placement is determined by the BlockNote package. - I need assistance in positioning it according to the Figma designs. - Attempted adding margin to the sidemenu, but this solution doesn't scale well across different screen sizes. 2. Props Spreading in `CustomSidemenu.tsx`: - Unable to avoid props spreading due to the third-party BlockNote components. - Added eslint-disable comments as a temporary solution. Your insights on these challenges would be greatly appreciated, especially regarding the sidemenu positioning and any potential alternatives to props spreading. https://github.com/user-attachments/assets/4914a037-a115-4189-88bc-a41d121d309d --------- Co-authored-by: Félix Malfait --- .../input/editor/components/BlockEditor.tsx | 50 ++++++++++++++ .../editor/components/CustomAddBlockItem.tsx | 42 ++++++++++++ .../editor/components/CustomSideMenu.tsx | 67 +++++++++++++++++++ .../components/CustomSideMenuOptions.tsx | 39 +++++++++++ .../components/ShowPageActivityContainer.tsx | 2 +- .../components/MenuItemSuggestion.tsx | 2 +- 6 files changed, 200 insertions(+), 2 deletions(-) create mode 100644 packages/twenty-front/src/modules/ui/input/editor/components/CustomAddBlockItem.tsx create mode 100644 packages/twenty-front/src/modules/ui/input/editor/components/CustomSideMenu.tsx create mode 100644 packages/twenty-front/src/modules/ui/input/editor/components/CustomSideMenuOptions.tsx diff --git a/packages/twenty-front/src/modules/ui/input/editor/components/BlockEditor.tsx b/packages/twenty-front/src/modules/ui/input/editor/components/BlockEditor.tsx index 62797f317c0e..3c9a30db6e5d 100644 --- a/packages/twenty-front/src/modules/ui/input/editor/components/BlockEditor.tsx +++ b/packages/twenty-front/src/modules/ui/input/editor/components/BlockEditor.tsx @@ -7,6 +7,7 @@ import { ClipboardEvent } from 'react'; import { blockSchema } from '@/activities/blocks/schema'; import { getSlashMenu } from '@/activities/blocks/slashMenu'; +import { CustomSideMenu } from '@/ui/input/editor/components/CustomSideMenu'; import { CustomSlashMenu, SuggestionItem, @@ -35,7 +36,12 @@ const StyledEditor = styled.div` font-style: normal; } & .mantine-ActionIcon-icon { + height: 20px; width: 20px; + background: transparent; + } + & .bn-editor { + padding-inline: 36px; } & .bn-container .bn-drag-handle { width: 20px; @@ -45,6 +51,48 @@ const StyledEditor = styled.div` display: flex; align-items: center; } + & .bn-drag-handle-menu { + background: ${({ theme }) => theme.background.transparent.secondary}; + backdrop-filter: blur(12px) saturate(200%) contrast(50%) brightness(130%); + box-shadow: + 0px 2px 4px rgba(0, 0, 0, 0.04), + 2px 4px 16px rgba(0, 0, 0, 0.12); + min-width: 160px; + min-height: 96px; + padding: 4px; + border-radius: 8px; + border: 1px solid ${({ theme }) => theme.border.color.medium}; + left: 26px; + } + & .mantine-Menu-item { + background-color: transparent; + min-width: 152px; + min-height: 32px; + + font-style: normal; + font-family: ${({ theme }) => theme.font.family}; + font-weight: ${({ theme }) => theme.font.weight.regular}; + color: ${({ theme }) => theme.font.color.secondary}; + } + & .mantine-ActionIcon-root:hover { + box-shadow: + 0px 0px 4px rgba(0, 0, 0, 0.08), + 0px 2px 4px rgba(0, 0, 0, 0.04); + background: ${({ theme }) => theme.background.transparent.primary}; + backdrop-filter: blur(20px); + border: 1px solid ${({ theme }) => theme.border.color.light}; + } + & .bn-side-menu .mantine-UnstyledButton-root:not(.mantine-Menu-item) svg { + height: 20px; + width: 20px; + } + + & .bn-mantine .bn-side-menu > [draggable='true'] { + margin-bottom: 5px; + } + & .bn-color-picker-dropdown { + margin-left: 8px; + } `; export const BlockEditor = ({ @@ -83,7 +131,9 @@ export const BlockEditor = ({ editor={editor} theme={blockNoteTheme} slashMenu={false} + sideMenu={false} > + diff --git a/packages/twenty-front/src/modules/ui/input/editor/components/CustomAddBlockItem.tsx b/packages/twenty-front/src/modules/ui/input/editor/components/CustomAddBlockItem.tsx new file mode 100644 index 000000000000..e4f603117d0b --- /dev/null +++ b/packages/twenty-front/src/modules/ui/input/editor/components/CustomAddBlockItem.tsx @@ -0,0 +1,42 @@ +import { blockSchema } from '@/activities/blocks/schema'; + +import { useComponentsContext } from '@blocknote/react'; + +type CustomAddBlockItemProps = { + editor: typeof blockSchema.BlockNoteEditor; + children: React.ReactNode; // Adding the children prop +}; + +type ContentItem = { + type: string; + text: string; + styles: any; +}; +export const CustomAddBlockItem = ({ + editor, + children, +}: CustomAddBlockItemProps) => { + const Components = useComponentsContext(); + + const handleClick = () => { + const blockIdentifier = editor.getTextCursorPosition().block; + const currentBlockContent = blockIdentifier?.content as + | Array + | undefined; + + const [firstElement] = currentBlockContent || []; + + if (firstElement === undefined) { + editor.openSelectionMenu('/'); + } else { + editor.sideMenu.addBlock(); + editor.openSelectionMenu('/'); + editor.sideMenu.unfreezeMenu(); + } + }; + return ( + + {children} + + ); +}; diff --git a/packages/twenty-front/src/modules/ui/input/editor/components/CustomSideMenu.tsx b/packages/twenty-front/src/modules/ui/input/editor/components/CustomSideMenu.tsx new file mode 100644 index 000000000000..6f44e0ebc501 --- /dev/null +++ b/packages/twenty-front/src/modules/ui/input/editor/components/CustomSideMenu.tsx @@ -0,0 +1,67 @@ +import { blockSchema } from '@/activities/blocks/schema'; +import { CustomAddBlockItem } from '@/ui/input/editor/components/CustomAddBlockItem'; +import { CustomSideMenuOptions } from '@/ui/input/editor/components/CustomSideMenuOptions'; +import { + BlockColorsItem, + DragHandleButton, + DragHandleMenu, + RemoveBlockItem, + SideMenu, + SideMenuController, +} from '@blocknote/react'; +import styled from '@emotion/styled'; +import { IconColorSwatch, IconPlus, IconTrash } from 'twenty-ui'; + +type CustomSideMenuProps = { + editor: typeof blockSchema.BlockNoteEditor; +}; + +const StyledDivToCreateGap = styled.div` + width: ${({ theme }) => theme.spacing(2)}; +`; + +export const CustomSideMenu = ({ editor }: CustomSideMenuProps) => { + return ( + ( + // eslint-disable-next-line react/jsx-props-no-spreading + + ( + // eslint-disable-next-line react/jsx-props-no-spreading + + + + + {/* eslint-disable-next-line react/jsx-props-no-spreading */} + + + + {/* eslint-disable-next-line react/jsx-props-no-spreading */} + + {' '} + + + + )} + /> + + + )} + /> + ); +}; diff --git a/packages/twenty-front/src/modules/ui/input/editor/components/CustomSideMenuOptions.tsx b/packages/twenty-front/src/modules/ui/input/editor/components/CustomSideMenuOptions.tsx new file mode 100644 index 000000000000..a767716246e2 --- /dev/null +++ b/packages/twenty-front/src/modules/ui/input/editor/components/CustomSideMenuOptions.tsx @@ -0,0 +1,39 @@ +import { useTheme } from '@emotion/react'; +import styled from '@emotion/styled'; +import { IconComponent } from 'twenty-ui'; + +const StyledContainer = styled.div<{ Variant: Variants }>` + color: ${({ theme, Variant }) => + Variant === 'danger' ? theme.color.red : 'inherit'}; + align-items: center; + display: flex; + flex-direction: row; + gap: ${({ theme }) => theme.spacing(2)}; +`; + +const StyledTextContainer = styled.div``; + +type CustomSideMenuOptionsProps = { + LeftIcon: IconComponent; // Any valid React node (e.g., a component) + Variant: Variants; + text: string; +}; + +type Variants = 'normal' | 'danger'; + +export const CustomSideMenuOptions = ({ + LeftIcon, + Variant, + text, +}: CustomSideMenuOptionsProps) => { + const theme = useTheme(); + return ( + + + {text} + + ); +}; diff --git a/packages/twenty-front/src/modules/ui/layout/show-page/components/ShowPageActivityContainer.tsx b/packages/twenty-front/src/modules/ui/layout/show-page/components/ShowPageActivityContainer.tsx index 4e89aa1af1e3..bdd81f97c93e 100644 --- a/packages/twenty-front/src/modules/ui/layout/show-page/components/ShowPageActivityContainer.tsx +++ b/packages/twenty-front/src/modules/ui/layout/show-page/components/ShowPageActivityContainer.tsx @@ -4,7 +4,7 @@ import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSi import styled from '@emotion/styled'; const StyledShowPageActivityContainer = styled.div` - margin-top: ${({ theme }) => theme.spacing(2)}; + margin-top: ${({ theme }) => theme.spacing(6)}; width: 100%; `; export const ShowPageActivityContainer = ({ diff --git a/packages/twenty-front/src/modules/ui/navigation/menu-item/components/MenuItemSuggestion.tsx b/packages/twenty-front/src/modules/ui/navigation/menu-item/components/MenuItemSuggestion.tsx index 7017864d3884..1f6548e4924c 100644 --- a/packages/twenty-front/src/modules/ui/navigation/menu-item/components/MenuItemSuggestion.tsx +++ b/packages/twenty-front/src/modules/ui/navigation/menu-item/components/MenuItemSuggestion.tsx @@ -1,5 +1,5 @@ -import { MouseEvent } from 'react'; import styled from '@emotion/styled'; +import { MouseEvent } from 'react'; import { HOVER_BACKGROUND, IconComponent } from 'twenty-ui'; import { MenuItemLeftContent } from '../internals/components/MenuItemLeftContent';