✨ (theme) Add container theme options: border, shadow, filter (#1436)
Closes #1332
This commit is contained in:
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@typebot.io/js",
|
||||
"version": "0.2.64",
|
||||
"version": "0.2.65",
|
||||
"description": "Javascript library to display typebots on your website",
|
||||
"type": "module",
|
||||
"main": "dist/index.js",
|
||||
@ -31,6 +31,7 @@
|
||||
"@typebot.io/env": "workspace:*",
|
||||
"@typebot.io/lib": "workspace:*",
|
||||
"@typebot.io/schemas": "workspace:*",
|
||||
"@typebot.io/theme": "workspace:*",
|
||||
"@typebot.io/tsconfig": "workspace:*",
|
||||
"@types/dompurify": "3.0.3",
|
||||
"autoprefixer": "10.4.14",
|
||||
|
@ -2,47 +2,6 @@
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
|
||||
:host {
|
||||
--typebot-container-bg-image: none;
|
||||
--typebot-container-bg-color: transparent;
|
||||
--typebot-container-font-family: 'Open Sans';
|
||||
--typebot-container-color: #303235;
|
||||
|
||||
--typebot-button-bg-color: #0042da;
|
||||
--typebot-button-bg-color-rgb: 0, 66, 218;
|
||||
--typebot-button-color: #ffffff;
|
||||
|
||||
--typebot-checkbox-bg-color: #ffffff;
|
||||
|
||||
--typebot-host-bubble-bg-color: #f7f8ff;
|
||||
--typebot-host-bubble-color: #303235;
|
||||
|
||||
--typebot-guest-bubble-bg-color: #ff8e21;
|
||||
--typebot-guest-bubble-color: #ffffff;
|
||||
|
||||
--typebot-input-bg-color: #ffffff;
|
||||
--typebot-input-color: #303235;
|
||||
--typebot-input-placeholder-color: #9095a0;
|
||||
|
||||
--typebot-header-bg-color: #ffffff;
|
||||
--typebot-header-color: #303235;
|
||||
|
||||
--selectable-base-alpha: 0;
|
||||
|
||||
--typebot-border-radius: 6px;
|
||||
|
||||
--typebot-progress-bar-position: fixed;
|
||||
--typebot-progress-bar-bg-color: #f7f8ff;
|
||||
--typebot-progress-bar-color: #0042da;
|
||||
--typebot-progress-bar-height: 6px;
|
||||
--typebot-progress-bar-top: 0;
|
||||
--typebot-progress-bar-bottom: auto;
|
||||
|
||||
/* Phone input */
|
||||
--PhoneInputCountryFlag-borderColor: transparent;
|
||||
--PhoneInput-color--focus: transparent;
|
||||
}
|
||||
|
||||
/* Hide scrollbar for Chrome, Safari and Opera */
|
||||
.scrollable-container::-webkit-scrollbar {
|
||||
display: none;
|
||||
@ -161,67 +120,100 @@ pre {
|
||||
.typebot-container {
|
||||
background-image: var(--typebot-container-bg-image);
|
||||
background-color: var(--typebot-container-bg-color);
|
||||
background-position: center;
|
||||
background-size: cover;
|
||||
font-family: var(--typebot-container-font-family), -apple-system,
|
||||
BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif,
|
||||
'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol';
|
||||
container-type: inline-size;
|
||||
}
|
||||
|
||||
.typebot-chat-view {
|
||||
max-width: var(--typebot-chat-container-max-width);
|
||||
background-color: rgba(
|
||||
var(--typebot-chat-container-bg-rgb),
|
||||
var(--typebot-chat-container-opacity)
|
||||
);
|
||||
color: rgb(var(--typebot-chat-container-color));
|
||||
min-height: 100%;
|
||||
backdrop-filter: blur(var(--typebot-chat-container-blur));
|
||||
border-width: var(--typebot-chat-container-border-width);
|
||||
border-color: rgba(
|
||||
var(--typebot-chat-container-border-rgb),
|
||||
var(--typebot-chat-container-border-opacity)
|
||||
);
|
||||
padding-left: 20px;
|
||||
padding-right: 20px;
|
||||
box-shadow: var(--typebot-chat-container-box-shadow);
|
||||
}
|
||||
|
||||
@container (min-width: 480px) {
|
||||
.typebot-chat-view {
|
||||
min-height: var(--typebot-chat-container-max-height);
|
||||
max-height: var(--typebot-chat-container-max-height);
|
||||
border-radius: var(--typebot-chat-container-border-radius);
|
||||
}
|
||||
}
|
||||
|
||||
.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);
|
||||
background-color: rgba(
|
||||
var(--typebot-button-bg-rgb),
|
||||
var(--typebot-button-opacity)
|
||||
);
|
||||
border-width: var(--typebot-button-border-width);
|
||||
border-color: rgba(
|
||||
var(--typebot-button-border-rgb),
|
||||
var(--typebot-button-border-opacity)
|
||||
);
|
||||
border-radius: var(--typebot-button-border-radius);
|
||||
box-shadow: var(--typebot-button-box-shadow);
|
||||
backdrop-filter: blur(var(--typebot-button-blur));
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.typebot-button.selectable {
|
||||
color: var(--typebot-host-bubble-color);
|
||||
background-color: var(--typebot-host-bubble-bg-color);
|
||||
border: 1px solid var(--typebot-button-bg-color);
|
||||
}
|
||||
|
||||
.typebot-selectable {
|
||||
border: 1px solid
|
||||
rgba(
|
||||
var(--typebot-button-bg-color-rgb),
|
||||
calc(var(--selectable-base-alpha) + 0.25)
|
||||
);
|
||||
border-radius: var(--typebot-border-radius);
|
||||
color: var(--typebot-container-color);
|
||||
border-width: var(--typebot-button-border-width);
|
||||
border-color: rgba(
|
||||
var(--typebot-button-border-rgb),
|
||||
calc(var(--selectable-alpha-ratio) * 0.25)
|
||||
);
|
||||
border-radius: var(--typebot-button-border-radius);
|
||||
color: rgb(var(--typebot-chat-container-color));
|
||||
background-color: rgba(
|
||||
var(--typebot-button-bg-color-rgb),
|
||||
calc(var(--selectable-base-alpha) + 0.08)
|
||||
var(--typebot-button-bg-rgb),
|
||||
calc(var(--selectable-alpha-ratio) * 0.08)
|
||||
);
|
||||
transition: all 0.3s ease;
|
||||
backdrop-filter: blur(2px);
|
||||
}
|
||||
|
||||
.typebot-selectable:hover {
|
||||
background-color: rgba(
|
||||
var(--typebot-button-bg-color-rgb),
|
||||
calc(var(--selectable-base-alpha) + 0.12)
|
||||
var(--typebot-button-bg-rgb),
|
||||
calc(var(--selectable-alpha-ratio) * 0.12)
|
||||
);
|
||||
border-color: rgba(
|
||||
var(--typebot-button-bg-color-rgb),
|
||||
calc(var(--selectable-base-alpha) + 0.3)
|
||||
var(--typebot-button-border-rgb),
|
||||
calc(var(--selectable-alpha-ratio) * 0.3)
|
||||
);
|
||||
}
|
||||
|
||||
.typebot-selectable.selected {
|
||||
background-color: rgba(
|
||||
var(--typebot-button-bg-color-rgb),
|
||||
calc(var(--selectable-base-alpha) + 0.18)
|
||||
var(--typebot-button-bg-rgb),
|
||||
calc(var(--selectable-alpha-ratio) * 0.18)
|
||||
);
|
||||
border-color: rgba(
|
||||
var(--typebot-button-bg-color-rgb),
|
||||
calc(var(--selectable-base-alpha) + 0.35)
|
||||
var(--typebot-button-border-rgb),
|
||||
calc(var(--selectable-alpha-ratio) * 0.35)
|
||||
);
|
||||
}
|
||||
|
||||
.typebot-checkbox {
|
||||
border: 1px solid var(--typebot-button-bg-color);
|
||||
border-radius: var(--typebot-border-radius);
|
||||
background-color: var(--typebot-checkbox-bg-color);
|
||||
border: 1px solid
|
||||
rgba(var(--typebot-button-bg-rgb), var(--typebot-button-opacity));
|
||||
border-radius: var(--typebot-button-border-radius);
|
||||
background-color: rgba(var(--typebot-checkbox-bg-rgb));
|
||||
color: var(--typebot-button-color);
|
||||
padding: 1px;
|
||||
border-radius: 2px;
|
||||
@ -229,7 +221,7 @@ pre {
|
||||
}
|
||||
|
||||
.typebot-checkbox.checked {
|
||||
background-color: var(--typebot-button-bg-color);
|
||||
background-color: rgb(var(--typebot-button-bg-rgb));
|
||||
}
|
||||
|
||||
.typebot-host-bubble {
|
||||
@ -237,22 +229,56 @@ pre {
|
||||
}
|
||||
|
||||
.typebot-host-bubble > .bubble-typing {
|
||||
background-color: var(--typebot-host-bubble-bg-color);
|
||||
border: var(--typebot-host-bubble-border);
|
||||
background-color: rgba(
|
||||
var(--typebot-host-bubble-bg-rgb),
|
||||
var(--typebot-host-bubble-opacity)
|
||||
);
|
||||
border-width: var(--typebot-host-bubble-border-width);
|
||||
border-color: rgba(
|
||||
var(--typebot-host-bubble-border-rgb),
|
||||
var(--typebot-host-bubble-border-opacity)
|
||||
);
|
||||
border-radius: var(--typebot-host-bubble-border-radius);
|
||||
box-shadow: var(--typebot-host-bubble-box-shadow);
|
||||
backdrop-filter: blur(var(--typebot-host-bubble-blur));
|
||||
}
|
||||
|
||||
.typebot-host-bubble img,
|
||||
.typebot-host-bubble video,
|
||||
.typebot-host-bubble iframe {
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
.typebot-guest-bubble {
|
||||
color: var(--typebot-guest-bubble-color);
|
||||
background-color: var(--typebot-guest-bubble-bg-color);
|
||||
border-radius: 6px;
|
||||
background-color: rgba(
|
||||
var(--typebot-guest-bubble-bg-rgb),
|
||||
var(--typebot-guest-bubble-opacity)
|
||||
);
|
||||
border-width: var(--typebot-guest-bubble-border-width);
|
||||
border-color: rgba(
|
||||
var(--typebot-guest-bubble-border-rgb),
|
||||
var(--typebot-guest-bubble-border-opacity)
|
||||
);
|
||||
border-radius: var(--typebot-guest-bubble-border-radius);
|
||||
box-shadow: var(--typebot-guest-bubble-box-shadow);
|
||||
backdrop-filter: blur(var(--typebot-guest-bubble-blur));
|
||||
}
|
||||
|
||||
.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);
|
||||
background-color: rgba(
|
||||
var(--typebot-input-bg-rgb),
|
||||
var(--typebot-input-opacity)
|
||||
);
|
||||
border-width: var(--typebot-input-border-width);
|
||||
border-color: rgba(
|
||||
var(--typebot-input-border-rgb),
|
||||
var(--typebot-input-border-opacity)
|
||||
);
|
||||
border-radius: var(--typebot-input-border-radius);
|
||||
box-shadow: var(--typebot-input-box-shadow);
|
||||
backdrop-filter: blur(var(--typebot-input-blur));
|
||||
}
|
||||
|
||||
.typebot-input-error-message {
|
||||
@ -263,24 +289,20 @@ pre {
|
||||
fill: var(--typebot-button-color);
|
||||
}
|
||||
|
||||
.typebot-chat-view {
|
||||
max-width: 900px;
|
||||
}
|
||||
|
||||
.ping span {
|
||||
background-color: var(--typebot-button-bg-color);
|
||||
background-color: rgb(var(--typebot-button-bg-rgb));
|
||||
}
|
||||
|
||||
.rating-icon-container svg {
|
||||
width: 42px;
|
||||
height: 42px;
|
||||
stroke: var(--typebot-button-bg-color);
|
||||
stroke: rgb(var(--typebot-button-bg-rgb));
|
||||
fill: var(--typebot-host-bubble-bg-color);
|
||||
transition: fill 100ms ease-out;
|
||||
}
|
||||
|
||||
.rating-icon-container.selected svg {
|
||||
fill: var(--typebot-button-bg-color);
|
||||
fill: rgb(var(--typebot-button-bg-rgb));
|
||||
}
|
||||
|
||||
.rating-icon-container:hover svg {
|
||||
@ -292,59 +314,60 @@ pre {
|
||||
}
|
||||
|
||||
.upload-progress-bar {
|
||||
background-color: var(--typebot-button-bg-color);
|
||||
border-radius: var(--typebot-border-radius);
|
||||
background-color: rgb(var(--typebot-button-bg-rgb));
|
||||
border-radius: var(--typebot-input-border-radius);
|
||||
}
|
||||
|
||||
.total-files-indicator {
|
||||
background-color: var(--typebot-button-bg-color);
|
||||
background-color: rgb(var(--typebot-button-bg-rgb));
|
||||
color: var(--typebot-button-color);
|
||||
font-size: 10px;
|
||||
}
|
||||
|
||||
.typebot-upload-input {
|
||||
transition: border-color 100ms ease-out;
|
||||
border-radius: var(--typebot-border-radius);
|
||||
border-radius: var(--typebot-input-border-radius);
|
||||
}
|
||||
|
||||
.typebot-upload-input.dragging-over {
|
||||
border-color: var(--typebot-button-bg-color);
|
||||
border-color: rgb(var(--typebot-button-bg-rgb));
|
||||
}
|
||||
|
||||
.secondary-button {
|
||||
background-color: var(--typebot-host-bubble-bg-color);
|
||||
color: var(--typebot-host-bubble-color);
|
||||
border-radius: var(--typebot-border-radius);
|
||||
border-radius: var(--typebot-button-border-radius);
|
||||
}
|
||||
|
||||
.typebot-country-select {
|
||||
color: var(--typebot-input-color);
|
||||
background-color: var(--typebot-input-bg-color);
|
||||
border-radius: var(--typebot-border-radius);
|
||||
border-radius: var(--typebot-button-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);
|
||||
border-radius: var(--typebot-input-border-radius);
|
||||
}
|
||||
|
||||
.typebot-popup-blocked-toast {
|
||||
border-radius: var(--typebot-border-radius);
|
||||
border-radius: var(--typebot-input-border-radius);
|
||||
}
|
||||
|
||||
.typebot-picture-button {
|
||||
color: var(--typebot-button-color);
|
||||
background-color: var(--typebot-button-bg-color);
|
||||
border-radius: var(--typebot-border-radius);
|
||||
background-color: rgb(var(--typebot-button-bg-rgb));
|
||||
border-radius: var(--typebot-button-border-radius);
|
||||
transition: all 0.3s ease;
|
||||
width: 236px;
|
||||
}
|
||||
|
||||
.typebot-picture-button > img,
|
||||
.typebot-selectable-picture > img {
|
||||
border-radius: var(--typebot-border-radius) var(--typebot-border-radius) 0 0;
|
||||
border-radius: var(--typebot-button-border-radius)
|
||||
var(--typebot-button-border-radius) 0 0;
|
||||
min-width: 200px;
|
||||
width: 100%;
|
||||
max-height: 200px;
|
||||
@ -362,14 +385,14 @@ pre {
|
||||
.typebot-selectable-picture {
|
||||
border: 1px solid
|
||||
rgba(
|
||||
var(--typebot-button-bg-color-rgb),
|
||||
calc(var(--selectable-base-alpha) + 0.25)
|
||||
var(--typebot-button-bg-rgb),
|
||||
calc(var(--selectable-alpha-ratio) * 0.25)
|
||||
);
|
||||
border-radius: var(--typebot-border-radius);
|
||||
color: var(--typebot-container-color);
|
||||
border-radius: var(--typebot-button-border-radius);
|
||||
color: rgb(var(--typebot-chat-container-color));
|
||||
background-color: rgba(
|
||||
var(--typebot-button-bg-color-rgb),
|
||||
calc(var(--selectable-base-alpha) + 0.08)
|
||||
var(--typebot-button-bg-rgb),
|
||||
calc(var(--selectable-alpha-ratio) * 0.08)
|
||||
);
|
||||
transition: all 0.3s ease;
|
||||
width: 236px;
|
||||
@ -377,23 +400,23 @@ pre {
|
||||
|
||||
.typebot-selectable-picture:hover {
|
||||
background-color: rgba(
|
||||
var(--typebot-button-bg-color-rgb),
|
||||
calc(var(--selectable-base-alpha) + 0.12)
|
||||
var(--typebot-button-bg-rgb),
|
||||
calc(var(--selectable-alpha-ratio) * 0.12)
|
||||
);
|
||||
border-color: rgba(
|
||||
var(--typebot-button-bg-color-rgb),
|
||||
calc(var(--selectable-base-alpha) + 0.3)
|
||||
var(--typebot-button-bg-rgb),
|
||||
calc(var(--selectable-alpha-ratio) * 0.3)
|
||||
);
|
||||
}
|
||||
|
||||
.typebot-selectable-picture.selected {
|
||||
background-color: rgba(
|
||||
var(--typebot-button-bg-color-rgb),
|
||||
calc(var(--selectable-base-alpha) + 0.18)
|
||||
var(--typebot-button-bg-rgb),
|
||||
calc(var(--selectable-alpha-ratio) * 0.18)
|
||||
);
|
||||
border-color: rgba(
|
||||
var(--typebot-button-bg-color-rgb),
|
||||
calc(var(--selectable-base-alpha) + 0.35)
|
||||
var(--typebot-button-bg-rgb),
|
||||
calc(var(--selectable-alpha-ratio) * 0.35)
|
||||
);
|
||||
}
|
||||
|
||||
@ -404,8 +427,8 @@ select option {
|
||||
|
||||
.typebot-progress-bar-container {
|
||||
background-color: rgba(
|
||||
var(--typebot-button-bg-color-rgb),
|
||||
calc(var(--selectable-base-alpha) + 0.12)
|
||||
var(--typebot-button-bg-rgb),
|
||||
calc(var(--selectable-alpha-ratio) * 0.12)
|
||||
);
|
||||
|
||||
height: var(--typebot-progress-bar-height);
|
||||
|
@ -16,7 +16,6 @@ import {
|
||||
import { setCssVariablesValue } from '@/utils/setCssVariablesValue'
|
||||
import immutableCss from '../assets/immutable.css'
|
||||
import { Font, InputBlock, StartFrom } from '@typebot.io/schemas'
|
||||
import { defaultTheme } from '@typebot.io/schemas/features/typebot/theme/constants'
|
||||
import { clsx } from 'clsx'
|
||||
import { HTTPError } from 'ky'
|
||||
import { injectFont } from '@/utils/injectFont'
|
||||
@ -25,6 +24,11 @@ import { Portal } from 'solid-js/web'
|
||||
import { defaultSettings } from '@typebot.io/schemas/features/typebot/settings/constants'
|
||||
import { persist } from '@/utils/persist'
|
||||
import { setBotContainerHeight } from '@/utils/botContainerHeightSignal'
|
||||
import {
|
||||
defaultFontFamily,
|
||||
defaultFontType,
|
||||
defaultProgressBarPosition,
|
||||
} from '@typebot.io/schemas/features/typebot/theme/constants'
|
||||
|
||||
export type BotProps = {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
@ -262,8 +266,10 @@ const BotContent = (props: BotContentProps) => {
|
||||
|
||||
createEffect(() => {
|
||||
injectFont(
|
||||
props.initialChatReply.typebot.theme.general?.font ??
|
||||
defaultTheme.general.font
|
||||
props.initialChatReply.typebot.theme.general?.font ?? {
|
||||
type: defaultFontType,
|
||||
family: defaultFontFamily,
|
||||
}
|
||||
)
|
||||
if (!botContainer) return
|
||||
setCssVariablesValue(
|
||||
@ -282,7 +288,7 @@ const BotContent = (props: BotContentProps) => {
|
||||
<div
|
||||
ref={botContainer}
|
||||
class={clsx(
|
||||
'relative flex w-full h-full text-base overflow-hidden bg-cover bg-center flex-col items-center typebot-container @container',
|
||||
'relative flex w-full h-full text-base overflow-hidden flex-col justify-center items-center typebot-container',
|
||||
props.class
|
||||
)}
|
||||
>
|
||||
@ -296,8 +302,7 @@ const BotContent = (props: BotContentProps) => {
|
||||
when={
|
||||
props.progressBarRef &&
|
||||
(props.initialChatReply.typebot.theme.general?.progressBar
|
||||
?.position ?? defaultTheme.general.progressBar.position) ===
|
||||
'fixed'
|
||||
?.position ?? defaultProgressBarPosition) === 'fixed'
|
||||
}
|
||||
fallback={<ProgressBar value={progressValue() as number} />}
|
||||
>
|
||||
@ -306,7 +311,7 @@ const BotContent = (props: BotContentProps) => {
|
||||
</Portal>
|
||||
</Show>
|
||||
</Show>
|
||||
<div class="flex w-full h-full justify-center">
|
||||
<div class="flex w-full h-full justify-center items-center">
|
||||
<ConversationContainer
|
||||
context={props.context}
|
||||
initialChatReply={props.initialChatReply}
|
||||
|
@ -6,8 +6,11 @@ import { HostBubble } from '../bubbles/HostBubble'
|
||||
import { InputChatBlock } from '../InputChatBlock'
|
||||
import { AvatarSideContainer } from './AvatarSideContainer'
|
||||
import { StreamingBubble } from '../bubbles/StreamingBubble'
|
||||
import { defaultTheme } from '@typebot.io/schemas/features/typebot/theme/constants'
|
||||
import { defaultSettings } from '@typebot.io/schemas/features/typebot/settings/constants'
|
||||
import {
|
||||
defaultGuestAvatarIsEnabled,
|
||||
defaultHostAvatarIsEnabled,
|
||||
} from '@typebot.io/schemas/features/typebot/theme/constants'
|
||||
|
||||
type Props = Pick<ContinueChatResponse, 'messages' | 'input'> & {
|
||||
theme: Theme
|
||||
@ -77,7 +80,7 @@ export const ChatChunk = (props: Props) => {
|
||||
<Show
|
||||
when={
|
||||
(props.theme.chat?.hostAvatar?.isEnabled ??
|
||||
defaultTheme.chat.hostAvatar.isEnabled) &&
|
||||
defaultHostAvatarIsEnabled) &&
|
||||
props.messages.length > 0
|
||||
}
|
||||
>
|
||||
@ -93,7 +96,7 @@ export const ChatChunk = (props: Props) => {
|
||||
style={{
|
||||
'max-width':
|
||||
props.theme.chat?.guestAvatar?.isEnabled ??
|
||||
defaultTheme.chat.guestAvatar.isEnabled
|
||||
defaultGuestAvatarIsEnabled
|
||||
? isMobile()
|
||||
? 'calc(100% - 32px - 32px)'
|
||||
: 'calc(100% - 48px - 48px)'
|
||||
@ -131,7 +134,7 @@ export const ChatChunk = (props: Props) => {
|
||||
chunkIndex={props.index}
|
||||
hasHostAvatar={
|
||||
props.theme.chat?.hostAvatar?.isEnabled ??
|
||||
defaultTheme.chat.hostAvatar.isEnabled
|
||||
defaultHostAvatarIsEnabled
|
||||
}
|
||||
guestAvatar={props.theme.chat?.guestAvatar}
|
||||
context={props.context}
|
||||
@ -151,7 +154,7 @@ export const ChatChunk = (props: Props) => {
|
||||
<Show
|
||||
when={
|
||||
props.theme.chat?.hostAvatar?.isEnabled ??
|
||||
defaultTheme.chat.hostAvatar.isEnabled
|
||||
defaultHostAvatarIsEnabled
|
||||
}
|
||||
>
|
||||
<AvatarSideContainer
|
||||
@ -165,7 +168,7 @@ export const ChatChunk = (props: Props) => {
|
||||
style={{
|
||||
'max-width':
|
||||
props.theme.chat?.hostAvatar?.isEnabled ??
|
||||
defaultTheme.chat.hostAvatar.isEnabled
|
||||
defaultHostAvatarIsEnabled
|
||||
? isMobile()
|
||||
? 'calc(100% - 32px - 32px)'
|
||||
: 'calc(100% - 48px - 48px)'
|
||||
|
@ -284,7 +284,7 @@ export const ConversationContainer = (props: Props) => {
|
||||
return (
|
||||
<div
|
||||
ref={chatContainer}
|
||||
class="flex flex-col overflow-y-auto w-full min-h-full px-3 pt-10 relative scrollable-container typebot-chat-view scroll-smooth gap-2"
|
||||
class="flex flex-col overflow-y-auto w-full px-3 pt-10 relative scrollable-container typebot-chat-view scroll-smooth gap-2"
|
||||
>
|
||||
<For each={chatChunks()}>
|
||||
{(chatChunk, index) => (
|
||||
|
@ -2,7 +2,7 @@ import { Theme } from '@typebot.io/schemas'
|
||||
import { Show } from 'solid-js'
|
||||
import { LoadingBubble } from '../bubbles/LoadingBubble'
|
||||
import { AvatarSideContainer } from './AvatarSideContainer'
|
||||
import { defaultTheme } from '@typebot.io/schemas/features/typebot/theme/constants'
|
||||
import { defaultHostAvatarIsEnabled } from '@typebot.io/schemas/features/typebot/theme/constants'
|
||||
|
||||
type Props = {
|
||||
theme: Theme
|
||||
@ -15,7 +15,7 @@ export const LoadingChunk = (props: Props) => (
|
||||
<Show
|
||||
when={
|
||||
props.theme.chat?.hostAvatar?.isEnabled ??
|
||||
defaultTheme.chat.hostAvatar.isEnabled
|
||||
defaultHostAvatarIsEnabled
|
||||
}
|
||||
>
|
||||
<AvatarSideContainer
|
||||
|
@ -35,8 +35,8 @@ import { MultiplePictureChoice } from '@/features/blocks/inputs/pictureChoice/Mu
|
||||
import { formattedMessages } from '@/utils/formattedMessagesSignal'
|
||||
import { InputBlockType } from '@typebot.io/schemas/features/blocks/inputs/constants'
|
||||
import { defaultPaymentInputOptions } from '@typebot.io/schemas/features/blocks/inputs/payment/constants'
|
||||
import { defaultTheme } from '@typebot.io/schemas/features/typebot/theme/constants'
|
||||
import { persist } from '@/utils/persist'
|
||||
import { defaultGuestAvatarIsEnabled } from '@typebot.io/schemas/features/typebot/theme/constants'
|
||||
|
||||
type Props = {
|
||||
ref: HTMLDivElement | undefined
|
||||
@ -82,8 +82,7 @@ export const InputChatBlock = (props: Props) => {
|
||||
<GuestBubble
|
||||
message={formattedMessage() ?? (answer() as string)}
|
||||
showAvatar={
|
||||
props.guestAvatar?.isEnabled ??
|
||||
defaultTheme.chat.guestAvatar.isEnabled
|
||||
props.guestAvatar?.isEnabled ?? defaultGuestAvatarIsEnabled
|
||||
}
|
||||
avatarSrc={props.guestAvatar?.url && props.guestAvatar.url}
|
||||
/>
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { SendButton } from '@/components/SendButton'
|
||||
import { InputSubmitContent } from '@/types'
|
||||
import type { RatingInputBlock } from '@typebot.io/schemas'
|
||||
import { createSignal, For, Match, Switch } from 'solid-js'
|
||||
import { createSignal, For, Match, Switch, Show } from 'solid-js'
|
||||
import { isDefined, isEmpty, isNotDefined } from '@typebot.io/lib'
|
||||
import { Button } from '@/components/Button'
|
||||
import { defaultRatingInputOptions } from '@typebot.io/schemas/features/blocks/inputs/rating/constants'
|
||||
@ -107,17 +107,24 @@ const RatingButton = (props: RatingButtonProps) => {
|
||||
'Numbers'
|
||||
}
|
||||
>
|
||||
<Button
|
||||
on:click={handleClick}
|
||||
class={
|
||||
props.isOneClickSubmitEnabled ||
|
||||
(isDefined(props.rating) && props.idx <= props.rating)
|
||||
? ''
|
||||
: 'selectable'
|
||||
}
|
||||
>
|
||||
{props.idx}
|
||||
</Button>
|
||||
<Show when={props.isOneClickSubmitEnabled}>
|
||||
<Button on:click={handleClick}>{props.idx}</Button>
|
||||
</Show>
|
||||
<Show when={!props.isOneClickSubmitEnabled}>
|
||||
<div
|
||||
role="checkbox"
|
||||
aria-checked={isDefined(props.rating) && props.idx <= props.rating}
|
||||
on:click={handleClick}
|
||||
class={
|
||||
'py-2 px-4 font-semibold focus:outline-none cursor-pointer select-none typebot-selectable' +
|
||||
(isDefined(props.rating) && props.idx <= props.rating
|
||||
? ' selected'
|
||||
: '')
|
||||
}
|
||||
>
|
||||
{props.idx}
|
||||
</div>
|
||||
</Show>
|
||||
</Match>
|
||||
<Match
|
||||
when={
|
||||
|
@ -6,6 +6,7 @@ import { isMobile } from '@/utils/isMobileSignal'
|
||||
import type { TextInputBlock } from '@typebot.io/schemas'
|
||||
import { createSignal, onCleanup, onMount } from 'solid-js'
|
||||
import { defaultTextInputOptions } from '@typebot.io/schemas/features/blocks/inputs/text/constants'
|
||||
import clsx from 'clsx'
|
||||
|
||||
type Props = {
|
||||
block: TextInputBlock
|
||||
@ -55,7 +56,10 @@ export const TextInput = (props: Props) => {
|
||||
|
||||
return (
|
||||
<div
|
||||
class={'flex items-end justify-between pr-2 typebot-input w-full'}
|
||||
class={clsx(
|
||||
'flex justify-between pr-2 typebot-input w-full',
|
||||
props.block.options?.isLong ? 'items-end' : 'items-center'
|
||||
)}
|
||||
data-testid="input"
|
||||
style={{
|
||||
'max-width': props.block.options?.isLong ? undefined : '350px',
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { isNotEmpty } from '@typebot.io/lib'
|
||||
import { Font } from '@typebot.io/schemas'
|
||||
import { defaultTheme } from '@typebot.io/schemas/features/typebot/theme/constants'
|
||||
import { defaultFontFamily } from '@typebot.io/schemas/features/typebot/theme/constants'
|
||||
|
||||
const googleFontCdnBaseUrl = 'https://fonts.bunny.net/css2'
|
||||
const elementId = 'typebot-font'
|
||||
@ -10,8 +10,7 @@ export const injectFont = (font: Font) => {
|
||||
|
||||
if (typeof font === 'string' || font.type === 'Google') {
|
||||
const fontFamily =
|
||||
(typeof font === 'string' ? font : font.family) ??
|
||||
defaultTheme.general.font.family
|
||||
(typeof font === 'string' ? font : font.family) ?? defaultFontFamily
|
||||
if (existingFont?.getAttribute('href')?.includes(fontFamily)) return
|
||||
existingFont?.remove()
|
||||
const fontElement = document.createElement('link')
|
||||
|
@ -1,24 +1,51 @@
|
||||
import {
|
||||
Background,
|
||||
ChatTheme,
|
||||
ContainerColors,
|
||||
ContainerBorderTheme,
|
||||
ContainerTheme,
|
||||
GeneralTheme,
|
||||
InputColors,
|
||||
InputTheme,
|
||||
Theme,
|
||||
} from '@typebot.io/schemas'
|
||||
import { isLight, hexToRgb } from '@typebot.io/lib/hexToRgb'
|
||||
import { isNotEmpty } from '@typebot.io/lib'
|
||||
import { isDefined, isEmpty } from '@typebot.io/lib'
|
||||
import {
|
||||
BackgroundType,
|
||||
defaultTheme,
|
||||
defaultBackgroundColor,
|
||||
defaultBackgroundType,
|
||||
defaultButtonsBackgroundColor,
|
||||
defaultButtonsColor,
|
||||
defaultButtonsBorderThickness,
|
||||
defaultContainerBackgroundColor,
|
||||
defaultContainerMaxHeight,
|
||||
defaultContainerMaxWidth,
|
||||
defaultDarkTextColor,
|
||||
defaultFontFamily,
|
||||
defaultGuestBubblesBackgroundColor,
|
||||
defaultGuestBubblesColor,
|
||||
defaultHostBubblesBackgroundColor,
|
||||
defaultHostBubblesColor,
|
||||
defaultInputsBackgroundColor,
|
||||
defaultInputsColor,
|
||||
defaultInputsPlaceholderColor,
|
||||
defaultLightTextColor,
|
||||
defaultProgressBarBackgroundColor,
|
||||
defaultProgressBarColor,
|
||||
defaultProgressBarPlacement,
|
||||
defaultProgressBarPosition,
|
||||
defaultProgressBarThickness,
|
||||
defaultInputsShadow,
|
||||
defaultOpacity,
|
||||
defaultBlur,
|
||||
defaultRoundness,
|
||||
} from '@typebot.io/schemas/features/typebot/theme/constants'
|
||||
import { isChatContainerLight } from '@typebot.io/theme/isChatContainerLight'
|
||||
|
||||
const cssVariableNames = {
|
||||
general: {
|
||||
bgImage: '--typebot-container-bg-image',
|
||||
bgColor: '--typebot-container-bg-color',
|
||||
fontFamily: '--typebot-container-font-family',
|
||||
color: '--typebot-container-color',
|
||||
progressBar: {
|
||||
position: '--typebot-progress-bar-position',
|
||||
color: '--typebot-progress-bar-color',
|
||||
@ -29,28 +56,67 @@ const cssVariableNames = {
|
||||
},
|
||||
},
|
||||
chat: {
|
||||
container: {
|
||||
maxWidth: '--typebot-chat-container-max-width',
|
||||
maxHeight: '--typebot-chat-container-max-height',
|
||||
bgColor: '--typebot-chat-container-bg-rgb',
|
||||
color: '--typebot-chat-container-color',
|
||||
borderRadius: '--typebot-chat-container-border-radius',
|
||||
borderWidth: '--typebot-chat-container-border-width',
|
||||
borderColor: '--typebot-chat-container-border-rgb',
|
||||
borderOpacity: '--typebot-chat-container-border-opacity',
|
||||
opacity: '--typebot-chat-container-opacity',
|
||||
blur: '--typebot-chat-container-blur',
|
||||
boxShadow: '--typebot-chat-container-box-shadow',
|
||||
},
|
||||
hostBubbles: {
|
||||
bgColor: '--typebot-host-bubble-bg-color',
|
||||
bgColor: '--typebot-host-bubble-bg-rgb',
|
||||
color: '--typebot-host-bubble-color',
|
||||
borderRadius: '--typebot-host-bubble-border-radius',
|
||||
borderWidth: '--typebot-host-bubble-border-width',
|
||||
borderColor: '--typebot-host-bubble-border-rgb',
|
||||
borderOpacity: '--typebot-host-bubble-border-opacity',
|
||||
opacity: '--typebot-host-bubble-opacity',
|
||||
blur: '--typebot-host-bubble-blur',
|
||||
boxShadow: '--typebot-host-bubble-box-shadow',
|
||||
},
|
||||
guestBubbles: {
|
||||
bgColor: '--typebot-guest-bubble-bg-color',
|
||||
bgColor: '--typebot-guest-bubble-bg-rgb',
|
||||
color: '--typebot-guest-bubble-color',
|
||||
borderRadius: '--typebot-guest-bubble-border-radius',
|
||||
borderWidth: '--typebot-guest-bubble-border-width',
|
||||
borderColor: '--typebot-guest-bubble-border-rgb',
|
||||
borderOpacity: '--typebot-guest-bubble-border-opacity',
|
||||
opacity: '--typebot-guest-bubble-opacity',
|
||||
blur: '--typebot-guest-bubble-blur',
|
||||
boxShadow: '--typebot-guest-bubble-box-shadow',
|
||||
},
|
||||
inputs: {
|
||||
bgColor: '--typebot-input-bg-color',
|
||||
bgColor: '--typebot-input-bg-rgb',
|
||||
color: '--typebot-input-color',
|
||||
placeholderColor: '--typebot-input-placeholder-color',
|
||||
borderRadius: '--typebot-input-border-radius',
|
||||
borderWidth: '--typebot-input-border-width',
|
||||
borderColor: '--typebot-input-border-rgb',
|
||||
borderOpacity: '--typebot-input-border-opacity',
|
||||
opacity: '--typebot-input-opacity',
|
||||
blur: '--typebot-input-blur',
|
||||
boxShadow: '--typebot-input-box-shadow',
|
||||
},
|
||||
buttons: {
|
||||
bgColor: '--typebot-button-bg-color',
|
||||
bgColorRgb: '--typebot-button-bg-color-rgb',
|
||||
bgRgb: '--typebot-button-bg-rgb',
|
||||
color: '--typebot-button-color',
|
||||
borderRadius: '--typebot-button-border-radius',
|
||||
borderWidth: '--typebot-button-border-width',
|
||||
borderColor: '--typebot-button-border-rgb',
|
||||
borderOpacity: '--typebot-button-border-opacity',
|
||||
opacity: '--typebot-button-opacity',
|
||||
blur: '--typebot-button-blur',
|
||||
boxShadow: '--typebot-button-box-shadow',
|
||||
},
|
||||
checkbox: {
|
||||
bgColor: '--typebot-checkbox-bg-color',
|
||||
color: '--typebot-checkbox-color',
|
||||
baseAlpha: '--selectable-base-alpha',
|
||||
bgRgb: '--typebot-checkbox-bg-rgb',
|
||||
alphaRatio: '--selectable-alpha-ratio',
|
||||
},
|
||||
},
|
||||
} as const
|
||||
@ -63,43 +129,31 @@ export const setCssVariablesValue = (
|
||||
if (!theme) return
|
||||
const documentStyle = container?.style
|
||||
if (!documentStyle) return
|
||||
setGeneralTheme(
|
||||
theme.general ?? defaultTheme.general,
|
||||
documentStyle,
|
||||
isPreview
|
||||
)
|
||||
setChatTheme(theme.chat ?? defaultTheme.chat, documentStyle)
|
||||
setGeneralTheme(theme.general, documentStyle, isPreview)
|
||||
setChatTheme(theme.chat, theme.general?.background, documentStyle)
|
||||
}
|
||||
|
||||
const setGeneralTheme = (
|
||||
generalTheme: GeneralTheme,
|
||||
generalTheme: GeneralTheme | undefined,
|
||||
documentStyle: CSSStyleDeclaration,
|
||||
isPreview?: boolean
|
||||
) => {
|
||||
setTypebotBackground(
|
||||
generalTheme.background ?? defaultTheme.general.background,
|
||||
documentStyle
|
||||
)
|
||||
setGeneralBackground(generalTheme?.background, documentStyle)
|
||||
documentStyle.setProperty(
|
||||
cssVariableNames.general.fontFamily,
|
||||
(typeof generalTheme.font === 'string'
|
||||
(typeof generalTheme?.font === 'string'
|
||||
? generalTheme.font
|
||||
: generalTheme.font?.family) ?? defaultTheme.general.font.family
|
||||
)
|
||||
setProgressBar(
|
||||
generalTheme.progressBar ?? defaultTheme.general.progressBar,
|
||||
documentStyle,
|
||||
isPreview
|
||||
: generalTheme?.font?.family) ?? defaultFontFamily
|
||||
)
|
||||
setProgressBar(generalTheme?.progressBar, documentStyle, isPreview)
|
||||
}
|
||||
|
||||
const setProgressBar = (
|
||||
progressBar: NonNullable<GeneralTheme['progressBar']>,
|
||||
progressBar: GeneralTheme['progressBar'],
|
||||
documentStyle: CSSStyleDeclaration,
|
||||
isPreview?: boolean
|
||||
) => {
|
||||
const position =
|
||||
progressBar.position ?? defaultTheme.general.progressBar.position
|
||||
const position = progressBar?.position ?? defaultProgressBarPosition
|
||||
|
||||
documentStyle.setProperty(
|
||||
cssVariableNames.general.progressBar.position,
|
||||
@ -107,22 +161,20 @@ const setProgressBar = (
|
||||
)
|
||||
documentStyle.setProperty(
|
||||
cssVariableNames.general.progressBar.color,
|
||||
progressBar.color ?? defaultTheme.general.progressBar.color
|
||||
progressBar?.color ?? defaultProgressBarColor
|
||||
)
|
||||
documentStyle.setProperty(
|
||||
cssVariableNames.general.progressBar.colorRgb,
|
||||
hexToRgb(
|
||||
progressBar.backgroundColor ??
|
||||
defaultTheme.general.progressBar.backgroundColor
|
||||
progressBar?.backgroundColor ?? defaultProgressBarBackgroundColor
|
||||
).join(', ')
|
||||
)
|
||||
documentStyle.setProperty(
|
||||
cssVariableNames.general.progressBar.height,
|
||||
`${progressBar.thickness ?? defaultTheme.general.progressBar.thickness}px`
|
||||
`${progressBar?.thickness ?? defaultProgressBarThickness}px`
|
||||
)
|
||||
|
||||
const placement =
|
||||
progressBar.placement ?? defaultTheme.general.progressBar.placement
|
||||
const placement = progressBar?.placement ?? defaultProgressBarPlacement
|
||||
|
||||
documentStyle.setProperty(
|
||||
cssVariableNames.general.progressBar.top,
|
||||
@ -136,123 +188,428 @@ const setProgressBar = (
|
||||
}
|
||||
|
||||
const setChatTheme = (
|
||||
chatTheme: ChatTheme,
|
||||
chatTheme: ChatTheme | undefined,
|
||||
generalBackground: GeneralTheme['background'],
|
||||
documentStyle: CSSStyleDeclaration
|
||||
) => {
|
||||
setHostBubbles(
|
||||
chatTheme.hostBubbles ?? defaultTheme.chat.hostBubbles,
|
||||
documentStyle
|
||||
setChatContainer(
|
||||
chatTheme?.container,
|
||||
generalBackground,
|
||||
documentStyle,
|
||||
chatTheme?.roundness
|
||||
)
|
||||
setGuestBubbles(
|
||||
chatTheme.guestBubbles ?? defaultTheme.chat.guestBubbles,
|
||||
documentStyle
|
||||
setHostBubbles(chatTheme?.hostBubbles, documentStyle, chatTheme?.roundness)
|
||||
setGuestBubbles(chatTheme?.guestBubbles, documentStyle, chatTheme?.roundness)
|
||||
setButtons(chatTheme?.buttons, documentStyle, chatTheme?.roundness)
|
||||
setInputs(chatTheme?.inputs, documentStyle, chatTheme?.roundness)
|
||||
setCheckbox(chatTheme?.container, generalBackground, documentStyle)
|
||||
}
|
||||
|
||||
const setChatContainer = (
|
||||
container: ChatTheme['container'],
|
||||
generalBackground: GeneralTheme['background'],
|
||||
documentStyle: CSSStyleDeclaration,
|
||||
legacyRoundness?: ChatTheme['roundness']
|
||||
) => {
|
||||
const chatContainerBgColor =
|
||||
container?.backgroundColor ?? defaultContainerBackgroundColor
|
||||
const isBgDisabled =
|
||||
chatContainerBgColor === 'transparent' || isEmpty(chatContainerBgColor)
|
||||
documentStyle.setProperty(
|
||||
cssVariableNames.chat.container.bgColor,
|
||||
isBgDisabled ? '0, 0, 0' : hexToRgb(chatContainerBgColor).join(', ')
|
||||
)
|
||||
setButtons(chatTheme.buttons ?? defaultTheme.chat.buttons, documentStyle)
|
||||
setInputs(chatTheme.inputs ?? defaultTheme.chat.inputs, documentStyle)
|
||||
setRoundness(
|
||||
chatTheme.roundness ?? defaultTheme.chat.roundness,
|
||||
documentStyle
|
||||
|
||||
documentStyle.setProperty(
|
||||
cssVariableNames.chat.container.color,
|
||||
hexToRgb(
|
||||
container?.color ??
|
||||
(isChatContainerLight({
|
||||
chatContainer: container,
|
||||
generalBackground,
|
||||
})
|
||||
? defaultLightTextColor
|
||||
: defaultDarkTextColor)
|
||||
).join(', ')
|
||||
)
|
||||
|
||||
documentStyle.setProperty(
|
||||
cssVariableNames.chat.container.maxWidth,
|
||||
container?.maxWidth ?? defaultContainerMaxWidth
|
||||
)
|
||||
documentStyle.setProperty(
|
||||
cssVariableNames.chat.container.maxHeight,
|
||||
container?.maxHeight ?? defaultContainerMaxHeight
|
||||
)
|
||||
const opacity = isBgDisabled
|
||||
? '1'
|
||||
: (container?.opacity ?? defaultOpacity).toString()
|
||||
documentStyle.setProperty(
|
||||
cssVariableNames.chat.container.opacity,
|
||||
isBgDisabled ? '0' : (container?.opacity ?? defaultOpacity).toString()
|
||||
)
|
||||
documentStyle.setProperty(
|
||||
cssVariableNames.chat.container.blur,
|
||||
opacity === '1' || isBgDisabled
|
||||
? '0xp'
|
||||
: `${container?.blur ?? defaultBlur}px`
|
||||
)
|
||||
setShadow(
|
||||
container?.shadow,
|
||||
documentStyle,
|
||||
cssVariableNames.chat.container.boxShadow
|
||||
)
|
||||
|
||||
setBorderRadius(
|
||||
container?.border ?? {
|
||||
roundeness: legacyRoundness ?? defaultRoundness,
|
||||
},
|
||||
documentStyle,
|
||||
cssVariableNames.chat.container.borderRadius
|
||||
)
|
||||
|
||||
documentStyle.setProperty(
|
||||
cssVariableNames.chat.container.borderWidth,
|
||||
isDefined(container?.border?.thickness)
|
||||
? `${container?.border?.thickness}px`
|
||||
: '0'
|
||||
)
|
||||
|
||||
documentStyle.setProperty(
|
||||
cssVariableNames.chat.container.borderOpacity,
|
||||
isDefined(container?.border?.opacity)
|
||||
? container.border.opacity.toString()
|
||||
: defaultOpacity.toString()
|
||||
)
|
||||
|
||||
documentStyle.setProperty(
|
||||
cssVariableNames.chat.container.borderColor,
|
||||
hexToRgb(container?.border?.color ?? '').join(', ')
|
||||
)
|
||||
}
|
||||
|
||||
const setHostBubbles = (
|
||||
hostBubbles: ContainerColors,
|
||||
documentStyle: CSSStyleDeclaration
|
||||
hostBubbles: ContainerTheme | undefined,
|
||||
documentStyle: CSSStyleDeclaration,
|
||||
legacyRoundness?: ChatTheme['roundness']
|
||||
) => {
|
||||
documentStyle.setProperty(
|
||||
cssVariableNames.chat.hostBubbles.bgColor,
|
||||
hostBubbles.backgroundColor ?? defaultTheme.chat.hostBubbles.backgroundColor
|
||||
hexToRgb(
|
||||
hostBubbles?.backgroundColor ?? defaultHostBubblesBackgroundColor
|
||||
).join(', ')
|
||||
)
|
||||
documentStyle.setProperty(
|
||||
cssVariableNames.chat.hostBubbles.color,
|
||||
hostBubbles.color ?? defaultTheme.chat.hostBubbles.color
|
||||
hostBubbles?.color ?? defaultHostBubblesColor
|
||||
)
|
||||
setBorderRadius(
|
||||
hostBubbles?.border ?? {
|
||||
roundeness: legacyRoundness ?? defaultRoundness,
|
||||
},
|
||||
documentStyle,
|
||||
cssVariableNames.chat.hostBubbles.borderRadius
|
||||
)
|
||||
|
||||
documentStyle.setProperty(
|
||||
cssVariableNames.chat.hostBubbles.borderWidth,
|
||||
isDefined(hostBubbles?.border?.thickness)
|
||||
? `${hostBubbles?.border?.thickness}px`
|
||||
: '0'
|
||||
)
|
||||
|
||||
documentStyle.setProperty(
|
||||
cssVariableNames.chat.hostBubbles.borderColor,
|
||||
hexToRgb(hostBubbles?.border?.color ?? '').join(', ')
|
||||
)
|
||||
|
||||
documentStyle.setProperty(
|
||||
cssVariableNames.chat.hostBubbles.opacity,
|
||||
isDefined(hostBubbles?.opacity)
|
||||
? hostBubbles.opacity.toString()
|
||||
: defaultOpacity.toString()
|
||||
)
|
||||
|
||||
documentStyle.setProperty(
|
||||
cssVariableNames.chat.hostBubbles.borderOpacity,
|
||||
isDefined(hostBubbles?.border?.opacity)
|
||||
? hostBubbles.border.opacity.toString()
|
||||
: defaultOpacity.toString()
|
||||
)
|
||||
|
||||
documentStyle.setProperty(
|
||||
cssVariableNames.chat.hostBubbles.blur,
|
||||
isDefined(hostBubbles?.blur)
|
||||
? `${hostBubbles.blur ?? 0}px`
|
||||
: defaultBlur.toString()
|
||||
)
|
||||
|
||||
setShadow(
|
||||
hostBubbles?.shadow,
|
||||
documentStyle,
|
||||
cssVariableNames.chat.hostBubbles.boxShadow
|
||||
)
|
||||
}
|
||||
|
||||
const setGuestBubbles = (
|
||||
guestBubbles: ContainerColors,
|
||||
documentStyle: CSSStyleDeclaration
|
||||
guestBubbles: ContainerTheme | undefined,
|
||||
documentStyle: CSSStyleDeclaration,
|
||||
legacyRoundness?: ChatTheme['roundness']
|
||||
) => {
|
||||
documentStyle.setProperty(
|
||||
cssVariableNames.chat.guestBubbles.bgColor,
|
||||
guestBubbles.backgroundColor ??
|
||||
defaultTheme.chat.guestBubbles.backgroundColor
|
||||
hexToRgb(
|
||||
guestBubbles?.backgroundColor ?? defaultGuestBubblesBackgroundColor
|
||||
).join(', ')
|
||||
)
|
||||
|
||||
documentStyle.setProperty(
|
||||
cssVariableNames.chat.guestBubbles.color,
|
||||
guestBubbles.color ?? defaultTheme.chat.guestBubbles.color
|
||||
guestBubbles?.color ?? defaultGuestBubblesColor
|
||||
)
|
||||
|
||||
setBorderRadius(
|
||||
guestBubbles?.border ?? {
|
||||
roundeness: legacyRoundness ?? defaultRoundness,
|
||||
},
|
||||
documentStyle,
|
||||
cssVariableNames.chat.guestBubbles.borderRadius
|
||||
)
|
||||
|
||||
documentStyle.setProperty(
|
||||
cssVariableNames.chat.guestBubbles.borderWidth,
|
||||
isDefined(guestBubbles?.border?.thickness)
|
||||
? `${guestBubbles?.border?.thickness}px`
|
||||
: '0'
|
||||
)
|
||||
|
||||
documentStyle.setProperty(
|
||||
cssVariableNames.chat.guestBubbles.borderColor,
|
||||
hexToRgb(guestBubbles?.border?.color ?? '').join(', ')
|
||||
)
|
||||
|
||||
documentStyle.setProperty(
|
||||
cssVariableNames.chat.guestBubbles.borderOpacity,
|
||||
isDefined(guestBubbles?.border?.opacity)
|
||||
? guestBubbles.border.opacity.toString()
|
||||
: defaultOpacity.toString()
|
||||
)
|
||||
|
||||
documentStyle.setProperty(
|
||||
cssVariableNames.chat.guestBubbles.opacity,
|
||||
isDefined(guestBubbles?.opacity)
|
||||
? guestBubbles.opacity.toString()
|
||||
: defaultOpacity.toString()
|
||||
)
|
||||
|
||||
documentStyle.setProperty(
|
||||
cssVariableNames.chat.guestBubbles.blur,
|
||||
isDefined(guestBubbles?.blur)
|
||||
? `${guestBubbles.blur ?? 0}px`
|
||||
: defaultBlur.toString()
|
||||
)
|
||||
|
||||
setShadow(
|
||||
guestBubbles?.shadow,
|
||||
documentStyle,
|
||||
cssVariableNames.chat.guestBubbles.boxShadow
|
||||
)
|
||||
}
|
||||
|
||||
const setButtons = (
|
||||
buttons: ContainerColors,
|
||||
documentStyle: CSSStyleDeclaration
|
||||
buttons: ContainerTheme | undefined,
|
||||
documentStyle: CSSStyleDeclaration,
|
||||
legacyRoundness?: ChatTheme['roundness']
|
||||
) => {
|
||||
const bgColor =
|
||||
buttons.backgroundColor ?? defaultTheme.chat.buttons.backgroundColor
|
||||
documentStyle.setProperty(cssVariableNames.chat.buttons.bgColor, bgColor)
|
||||
const bgColor = buttons?.backgroundColor ?? defaultButtonsBackgroundColor
|
||||
|
||||
documentStyle.setProperty(
|
||||
cssVariableNames.chat.buttons.bgColorRgb,
|
||||
cssVariableNames.chat.buttons.bgRgb,
|
||||
hexToRgb(bgColor).join(', ')
|
||||
)
|
||||
|
||||
documentStyle.setProperty(
|
||||
cssVariableNames.chat.buttons.bgRgb,
|
||||
hexToRgb(bgColor).join(', ')
|
||||
)
|
||||
|
||||
documentStyle.setProperty(
|
||||
cssVariableNames.chat.buttons.color,
|
||||
buttons.color ?? defaultTheme.chat.buttons.color
|
||||
buttons?.color ?? defaultButtonsColor
|
||||
)
|
||||
|
||||
setBorderRadius(
|
||||
buttons?.border ?? {
|
||||
roundeness: legacyRoundness ?? defaultRoundness,
|
||||
},
|
||||
documentStyle,
|
||||
cssVariableNames.chat.buttons.borderRadius
|
||||
)
|
||||
|
||||
documentStyle.setProperty(
|
||||
cssVariableNames.chat.buttons.borderWidth,
|
||||
isDefined(buttons?.border?.thickness)
|
||||
? `${buttons?.border?.thickness}px`
|
||||
: `${defaultButtonsBorderThickness}px`
|
||||
)
|
||||
|
||||
documentStyle.setProperty(
|
||||
cssVariableNames.chat.buttons.borderColor,
|
||||
hexToRgb(
|
||||
buttons?.border?.color ??
|
||||
buttons?.backgroundColor ??
|
||||
defaultButtonsBackgroundColor
|
||||
).join(', ')
|
||||
)
|
||||
|
||||
documentStyle.setProperty(
|
||||
cssVariableNames.chat.buttons.borderOpacity,
|
||||
isDefined(buttons?.border?.opacity)
|
||||
? buttons.border.opacity.toString()
|
||||
: defaultOpacity.toString()
|
||||
)
|
||||
|
||||
documentStyle.setProperty(
|
||||
cssVariableNames.chat.buttons.opacity,
|
||||
isDefined(buttons?.opacity)
|
||||
? buttons.opacity.toString()
|
||||
: defaultOpacity.toString()
|
||||
)
|
||||
|
||||
documentStyle.setProperty(
|
||||
cssVariableNames.chat.buttons.blur,
|
||||
isDefined(buttons?.blur) ? `${buttons.blur ?? 0}px` : defaultBlur.toString()
|
||||
)
|
||||
|
||||
setShadow(
|
||||
buttons?.shadow,
|
||||
documentStyle,
|
||||
cssVariableNames.chat.buttons.boxShadow
|
||||
)
|
||||
}
|
||||
|
||||
const setInputs = (inputs: InputColors, documentStyle: CSSStyleDeclaration) => {
|
||||
const setInputs = (
|
||||
inputs: InputTheme | undefined,
|
||||
documentStyle: CSSStyleDeclaration,
|
||||
legacyRoundness?: ChatTheme['roundness']
|
||||
) => {
|
||||
documentStyle.setProperty(
|
||||
cssVariableNames.chat.inputs.bgColor,
|
||||
inputs.backgroundColor ?? defaultTheme.chat.inputs.backgroundColor
|
||||
hexToRgb(inputs?.backgroundColor ?? defaultInputsBackgroundColor).join(', ')
|
||||
)
|
||||
|
||||
documentStyle.setProperty(
|
||||
cssVariableNames.chat.inputs.color,
|
||||
inputs.color ?? defaultTheme.chat.inputs.color
|
||||
inputs?.color ?? defaultInputsColor
|
||||
)
|
||||
|
||||
documentStyle.setProperty(
|
||||
cssVariableNames.chat.inputs.placeholderColor,
|
||||
inputs.placeholderColor ?? defaultTheme.chat.inputs.placeholderColor
|
||||
inputs?.placeholderColor ?? defaultInputsPlaceholderColor
|
||||
)
|
||||
|
||||
setBorderRadius(
|
||||
inputs?.border ?? {
|
||||
roundeness: legacyRoundness ?? defaultRoundness,
|
||||
},
|
||||
documentStyle,
|
||||
cssVariableNames.chat.inputs.borderRadius
|
||||
)
|
||||
|
||||
documentStyle.setProperty(
|
||||
cssVariableNames.chat.inputs.borderWidth,
|
||||
isDefined(inputs?.border?.thickness)
|
||||
? `${inputs?.border?.thickness}px`
|
||||
: '0'
|
||||
)
|
||||
|
||||
documentStyle.setProperty(
|
||||
cssVariableNames.chat.inputs.borderColor,
|
||||
hexToRgb(inputs?.border?.color ?? '').join(', ')
|
||||
)
|
||||
|
||||
documentStyle.setProperty(
|
||||
cssVariableNames.chat.inputs.opacity,
|
||||
isDefined(inputs?.opacity)
|
||||
? inputs.opacity.toString()
|
||||
: defaultOpacity.toString()
|
||||
)
|
||||
|
||||
documentStyle.setProperty(
|
||||
cssVariableNames.chat.inputs.blur,
|
||||
isDefined(inputs?.blur) ? `${inputs.blur ?? 0}px` : defaultBlur.toString()
|
||||
)
|
||||
|
||||
setShadow(
|
||||
inputs?.shadow ?? defaultInputsShadow,
|
||||
documentStyle,
|
||||
cssVariableNames.chat.inputs.boxShadow
|
||||
)
|
||||
}
|
||||
|
||||
const setTypebotBackground = (
|
||||
background: Background,
|
||||
const setCheckbox = (
|
||||
container: ChatTheme['container'],
|
||||
generalBackground: GeneralTheme['background'],
|
||||
documentStyle: CSSStyleDeclaration
|
||||
) => {
|
||||
const chatContainerBgColor =
|
||||
container?.backgroundColor ?? defaultContainerBackgroundColor
|
||||
const isChatBgTransparent =
|
||||
chatContainerBgColor === 'transparent' ||
|
||||
isEmpty(chatContainerBgColor) ||
|
||||
(container?.opacity ?? defaultOpacity) <= 0.2
|
||||
|
||||
if (isChatBgTransparent) {
|
||||
const bgType = generalBackground?.type ?? defaultBackgroundType
|
||||
documentStyle.setProperty(
|
||||
cssVariableNames.chat.checkbox.bgRgb,
|
||||
bgType === BackgroundType.IMAGE
|
||||
? 'rgba(255, 255, 255, 0.75)'
|
||||
: hexToRgb(
|
||||
(bgType === BackgroundType.COLOR
|
||||
? generalBackground?.content
|
||||
: '#ffffff') ?? '#ffffff'
|
||||
).join(', ')
|
||||
)
|
||||
if (bgType === BackgroundType.IMAGE) {
|
||||
documentStyle.setProperty(cssVariableNames.chat.checkbox.alphaRatio, '3')
|
||||
} else {
|
||||
documentStyle.setProperty(
|
||||
cssVariableNames.chat.checkbox.alphaRatio,
|
||||
generalBackground?.content && isLight(generalBackground?.content)
|
||||
? '1'
|
||||
: '2'
|
||||
)
|
||||
}
|
||||
} else {
|
||||
documentStyle.setProperty(
|
||||
cssVariableNames.chat.checkbox.bgRgb,
|
||||
hexToRgb(chatContainerBgColor)
|
||||
.concat(container?.opacity ?? 1)
|
||||
.join(', ')
|
||||
)
|
||||
documentStyle.setProperty(
|
||||
cssVariableNames.chat.checkbox.alphaRatio,
|
||||
isLight(chatContainerBgColor) ? '1' : '2'
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
const setGeneralBackground = (
|
||||
background: Background | undefined,
|
||||
documentStyle: CSSStyleDeclaration
|
||||
) => {
|
||||
documentStyle.setProperty(cssVariableNames.general.bgImage, null)
|
||||
documentStyle.setProperty(cssVariableNames.general.bgColor, null)
|
||||
documentStyle.setProperty(
|
||||
background?.type === BackgroundType.IMAGE
|
||||
(background?.type ?? defaultBackgroundType) === BackgroundType.IMAGE
|
||||
? cssVariableNames.general.bgImage
|
||||
: cssVariableNames.general.bgColor,
|
||||
parseBackgroundValue(background)
|
||||
parseBackgroundValue({
|
||||
type: background?.type ?? defaultBackgroundType,
|
||||
content: background?.content ?? defaultBackgroundColor,
|
||||
})
|
||||
)
|
||||
documentStyle.setProperty(
|
||||
cssVariableNames.chat.checkbox.bgColor,
|
||||
background?.type === BackgroundType.IMAGE
|
||||
? 'rgba(255, 255, 255, 0.75)'
|
||||
: (background?.type === BackgroundType.COLOR
|
||||
? background.content
|
||||
: '#ffffff') ?? '#ffffff'
|
||||
)
|
||||
const backgroundColor =
|
||||
background.type === BackgroundType.IMAGE
|
||||
? '#000000'
|
||||
: background?.type === BackgroundType.COLOR &&
|
||||
isNotEmpty(background.content)
|
||||
? background.content
|
||||
: '#ffffff'
|
||||
documentStyle.setProperty(
|
||||
cssVariableNames.general.color,
|
||||
isLight(backgroundColor) ? '#303235' : '#ffffff'
|
||||
)
|
||||
if (background.type === BackgroundType.IMAGE) {
|
||||
documentStyle.setProperty(cssVariableNames.chat.checkbox.baseAlpha, '0.40')
|
||||
} else {
|
||||
documentStyle.setProperty(cssVariableNames.chat.checkbox.baseAlpha, '0')
|
||||
}
|
||||
}
|
||||
|
||||
const parseBackgroundValue = ({ type, content }: Background = {}) => {
|
||||
@ -261,25 +618,80 @@ const parseBackgroundValue = ({ type, content }: Background = {}) => {
|
||||
return 'transparent'
|
||||
case undefined:
|
||||
case BackgroundType.COLOR:
|
||||
return content ?? defaultTheme.general.background.content
|
||||
return content ?? defaultBackgroundColor
|
||||
case BackgroundType.IMAGE:
|
||||
return `url(${content})`
|
||||
}
|
||||
}
|
||||
|
||||
const setRoundness = (
|
||||
roundness: NonNullable<ChatTheme['roundness']>,
|
||||
documentStyle: CSSStyleDeclaration
|
||||
const setBorderRadius = (
|
||||
border: ContainerBorderTheme,
|
||||
documentStyle: CSSStyleDeclaration,
|
||||
variableName: string
|
||||
) => {
|
||||
switch (roundness) {
|
||||
switch (border?.roundeness ?? defaultRoundness) {
|
||||
case 'none': {
|
||||
documentStyle.setProperty(variableName, '0')
|
||||
break
|
||||
}
|
||||
case 'medium': {
|
||||
documentStyle.setProperty(variableName, '6px')
|
||||
break
|
||||
}
|
||||
case 'large': {
|
||||
documentStyle.setProperty(variableName, '20px')
|
||||
break
|
||||
}
|
||||
case 'custom': {
|
||||
documentStyle.setProperty(
|
||||
variableName,
|
||||
`${border.customRoundeness ?? 6}px`
|
||||
)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Props taken from https://tailwindcss.com/docs/box-shadow
|
||||
const setShadow = (
|
||||
shadow: ContainerTheme['shadow'],
|
||||
documentStyle: CSSStyleDeclaration,
|
||||
variableName: string
|
||||
) => {
|
||||
if (shadow === undefined) {
|
||||
documentStyle.setProperty(variableName, '0 0 #0000')
|
||||
return
|
||||
}
|
||||
switch (shadow) {
|
||||
case 'none':
|
||||
documentStyle.setProperty('--typebot-border-radius', '0')
|
||||
documentStyle.setProperty(variableName, '0 0 #0000')
|
||||
break
|
||||
case 'medium':
|
||||
documentStyle.setProperty('--typebot-border-radius', '6px')
|
||||
case 'sm':
|
||||
documentStyle.setProperty(variableName, '0 1px 2px 0 rgb(0 0 0 / 0.05)')
|
||||
break
|
||||
case 'large':
|
||||
documentStyle.setProperty('--typebot-border-radius', '20px')
|
||||
case 'md':
|
||||
documentStyle.setProperty(
|
||||
variableName,
|
||||
'0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1)'
|
||||
)
|
||||
break
|
||||
case 'lg':
|
||||
documentStyle.setProperty(
|
||||
variableName,
|
||||
'0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1)'
|
||||
)
|
||||
break
|
||||
case 'xl':
|
||||
documentStyle.setProperty(
|
||||
variableName,
|
||||
'0 20px 25px -5px rgb(0 0 0 / 0.1), 0 8px 10px -6px rgb(0 0 0 / 0.1)'
|
||||
)
|
||||
break
|
||||
case '2xl':
|
||||
documentStyle.setProperty(
|
||||
variableName,
|
||||
'0 25px 50px -12px rgb(0 0 0 / 0.25)'
|
||||
)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@typebot.io/nextjs",
|
||||
"version": "0.2.64",
|
||||
"version": "0.2.65",
|
||||
"description": "Convenient library to display typebots on your Next.js website",
|
||||
"main": "dist/index.js",
|
||||
"types": "dist/index.d.ts",
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@typebot.io/react",
|
||||
"version": "0.2.64",
|
||||
"version": "0.2.65",
|
||||
"description": "Convenient library to display typebots on your React app",
|
||||
"main": "dist/index.js",
|
||||
"types": "dist/index.d.ts",
|
||||
|
Reference in New Issue
Block a user