From b698f445001d587023db3612057c61cdac7c6a94 Mon Sep 17 00:00:00 2001 From: Aaryan Khandelwal <65252264+aaryan610@users.noreply.github.com> Date: Tue, 28 Jan 2025 20:21:09 +0530 Subject: [PATCH] [PE-155] chore: floating toolbar for pages (#6482) * chore: add floating toolbar to pages * fix: locked page toolbar --- .../editors/document/collaborative-editor.tsx | 4 ++- .../editors/document/page-renderer.tsx | 6 ++-- .../editors/document/read-only-editor.tsx | 1 + packages/editor/src/core/types/editor.ts | 3 +- .../components/pages/dropdowns/actions.tsx | 1 + .../pages/editor/header/options-dropdown.tsx | 28 +++++++++++++++++-- .../components/pages/editor/header/root.tsx | 6 ++-- web/core/hooks/use-page-filters.ts | 28 ++++++++++++++++++- 8 files changed, 67 insertions(+), 10 deletions(-) diff --git a/packages/editor/src/core/components/editors/document/collaborative-editor.tsx b/packages/editor/src/core/components/editors/document/collaborative-editor.tsx index 44c18c2f680..d7d3819f21d 100644 --- a/packages/editor/src/core/components/editors/document/collaborative-editor.tsx +++ b/packages/editor/src/core/components/editors/document/collaborative-editor.tsx @@ -16,6 +16,7 @@ const CollaborativeDocumentEditor = (props: ICollaborativeDocumentEditor) => { const { onTransaction, aiHandler, + bubbleMenuEnabled = true, containerClassName, disabledExtensions, displayConfig = DEFAULT_DISPLAY_CONFIG, @@ -75,8 +76,9 @@ const CollaborativeDocumentEditor = (props: ICollaborativeDocumentEditor) => { return ( { - const { aiHandler, displayConfig, editor, editorContainerClassName, id, tabIndex } = props; + const { aiHandler, bubbleMenuEnabled, displayConfig, editor, editorContainerClassName, id, tabIndex } = props; // states const [linkViewProps, setLinkViewProps] = useState(); const [isOpen, setIsOpen] = useState(false); @@ -141,6 +142,7 @@ export const PageRenderer = (props: IPageRenderer) => { {editor.isEditable && (
+ {bubbleMenuEnabled && }
diff --git a/packages/editor/src/core/components/editors/document/read-only-editor.tsx b/packages/editor/src/core/components/editors/document/read-only-editor.tsx index 0e8ab63f8a8..c8753fe42fd 100644 --- a/packages/editor/src/core/components/editors/document/read-only-editor.tsx +++ b/packages/editor/src/core/components/editors/document/read-only-editor.tsx @@ -69,6 +69,7 @@ const DocumentReadOnlyEditor = (props: IDocumentReadOnlyEditor) => { return ( { - editable: boolean; aiHandler?: TAIHandler; + bubbleMenuEnabled?: boolean; + editable: boolean; embedHandler: TEmbedConfig; handleEditorReady?: (value: boolean) => void; id: string; diff --git a/web/core/components/pages/dropdowns/actions.tsx b/web/core/components/pages/dropdowns/actions.tsx index e4af59abe6c..b948ca6bcbd 100644 --- a/web/core/components/pages/dropdowns/actions.tsx +++ b/web/core/components/pages/dropdowns/actions.tsx @@ -36,6 +36,7 @@ import { TPageInstance } from "@/store/pages/base-page"; export type TPageActions = | "full-screen" + | "sticky-toolbar" | "copy-markdown" | "toggle-lock" | "toggle-access" diff --git a/web/core/components/pages/editor/header/options-dropdown.tsx b/web/core/components/pages/editor/header/options-dropdown.tsx index fb096ed2c66..e1807bcc9c6 100644 --- a/web/core/components/pages/editor/header/options-dropdown.tsx +++ b/web/core/components/pages/editor/header/options-dropdown.tsx @@ -30,9 +30,9 @@ export const PageOptionsDropdown: React.FC = observer((props) => { // router const router = useRouter(); // store values - const { name } = page; + const { name, isContentEditable } = page; // page filters - const { isFullWidth, handleFullWidth } = usePageFilters(); + const { isFullWidth, handleFullWidth, isStickyToolbarEnabled, handleStickyToolbar } = usePageFilters(); // update query params const { updateQueryParams } = useQueryParams(); // menu items list @@ -49,6 +49,18 @@ export const PageOptionsDropdown: React.FC = observer((props) => { ), className: "flex items-center justify-between gap-2", }, + { + key: "sticky-toolbar", + action: () => handleStickyToolbar(!isStickyToolbarEnabled), + customContent: ( + <> + Sticky toolbar + {}} /> + + ), + className: "flex items-center justify-between gap-2", + shouldRender: isContentEditable, + }, { key: "copy-markdown", action: () => { @@ -86,7 +98,16 @@ export const PageOptionsDropdown: React.FC = observer((props) => { shouldRender: true, }, ], - [editorRef, handleFullWidth, isFullWidth, router, updateQueryParams] + [ + editorRef, + handleFullWidth, + handleStickyToolbar, + isContentEditable, + isFullWidth, + isStickyToolbarEnabled, + router, + updateQueryParams, + ] ); return ( @@ -102,6 +123,7 @@ export const PageOptionsDropdown: React.FC = observer((props) => { extraOptions={EXTRA_MENU_OPTIONS} optionsOrder={[ "full-screen", + "sticky-toolbar", "copy-link", "make-a-copy", "move", diff --git a/web/core/components/pages/editor/header/root.tsx b/web/core/components/pages/editor/header/root.tsx index 996f501bb3f..a9dfdad51b3 100644 --- a/web/core/components/pages/editor/header/root.tsx +++ b/web/core/components/pages/editor/header/root.tsx @@ -23,7 +23,7 @@ export const PageEditorHeaderRoot: React.FC = observer((props) => { // derived values const { isContentEditable } = page; // page filters - const { isFullWidth } = usePageFilters(); + const { isFullWidth, isStickyToolbarEnabled } = usePageFilters(); // derived values const resolvedEditorRef = editorRef.current; @@ -48,7 +48,9 @@ export const PageEditorHeaderRoot: React.FC = observer((props) => { /> )} - {editorReady && isContentEditable && editorRef.current && } + {isStickyToolbarEnabled && editorReady && isContentEditable && editorRef.current && ( + + )} diff --git a/web/core/hooks/use-page-filters.ts b/web/core/hooks/use-page-filters.ts index e7698a93405..448c589777b 100644 --- a/web/core/hooks/use-page-filters.ts +++ b/web/core/hooks/use-page-filters.ts @@ -8,12 +8,14 @@ export type TPagesPersonalizationConfig = { full_width: boolean; font_size: TEditorFontSize; font_style: TEditorFontStyle; + sticky_toolbar: boolean; }; const DEFAULT_PERSONALIZATION_VALUES: TPagesPersonalizationConfig = { full_width: false, font_size: "large-font", font_style: "sans-serif", + sticky_toolbar: true, }; export const usePageFilters = () => { @@ -23,7 +25,17 @@ export const usePageFilters = () => { DEFAULT_PERSONALIZATION_VALUES ); // stored values - const isFullWidth = useMemo(() => !!pagesConfig?.full_width, [pagesConfig?.full_width]); + const isFullWidth = useMemo( + () => (pagesConfig?.full_width === undefined ? DEFAULT_PERSONALIZATION_VALUES.full_width : pagesConfig?.full_width), + [pagesConfig?.full_width] + ); + const isStickyToolbarEnabled = useMemo( + () => + pagesConfig?.sticky_toolbar === undefined + ? DEFAULT_PERSONALIZATION_VALUES.sticky_toolbar + : pagesConfig?.sticky_toolbar, + [pagesConfig?.sticky_toolbar] + ); const fontSize = useMemo( () => pagesConfig?.font_size ?? DEFAULT_PERSONALIZATION_VALUES.font_size, [pagesConfig?.font_size] @@ -78,6 +90,18 @@ export const usePageFilters = () => { }, [handleUpdateConfig] ); + /** + * @description action to update full_width value + * @param {boolean} value + */ + const handleStickyToolbar = useCallback( + (value: boolean) => { + handleUpdateConfig({ + sticky_toolbar: value, + }); + }, + [handleUpdateConfig] + ); return { fontSize, @@ -86,5 +110,7 @@ export const usePageFilters = () => { handleFontStyle, isFullWidth, handleFullWidth, + isStickyToolbarEnabled, + handleStickyToolbar, }; };