♻️ (builder) Remove barrel export and flatten folder arch
This commit is contained in:
103
apps/builder/src/features/theme/components/chat/AvatarForm.tsx
Normal file
103
apps/builder/src/features/theme/components/chat/AvatarForm.tsx
Normal file
@@ -0,0 +1,103 @@
|
||||
import React from 'react'
|
||||
import { AvatarProps } from '@typebot.io/schemas'
|
||||
import {
|
||||
Heading,
|
||||
HStack,
|
||||
Popover,
|
||||
PopoverContent,
|
||||
Stack,
|
||||
Switch,
|
||||
Image,
|
||||
Flex,
|
||||
Box,
|
||||
Portal,
|
||||
PopoverAnchor,
|
||||
useDisclosure,
|
||||
} from '@chakra-ui/react'
|
||||
import { ImageUploadContent } from '@/components/ImageUploadContent'
|
||||
import { DefaultAvatar } from '../DefaultAvatar'
|
||||
import { useOutsideClick } from '@/hooks/useOutsideClick'
|
||||
|
||||
type Props = {
|
||||
uploadFilePath: string
|
||||
title: string
|
||||
avatarProps?: AvatarProps
|
||||
isDefaultCheck?: boolean
|
||||
onAvatarChange: (avatarProps: AvatarProps) => void
|
||||
}
|
||||
|
||||
export const AvatarForm = ({
|
||||
uploadFilePath,
|
||||
title,
|
||||
avatarProps,
|
||||
isDefaultCheck = false,
|
||||
onAvatarChange,
|
||||
}: Props) => {
|
||||
const { isOpen, onOpen, onClose } = useDisclosure()
|
||||
const isChecked = avatarProps ? avatarProps.isEnabled : isDefaultCheck
|
||||
const handleOnCheck = () =>
|
||||
onAvatarChange({ ...avatarProps, isEnabled: !isChecked })
|
||||
const handleImageUrl = (url: string) =>
|
||||
onAvatarChange({ isEnabled: isChecked, url })
|
||||
const popoverContainerRef = React.useRef<HTMLDivElement>(null)
|
||||
|
||||
useOutsideClick({
|
||||
ref: popoverContainerRef,
|
||||
handler: onClose,
|
||||
})
|
||||
|
||||
const isDefaultAvatar = !avatarProps?.url || avatarProps.url.includes('{{')
|
||||
return (
|
||||
<Stack borderWidth={1} rounded="md" p="4" spacing={4}>
|
||||
<Flex justifyContent="space-between">
|
||||
<HStack>
|
||||
<Heading as="label" fontSize="lg" htmlFor={title} mb="1">
|
||||
{title}
|
||||
</Heading>
|
||||
<Switch isChecked={isChecked} id={title} onChange={handleOnCheck} />
|
||||
</HStack>
|
||||
{isChecked && (
|
||||
<Flex ref={popoverContainerRef}>
|
||||
<Popover isLazy isOpen={isOpen}>
|
||||
<PopoverAnchor>
|
||||
{isDefaultAvatar ? (
|
||||
<Box onClick={onOpen}>
|
||||
<DefaultAvatar
|
||||
cursor="pointer"
|
||||
_hover={{ filter: 'brightness(.9)' }}
|
||||
/>
|
||||
</Box>
|
||||
) : (
|
||||
<Image
|
||||
onClick={onOpen}
|
||||
src={avatarProps.url}
|
||||
alt="Website image"
|
||||
cursor="pointer"
|
||||
_hover={{ filter: 'brightness(.9)' }}
|
||||
transition="filter 200ms"
|
||||
rounded="full"
|
||||
boxSize="40px"
|
||||
objectFit="cover"
|
||||
/>
|
||||
)}
|
||||
</PopoverAnchor>
|
||||
<Portal>
|
||||
<PopoverContent
|
||||
p="4"
|
||||
onMouseDown={(e) => e.stopPropagation()}
|
||||
onPointerDown={(e) => e.stopPropagation()}
|
||||
>
|
||||
<ImageUploadContent
|
||||
filePath={uploadFilePath}
|
||||
defaultUrl={avatarProps?.url}
|
||||
onSubmit={handleImageUrl}
|
||||
/>
|
||||
</PopoverContent>
|
||||
</Portal>
|
||||
</Popover>
|
||||
</Flex>
|
||||
)}
|
||||
</Flex>
|
||||
</Stack>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
import { Stack, Flex, Text } from '@chakra-ui/react'
|
||||
import { ContainerColors } from '@typebot.io/schemas'
|
||||
import React from 'react'
|
||||
import { ColorPicker } from '../../../../components/ColorPicker'
|
||||
|
||||
type Props = {
|
||||
buttons: ContainerColors
|
||||
onButtonsChange: (buttons: ContainerColors) => void
|
||||
}
|
||||
|
||||
export const ButtonsTheme = ({ buttons, onButtonsChange }: Props) => {
|
||||
const handleBackgroundChange = (backgroundColor: string) =>
|
||||
onButtonsChange({ ...buttons, backgroundColor })
|
||||
const handleTextChange = (color: string) =>
|
||||
onButtonsChange({ ...buttons, color })
|
||||
|
||||
return (
|
||||
<Stack data-testid="buttons-theme">
|
||||
<Flex justify="space-between" align="center">
|
||||
<Text>Background:</Text>
|
||||
<ColorPicker
|
||||
initialColor={buttons.backgroundColor}
|
||||
onColorChange={handleBackgroundChange}
|
||||
/>
|
||||
</Flex>
|
||||
<Flex justify="space-between" align="center">
|
||||
<Text>Text:</Text>
|
||||
<ColorPicker
|
||||
initialColor={buttons.color}
|
||||
onColorChange={handleTextChange}
|
||||
/>
|
||||
</Flex>
|
||||
</Stack>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
import { Heading, Stack } from '@chakra-ui/react'
|
||||
import {
|
||||
AvatarProps,
|
||||
ChatTheme,
|
||||
ContainerColors,
|
||||
InputColors,
|
||||
} from '@typebot.io/schemas'
|
||||
import React from 'react'
|
||||
import { AvatarForm } from './AvatarForm'
|
||||
import { ButtonsTheme } from './ButtonsTheme'
|
||||
import { GuestBubbles } from './GuestBubbles'
|
||||
import { HostBubbles } from './HostBubbles'
|
||||
import { InputsTheme } from './InputsTheme'
|
||||
|
||||
type Props = {
|
||||
typebotId: string
|
||||
chatTheme: ChatTheme
|
||||
onChatThemeChange: (chatTheme: ChatTheme) => void
|
||||
}
|
||||
|
||||
export const ChatThemeSettings = ({
|
||||
typebotId,
|
||||
chatTheme,
|
||||
onChatThemeChange,
|
||||
}: Props) => {
|
||||
const handleHostBubblesChange = (hostBubbles: ContainerColors) =>
|
||||
onChatThemeChange({ ...chatTheme, hostBubbles })
|
||||
const handleGuestBubblesChange = (guestBubbles: ContainerColors) =>
|
||||
onChatThemeChange({ ...chatTheme, guestBubbles })
|
||||
const handleButtonsChange = (buttons: ContainerColors) =>
|
||||
onChatThemeChange({ ...chatTheme, buttons })
|
||||
const handleInputsChange = (inputs: InputColors) =>
|
||||
onChatThemeChange({ ...chatTheme, inputs })
|
||||
|
||||
const handleHostAvatarChange = (hostAvatar: AvatarProps) =>
|
||||
onChatThemeChange({ ...chatTheme, hostAvatar })
|
||||
const handleGuestAvatarChange = (guestAvatar: AvatarProps) =>
|
||||
onChatThemeChange({ ...chatTheme, guestAvatar })
|
||||
|
||||
return (
|
||||
<Stack spacing={6}>
|
||||
<AvatarForm
|
||||
uploadFilePath={`typebots/${typebotId}/hostAvatar`}
|
||||
title="Bot avatar"
|
||||
avatarProps={chatTheme.hostAvatar}
|
||||
isDefaultCheck
|
||||
onAvatarChange={handleHostAvatarChange}
|
||||
/>
|
||||
<AvatarForm
|
||||
uploadFilePath={`typebots/${typebotId}/guestAvatar`}
|
||||
title="User avatar"
|
||||
avatarProps={chatTheme.guestAvatar}
|
||||
onAvatarChange={handleGuestAvatarChange}
|
||||
/>
|
||||
<Stack borderWidth={1} rounded="md" p="4" spacing={4}>
|
||||
<Heading fontSize="lg">Bot bubbles</Heading>
|
||||
<HostBubbles
|
||||
hostBubbles={chatTheme.hostBubbles}
|
||||
onHostBubblesChange={handleHostBubblesChange}
|
||||
/>
|
||||
</Stack>
|
||||
<Stack borderWidth={1} rounded="md" p="4" spacing={4}>
|
||||
<Heading fontSize="lg">User bubbles</Heading>
|
||||
<GuestBubbles
|
||||
guestBubbles={chatTheme.guestBubbles}
|
||||
onGuestBubblesChange={handleGuestBubblesChange}
|
||||
/>
|
||||
</Stack>
|
||||
<Stack borderWidth={1} rounded="md" p="4" spacing={4}>
|
||||
<Heading fontSize="lg">Buttons</Heading>
|
||||
<ButtonsTheme
|
||||
buttons={chatTheme.buttons}
|
||||
onButtonsChange={handleButtonsChange}
|
||||
/>
|
||||
</Stack>
|
||||
<Stack borderWidth={1} rounded="md" p="4" spacing={4}>
|
||||
<Heading fontSize="lg">Inputs</Heading>
|
||||
<InputsTheme
|
||||
inputs={chatTheme.inputs}
|
||||
onInputsChange={handleInputsChange}
|
||||
/>
|
||||
</Stack>
|
||||
</Stack>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
import { Stack, Flex, Text } from '@chakra-ui/react'
|
||||
import { ContainerColors } from '@typebot.io/schemas'
|
||||
import React from 'react'
|
||||
import { ColorPicker } from '../../../../components/ColorPicker'
|
||||
|
||||
type Props = {
|
||||
guestBubbles: ContainerColors
|
||||
onGuestBubblesChange: (hostBubbles: ContainerColors) => void
|
||||
}
|
||||
|
||||
export const GuestBubbles = ({ guestBubbles, onGuestBubblesChange }: Props) => {
|
||||
const handleBackgroundChange = (backgroundColor: string) =>
|
||||
onGuestBubblesChange({ ...guestBubbles, backgroundColor })
|
||||
const handleTextChange = (color: string) =>
|
||||
onGuestBubblesChange({ ...guestBubbles, color })
|
||||
|
||||
return (
|
||||
<Stack data-testid="guest-bubbles-theme">
|
||||
<Flex justify="space-between" align="center">
|
||||
<Text>Background:</Text>
|
||||
<ColorPicker
|
||||
initialColor={guestBubbles.backgroundColor}
|
||||
onColorChange={handleBackgroundChange}
|
||||
/>
|
||||
</Flex>
|
||||
<Flex justify="space-between" align="center">
|
||||
<Text>Text:</Text>
|
||||
<ColorPicker
|
||||
initialColor={guestBubbles.color}
|
||||
onColorChange={handleTextChange}
|
||||
/>
|
||||
</Flex>
|
||||
</Stack>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
import { Stack, Flex, Text } from '@chakra-ui/react'
|
||||
import { ContainerColors } from '@typebot.io/schemas'
|
||||
import React from 'react'
|
||||
import { ColorPicker } from '../../../../components/ColorPicker'
|
||||
|
||||
type Props = {
|
||||
hostBubbles: ContainerColors
|
||||
onHostBubblesChange: (hostBubbles: ContainerColors) => void
|
||||
}
|
||||
|
||||
export const HostBubbles = ({ hostBubbles, onHostBubblesChange }: Props) => {
|
||||
const handleBackgroundChange = (backgroundColor: string) =>
|
||||
onHostBubblesChange({ ...hostBubbles, backgroundColor })
|
||||
const handleTextChange = (color: string) =>
|
||||
onHostBubblesChange({ ...hostBubbles, color })
|
||||
|
||||
return (
|
||||
<Stack data-testid="host-bubbles-theme">
|
||||
<Flex justify="space-between" align="center">
|
||||
<Text>Background:</Text>
|
||||
<ColorPicker
|
||||
initialColor={hostBubbles.backgroundColor}
|
||||
onColorChange={handleBackgroundChange}
|
||||
/>
|
||||
</Flex>
|
||||
<Flex justify="space-between" align="center">
|
||||
<Text>Text:</Text>
|
||||
<ColorPicker
|
||||
initialColor={hostBubbles.color}
|
||||
onColorChange={handleTextChange}
|
||||
/>
|
||||
</Flex>
|
||||
</Stack>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
import { Stack, Flex, Text } from '@chakra-ui/react'
|
||||
import { InputColors } from '@typebot.io/schemas'
|
||||
import React from 'react'
|
||||
import { ColorPicker } from '../../../../components/ColorPicker'
|
||||
|
||||
type Props = {
|
||||
inputs: InputColors
|
||||
onInputsChange: (buttons: InputColors) => void
|
||||
}
|
||||
|
||||
export const InputsTheme = ({ inputs, onInputsChange }: Props) => {
|
||||
const handleBackgroundChange = (backgroundColor: string) =>
|
||||
onInputsChange({ ...inputs, backgroundColor })
|
||||
const handleTextChange = (color: string) =>
|
||||
onInputsChange({ ...inputs, color })
|
||||
const handlePlaceholderChange = (placeholderColor: string) =>
|
||||
onInputsChange({ ...inputs, placeholderColor })
|
||||
|
||||
return (
|
||||
<Stack data-testid="inputs-theme">
|
||||
<Flex justify="space-between" align="center">
|
||||
<Text>Background:</Text>
|
||||
<ColorPicker
|
||||
initialColor={inputs.backgroundColor}
|
||||
onColorChange={handleBackgroundChange}
|
||||
/>
|
||||
</Flex>
|
||||
<Flex justify="space-between" align="center">
|
||||
<Text>Text:</Text>
|
||||
<ColorPicker
|
||||
initialColor={inputs.color}
|
||||
onColorChange={handleTextChange}
|
||||
/>
|
||||
</Flex>
|
||||
<Flex justify="space-between" align="center">
|
||||
<Text>Placeholder text:</Text>
|
||||
<ColorPicker
|
||||
initialColor={inputs.placeholderColor}
|
||||
onColorChange={handlePlaceholderChange}
|
||||
/>
|
||||
</Flex>
|
||||
</Stack>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user