⚡ (embed) Add size and icon picker in bubble settings (#508)
This commit is contained in:
@@ -19,7 +19,7 @@ import tinyColor from 'tinycolor2'
|
||||
|
||||
const colorsSelection: `#${string}`[] = [
|
||||
'#666460',
|
||||
'#AFABA3',
|
||||
'#FFFFFF',
|
||||
'#A87964',
|
||||
'#D09C46',
|
||||
'#DE8031',
|
||||
@@ -27,7 +27,7 @@ const colorsSelection: `#${string}`[] = [
|
||||
'#4A8BB2',
|
||||
'#9B74B7',
|
||||
'#C75F96',
|
||||
'#C75F96',
|
||||
'#0042DA',
|
||||
]
|
||||
|
||||
type Props = {
|
||||
@@ -78,18 +78,19 @@ export const ColorPicker = ({ value, defaultValue, onColorChange }: Props) => {
|
||||
</PopoverHeader>
|
||||
<PopoverBody as={Stack}>
|
||||
<SimpleGrid columns={5} spacing={2}>
|
||||
{colorsSelection.map((c) => (
|
||||
{colorsSelection.map((color) => (
|
||||
<Button
|
||||
key={c}
|
||||
aria-label={c}
|
||||
background={c}
|
||||
key={color}
|
||||
aria-label={color}
|
||||
background={color}
|
||||
height="22px"
|
||||
width="22px"
|
||||
padding={0}
|
||||
minWidth="unset"
|
||||
borderRadius={3}
|
||||
_hover={{ background: c }}
|
||||
onClick={handleClick(c)}
|
||||
borderWidth={color === '#FFFFFF' ? 1 : undefined}
|
||||
_hover={{ background: color }}
|
||||
onClick={handleClick(color)}
|
||||
/>
|
||||
))}
|
||||
</SimpleGrid>
|
||||
|
||||
@@ -57,10 +57,9 @@ export const EditableEmojiOrImageIcon = ({
|
||||
filePath={uploadFilePath}
|
||||
defaultUrl={icon ?? ''}
|
||||
onSubmit={onChangeIcon}
|
||||
isGiphyEnabled={false}
|
||||
isUnsplashEnabled={false}
|
||||
isEmojiEnabled={true}
|
||||
excludedTabs={['giphy', 'unsplash']}
|
||||
onClose={onClose}
|
||||
initialTab="icon"
|
||||
/>
|
||||
</PopoverContent>
|
||||
</>
|
||||
|
||||
@@ -26,6 +26,13 @@ export const IconPicker = ({ onIconSelected }: Props) => {
|
||||
)
|
||||
const searchQuery = useRef<string>('')
|
||||
const [selectedColor, setSelectedColor] = useState(initialIconColor)
|
||||
const isWhite = useMemo(
|
||||
() =>
|
||||
selectedColor.toLowerCase() === '#ffffff' ||
|
||||
selectedColor.toLowerCase() === '#fff' ||
|
||||
selectedColor === 'white',
|
||||
[selectedColor]
|
||||
)
|
||||
|
||||
useEffect(() => {
|
||||
if (!bottomElement.current) return
|
||||
@@ -68,10 +75,9 @@ export const IconPicker = ({ onIconSelected }: Props) => {
|
||||
|
||||
const selectIcon = async (iconName: string) => {
|
||||
const svg = await (await fetch(`/icons/${iconName}.svg`)).text()
|
||||
const dataUri = `data:image/svg+xml;utf8,${svg.replace(
|
||||
'<svg',
|
||||
`<svg fill='${encodeURIComponent(selectedColor)}'`
|
||||
)}`
|
||||
const dataUri = `data:image/svg+xml;utf8,${svg
|
||||
.replace('<svg', `<svg fill='${encodeURIComponent(selectedColor)}'`)
|
||||
.replace(/"/g, "'")}`
|
||||
onIconSelected(dataUri)
|
||||
}
|
||||
|
||||
@@ -96,8 +102,9 @@ export const IconPicker = ({ onIconSelected }: Props) => {
|
||||
>
|
||||
{displayedIconNames.map((iconName) => (
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
variant={isWhite ? 'solid' : 'ghost'}
|
||||
colorScheme={isWhite ? 'blackAlpha' : undefined}
|
||||
fontSize="xl"
|
||||
w="38px"
|
||||
h="38px"
|
||||
|
||||
@@ -10,30 +10,52 @@ import { IconPicker } from './IconPicker'
|
||||
type Tabs = 'link' | 'upload' | 'giphy' | 'emoji' | 'unsplash' | 'icon'
|
||||
|
||||
type Props = {
|
||||
filePath: string
|
||||
filePath: string | undefined
|
||||
includeFileName?: boolean
|
||||
defaultUrl?: string
|
||||
isEmojiEnabled?: boolean
|
||||
isGiphyEnabled?: boolean
|
||||
isUnsplashEnabled?: boolean
|
||||
imageSize?: 'small' | 'regular' | 'thumb'
|
||||
initialTab?: Tabs
|
||||
onSubmit: (url: string) => void
|
||||
onClose?: () => void
|
||||
}
|
||||
} & (
|
||||
| {
|
||||
includedTabs?: Tabs[]
|
||||
}
|
||||
| {
|
||||
excludedTabs?: Tabs[]
|
||||
}
|
||||
)
|
||||
|
||||
const defaultDisplayedTabs: Tabs[] = [
|
||||
'link',
|
||||
'upload',
|
||||
'giphy',
|
||||
'emoji',
|
||||
'unsplash',
|
||||
'icon',
|
||||
]
|
||||
|
||||
export const ImageUploadContent = ({
|
||||
filePath,
|
||||
includeFileName,
|
||||
defaultUrl,
|
||||
onSubmit,
|
||||
isEmojiEnabled = false,
|
||||
isGiphyEnabled = true,
|
||||
isUnsplashEnabled = true,
|
||||
imageSize = 'regular',
|
||||
onClose,
|
||||
initialTab,
|
||||
...props
|
||||
}: Props) => {
|
||||
const includedTabs =
|
||||
'includedTabs' in props
|
||||
? props.includedTabs ?? defaultDisplayedTabs
|
||||
: defaultDisplayedTabs
|
||||
const excludedTabs = 'excludedTabs' in props ? props.excludedTabs ?? [] : []
|
||||
const displayedTabs = defaultDisplayedTabs.filter(
|
||||
(tab) => !excludedTabs.includes(tab) && includedTabs.includes(tab)
|
||||
)
|
||||
|
||||
const [currentTab, setCurrentTab] = useState<Tabs>(
|
||||
isEmojiEnabled ? 'emoji' : 'link'
|
||||
initialTab ?? displayedTabs[0]
|
||||
)
|
||||
|
||||
const handleSubmit = (url: string) => {
|
||||
@@ -44,7 +66,25 @@ export const ImageUploadContent = ({
|
||||
return (
|
||||
<Stack>
|
||||
<HStack>
|
||||
{isEmojiEnabled && (
|
||||
{displayedTabs.includes('link') && (
|
||||
<Button
|
||||
variant={currentTab === 'link' ? 'solid' : 'ghost'}
|
||||
onClick={() => setCurrentTab('link')}
|
||||
size="sm"
|
||||
>
|
||||
Link
|
||||
</Button>
|
||||
)}
|
||||
{displayedTabs.includes('upload') && (
|
||||
<Button
|
||||
variant={currentTab === 'upload' ? 'solid' : 'ghost'}
|
||||
onClick={() => setCurrentTab('upload')}
|
||||
size="sm"
|
||||
>
|
||||
Upload
|
||||
</Button>
|
||||
)}
|
||||
{displayedTabs.includes('emoji') && (
|
||||
<Button
|
||||
variant={currentTab === 'emoji' ? 'solid' : 'ghost'}
|
||||
onClick={() => setCurrentTab('emoji')}
|
||||
@@ -53,21 +93,7 @@ export const ImageUploadContent = ({
|
||||
Emoji
|
||||
</Button>
|
||||
)}
|
||||
<Button
|
||||
variant={currentTab === 'link' ? 'solid' : 'ghost'}
|
||||
onClick={() => setCurrentTab('link')}
|
||||
size="sm"
|
||||
>
|
||||
Link
|
||||
</Button>
|
||||
<Button
|
||||
variant={currentTab === 'upload' ? 'solid' : 'ghost'}
|
||||
onClick={() => setCurrentTab('upload')}
|
||||
size="sm"
|
||||
>
|
||||
Upload
|
||||
</Button>
|
||||
{isGiphyEnabled && (
|
||||
{displayedTabs.includes('giphy') && (
|
||||
<Button
|
||||
variant={currentTab === 'giphy' ? 'solid' : 'ghost'}
|
||||
onClick={() => setCurrentTab('giphy')}
|
||||
@@ -76,7 +102,7 @@ export const ImageUploadContent = ({
|
||||
Giphy
|
||||
</Button>
|
||||
)}
|
||||
{isUnsplashEnabled && (
|
||||
{displayedTabs.includes('unsplash') && (
|
||||
<Button
|
||||
variant={currentTab === 'unsplash' ? 'solid' : 'ghost'}
|
||||
onClick={() => setCurrentTab('unsplash')}
|
||||
@@ -85,13 +111,15 @@ export const ImageUploadContent = ({
|
||||
Unsplash
|
||||
</Button>
|
||||
)}
|
||||
<Button
|
||||
variant={currentTab === 'icon' ? 'solid' : 'ghost'}
|
||||
onClick={() => setCurrentTab('icon')}
|
||||
size="sm"
|
||||
>
|
||||
Icon
|
||||
</Button>
|
||||
{displayedTabs.includes('icon') && (
|
||||
<Button
|
||||
variant={currentTab === 'icon' ? 'solid' : 'ghost'}
|
||||
onClick={() => setCurrentTab('icon')}
|
||||
size="sm"
|
||||
>
|
||||
Icon
|
||||
</Button>
|
||||
)}
|
||||
</HStack>
|
||||
|
||||
<BodyContent
|
||||
@@ -115,14 +143,15 @@ const BodyContent = ({
|
||||
onSubmit,
|
||||
}: {
|
||||
includeFileName?: boolean
|
||||
filePath: string
|
||||
filePath: string | undefined
|
||||
tab: Tabs
|
||||
defaultUrl?: string
|
||||
imageSize: 'small' | 'regular' | 'thumb'
|
||||
onSubmit: (url: string) => void
|
||||
}) => {
|
||||
switch (tab) {
|
||||
case 'upload':
|
||||
case 'upload': {
|
||||
if (!filePath) return null
|
||||
return (
|
||||
<UploadFileContent
|
||||
filePath={filePath}
|
||||
@@ -130,6 +159,7 @@ const BodyContent = ({
|
||||
onNewUrl={onSubmit}
|
||||
/>
|
||||
)
|
||||
}
|
||||
case 'link':
|
||||
return <EmbedLinkContent defaultUrl={defaultUrl} onNewUrl={onSubmit} />
|
||||
case 'giphy':
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@typebot.io/js",
|
||||
"version": "0.0.50",
|
||||
"version": "0.0.51",
|
||||
"description": "Javascript library to display typebots on your website",
|
||||
"type": "module",
|
||||
"main": "dist/index.js",
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { Show } from 'solid-js'
|
||||
import { isNotDefined } from '@typebot.io/lib'
|
||||
import { isNotDefined, isSvgSrc } from '@typebot.io/lib'
|
||||
import { ButtonTheme } from '../types'
|
||||
import { isLight } from '@typebot.io/lib/hexToRgb'
|
||||
|
||||
type Props = ButtonTheme & {
|
||||
isBotOpened: boolean
|
||||
@@ -8,7 +9,9 @@ type Props = ButtonTheme & {
|
||||
}
|
||||
|
||||
const defaultButtonColor = '#0042DA'
|
||||
const defaultIconColor = 'white'
|
||||
|
||||
const isImageSrc = (src: string) =>
|
||||
src.startsWith('http') || src.startsWith('data:image/svg+xml')
|
||||
|
||||
export const BubbleButton = (props: Props) => {
|
||||
return (
|
||||
@@ -28,7 +31,11 @@ export const BubbleButton = (props: Props) => {
|
||||
<svg
|
||||
viewBox="0 0 24 24"
|
||||
style={{
|
||||
stroke: props.iconColor ?? defaultIconColor,
|
||||
stroke:
|
||||
props.iconColor ??
|
||||
isLight(props.backgroundColor ?? defaultButtonColor)
|
||||
? '#27272A'
|
||||
: '#fff',
|
||||
}}
|
||||
class={
|
||||
`stroke-2 fill-transparent absolute duration-200 transition ` +
|
||||
@@ -41,18 +48,42 @@ export const BubbleButton = (props: Props) => {
|
||||
<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>
|
||||
</Show>
|
||||
<Show when={props.customIconSrc}>
|
||||
<Show when={props.customIconSrc && isImageSrc(props.customIconSrc)}>
|
||||
<img
|
||||
src={props.customIconSrc}
|
||||
class={
|
||||
'rounded-full object-cover' +
|
||||
(props.size === 'large' ? ' w-9 h-9' : ' w-7 h-7')
|
||||
'duration-200 transition' +
|
||||
(props.isBotOpened
|
||||
? ' scale-0 opacity-0'
|
||||
: ' scale-100 opacity-100') +
|
||||
(isSvgSrc(props.customIconSrc)
|
||||
? props.size === 'large'
|
||||
? ' w-9 h-9'
|
||||
: ' w-7 h-7'
|
||||
: ' w-[90%] h-[90%]') +
|
||||
(isSvgSrc(props.customIconSrc) ? '' : ' object-cover rounded-full')
|
||||
}
|
||||
alt="Bubble button icon"
|
||||
elementtiming={'Bubble button icon'}
|
||||
fetchpriority={'high'}
|
||||
/>
|
||||
</Show>
|
||||
<Show when={props.customIconSrc && !isImageSrc(props.customIconSrc)}>
|
||||
<span
|
||||
class={
|
||||
'text-4xl duration-200 transition' +
|
||||
(props.isBotOpened
|
||||
? ' scale-0 opacity-0'
|
||||
: ' scale-100 opacity-100')
|
||||
}
|
||||
style={{
|
||||
'font-family':
|
||||
"-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'",
|
||||
}}
|
||||
>
|
||||
{props.customIconSrc}
|
||||
</span>
|
||||
</Show>
|
||||
|
||||
<svg
|
||||
viewBox="0 0 24 24"
|
||||
|
||||
@@ -7,8 +7,7 @@ import {
|
||||
Theme,
|
||||
} from '@typebot.io/schemas'
|
||||
import { BackgroundType } from '@typebot.io/schemas/features/typebot/theme/enums'
|
||||
import { hexToRgb } from './hexToRgb'
|
||||
import { isLight } from './hexToRgb'
|
||||
import { isLight, hexToRgb } from '@typebot.io/lib/hexToRgb'
|
||||
|
||||
const cssVariableNames = {
|
||||
general: {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@typebot.io/react",
|
||||
"version": "0.0.50",
|
||||
"version": "0.0.51",
|
||||
"description": "React library to display typebots on your website",
|
||||
"main": "dist/index.js",
|
||||
"types": "dist/index.d.ts",
|
||||
|
||||
Reference in New Issue
Block a user