From 65d33e04bc6b993d2c9e3d42ee7509cd90a88aed Mon Sep 17 00:00:00 2001 From: Baptiste Arnaud Date: Wed, 22 Mar 2023 16:43:34 +0100 Subject: [PATCH] :zap: (theme) Add corner roundness customization Closes #415 --- apps/builder/src/components/icons.tsx | 39 +++++++++++++++++++ .../inputs/RadioButtons.tsx} | 39 ++++++++++--------- .../components/chat/ChatThemeSettings.tsx | 29 ++++++++++++++ .../components/general/BackgroundSelector.tsx | 13 +++++-- apps/builder/src/features/theme/theme.spec.ts | 26 +++++++++++++ packages/embeds/js/package.json | 2 +- packages/embeds/js/src/assets/index.css | 25 +++++++++--- .../ConversationContainer.tsx | 2 +- .../PopupBlockedToast.tsx | 4 +- .../embeds/js/src/components/SendButton.tsx | 2 +- .../js/src/components/bubbles/GuestBubble.tsx | 2 +- .../src/components/bubbles/LoadingBubble.tsx | 2 +- .../bubbles/audio/components/AudioBubble.tsx | 2 +- .../bubbles/embed/components/EmbedBubble.tsx | 4 +- .../bubbles/image/components/ImageBubble.tsx | 4 +- .../textBubble/components/TextBubble.tsx | 4 +- .../bubbles/video/components/VideoBubble.tsx | 6 +-- .../inputs/buttons/components/ChoiceForm.tsx | 2 +- .../inputs/date/components/DateForm.tsx | 2 +- .../inputs/email/components/EmailInput.tsx | 4 +- .../fileUpload/components/FileUploadForm.tsx | 6 +-- .../inputs/number/components/NumberInput.tsx | 4 +- .../payment/components/StripePaymentForm.tsx | 2 +- .../inputs/phone/components/PhoneInput.tsx | 4 +- .../inputs/rating/components/RatingForm.tsx | 2 +- .../inputs/textInput/components/TextInput.tsx | 4 +- .../blocks/inputs/url/components/UrlInput.tsx | 4 +- .../js/src/utils/setCssVariablesValue.ts | 20 +++++++++- packages/embeds/react/package.json | 2 +- .../schemas/features/typebot/theme/schemas.ts | 1 + 30 files changed, 195 insertions(+), 67 deletions(-) rename apps/builder/src/{features/theme/components/general/BackgroundTypeRadioButtons.tsx => components/inputs/RadioButtons.tsx} (63%) diff --git a/apps/builder/src/components/icons.tsx b/apps/builder/src/components/icons.tsx index d80aa02581..4d09d806f8 100644 --- a/apps/builder/src/components/icons.tsx +++ b/apps/builder/src/components/icons.tsx @@ -552,3 +552,42 @@ export const CloseIcon = (props: IconProps) => ( ) + +export const NoRadiusIcon = (props: IconProps) => ( + + + + + + +) + +export const MediumRadiusIcon = (props: IconProps) => ( + + + + + + +) + +export const LargeRadiusIcon = (props: IconProps) => ( + + + + + + +) diff --git a/apps/builder/src/features/theme/components/general/BackgroundTypeRadioButtons.tsx b/apps/builder/src/components/inputs/RadioButtons.tsx similarity index 63% rename from apps/builder/src/features/theme/components/general/BackgroundTypeRadioButtons.tsx rename to apps/builder/src/components/inputs/RadioButtons.tsx index 596c7dbd9a..8d6acb19fd 100644 --- a/apps/builder/src/features/theme/components/general/BackgroundTypeRadioButtons.tsx +++ b/apps/builder/src/components/inputs/RadioButtons.tsx @@ -7,35 +7,32 @@ import { useRadioGroup, UseRadioProps, } from '@chakra-ui/react' -import { BackgroundType } from '@typebot.io/schemas' import { ReactNode } from 'react' -type Props = { - backgroundType: BackgroundType - onBackgroundTypeChange: (type: BackgroundType) => void +type Props = { + options: (T | { value: T; label: ReactNode })[] + defaultValue: T + onSelect: (newValue: T) => void } -export const BackgroundTypeRadioButtons = ({ - backgroundType, - onBackgroundTypeChange, -}: Props) => { - const options = ['Color', 'Image', 'None'] - +export const RadioButtons = ({ + options, + defaultValue, + onSelect, +}: Props) => { const { getRootProps, getRadioProps } = useRadioGroup({ - name: 'background-type', - defaultValue: backgroundType, - onChange: (nextVal: string) => - onBackgroundTypeChange(nextVal as BackgroundType), + defaultValue, + onChange: onSelect, }) const group = getRootProps() return ( - {options.map((value) => { - const radio = getRadioProps({ value }) + {options.map((item) => { + const radio = getRadioProps({ value: parseValue(item) }) return ( - - {value} + + {parseLabel(item)} ) })} @@ -76,3 +73,9 @@ export const RadioCard = (props: UseRadioProps & { children: ReactNode }) => { ) } + +const parseValue = (item: string | { value: string; label: ReactNode }) => + typeof item === 'string' ? item : item.value + +const parseLabel = (item: string | { value: string; label: ReactNode }) => + typeof item === 'string' ? item : item.label diff --git a/apps/builder/src/features/theme/components/chat/ChatThemeSettings.tsx b/apps/builder/src/features/theme/components/chat/ChatThemeSettings.tsx index 57725db915..a7b36ee29b 100644 --- a/apps/builder/src/features/theme/components/chat/ChatThemeSettings.tsx +++ b/apps/builder/src/features/theme/components/chat/ChatThemeSettings.tsx @@ -1,3 +1,9 @@ +import { + LargeRadiusIcon, + MediumRadiusIcon, + NoRadiusIcon, +} from '@/components/icons' +import { RadioButtons } from '@/components/inputs/RadioButtons' import { Heading, Stack } from '@chakra-ui/react' import { AvatarProps, @@ -59,6 +65,29 @@ export const ChatThemeSettings = ({ onHostBubblesChange={handleHostBubblesChange} /> + + Corners roundness + , + value: 'none', + }, + { + label: , + value: 'medium', + }, + { + label: , + value: 'large', + }, + ]} + defaultValue={chatTheme.roundness ?? 'medium'} + onSelect={(roundness) => + onChatThemeChange({ ...chatTheme, roundness }) + } + /> + User bubbles Background - { await expect(page.locator('.typebot-container img')).toBeHidden() + // Roundness + await expect(page.getByRole('button', { name: 'Go' })).toHaveCSS( + 'border-radius', + '6px' + ) + await page + .getByRole('region', { name: 'Chat' }) + .getByRole('radiogroup') + .locator('div') + .first() + .click() + await expect(page.getByRole('button', { name: 'Go' })).toHaveCSS( + 'border-radius', + '0px' + ) + await page + .getByRole('region', { name: 'Chat' }) + .getByRole('radiogroup') + .locator('div') + .nth(2) + .click() + await expect(page.getByRole('button', { name: 'Go' })).toHaveCSS( + 'border-radius', + '20px' + ) + // Host bubbles await page.click( '[data-testid="host-bubbles-theme"] >> [aria-label="Pick a color"] >> nth=0' diff --git a/packages/embeds/js/package.json b/packages/embeds/js/package.json index 1947351b2d..e818a9b886 100644 --- a/packages/embeds/js/package.json +++ b/packages/embeds/js/package.json @@ -1,6 +1,6 @@ { "name": "@typebot.io/js", - "version": "0.0.28", + "version": "0.0.29", "description": "Javascript library to display typebots on your website", "type": "module", "main": "dist/index.js", diff --git a/packages/embeds/js/src/assets/index.css b/packages/embeds/js/src/assets/index.css index ad98fd9f2a..6295671ade 100644 --- a/packages/embeds/js/src/assets/index.css +++ b/packages/embeds/js/src/assets/index.css @@ -23,6 +23,8 @@ --typebot-header-bg-color: #ffffff; --typebot-header-color: #303235; + --typebot-border-radius: 6px; + /* Phone input */ --PhoneInputCountryFlag-borderColor: transparent; --PhoneInput-color--focus: transparent; @@ -127,15 +129,11 @@ textarea { 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; } -.custom-header { - color: var(--typebot-header-color); - background-color: var(--typebot-header-bg-color); -} - .typebot-button { color: var(--typebot-button-color); background-color: var(--typebot-button-bg-color); border: 1px solid var(--typebot-button-bg-color); + border-radius: var(--typebot-border-radius); } .typebot-button.selectable { @@ -151,17 +149,26 @@ textarea { .typebot-host-bubble > .bubble-typing { background-color: var(--typebot-host-bubble-bg-color); border: var(--typebot-host-bubble-border); + border-radius: 6px; +} + +.typebot-host-bubble img, +.typebot-host-bubble iframe, +.typebot-host-bubble video { + border-radius: var(--typebot-border-radius); } .typebot-guest-bubble { color: var(--typebot-guest-bubble-color); background-color: var(--typebot-guest-bubble-bg-color); + border-radius: 6px; } .typebot-input { color: var(--typebot-input-color); background-color: var(--typebot-input-bg-color); box-shadow: 0 2px 6px -1px rgba(0, 0, 0, 0.1); + border-radius: var(--typebot-border-radius); } .typebot-input-error-message { @@ -202,6 +209,7 @@ textarea { .upload-progress-bar { background-color: var(--typebot-button-bg-color); + border-radius: var(--typebot-border-radius); } .total-files-indicator { @@ -221,15 +229,22 @@ textarea { .secondary-button { background-color: var(--typebot-host-bubble-bg-color); color: var(--typebot-host-bubble-color); + border-radius: var(--typebot-border-radius); } .typebot-country-select { color: var(--typebot-input-color); background-color: var(--typebot-input-bg-color); + border-radius: var(--typebot-border-radius); } .typebot-date-input { color-scheme: light; color: var(--typebot-input-color); background-color: var(--typebot-input-bg-color); + border-radius: var(--typebot-border-radius); +} + +.typebot-popup-blocked-toast { + border-radius: var(--typebot-border-radius); } diff --git a/packages/embeds/js/src/components/ConversationContainer/ConversationContainer.tsx b/packages/embeds/js/src/components/ConversationContainer/ConversationContainer.tsx index 0701f0e717..aa341feaa1 100644 --- a/packages/embeds/js/src/components/ConversationContainer/ConversationContainer.tsx +++ b/packages/embeds/js/src/components/ConversationContainer/ConversationContainer.tsx @@ -157,7 +157,7 @@ export const ConversationContainer = (props: Props) => { return (
{(chatChunk, index) => ( diff --git a/packages/embeds/js/src/components/ConversationContainer/PopupBlockedToast.tsx b/packages/embeds/js/src/components/ConversationContainer/PopupBlockedToast.tsx index f8a0f3907d..54f0733824 100644 --- a/packages/embeds/js/src/components/ConversationContainer/PopupBlockedToast.tsx +++ b/packages/embeds/js/src/components/ConversationContainer/PopupBlockedToast.tsx @@ -6,7 +6,7 @@ type Props = { export const PopupBlockedToast = (props: Props) => { return (