From 5dafb6496339a7885fefd0af8502d644d882966b Mon Sep 17 00:00:00 2001 From: Baptiste Arnaud Date: Thu, 7 Mar 2024 10:09:00 +0100 Subject: [PATCH] :lipstick: Improve editor header responsiveness Closes #1204 --- .../editor/components/TypebotHeader.tsx | 523 ++++++++++-------- .../share/components/ShareTypebotButton.tsx | 6 +- 2 files changed, 293 insertions(+), 236 deletions(-) diff --git a/apps/builder/src/features/editor/components/TypebotHeader.tsx b/apps/builder/src/features/editor/components/TypebotHeader.tsx index d26200525..17228d81e 100644 --- a/apps/builder/src/features/editor/components/TypebotHeader.tsx +++ b/apps/builder/src/features/editor/components/TypebotHeader.tsx @@ -8,6 +8,8 @@ import { Text, useColorModeValue, useDisclosure, + StackProps, + chakra, } from '@chakra-ui/react' import { BuoyIcon, @@ -37,70 +39,12 @@ import { useWorkspace } from '@/features/workspace/WorkspaceProvider' import { Plan } from '@typebot.io/prisma' export const TypebotHeader = () => { - const { t } = useTranslate() - const router = useRouter() - const { - typebot, - publishedTypebot, - updateTypebot, - save, - undo, - redo, - canUndo, - canRedo, - isSavingLoading, - currentUserMode, - } = useTypebot() + const { typebot, publishedTypebot, currentUserMode } = useTypebot() const { workspace } = useWorkspace() - const { - setRightPanel, - rightPanel, - setStartPreviewAtGroup, - setStartPreviewAtEvent, - } = useEditor() - const [isUndoShortcutTooltipOpen, setUndoShortcutTooltipOpen] = - useState(false) - const hideUndoShortcutTooltipLater = useDebouncedCallback(() => { - setUndoShortcutTooltipOpen(false) - }, 1000) - const [isRedoShortcutTooltipOpen, setRedoShortcutTooltipOpen] = - useState(false) - const hideRedoShortcutTooltipLater = useDebouncedCallback(() => { - setRedoShortcutTooltipOpen(false) - }, 1000) + const { isOpen, onOpen } = useDisclosure() const headerBgColor = useColorModeValue('white', 'gray.900') - const handleNameSubmit = (name: string) => - updateTypebot({ updates: { name } }) - - const handleChangeIcon = (icon: string) => - updateTypebot({ updates: { icon } }) - - const handlePreviewClick = async () => { - setStartPreviewAtGroup(undefined) - setStartPreviewAtEvent(undefined) - save().then() - setRightPanel(RightPanel.PREVIEW) - } - - useKeyboardShortcuts({ - undo: () => { - if (!canUndo) return - hideUndoShortcutTooltipLater.flush() - setUndoShortcutTooltipOpen(true) - hideUndoShortcutTooltipLater() - undo() - }, - redo: () => { - if (!canRedo) return - hideUndoShortcutTooltipLater.flush() - setRedoShortcutTooltipOpen(true) - hideRedoShortcutTooltipLater() - redo() - }, - }) - const handleHelpClick = () => { isCloudProdInstance() && workspace?.plan && workspace.plan !== Plan.FREE ? onOpen() @@ -121,182 +65,291 @@ export const TypebotHeader = () => { flexShrink={0} > {isOpen && } - - - - - - {isDefined(publishedTypebot) && ( - - )} - - + + - - } - href={{ - pathname: router.query.parentId - ? '/typebots/[typebotId]/edit' - : typebot?.folderId - ? '/typebots/folders/[folderId]' - : '/typebots', - query: { - folderId: typebot?.folderId ?? [], - parentId: Array.isArray(router.query.parentId) - ? router.query.parentId.slice(0, -1) - : [], - typebotId: Array.isArray(router.query.parentId) - ? [...router.query.parentId].pop() - : router.query.parentId ?? [], - }, - }} - size="sm" - /> - - {typebot && ( - - )} - ( - - ) - - - {currentUserMode === 'write' && ( - - - } - size="sm" - aria-label={t('editor.header.undoButton.label')} - onClick={undo} - isDisabled={!canUndo} - /> - - - - } - size="sm" - aria-label={t('editor.header.redoButton.label')} - onClick={redo} - isDisabled={!canRedo} - /> - - - )} - - - {isSavingLoading && ( - - - - {t('editor.header.savingSpinner.label')} - - - )} - - - - - - - {router.pathname.includes('/edit') && isNotDefined(rightPanel) && ( - - )} - {currentUserMode === 'write' && } - + display={['none', 'flex']} + isResultsDisplayed={isDefined(publishedTypebot)} + /> ) } + +const LeftElements = (props: StackProps & { onHelpClick: () => void }) => { + const { t } = useTranslate() + const router = useRouter() + const { + typebot, + updateTypebot, + canUndo, + canRedo, + undo, + redo, + currentUserMode, + isSavingLoading, + } = useTypebot() + + const [isRedoShortcutTooltipOpen, setRedoShortcutTooltipOpen] = + useState(false) + + const [isUndoShortcutTooltipOpen, setUndoShortcutTooltipOpen] = + useState(false) + + const hideUndoShortcutTooltipLater = useDebouncedCallback(() => { + setUndoShortcutTooltipOpen(false) + }, 1000) + + const hideRedoShortcutTooltipLater = useDebouncedCallback(() => { + setRedoShortcutTooltipOpen(false) + }, 1000) + + const handleNameSubmit = (name: string) => + updateTypebot({ updates: { name } }) + + const handleChangeIcon = (icon: string) => + updateTypebot({ updates: { icon } }) + + useKeyboardShortcuts({ + undo: () => { + if (!canUndo) return + hideUndoShortcutTooltipLater.flush() + setUndoShortcutTooltipOpen(true) + hideUndoShortcutTooltipLater() + undo() + }, + redo: () => { + if (!canRedo) return + hideUndoShortcutTooltipLater.flush() + setRedoShortcutTooltipOpen(true) + hideRedoShortcutTooltipLater() + redo() + }, + }) + + return ( + + + } + href={{ + pathname: router.query.parentId + ? '/typebots/[typebotId]/edit' + : typebot?.folderId + ? '/typebots/folders/[folderId]' + : '/typebots', + query: { + folderId: typebot?.folderId ?? [], + parentId: Array.isArray(router.query.parentId) + ? router.query.parentId.slice(0, -1) + : [], + typebotId: Array.isArray(router.query.parentId) + ? [...router.query.parentId].pop() + : router.query.parentId ?? [], + }, + }} + size="sm" + /> + + {typebot && ( + + )} + ( + + ) + + + {currentUserMode === 'write' && ( + + + } + size="sm" + aria-label={t('editor.header.undoButton.label')} + onClick={undo} + isDisabled={!canUndo} + /> + + + + } + size="sm" + aria-label={t('editor.header.redoButton.label')} + onClick={redo} + isDisabled={!canRedo} + /> + + + )} + + + {isSavingLoading && ( + + + + {t('editor.header.savingSpinner.label')} + + + )} + + ) +} + +const RightElements = (props: StackProps & { isResultsDisplayed: boolean }) => { + const router = useRouter() + const { t } = useTranslate() + const { typebot, currentUserMode, save } = useTypebot() + const { + setRightPanel, + rightPanel, + setStartPreviewAtGroup, + setStartPreviewAtEvent, + } = useEditor() + + const handlePreviewClick = async () => { + setStartPreviewAtGroup(undefined) + setStartPreviewAtEvent(undefined) + save().then() + setRightPanel(RightPanel.PREVIEW) + } + + return ( + + + + + + {router.pathname.includes('/edit') && isNotDefined(rightPanel) && ( + + )} + {currentUserMode === 'write' && } + + ) +} + +const TypebotNav = ({ + typebotId, + isResultsDisplayed, + ...stackProps +}: { + typebotId?: string + isResultsDisplayed: boolean +} & StackProps) => { + const { t } = useTranslate() + const router = useRouter() + + return ( + + + + + + {isResultsDisplayed && ( + + )} + + ) +} diff --git a/apps/builder/src/features/share/components/ShareTypebotButton.tsx b/apps/builder/src/features/share/components/ShareTypebotButton.tsx index 69368add2..574c9da77 100644 --- a/apps/builder/src/features/share/components/ShareTypebotButton.tsx +++ b/apps/builder/src/features/share/components/ShareTypebotButton.tsx @@ -3,6 +3,7 @@ import { PopoverTrigger, PopoverContent, Button, + chakra, } from '@chakra-ui/react' import { UsersIcon } from '@/components/icons' import React from 'react' @@ -20,8 +21,11 @@ export const ShareTypebotButton = ({ isLoading }: { isLoading: boolean }) => { leftIcon={} aria-label={t('share.button.popover.ariaLabel')} size="sm" + iconSpacing={{ base: 0, xl: 2 }} > - {t('share.button.label')} + + {t('share.button.label')} +