@ -26,7 +26,7 @@ export const ImageUploadContent = ({
|
|||||||
}: Props) => {
|
}: Props) => {
|
||||||
const [currentTab, setCurrentTab] = useState<
|
const [currentTab, setCurrentTab] = useState<
|
||||||
'link' | 'upload' | 'giphy' | 'emoji'
|
'link' | 'upload' | 'giphy' | 'emoji'
|
||||||
>(isEmojiEnabled ? 'emoji' : 'upload')
|
>(isEmojiEnabled ? 'emoji' : 'link')
|
||||||
|
|
||||||
const handleSubmit = (url: string) => {
|
const handleSubmit = (url: string) => {
|
||||||
onSubmit(url)
|
onSubmit(url)
|
||||||
@ -45,13 +45,6 @@ export const ImageUploadContent = ({
|
|||||||
Emoji
|
Emoji
|
||||||
</Button>
|
</Button>
|
||||||
)}
|
)}
|
||||||
<Button
|
|
||||||
variant={currentTab === 'upload' ? 'solid' : 'ghost'}
|
|
||||||
onClick={() => setCurrentTab('upload')}
|
|
||||||
size="sm"
|
|
||||||
>
|
|
||||||
Upload
|
|
||||||
</Button>
|
|
||||||
<Button
|
<Button
|
||||||
variant={currentTab === 'link' ? 'solid' : 'ghost'}
|
variant={currentTab === 'link' ? 'solid' : 'ghost'}
|
||||||
onClick={() => setCurrentTab('link')}
|
onClick={() => setCurrentTab('link')}
|
||||||
@ -59,6 +52,13 @@ export const ImageUploadContent = ({
|
|||||||
>
|
>
|
||||||
Embed link
|
Embed link
|
||||||
</Button>
|
</Button>
|
||||||
|
<Button
|
||||||
|
variant={currentTab === 'upload' ? 'solid' : 'ghost'}
|
||||||
|
onClick={() => setCurrentTab('upload')}
|
||||||
|
size="sm"
|
||||||
|
>
|
||||||
|
Upload
|
||||||
|
</Button>
|
||||||
{isGiphyEnabled && (
|
{isGiphyEnabled && (
|
||||||
<Button
|
<Button
|
||||||
variant={currentTab === 'giphy' ? 'solid' : 'ghost'}
|
variant={currentTab === 'giphy' ? 'solid' : 'ghost'}
|
||||||
|
@ -1,4 +1,15 @@
|
|||||||
import { Flex, Text } from '@chakra-ui/react'
|
import { ImageUploadContent } from '@/components/ImageUploadContent'
|
||||||
|
import { useTypebot } from '@/features/editor/providers/TypebotProvider'
|
||||||
|
import {
|
||||||
|
Flex,
|
||||||
|
Popover,
|
||||||
|
PopoverContent,
|
||||||
|
PopoverTrigger,
|
||||||
|
Text,
|
||||||
|
Image,
|
||||||
|
Button,
|
||||||
|
} from '@chakra-ui/react'
|
||||||
|
import { isNotEmpty } from '@typebot.io/lib'
|
||||||
import { Background, BackgroundType } from '@typebot.io/schemas'
|
import { Background, BackgroundType } from '@typebot.io/schemas'
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
import { ColorPicker } from '../../../../components/ColorPicker'
|
import { ColorPicker } from '../../../../components/ColorPicker'
|
||||||
@ -14,6 +25,7 @@ export const BackgroundContent = ({
|
|||||||
background,
|
background,
|
||||||
onBackgroundContentChange,
|
onBackgroundContentChange,
|
||||||
}: BackgroundContentProps) => {
|
}: BackgroundContentProps) => {
|
||||||
|
const { typebot } = useTypebot()
|
||||||
const handleContentChange = (content: string) =>
|
const handleContentChange = (content: string) =>
|
||||||
onBackgroundContentChange(content)
|
onBackgroundContentChange(content)
|
||||||
|
|
||||||
@ -30,9 +42,30 @@ export const BackgroundContent = ({
|
|||||||
)
|
)
|
||||||
case BackgroundType.IMAGE:
|
case BackgroundType.IMAGE:
|
||||||
return (
|
return (
|
||||||
<Flex>
|
<Popover isLazy placement="top">
|
||||||
<Text>Image</Text>
|
<PopoverTrigger>
|
||||||
</Flex>
|
{isNotEmpty(background.content) ? (
|
||||||
|
<Image
|
||||||
|
src={background.content}
|
||||||
|
alt="Background image"
|
||||||
|
cursor="pointer"
|
||||||
|
_hover={{ filter: 'brightness(.9)' }}
|
||||||
|
transition="filter 200ms"
|
||||||
|
rounded="md"
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
<Button>Select an image</Button>
|
||||||
|
)}
|
||||||
|
</PopoverTrigger>
|
||||||
|
<PopoverContent p="4">
|
||||||
|
<ImageUploadContent
|
||||||
|
filePath={`typebots/${typebot?.id}/background`}
|
||||||
|
defaultUrl={background.content}
|
||||||
|
onSubmit={handleContentChange}
|
||||||
|
isGiphyEnabled={false}
|
||||||
|
/>
|
||||||
|
</PopoverContent>
|
||||||
|
</Popover>
|
||||||
)
|
)
|
||||||
default:
|
default:
|
||||||
return <></>
|
return <></>
|
||||||
|
@ -16,7 +16,8 @@ export const BackgroundSelector = ({
|
|||||||
onBackgroundChange,
|
onBackgroundChange,
|
||||||
}: Props) => {
|
}: Props) => {
|
||||||
const handleBackgroundTypeChange = (type: BackgroundType) =>
|
const handleBackgroundTypeChange = (type: BackgroundType) =>
|
||||||
background && onBackgroundChange({ ...background, type })
|
background &&
|
||||||
|
onBackgroundChange({ ...background, type, content: undefined })
|
||||||
|
|
||||||
const handleBackgroundContentChange = (content: string) =>
|
const handleBackgroundContentChange = (content: string) =>
|
||||||
background && onBackgroundChange({ ...background, content })
|
background && onBackgroundChange({ ...background, content })
|
||||||
|
@ -18,7 +18,7 @@ export const BackgroundTypeRadioButtons = ({
|
|||||||
backgroundType,
|
backgroundType,
|
||||||
onBackgroundTypeChange,
|
onBackgroundTypeChange,
|
||||||
}: Props) => {
|
}: Props) => {
|
||||||
const options = ['Color', 'None']
|
const options = ['Color', 'Image', 'None']
|
||||||
|
|
||||||
const { getRootProps, getRadioProps } = useRadioGroup({
|
const { getRootProps, getRadioProps } = useRadioGroup({
|
||||||
name: 'background-type',
|
name: 'background-type',
|
||||||
@ -55,10 +55,9 @@ export const RadioCard = (props: UseRadioProps & { children: ReactNode }) => {
|
|||||||
<Flex
|
<Flex
|
||||||
{...checkbox}
|
{...checkbox}
|
||||||
cursor="pointer"
|
cursor="pointer"
|
||||||
borderWidth="1px"
|
borderWidth="2px"
|
||||||
borderRadius="md"
|
borderRadius="md"
|
||||||
_checked={{
|
_checked={{
|
||||||
borderWidth: '2px',
|
|
||||||
borderColor: 'blue.400',
|
borderColor: 'blue.400',
|
||||||
}}
|
}}
|
||||||
_hover={{
|
_hover={{
|
||||||
|
@ -7,6 +7,8 @@ const hostAvatarUrl =
|
|||||||
'https://images.unsplash.com/photo-1535713875002-d1d0cf377fde?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1760&q=80'
|
'https://images.unsplash.com/photo-1535713875002-d1d0cf377fde?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1760&q=80'
|
||||||
const guestAvatarUrl =
|
const guestAvatarUrl =
|
||||||
'https://images.unsplash.com/photo-1494790108377-be9c29b29330?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1287&q=80'
|
'https://images.unsplash.com/photo-1494790108377-be9c29b29330?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1287&q=80'
|
||||||
|
const backgroundImageUrl =
|
||||||
|
'https://images.unsplash.com/photo-1508739773434-c26b3d09e071?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=2940&q=80'
|
||||||
|
|
||||||
test.describe.parallel('Theme page', () => {
|
test.describe.parallel('Theme page', () => {
|
||||||
test.describe('General', () => {
|
test.describe('General', () => {
|
||||||
@ -38,6 +40,20 @@ test.describe.parallel('Theme page', () => {
|
|||||||
'background-color',
|
'background-color',
|
||||||
'rgb(42, 157, 143)'
|
'rgb(42, 157, 143)'
|
||||||
)
|
)
|
||||||
|
await page.click('text=Color')
|
||||||
|
|
||||||
|
await page.click('text="Image"')
|
||||||
|
await page.getByRole('button', { name: 'Select an image' }).click()
|
||||||
|
await page
|
||||||
|
.getByPlaceholder('Paste the image link...')
|
||||||
|
.fill(backgroundImageUrl)
|
||||||
|
await expect(
|
||||||
|
page.getByRole('img', { name: 'Background image' })
|
||||||
|
).toHaveAttribute('src', backgroundImageUrl)
|
||||||
|
await expect(page.locator('.typebot-container')).toHaveCSS(
|
||||||
|
'background-image',
|
||||||
|
`url("${backgroundImageUrl}")`
|
||||||
|
)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -137,8 +137,17 @@ const setTypebotBackground = (
|
|||||||
background?.type === BackgroundType.IMAGE
|
background?.type === BackgroundType.IMAGE
|
||||||
? cssVariableNames.general.bgImage
|
? cssVariableNames.general.bgImage
|
||||||
: cssVariableNames.general.bgColor,
|
: cssVariableNames.general.bgColor,
|
||||||
background.type === BackgroundType.NONE
|
parseBackgroundValue(background)
|
||||||
? 'transparent'
|
|
||||||
: background.content ?? '#ffffff'
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const parseBackgroundValue = ({ type, content }: Background) => {
|
||||||
|
switch (type) {
|
||||||
|
case BackgroundType.NONE:
|
||||||
|
return 'transparent'
|
||||||
|
case BackgroundType.COLOR:
|
||||||
|
return content ?? '#ffffff'
|
||||||
|
case BackgroundType.IMAGE:
|
||||||
|
return `url(${content})`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Reference in New Issue
Block a user