diff --git a/apps/builder/assets/icons.tsx b/apps/builder/assets/icons.tsx index 57f9a8c04e..a8e6fa1be5 100644 --- a/apps/builder/assets/icons.tsx +++ b/apps/builder/assets/icons.tsx @@ -250,3 +250,12 @@ export const UserIcon = (props: IconProps) => ( ) + +export const ExpandIcon = (props: IconProps) => ( + + + + + + +) diff --git a/apps/builder/components/board/Board.tsx b/apps/builder/components/board/Board.tsx index c5ba41159c..db37603a72 100644 --- a/apps/builder/components/board/Board.tsx +++ b/apps/builder/components/board/Board.tsx @@ -16,7 +16,7 @@ export const Board = () => { - + {rightPanel === RightPanel.PREVIEW && } diff --git a/apps/builder/components/board/BoardMenuButton.tsx b/apps/builder/components/board/BoardMenuButton.tsx index feef5c31bc..9218544229 100644 --- a/apps/builder/components/board/BoardMenuButton.tsx +++ b/apps/builder/components/board/BoardMenuButton.tsx @@ -35,6 +35,8 @@ export const BoardMenuButton = (props: MenuButtonProps) => { } isLoading={isDownloading} {...props} diff --git a/apps/builder/components/board/StepTypesList/StepCard.tsx b/apps/builder/components/board/StepTypesList/StepCard.tsx index ba6076a5e5..a63f5dbffb 100644 --- a/apps/builder/components/board/StepTypesList/StepCard.tsx +++ b/apps/builder/components/board/StepTypesList/StepCard.tsx @@ -1,4 +1,4 @@ -import { Button, ButtonProps, Flex, HStack } from '@chakra-ui/react' +import { Flex, HStack, StackProps, Text } from '@chakra-ui/react' import { StepType, DraggableStepType } from 'models' import { useDnd } from 'contexts/DndContext' import React, { useEffect, useState } from 'react' @@ -23,22 +23,31 @@ export const StepCard = ({ return ( - + ) } @@ -46,23 +55,24 @@ export const StepCard = ({ export const StepCardOverlay = ({ type, ...props -}: Omit & { type: StepType }) => { +}: StackProps & { type: StepType }) => { return ( - + ) } diff --git a/apps/builder/components/board/StepTypesList/StepTypesList.tsx b/apps/builder/components/board/StepTypesList/StepTypesList.tsx index 000d9831b8..c8f7fb6b03 100644 --- a/apps/builder/components/board/StepTypesList/StepTypesList.tsx +++ b/apps/builder/components/board/StepTypesList/StepTypesList.tsx @@ -4,6 +4,7 @@ import { Text, SimpleGrid, useEventListener, + Portal, } from '@chakra-ui/react' import { BubbleStepType, @@ -38,10 +39,11 @@ export const StepTypesList = () => { const handleMouseDown = (e: React.MouseEvent, type: DraggableStepType) => { const element = e.currentTarget as HTMLDivElement const rect = element.getBoundingClientRect() - const relativeX = e.clientX - rect.left - const relativeY = e.clientY - rect.top - setPosition({ x: e.clientX - relativeX, y: e.clientY - relativeY }) - setRelativeCoordinates({ x: relativeX, y: relativeY }) + setPosition({ x: rect.left, y: rect.top }) + const x = e.clientX - rect.left + const y = e.clientY - rect.top + setRelativeCoordinates({ x, y }) + console.log({ x: rect.left, y: rect.top }) setDraggedStepType(type) } @@ -60,60 +62,76 @@ export const StepTypesList = () => { w="320px" pos="absolute" left="10px" - top="20px" - h="calc(100vh - 100px)" + top="10px" + h="calc(100vh - 80px)" rounded="lg" - shadow="lg" + shadow="xl" borderWidth="1px" - zIndex="10" + zIndex="2" py="4" px="2" - bgColor="white" + bgColor="gray.50" + spacing={6} + userSelect="none" > - - - Bubbles - - - {Object.values(BubbleStepType).map((type) => ( - - ))} - + + + + Bubbles + + + {Object.values(BubbleStepType).map((type) => ( + + ))} + + - - Inputs - - - {Object.values(InputStepType).map((type) => ( - - ))} - + + + Inputs + + + {Object.values(InputStepType).map((type) => ( + + ))} + + - - Logic - - - {Object.values(LogicStepType).map((type) => ( - - ))} - + + + Logic + + + {Object.values(LogicStepType).map((type) => ( + + ))} + + + + + + Integrations + + + {Object.values(IntegrationStepType).map((type) => ( + + ))} + + - - Integrations - - - {Object.values(IntegrationStepType).map((type) => ( - - ))} - {draggedStepType && ( - + + + )} ) diff --git a/apps/builder/components/board/graph/BlockNode/BlockNode.tsx b/apps/builder/components/board/graph/BlockNode/BlockNode.tsx index aa671df296..922f5b92a2 100644 --- a/apps/builder/components/board/graph/BlockNode/BlockNode.tsx +++ b/apps/builder/components/board/graph/BlockNode/BlockNode.tsx @@ -25,7 +25,6 @@ export const BlockNode = ({ block }: Props) => { const { setMouseOverBlockId } = useDnd() const { draggedStep, draggedStepType } = useDnd() const [isMouseDown, setIsMouseDown] = useState(false) - const [titleValue, setTitleValue] = useState(block.title) const [isConnecting, setIsConnecting] = useState(false) const isPreviewing = useMemo( () => @@ -41,7 +40,7 @@ export const BlockNode = ({ block }: Props) => { ) }, [block.id, connectingIds]) - const handleTitleChange = (title: string) => setTitleValue(title) + const handleTitleSubmit = (title: string) => updateBlock(block.id, { title }) const handleMouseDown = () => { setIsMouseDown(true) @@ -49,6 +48,7 @@ export const BlockNode = ({ block }: Props) => { const handleMouseUp = () => { setIsMouseDown(false) } + useEventListener('mouseup', handleMouseUp) const handleMouseMove = (event: MouseEvent) => { if (!isMouseDown) return @@ -85,24 +85,31 @@ export const BlockNode = ({ block }: Props) => { p="4" rounded="lg" bgColor="blue.50" + backgroundImage="linear-gradient(rgb(235, 239, 244), rgb(231, 234, 241))" borderWidth="2px" borderColor={ - isConnecting || isOpened || isPreviewing ? 'blue.400' : 'gray.400' + isConnecting || isOpened || isPreviewing ? 'blue.400' : 'white' } minW="300px" - transition="border 300ms" + transition="border 300ms, box-shadow 200ms" pos="absolute" style={{ transform: `translate(${block.graphCoordinates.x}px, ${block.graphCoordinates.y}px)`, }} onMouseDown={handleMouseDown} - onMouseUp={handleMouseUp} onMouseEnter={handleMouseEnter} onMouseLeave={handleMouseLeave} + cursor={isMouseDown ? 'grabbing' : 'pointer'} + boxShadow="0px 0px 0px 1px #e9edf3;" + _hover={{ shadow: 'lg' }} > - + diff --git a/apps/builder/components/board/graph/BlockNode/StepNode/ChoiceInputStepNode/ChoiceItemNode.tsx b/apps/builder/components/board/graph/BlockNode/StepNode/ChoiceInputStepNode/ChoiceItemNode.tsx index bbca20cd5a..f17de12cf4 100644 --- a/apps/builder/components/board/graph/BlockNode/StepNode/ChoiceInputStepNode/ChoiceItemNode.tsx +++ b/apps/builder/components/board/graph/BlockNode/StepNode/ChoiceInputStepNode/ChoiceItemNode.tsx @@ -99,15 +99,17 @@ export const ChoiceItemNode = ({ onMouseEnter={handleMouseEnter} onMouseLeave={handleMouseLeave} justifyContent="center" + shadow="sm" + _hover={{ shadow: 'md' }} + transition="box-shadow 200ms" + borderWidth="1px" + rounded="md" + px="4" + py="2" + borderColor={isOpened ? 'blue.400' : 'gray.300'} > - + {typebot && isSingleChoiceInput(typebot.steps.byId[item.stepId]) && ( @@ -138,6 +143,8 @@ export const ChoiceItemNode = ({ aria-label="Add item" icon={} size="xs" + shadow="md" + colorScheme="blue" onClick={handlePlusClick} /> diff --git a/apps/builder/components/board/graph/BlockNode/StepNode/ChoiceInputStepNode/ChoiceItemNodeOverlay.tsx b/apps/builder/components/board/graph/BlockNode/StepNode/ChoiceInputStepNode/ChoiceItemNodeOverlay.tsx index de0b0fefcd..79f69e453d 100644 --- a/apps/builder/components/board/graph/BlockNode/StepNode/ChoiceInputStepNode/ChoiceItemNodeOverlay.tsx +++ b/apps/builder/components/board/graph/BlockNode/StepNode/ChoiceInputStepNode/ChoiceItemNodeOverlay.tsx @@ -15,11 +15,12 @@ export const ChoiceItemNodeOverlay = ({ px="4" py="2" rounded="md" - bgColor="green.200" - borderWidth="2px" - borderColor={'gray.400'} + bgColor="white" + borderWidth="1px" + borderColor={'gray.300'} w="212px" pointerEvents="none" + shadow="lg" {...props} > {item.content ?? 'Click to edit'} diff --git a/apps/builder/components/board/graph/BlockNode/StepNode/ChoiceInputStepNode/ChoiceItemsList.tsx b/apps/builder/components/board/graph/BlockNode/StepNode/ChoiceInputStepNode/ChoiceItemsList.tsx index dba6b6f3c9..78f2d577a6 100644 --- a/apps/builder/components/board/graph/BlockNode/StepNode/ChoiceInputStepNode/ChoiceItemsList.tsx +++ b/apps/builder/components/board/graph/BlockNode/StepNode/ChoiceInputStepNode/ChoiceItemsList.tsx @@ -44,14 +44,17 @@ export const ChoiceItemsList = ({ step }: ChoiceItemsListProps) => { } useEventListener('mousemove', handleStepMove) - const handleMouseUp = (e: React.MouseEvent) => { - if (expandedPlaceholderIndex === undefined || !draggedChoiceItem) return - e.stopPropagation() + const handleMouseUp = (e: MouseEvent) => { + if (!draggedChoiceItem) return + if (expandedPlaceholderIndex !== -1) { + e.stopPropagation() + createChoiceItem(draggedChoiceItem, expandedPlaceholderIndex) + } setMouseOverBlockId(undefined) setExpandedPlaceholderIndex(undefined) setDraggedChoiceItem(undefined) - createChoiceItem(draggedChoiceItem, expandedPlaceholderIndex) } + useEventListener('mouseup', handleMouseUp, undefined, { capture: true }) const handleStepMouseDown = ( { absolute, relative }: { absolute: Coordinates; relative: Coordinates }, @@ -76,15 +79,10 @@ export const ChoiceItemsList = ({ step }: ChoiceItemsListProps) => { const stopPropagating = (e: React.MouseEvent) => e.stopPropagation() return ( - + { ? '50px' : '2px' } - bgColor={'gray.400'} + bgColor={'gray.300'} visibility={showSortPlaceholders ? 'visible' : 'hidden'} rounded="lg" transition={showSortPlaceholders ? 'height 200ms' : 'none'} @@ -118,13 +116,15 @@ export const ChoiceItemsList = ({ step }: ChoiceItemsListProps) => { - Default + Default { void +} + +export const SettingsModal = ({ + isOpen, + onClose, + ...props +}: Props & ModalBodyProps) => { + return ( + + + + + + {props.children} + + + + ) +} diff --git a/apps/builder/components/board/graph/BlockNode/StepNode/SettingsPopoverContent/SettingsPopoverContent.tsx b/apps/builder/components/board/graph/BlockNode/StepNode/SettingsPopoverContent/SettingsPopoverContent.tsx index 2791934b41..c2cbc885ef 100644 --- a/apps/builder/components/board/graph/BlockNode/StepNode/SettingsPopoverContent/SettingsPopoverContent.tsx +++ b/apps/builder/components/board/graph/BlockNode/StepNode/SettingsPopoverContent/SettingsPopoverContent.tsx @@ -4,7 +4,11 @@ import { PopoverBody, useEventListener, Portal, + Stack, + IconButton, + Flex, } from '@chakra-ui/react' +import { ExpandIcon } from 'assets/icons' import { useTypebot } from 'contexts/TypebotContext/TypebotContext' import { InputStep, @@ -30,9 +34,10 @@ import { SetVariableSettingsBody } from './bodies/SetVariableSettingsBody' type Props = { step: Step + onExpandClick: () => void } -export const SettingsPopoverContent = ({ step }: Props) => { +export const SettingsPopoverContent = ({ step, onExpandClick }: Props) => { const ref = useRef(null) const handleMouseDown = (e: React.MouseEvent) => e.stopPropagation() @@ -44,15 +49,33 @@ export const SettingsPopoverContent = ({ step }: Props) => { - - + + + + } + size="xs" + onClick={onExpandClick} + /> + + + ) } -const SettingsPopoverBodyContent = ({ step }: Props) => { +export const StepSettings = ({ step }: { step: Step }) => { const { updateStep } = useTypebot() const handleOptionsChange = (options: StepOptions) => updateStep(step.id, { options } as Partial) diff --git a/apps/builder/components/board/graph/BlockNode/StepNode/SettingsPopoverContent/bodies/ConditionSettingsBody/ComparisonsList.tsx b/apps/builder/components/board/graph/BlockNode/StepNode/SettingsPopoverContent/bodies/ConditionSettingsBody/ComparisonsList.tsx index 8ce6b7b0e7..89ef41a71e 100644 --- a/apps/builder/components/board/graph/BlockNode/StepNode/SettingsPopoverContent/bodies/ConditionSettingsBody/ComparisonsList.tsx +++ b/apps/builder/components/board/graph/BlockNode/StepNode/SettingsPopoverContent/bodies/ConditionSettingsBody/ComparisonsList.tsx @@ -107,22 +107,20 @@ export const ComparisonsList = ({ > currentItem={comparisons.byId[comparisonId].comparisonOperator} onItemSelect={handleComparisonOperatorSelected(comparisonId)} items={Object.values(ComparisonOperators)} - bgColor="white" /> {comparisons.byId[comparisonId].comparisonOperator !== ComparisonOperators.IS_SET && ( @@ -130,7 +128,6 @@ export const ComparisonsList = ({ delay={100} initialValue={comparisons.byId[comparisonId].value ?? ''} onChange={handleValueChange(comparisonId)} - bgColor="white" placeholder="Type a value..." /> )} @@ -141,16 +138,22 @@ export const ComparisonsList = ({ aria-label="Remove comparison" onClick={deleteComparison(comparisonId)} pos="absolute" - left="-10px" - top="-10px" + left="-15px" + top="-15px" size="sm" + shadow="md" /> ))} - ) diff --git a/apps/builder/components/board/graph/BlockNode/StepNode/SettingsPopoverContent/bodies/GoogleSheetsSettingsBody/ExtractCellList.tsx b/apps/builder/components/board/graph/BlockNode/StepNode/SettingsPopoverContent/bodies/GoogleSheetsSettingsBody/ExtractCellList.tsx index 456e786467..2121e50b52 100644 --- a/apps/builder/components/board/graph/BlockNode/StepNode/SettingsPopoverContent/bodies/GoogleSheetsSettingsBody/ExtractCellList.tsx +++ b/apps/builder/components/board/graph/BlockNode/StepNode/SettingsPopoverContent/bodies/GoogleSheetsSettingsBody/ExtractCellList.tsx @@ -87,16 +87,22 @@ export const ExtractCellList = ({ aria-label="Remove cell" onClick={deleteCell(cellId)} pos="absolute" - left="-10px" - top="-10px" + left="-15px" + top="-15px" size="sm" + shadow="md" /> ))} - ) @@ -118,12 +124,11 @@ export const CellWithVariableIdStack = ({ onCellChange({ ...cell, variableId: variable.id }) } return ( - + currentItem={cell.column} onItemSelect={handleColumnSelect} items={columns} - bgColor="white" placeholder="Select a column" /> ))} - ) @@ -118,12 +124,11 @@ export const CellWithValueStack = ({ onCellChange({ ...cell, value }) } return ( - + currentItem={cell.column} onItemSelect={handleColumnSelect} items={columns} - bgColor="white" placeholder="Select a column" /> + > + + ) } diff --git a/apps/builder/components/board/graph/BlockNode/StepNode/StepNode.tsx b/apps/builder/components/board/graph/BlockNode/StepNode/StepNode.tsx index b43ba0670c..d2fa76f445 100644 --- a/apps/builder/components/board/graph/BlockNode/StepNode/StepNode.tsx +++ b/apps/builder/components/board/graph/BlockNode/StepNode/StepNode.tsx @@ -4,6 +4,7 @@ import { HStack, Popover, PopoverTrigger, + useDisclosure, useEventListener, } from '@chakra-ui/react' import React, { useEffect, useMemo, useState } from 'react' @@ -28,6 +29,8 @@ import { SourceEndpoint } from './SourceEndpoint' import { hasDefaultConnector } from 'services/typebots' import { TargetEndpoint } from './TargetEndpoint' import { useRouter } from 'next/router' +import { SettingsModal } from './SettingsPopoverContent/SettingsModal' +import { StepSettings } from './SettingsPopoverContent/SettingsPopoverContent' export const StepNode = ({ step, @@ -54,6 +57,11 @@ export const StepNode = ({ const [isEditing, setIsEditing] = useState( isTextBubbleStep(step) && step.content.plainText === '' ) + const { + isOpen: isModalOpen, + onOpen: onModalOpen, + onClose: onModalClose, + } = useDisclosure() useEffect(() => { setIsConnecting( @@ -190,8 +198,8 @@ export const StepNode = ({ flex="1" userSelect="none" p="3" - borderWidth="2px" - borderColor={isConnecting || isOpened ? 'blue.400' : 'gray.400'} + borderWidth="1px" + borderColor={isConnecting || isOpened ? 'blue.400' : 'gray.300'} rounded="lg" cursor={'pointer'} bgColor="white" @@ -213,7 +221,7 @@ export const StepNode = ({ }} pos="absolute" right="15px" - top="19px" + top="18px" /> )} @@ -237,7 +245,12 @@ export const StepNode = ({ )} - {hasPopover(step) && } + {hasPopover(step) && ( + + )} + + + )} diff --git a/apps/builder/components/board/graph/BlockNode/StepNode/StepNodeOverlay.tsx b/apps/builder/components/board/graph/BlockNode/StepNode/StepNodeOverlay.tsx index ebf47158a8..c25c3bc855 100644 --- a/apps/builder/components/board/graph/BlockNode/StepNode/StepNodeOverlay.tsx +++ b/apps/builder/components/board/graph/BlockNode/StepNode/StepNodeOverlay.tsx @@ -16,6 +16,7 @@ export const StepNodeOverlay = ({ cursor={'grab'} w="264px" pointerEvents="none" + shadow="lg" {...props} > diff --git a/apps/builder/components/board/graph/BlockNode/StepsList.tsx b/apps/builder/components/board/graph/BlockNode/StepsList.tsx index eb0cf81007..9a87bf674e 100644 --- a/apps/builder/components/board/graph/BlockNode/StepsList.tsx +++ b/apps/builder/components/board/graph/BlockNode/StepsList.tsx @@ -102,7 +102,7 @@ export const StepsList = ({ ? '50px' : '2px' } - bgColor={'gray.400'} + bgColor={'gray.300'} visibility={showSortPlaceholders ? 'visible' : 'hidden'} rounded="lg" transition={showSortPlaceholders ? 'height 200ms' : 'none'} @@ -125,7 +125,7 @@ export const StepsList = ({ ? '50px' : '2px' } - bgColor={'gray.400'} + bgColor={'gray.300'} visibility={showSortPlaceholders ? 'visible' : 'hidden'} rounded="lg" transition={showSortPlaceholders ? 'height 200ms' : 'none'} diff --git a/apps/builder/components/board/graph/Edges/DrawingEdge.tsx b/apps/builder/components/board/graph/Edges/DrawingEdge.tsx index c5cd60f814..a4d81f8261 100644 --- a/apps/builder/components/board/graph/Edges/DrawingEdge.tsx +++ b/apps/builder/components/board/graph/Edges/DrawingEdge.tsx @@ -103,9 +103,9 @@ export const DrawingEdge = () => { return ( ) diff --git a/apps/builder/components/board/graph/Edges/Edge.tsx b/apps/builder/components/board/graph/Edges/Edge.tsx index fdf3f36a6f..c0f30e1186 100644 --- a/apps/builder/components/board/graph/Edges/Edge.tsx +++ b/apps/builder/components/board/graph/Edges/Edge.tsx @@ -126,7 +126,7 @@ export const Edge = ({ d={path} stroke={isPreviewing ? '#1a5fff' : '#718096'} strokeWidth="2px" - markerEnd="url(#arrow)" + markerEnd={isPreviewing ? 'url(#blue-arrow)' : 'url(#arrow)'} fill="none" /> ) diff --git a/apps/builder/components/board/graph/Edges/Edges.tsx b/apps/builder/components/board/graph/Edges/Edges.tsx index 77887fe9a8..17b192194a 100644 --- a/apps/builder/components/board/graph/Edges/Edges.tsx +++ b/apps/builder/components/board/graph/Edges/Edges.tsx @@ -74,6 +74,21 @@ export const Edges = () => { fill="#718096" /> + + + ) } diff --git a/apps/builder/libs/chakra.ts b/apps/builder/libs/chakra.ts index 94406532ae..27be24e640 100644 --- a/apps/builder/libs/chakra.ts +++ b/apps/builder/libs/chakra.ts @@ -6,6 +6,18 @@ const fonts = { } const colors = { + gray: { + 50: '#F9FAFB', + 100: '#F3F4F6', + 200: '#E5E7EB', + 300: '#D1D5DB', + 400: '#9CA3AF', + 500: '#6B7280', + 600: '#4B5563', + 700: '#374151', + 800: '#1F2937', + 900: '#111827', + }, blue: { 50: '#e0edff', 100: '#b0caff', diff --git a/apps/builder/services/graph.ts b/apps/builder/services/graph.ts index 24876a5da3..ecb0377d71 100644 --- a/apps/builder/services/graph.ts +++ b/apps/builder/services/graph.ts @@ -291,7 +291,7 @@ export const getEndpointTopOffset = ( const endpointRef = endpoints.byId[id]?.ref if (!endpointRef) return 0 return ( - 7 + + 8 + (endpointRef.current?.getBoundingClientRect().top ?? 0) - graphPosition.y - headerHeight