⚡ (embed) Add size and icon picker in bubble settings (#508)
This commit is contained in:
@@ -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',
|
||||
},
|
||||
})
|
||||
|
||||
|
||||
@@ -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>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -62,7 +62,7 @@ export const BackgroundContent = ({
|
||||
filePath={`typebots/${typebot?.id}/background`}
|
||||
defaultUrl={background.content}
|
||||
onSubmit={handleContentChange}
|
||||
isGiphyEnabled={false}
|
||||
excludedTabs={['giphy', 'icon']}
|
||||
/>
|
||||
</PopoverContent>
|
||||
</Popover>
|
||||
|
||||
Reference in New Issue
Block a user