2
0

Add dark mode (#191)

Closes #189
This commit is contained in:
Baptiste Arnaud
2022-12-20 16:55:43 +01:00
committed by GitHub
parent 054cbb3585
commit 3394fa5e0a
77 changed files with 1782 additions and 601 deletions

View File

@ -1,7 +1,7 @@
import { Coordinates, useGraph, useGroupsCoordinates } from '../../providers'
import React, { useEffect, useLayoutEffect, useMemo, useState } from 'react'
import { Edge as EdgeProps } from 'models'
import { Portal, useDisclosure } from '@chakra-ui/react'
import { color, Portal, useColorMode, useDisclosure } from '@chakra-ui/react'
import { useTypebot } from '@/features/editor'
import { EdgeMenu } from './EdgeMenu'
import { colors } from '@/lib/theme'
@ -23,6 +23,7 @@ type Props = {
edge: EdgeProps
}
export const Edge = ({ edge }: Props) => {
const isDark = useColorMode().colorMode === 'dark'
const { deleteEdge } = useTypebot()
const {
previewingEdge,
@ -141,7 +142,13 @@ export const Edge = ({ edge }: Props) => {
<path
data-testid="edge"
d={path}
stroke={isPreviewing ? colors.blue[400] : colors.gray[400]}
stroke={
isPreviewing
? colors.blue[400]
: isDark
? colors.gray[700]
: colors.gray[400]
}
strokeWidth="2px"
markerEnd={isPreviewing ? 'url(#blue-arrow)' : 'url(#arrow)'}
fill="none"

View File

@ -1,4 +1,4 @@
import { chakra } from '@chakra-ui/react'
import { chakra, useColorMode } from '@chakra-ui/react'
import { colors } from '@/lib/theme'
import { Edge as EdgeProps } from 'models'
import React from 'react'
@ -17,72 +17,75 @@ export const Edges = ({
edges,
answersCounts,
onUnlockProPlanClick,
}: Props) => (
<chakra.svg
width="full"
height="full"
overflow="visible"
pos="absolute"
left="0"
top="0"
shapeRendering="geometricPrecision"
>
<DrawingEdge />
{edges.map((edge) => (
<Edge key={edge.id} edge={edge} />
))}
{answersCounts?.map((answerCount) => (
<DropOffEdge
key={answerCount.groupId}
answersCounts={answersCounts}
groupId={answerCount.groupId}
onUnlockProPlanClick={onUnlockProPlanClick}
/>
))}
<marker
id={'arrow'}
refX="8"
refY="4"
orient="auto"
viewBox="0 0 20 20"
markerUnits="userSpaceOnUse"
markerWidth="20"
markerHeight="20"
}: Props) => {
const isDark = useColorMode().colorMode === 'dark'
return (
<chakra.svg
width="full"
height="full"
overflow="visible"
pos="absolute"
left="0"
top="0"
shapeRendering="geometricPrecision"
>
<path
d="M7.07138888,5.50174526 L2.43017246,7.82235347 C1.60067988,8.23709976 0.592024983,7.90088146 0.177278692,7.07138888 C0.0606951226,6.83822174 0,6.58111307 0,6.32042429 L0,1.67920787 C0,0.751806973 0.751806973,0 1.67920787,0 C1.93989666,0 2.19700532,0.0606951226 2.43017246,0.177278692 L7,3 C7.82949258,3.41474629 8.23709976,3.92128809 7.82235347,4.75078067 C7.6598671,5.07575341 7.39636161,5.33925889 7.07138888,5.50174526 Z"
fill={colors.gray[400]}
/>
</marker>
<marker
id={'blue-arrow'}
refX="8"
refY="4"
orient="auto"
viewBox="0 0 20 20"
markerUnits="userSpaceOnUse"
markerWidth="20"
markerHeight="20"
>
<path
d="M7.07138888,5.50174526 L2.43017246,7.82235347 C1.60067988,8.23709976 0.592024983,7.90088146 0.177278692,7.07138888 C0.0606951226,6.83822174 0,6.58111307 0,6.32042429 L0,1.67920787 C0,0.751806973 0.751806973,0 1.67920787,0 C1.93989666,0 2.19700532,0.0606951226 2.43017246,0.177278692 L7,3 C7.82949258,3.41474629 8.23709976,3.92128809 7.82235347,4.75078067 C7.6598671,5.07575341 7.39636161,5.33925889 7.07138888,5.50174526 Z"
fill={colors.blue[400]}
/>
</marker>
<marker
id={'red-arrow'}
refX="8"
refY="4"
orient="auto"
viewBox="0 0 20 20"
markerUnits="userSpaceOnUse"
markerWidth="20"
markerHeight="20"
>
<path
d="M7.07138888,5.50174526 L2.43017246,7.82235347 C1.60067988,8.23709976 0.592024983,7.90088146 0.177278692,7.07138888 C0.0606951226,6.83822174 0,6.58111307 0,6.32042429 L0,1.67920787 C0,0.751806973 0.751806973,0 1.67920787,0 C1.93989666,0 2.19700532,0.0606951226 2.43017246,0.177278692 L7,3 C7.82949258,3.41474629 8.23709976,3.92128809 7.82235347,4.75078067 C7.6598671,5.07575341 7.39636161,5.33925889 7.07138888,5.50174526 Z"
fill="#e53e3e"
/>
</marker>
</chakra.svg>
)
<DrawingEdge />
{edges.map((edge) => (
<Edge key={edge.id} edge={edge} />
))}
{answersCounts?.map((answerCount) => (
<DropOffEdge
key={answerCount.groupId}
answersCounts={answersCounts}
groupId={answerCount.groupId}
onUnlockProPlanClick={onUnlockProPlanClick}
/>
))}
<marker
id={'arrow'}
refX="8"
refY="4"
orient="auto"
viewBox="0 0 20 20"
markerUnits="userSpaceOnUse"
markerWidth="20"
markerHeight="20"
>
<path
d="M7.07138888,5.50174526 L2.43017246,7.82235347 C1.60067988,8.23709976 0.592024983,7.90088146 0.177278692,7.07138888 C0.0606951226,6.83822174 0,6.58111307 0,6.32042429 L0,1.67920787 C0,0.751806973 0.751806973,0 1.67920787,0 C1.93989666,0 2.19700532,0.0606951226 2.43017246,0.177278692 L7,3 C7.82949258,3.41474629 8.23709976,3.92128809 7.82235347,4.75078067 C7.6598671,5.07575341 7.39636161,5.33925889 7.07138888,5.50174526 Z"
fill={isDark ? colors.gray[600] : colors.gray[400]}
/>
</marker>
<marker
id={'blue-arrow'}
refX="8"
refY="4"
orient="auto"
viewBox="0 0 20 20"
markerUnits="userSpaceOnUse"
markerWidth="20"
markerHeight="20"
>
<path
d="M7.07138888,5.50174526 L2.43017246,7.82235347 C1.60067988,8.23709976 0.592024983,7.90088146 0.177278692,7.07138888 C0.0606951226,6.83822174 0,6.58111307 0,6.32042429 L0,1.67920787 C0,0.751806973 0.751806973,0 1.67920787,0 C1.93989666,0 2.19700532,0.0606951226 2.43017246,0.177278692 L7,3 C7.82949258,3.41474629 8.23709976,3.92128809 7.82235347,4.75078067 C7.6598671,5.07575341 7.39636161,5.33925889 7.07138888,5.50174526 Z"
fill={colors.blue[400]}
/>
</marker>
<marker
id={'red-arrow'}
refX="8"
refY="4"
orient="auto"
viewBox="0 0 20 20"
markerUnits="userSpaceOnUse"
markerWidth="20"
markerHeight="20"
>
<path
d="M7.07138888,5.50174526 L2.43017246,7.82235347 C1.60067988,8.23709976 0.592024983,7.90088146 0.177278692,7.07138888 C0.0606951226,6.83822174 0,6.58111307 0,6.32042429 L0,1.67920787 C0,0.751806973 0.751806973,0 1.67920787,0 C1.93989666,0 2.19700532,0.0606951226 2.43017246,0.177278692 L7,3 C7.82949258,3.41474629 8.23709976,3.92128809 7.82235347,4.75078067 C7.6598671,5.07575341 7.39636161,5.33925889 7.07138888,5.50174526 Z"
fill="#e53e3e"
/>
</marker>
</chakra.svg>
)
}

View File

@ -1,4 +1,9 @@
import { BoxProps, Flex, useEventListener } from '@chakra-ui/react'
import {
BoxProps,
Flex,
useColorModeValue,
useEventListener,
} from '@chakra-ui/react'
import { useGraph, useGroupsCoordinates } from '../../providers'
import { Source } from 'models'
import React, { useEffect, useRef, useState } from 'react'
@ -9,6 +14,9 @@ export const SourceEndpoint = ({
}: BoxProps & {
source: Source
}) => {
const color = useColorModeValue('blue.200', 'blue.100')
const connectedColor = useColorModeValue('blue.300', 'blue.200')
const bg = useColorModeValue('gray.100', 'gray.700')
const [ranOnce, setRanOnce] = useState(false)
const { setConnectingIds, addSourceEndpoint, previewingEdge } = useGraph()
@ -61,7 +69,7 @@ export const SourceEndpoint = ({
boxSize="20px"
justify="center"
align="center"
bgColor="gray.100"
bg={bg}
rounded="full"
>
<Flex
@ -72,8 +80,8 @@ export const SourceEndpoint = ({
borderColor={
previewingEdge?.from.blockId === source.blockId &&
previewingEdge.from.itemId === source.itemId
? 'blue.300'
: 'blue.200'
? connectedColor
: color
}
/>
</Flex>

View File

@ -3,6 +3,7 @@ import {
HStack,
Popover,
PopoverTrigger,
useColorModeValue,
useDisclosure,
useEventListener,
} from '@chakra-ui/react'
@ -26,17 +27,17 @@ import { SourceEndpoint } from '../../Endpoints/SourceEndpoint'
import { useRouter } from 'next/router'
import { SettingsModal } from './SettingsPopoverContent/SettingsModal'
import { BlockSettings } from './SettingsPopoverContent/SettingsPopoverContent'
import { TextBubbleEditor } from '../../../../blocks/bubbles/textBubble/components/TextBubbleEditor'
import { TargetEndpoint } from '../../Endpoints'
import { MediaBubblePopoverContent } from './MediaBubblePopoverContent'
import {
NodePosition,
useBlockDnd,
useDragDistance,
useGraph,
} from '../../../providers'
import { ContextMenu } from '@/components/ContextMenu'
import { setMultipleRefs } from '@/utils/helpers'
import { TextBubbleEditor } from '@/features/blocks/bubbles/textBubble'
import {
NodePosition,
useGraph,
useBlockDnd,
useDragDistance,
} from '../../../providers'
import { hasDefaultConnector } from '../../../utils'
export const BlockNode = ({
@ -50,6 +51,9 @@ export const BlockNode = ({
indices: { blockIndex: number; groupIndex: number }
onMouseDown?: (blockNodePosition: NodePosition, block: DraggableBlock) => void
}) => {
const bg = useColorModeValue('gray.50', 'gray.850')
const previewingBorderColor = useColorModeValue('blue.400', 'blue.300')
const borderColor = useColorModeValue('gray.200', 'gray.800')
const { query } = useRouter()
const {
setConnectingIds,
@ -165,7 +169,7 @@ export const BlockNode = ({
<ContextMenu<HTMLDivElement>
renderMenu={() => <BlockNodeContextMenu indices={indices} />}
>
{(ref, isOpened) => (
{(ref, isContextMenuOpened) => (
<Popover
placement="left"
isLazy
@ -186,12 +190,18 @@ export const BlockNode = ({
flex="1"
userSelect="none"
p="3"
borderWidth={isOpened || isPreviewing ? '2px' : '1px'}
borderColor={isOpened || isPreviewing ? 'blue.400' : 'gray.200'}
margin={isOpened || isPreviewing ? '-1px' : 0}
borderWidth={
isContextMenuOpened || isPreviewing ? '2px' : '1px'
}
borderColor={
isContextMenuOpened || isPreviewing
? previewingBorderColor
: borderColor
}
margin={isContextMenuOpened || isPreviewing ? '-1px' : 0}
rounded="lg"
cursor={'pointer'}
bgColor="gray.50"
bg={bg}
align="flex-start"
w="full"
transition="border-color 0.2s"

View File

@ -1,5 +1,5 @@
import { BlockIcon } from '@/features/editor'
import { StackProps, HStack } from '@chakra-ui/react'
import { StackProps, HStack, useColorModeValue } from '@chakra-ui/react'
import { StartBlock, Block, BlockIndices } from 'models'
import { BlockNodeContent } from './BlockNodeContent/BlockNodeContent'
@ -13,7 +13,8 @@ export const BlockNodeOverlay = ({
p="3"
borderWidth="1px"
rounded="lg"
bgColor="white"
borderColor={useColorModeValue('gray.200', 'gray.800')}
bgColor={useColorModeValue('gray.50', 'gray.850')}
cursor={'grab'}
w="264px"
pointerEvents="none"

View File

@ -10,6 +10,8 @@ import { useEffect, useRef, useState } from 'react'
import { useTypebot } from '@/features/editor'
import { BlockNode } from './BlockNode'
import { BlockNodeOverlay } from './BlockNodeOverlay'
import { PlaceholderNode } from '../PlaceholderNode'
import { isDefined } from 'utils'
type Props = {
groupId: string
@ -49,7 +51,7 @@ export const BlockNodesList = ({
const isDraggingOnCurrentGroup =
(draggedBlock || draggedBlockType) && mouseOverGroup?.id === groupId
const showSortPlaceholders =
!isStartGroup && (draggedBlock || draggedBlockType)
!isStartGroup && isDefined(draggedBlock || draggedBlockType)
useEffect(() => {
if (mouseOverGroup?.id !== groupId) setExpandedPlaceholderIndex(undefined)
@ -126,17 +128,10 @@ export const BlockNodesList = ({
transition="none"
pointerEvents={isReadOnly || isStartGroup ? 'none' : 'auto'}
>
<Flex
ref={handlePushElementRef(0)}
h={
showSortPlaceholders && expandedPlaceholderIndex === 0
? '50px'
: '2px'
}
bgColor={'gray.300'}
visibility={showSortPlaceholders ? 'visible' : 'hidden'}
rounded="lg"
transition={showSortPlaceholders ? 'height 200ms' : 'none'}
<PlaceholderNode
isVisible={showSortPlaceholders}
isExpanded={expandedPlaceholderIndex === 0}
onRef={handlePushElementRef(0)}
/>
{typebot &&
blocks.map((block, idx) => (
@ -148,17 +143,10 @@ export const BlockNodesList = ({
isConnectable={blocks.length - 1 === idx}
onMouseDown={handleBlockMouseDown(idx)}
/>
<Flex
ref={handlePushElementRef(idx + 1)}
h={
showSortPlaceholders && expandedPlaceholderIndex === idx + 1
? '50px'
: '2px'
}
bgColor={'gray.300'}
visibility={showSortPlaceholders ? 'visible' : 'hidden'}
rounded="lg"
transition={showSortPlaceholders ? 'height 200ms' : 'none'}
<PlaceholderNode
isVisible={showSortPlaceholders}
isExpanded={expandedPlaceholderIndex === idx + 1}
onRef={handlePushElementRef(idx + 1)}
/>
</Stack>
))}

View File

@ -4,6 +4,7 @@ import {
EditablePreview,
IconButton,
Stack,
useColorModeValue,
} from '@chakra-ui/react'
import React, { memo, useCallback, useEffect, useRef, useState } from 'react'
import { Group } from 'models'
@ -52,6 +53,10 @@ const NonMemoizedDraggableGroupNode = ({
groupIndex,
onGroupDrag,
}: Props & { onGroupDrag: (newCoord: Coordinates) => void }) => {
const bg = useColorModeValue('white', 'gray.900')
const previewingBorderColor = useColorModeValue('blue.400', 'blue.300')
const borderColor = useColorModeValue('white', 'gray.800')
const editableHoverBg = useColorModeValue('gray.100', 'gray.700')
const {
connectingIds,
setConnectingIds,
@ -172,16 +177,20 @@ const NonMemoizedDraggableGroupNode = ({
renderMenu={() => <GroupNodeContextMenu groupIndex={groupIndex} />}
isDisabled={isReadOnly || isStartGroup}
>
{(ref, isOpened) => (
{(ref, isContextMenuOpened) => (
<Stack
ref={setMultipleRefs([ref, groupRef])}
data-testid="group"
p="4"
rounded="xl"
bgColor="#ffffff"
borderWidth="2px"
bg={bg}
borderWidth={
isConnecting || isContextMenuOpened || isPreviewing ? '2px' : '1px'
}
borderColor={
isConnecting || isOpened || isPreviewing ? 'blue.400' : '#ffffff'
isConnecting || isContextMenuOpened || isPreviewing
? previewingBorderColor
: borderColor
}
w="300px"
transition="border 300ms, box-shadow 200ms"
@ -208,7 +217,9 @@ const NonMemoizedDraggableGroupNode = ({
pr="8"
>
<EditablePreview
_hover={{ bgColor: 'gray.200' }}
_hover={{
bg: editableHoverBg,
}}
px="1"
userSelect={'none'}
/>

View File

@ -1,4 +1,4 @@
import { Flex } from '@chakra-ui/react'
import { Flex, useColorModeValue } from '@chakra-ui/react'
import {
Coordinates,
useGraph,
@ -30,6 +30,9 @@ export const ItemNode = ({
onMouseDown,
connectionDisabled,
}: Props) => {
const previewingBorderColor = useColorModeValue('blue.400', 'blue.300')
const borderColor = useColorModeValue('gray.200', 'gray.700')
const bg = useColorModeValue('white', undefined)
const { typebot } = useTypebot()
const { previewingEdge } = useGraph()
const [isMouseOver, setIsMouseOver] = useState(false)
@ -59,7 +62,7 @@ export const ItemNode = ({
<ContextMenu<HTMLDivElement>
renderMenu={() => <ItemNodeContextMenu indices={indices} />}
>
{(ref, isOpened) => (
{(ref, isContextMenuOpened) => (
<Flex
data-testid="item"
pos="relative"
@ -74,10 +77,14 @@ export const ItemNode = ({
_hover={{ shadow: 'md' }}
transition="box-shadow 200ms, border-color 200ms"
rounded="md"
borderWidth={isOpened || isPreviewing ? '2px' : '1px'}
borderColor={isOpened || isPreviewing ? 'blue.400' : 'gray.100'}
margin={isOpened || isPreviewing ? '-1px' : 0}
bgColor="white"
bg={bg}
borderWidth={isContextMenuOpened || isPreviewing ? '2px' : '1px'}
borderColor={
isContextMenuOpened || isPreviewing
? previewingBorderColor
: borderColor
}
margin={isContextMenuOpened || isPreviewing ? '-1px' : 0}
w="full"
>
<ItemNodeContent

View File

@ -1,4 +1,4 @@
import { Flex, FlexProps } from '@chakra-ui/react'
import { Flex, FlexProps, useColorModeValue } from '@chakra-ui/react'
import { Item } from 'models'
import React, { ReactNode } from 'react'
@ -12,9 +12,9 @@ export const ItemNodeOverlay = ({ item, ...props }: Props) => {
px="4"
py="2"
rounded="md"
bgColor="white"
bgColor={useColorModeValue('white', 'gray.850')}
borderWidth="1px"
borderColor={'gray.300'}
borderColor={useColorModeValue('gray.200', 'gray.700')}
w="212px"
pointerEvents="none"
shadow="lg"

View File

@ -1,4 +1,11 @@
import { Flex, Portal, Stack, Text, useEventListener } from '@chakra-ui/react'
import {
Flex,
Portal,
Stack,
Text,
useColorModeValue,
useEventListener,
} from '@chakra-ui/react'
import {
computeNearestPlaceholderIndex,
useBlockDnd,
@ -10,6 +17,8 @@ import { BlockIndices, BlockWithItems, LogicBlockType, Item } from 'models'
import React, { useEffect, useRef, useState } from 'react'
import { ItemNode } from './ItemNode'
import { SourceEndpoint } from '../../Endpoints'
import { ItemNodeOverlay } from './ItemNodeOverlay'
import { PlaceholderNode } from '../PlaceholderNode'
type Props = {
block: BlockWithItems
@ -121,13 +130,10 @@ export const ItemNodesList = ({
return (
<Stack flex={1} spacing={1} maxW="full" onClick={stopPropagating}>
<Flex
ref={handlePushElementRef(0)}
h={showPlaceholders && expandedPlaceholderIndex === 0 ? '50px' : '2px'}
bgColor={'gray.300'}
visibility={showPlaceholders ? 'visible' : 'hidden'}
rounded="lg"
transition={showPlaceholders ? 'height 200ms' : 'none'}
<PlaceholderNode
isVisible={showPlaceholders}
isExpanded={expandedPlaceholderIndex === 0}
onRef={handlePushElementRef(0)}
/>
{block.items.map((item, idx) => (
<Stack key={item.id} spacing={1}>
@ -136,45 +142,14 @@ export const ItemNodesList = ({
indices={{ groupIndex, blockIndex, itemIndex: idx }}
onMouseDown={handleBlockMouseDown(idx)}
/>
<Flex
ref={handlePushElementRef(idx + 1)}
h={
showPlaceholders && expandedPlaceholderIndex === idx + 1
? '50px'
: '2px'
}
bgColor={'gray.300'}
visibility={showPlaceholders ? 'visible' : 'hidden'}
rounded="lg"
transition={showPlaceholders ? 'height 200ms' : 'none'}
<PlaceholderNode
isVisible={showPlaceholders}
isExpanded={expandedPlaceholderIndex === idx + 1}
onRef={handlePushElementRef(idx + 1)}
/>
</Stack>
))}
{isLastBlock && (
<Flex
px="4"
py="2"
borderWidth="1px"
borderColor="gray.300"
bgColor={'gray.50'}
rounded="md"
pos="relative"
align="center"
cursor="not-allowed"
>
<Text color="gray.500">
{block.type === LogicBlockType.CONDITION ? 'Else' : 'Default'}
</Text>
<SourceEndpoint
source={{
groupId: block.groupId,
blockId: block.id,
}}
pos="absolute"
right="-49px"
/>
</Flex>
)}
{isLastBlock && <DefaultItemNode block={block} />}
{draggedItem && draggedItem.blockId === block.id && (
<Portal>
@ -189,14 +164,38 @@ export const ItemNodesList = ({
w="220px"
transformOrigin="0 0 0"
>
<ItemNode
item={draggedItem}
indices={{ groupIndex, blockIndex, itemIndex: 0 }}
connectionDisabled
/>
<ItemNodeOverlay item={draggedItem} />
</Flex>
</Portal>
)}
</Stack>
)
}
const DefaultItemNode = ({ block }: { block: BlockWithItems }) => {
return (
<Flex
px="4"
py="2"
borderWidth="1px"
borderColor={useColorModeValue('gray.300', undefined)}
bgColor={useColorModeValue('gray.50', 'gray.850')}
rounded="md"
pos="relative"
align="center"
cursor="not-allowed"
>
<Text color="gray.500">
{block.type === LogicBlockType.CONDITION ? 'Else' : 'Default'}
</Text>
<SourceEndpoint
source={{
groupId: block.groupId,
blockId: block.id,
}}
pos="absolute"
right="-49px"
/>
</Flex>
)
}

View File

@ -0,0 +1,21 @@
import { Flex, useColorModeValue } from '@chakra-ui/react'
import React from 'react'
type Props = {
isVisible: boolean
isExpanded: boolean
onRef: (ref: HTMLDivElement) => void
}
export const PlaceholderNode = ({ isVisible, isExpanded, onRef }: Props) => {
return (
<Flex
ref={onRef}
h={isExpanded ? '50px' : '2px'}
bgColor={useColorModeValue('gray.300', 'gray.700')}
visibility={isVisible ? 'visible' : 'hidden'}
rounded="lg"
transition={isVisible ? 'height 200ms' : 'none'}
/>
)
}

View File

@ -1,4 +1,4 @@
import { Stack, IconButton } from '@chakra-ui/react'
import { Stack, IconButton, useColorModeValue } from '@chakra-ui/react'
import { PlusIcon, MinusIcon } from '@/components/icons'
import { headerHeight } from '@/features/editor'
@ -14,7 +14,7 @@ export const ZoomButtons = ({
pos="fixed"
top={`calc(${headerHeight}px + 70px)`}
right="40px"
bgColor="white"
bgColor={useColorModeValue('white', 'gray.900')}
rounded="md"
zIndex={1}
spacing="0"
@ -25,7 +25,7 @@ export const ZoomButtons = ({
aria-label={'Zoom in'}
size="sm"
onClick={onZoomIn}
bgColor="white"
bgColor={useColorModeValue('white', undefined)}
borderBottomRadius={0}
/>
<IconButton
@ -33,7 +33,7 @@ export const ZoomButtons = ({
aria-label={'Zoom out'}
size="sm"
onClick={onZoomOut}
bgColor="white"
bgColor={useColorModeValue('white', undefined)}
borderTopRadius={0}
/>
</Stack>