(embed) Add size and icon picker in bubble settings (#508)

This commit is contained in:
Baptiste Arnaud
2023-05-15 15:22:04 +02:00
committed by GitHub
parent 123926f273
commit 0f91b34497
15 changed files with 256 additions and 108 deletions

View File

@@ -9,11 +9,6 @@ import { JavascriptBubbleSnippet } from '../JavascriptBubbleSnippet'
export const parseDefaultBubbleTheme = (typebot?: Typebot) => ({
button: {
backgroundColor: typebot?.theme.chat.buttons.backgroundColor,
iconColor: typebot?.theme.chat.buttons.color,
},
previewMessage: {
backgroundColor: typebot?.theme.general.background.content ?? 'white',
textColor: 'black',
},
})

View File

@@ -1,8 +1,17 @@
import { Stack, Heading, HStack, Flex, Text, Image } from '@chakra-ui/react'
import {
Stack,
Heading,
HStack,
Flex,
Text,
Image,
chakra,
} from '@chakra-ui/react'
import { BubbleProps } from '@typebot.io/js'
import { isDefined } from '@typebot.io/lib'
import { isDefined, isSvgSrc } from '@typebot.io/lib'
import { PreviewMessageSettings } from './PreviewMessageSettings'
import { ThemeSettings } from './ThemeSettings'
import { isLight } from '@typebot.io/lib/hexToRgb'
type Props = {
defaultPreviewMessageAvatar: string
@@ -79,24 +88,72 @@ export const BubbleSettings = ({
<Flex
align="center"
justifyContent="center"
boxSize="3rem"
transition="all 0.2s ease-in-out"
boxSize={theme?.button?.size === 'large' ? '64px' : '48px'}
bgColor={theme?.button?.backgroundColor}
rounded="full"
boxShadow="0 0 #0000,0 0 #0000,0 4px 6px -1px rgba(0,0,0,.1),0 2px 4px -2px rgba(0,0,0,.1)"
>
<svg
viewBox="0 0 24 24"
style={{
stroke: theme?.button?.iconColor,
}}
width="30px"
strokeWidth="2px"
fill="transparent"
>
<path d="M21 11.5a8.38 8.38 0 0 1-.9 3.8 8.5 8.5 0 0 1-7.6 4.7 8.38 8.38 0 0 1-3.8-.9L3 21l1.9-5.7a8.38 8.38 0 0 1-.9-3.8 8.5 8.5 0 0 1 4.7-7.6 8.38 8.38 0 0 1 3.8-.9h.5a8.48 8.48 0 0 1 8 8v.5z" />
</svg>
<BubbleIcon buttonTheme={theme?.button} />
</Flex>
</Stack>
</Stack>
</Stack>
)
}
const BubbleIcon = ({
buttonTheme,
}: {
buttonTheme: NonNullable<BubbleProps['theme']>['button']
}) => {
if (!buttonTheme?.customIconSrc)
return (
<svg
viewBox="0 0 24 24"
style={{
stroke: buttonTheme?.backgroundColor
? isLight(buttonTheme?.backgroundColor)
? '#000'
: '#fff'
: '#fff',
transition: 'all 0.2s ease-in-out',
}}
width={buttonTheme?.size === 'large' ? '36px' : '28px'}
strokeWidth="2px"
fill="transparent"
>
<path d="M21 11.5a8.38 8.38 0 0 1-.9 3.8 8.5 8.5 0 0 1-7.6 4.7 8.38 8.38 0 0 1-3.8-.9L3 21l1.9-5.7a8.38 8.38 0 0 1-.9-3.8 8.5 8.5 0 0 1 4.7-7.6 8.38 8.38 0 0 1 3.8-.9h.5a8.48 8.48 0 0 1 8 8v.5z" />
</svg>
)
if (
buttonTheme.customIconSrc.startsWith('http') ||
buttonTheme.customIconSrc.startsWith('data:image/svg+xml')
)
return (
<Image
src={buttonTheme.customIconSrc}
transition="all 0.2s ease-in-out"
boxSize={
isSvgSrc(buttonTheme.customIconSrc)
? buttonTheme?.size === 'large'
? '36px'
: '28px'
: '90%'
}
rounded={isSvgSrc(buttonTheme.customIconSrc) ? undefined : 'full'}
alt="Bubble button icon"
objectFit={isSvgSrc(buttonTheme.customIconSrc) ? undefined : 'cover'}
/>
)
return (
<chakra.span
transition="all 0.2s ease-in-out"
fontSize={buttonTheme.size === 'large' ? '36px' : '24px'}
lineHeight={buttonTheme.size === 'large' ? '40px' : '32px'}
>
{buttonTheme.customIconSrc}
</chakra.span>
)
}

View File

@@ -1,5 +1,21 @@
import { ColorPicker } from '@/components/ColorPicker'
import { Heading, HStack, Input, Stack, Text } from '@chakra-ui/react'
import { ImageUploadContent } from '@/components/ImageUploadContent'
import { ChevronDownIcon } from '@/components/icons'
import {
Button,
Heading,
HStack,
Menu,
MenuButton,
MenuItem,
MenuList,
Popover,
PopoverAnchor,
PopoverContent,
Stack,
Text,
useDisclosure,
} from '@chakra-ui/react'
import { ButtonTheme } from '@typebot.io/js/dist/features/bubble/types'
import React from 'react'
@@ -9,6 +25,8 @@ type Props = {
}
export const ButtonThemeSettings = ({ buttonTheme, onChange }: Props) => {
const { isOpen, onOpen, onClose } = useDisclosure()
const updateBackgroundColor = (backgroundColor: string) => {
onChange({
...buttonTheme,
@@ -16,48 +34,58 @@ export const ButtonThemeSettings = ({ buttonTheme, onChange }: Props) => {
})
}
const updateIconColor = (iconColor: string) => {
onChange({
...buttonTheme,
iconColor,
})
}
const updateCustomIconSrc = (customIconSrc: string) => {
onChange({
...buttonTheme,
customIconSrc,
})
onClose()
}
const updateSize = (size: ButtonTheme['size']) =>
onChange({
...buttonTheme,
size,
})
return (
<Stack spacing={4} borderWidth="1px" rounded="md" p="4">
<Heading size="sm">Button</Heading>
<Stack spacing={4}>
<HStack justify="space-between">
<Text>Background color</Text>
<Text>Size</Text>
<Menu>
<MenuButton as={Button} size="sm" rightIcon={<ChevronDownIcon />}>
{buttonTheme?.size ?? 'medium'}
</MenuButton>
<MenuList>
<MenuItem onClick={() => updateSize('medium')}>medium</MenuItem>
<MenuItem onClick={() => updateSize('large')}>large</MenuItem>
</MenuList>
</Menu>
</HStack>
<HStack justify="space-between">
<Text>Color</Text>
<ColorPicker
defaultValue={buttonTheme?.backgroundColor}
onColorChange={updateBackgroundColor}
/>
</HStack>
<HStack justify="space-between">
<Text>Icon color</Text>
<ColorPicker
defaultValue={buttonTheme?.iconColor}
onColorChange={updateIconColor}
/>
</HStack>
<HStack justify="space-between">
<Text>Custom icon</Text>
<Input
placeholder={'Paste image link (.png, .svg)'}
value={buttonTheme?.customIconSrc}
onChange={(e) => updateCustomIconSrc(e.target.value)}
minW="0"
w="300px"
size="sm"
/>
<Popover isLazy isOpen={isOpen}>
<PopoverAnchor>
<Button size="sm" onClick={onOpen}>
Pick an image
</Button>
</PopoverAnchor>
<PopoverContent p="4" w="500px">
<ImageUploadContent
onSubmit={updateCustomIconSrc}
filePath={undefined}
/>
</PopoverContent>
</Popover>
</HStack>
</Stack>
</Stack>

View File

@@ -19,7 +19,8 @@ const parseButtonTheme = (
)
const iconColorLine = parseStringParam('iconColor', iconColor)
const customIconLine = parseStringParam('customIconSrc', customIconSrc)
const line = `button: {${backgroundColorLine}${iconColorLine}${customIconLine}},`
const sizeLine = parseStringParam('size', button.size)
const line = `button: {${backgroundColorLine}${iconColorLine}${customIconLine}${sizeLine}},`
if (line === 'button: {},') return ''
return line
}

View File

@@ -64,7 +64,7 @@ export const MetadataForm = ({
filePath={`typebots/${typebotId}/favIcon`}
defaultUrl={metadata.favIconUrl ?? ''}
onSubmit={handleFavIconSubmit}
isGiphyEnabled={false}
excludedTabs={['giphy', 'unsplash', 'emoji']}
imageSize="thumb"
/>
</PopoverContent>
@@ -90,7 +90,7 @@ export const MetadataForm = ({
filePath={`typebots/${typebotId}/ogImage`}
defaultUrl={metadata.imageUrl}
onSubmit={handleImageSubmit}
isGiphyEnabled={false}
excludedTabs={['giphy', 'icon', 'emoji']}
/>
</PopoverContent>
</Popover>

View File

@@ -62,7 +62,7 @@ export const BackgroundContent = ({
filePath={`typebots/${typebot?.id}/background`}
defaultUrl={background.content}
onSubmit={handleContentChange}
isGiphyEnabled={false}
excludedTabs={['giphy', 'icon']}
/>
</PopoverContent>
</Popover>