diff --git a/apps/builder/components/board/graph/BlockNode/StepNode/SettingsPopoverContent/bodies/WebhookSettings/WebhookSettings.tsx b/apps/builder/components/board/graph/BlockNode/StepNode/SettingsPopoverContent/bodies/WebhookSettings/WebhookSettings.tsx
index 1e48f46731..506bddd6b5 100644
--- a/apps/builder/components/board/graph/BlockNode/StepNode/SettingsPopoverContent/bodies/WebhookSettings/WebhookSettings.tsx
+++ b/apps/builder/components/board/graph/BlockNode/StepNode/SettingsPopoverContent/bodies/WebhookSettings/WebhookSettings.tsx
@@ -159,6 +159,7 @@ export const WebhookSettings = ({
@@ -181,7 +182,9 @@ export const WebhookSettings = ({
- {testResponse && }
+ {testResponse && (
+
+ )}
{(testResponse || options?.responseVariableMapping) && (
diff --git a/apps/builder/components/shared/CodeEditor.tsx b/apps/builder/components/shared/CodeEditor.tsx
index 0145de8202..7d95292f2d 100644
--- a/apps/builder/components/shared/CodeEditor.tsx
+++ b/apps/builder/components/shared/CodeEditor.tsx
@@ -1,15 +1,18 @@
import { Box, BoxProps } from '@chakra-ui/react'
import { EditorState, EditorView, basicSetup } from '@codemirror/basic-setup'
import { json } from '@codemirror/lang-json'
+import { css } from '@codemirror/lang-css'
import { useEffect, useRef } from 'react'
type Props = {
value: string
+ lang: 'css' | 'json'
onChange?: (value: string) => void
isReadOnly?: boolean
}
export const CodeEditor = ({
value,
+ lang,
onChange,
isReadOnly = false,
...props
@@ -31,14 +34,15 @@ export const CodeEditor = ({
if (update.docChanged && onChange)
onChange(update.state.doc.toJSON().join(' '))
})
+ const extensions = [
+ updateListenerExtension,
+ basicSetup,
+ EditorState.readOnly.of(isReadOnly),
+ ]
+ extensions.push(lang === 'json' ? json() : css())
const editor = new EditorView({
state: EditorState.create({
- extensions: [
- updateListenerExtension,
- basicSetup,
- json(),
- EditorState.readOnly.of(isReadOnly),
- ],
+ extensions,
}),
parent: editorContainer.current,
})
diff --git a/apps/builder/components/theme/CustomCssSettings/CustomCssSettings.tsx b/apps/builder/components/theme/CustomCssSettings/CustomCssSettings.tsx
new file mode 100644
index 0000000000..f876fee781
--- /dev/null
+++ b/apps/builder/components/theme/CustomCssSettings/CustomCssSettings.tsx
@@ -0,0 +1,17 @@
+import { CodeEditor } from 'components/shared/CodeEditor'
+import React from 'react'
+
+type Props = {
+ customCss?: string
+ onCustomCssChange: (css: string) => void
+}
+
+export const CustomCssSettings = ({ customCss, onCustomCssChange }: Props) => {
+ return (
+
+ )
+}
diff --git a/apps/builder/components/theme/SideMenu.tsx b/apps/builder/components/theme/SideMenu.tsx
index 71e71cdcd1..8c4eee3f0c 100644
--- a/apps/builder/components/theme/SideMenu.tsx
+++ b/apps/builder/components/theme/SideMenu.tsx
@@ -8,12 +8,13 @@ import {
HStack,
Stack,
} from '@chakra-ui/react'
-import { ChatIcon, CodeIcon, LayoutIcon, PencilIcon } from 'assets/icons'
+import { ChatIcon, CodeIcon, PencilIcon } from 'assets/icons'
import { headerHeight } from 'components/shared/TypebotHeader'
import { useTypebot } from 'contexts/TypebotContext'
import { ChatTheme, GeneralTheme } from 'models'
import React from 'react'
import { ChatThemeSettings } from './ChatSettings'
+import { CustomCssSettings } from './CustomCssSettings/CustomCssSettings'
import { GeneralSettings } from './GeneralSettings'
export const SideMenu = () => {
@@ -25,6 +26,9 @@ export const SideMenu = () => {
const handleGeneralThemeChange = (general: GeneralTheme) =>
updateTypebot({ theme: { ...typebot?.theme, general } })
+ const handleCustomCssChange = (customCss: string) =>
+ updateTypebot({ theme: { ...typebot?.theme, customCss } })
+
return (
{
/>
-
-
-
-
- Layout
-
-
-
-
- Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do
- eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim
- ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut
- aliquip ex ea commodo consequat.
-
-
@@ -94,10 +83,10 @@ export const SideMenu = () => {
- Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do
- eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim
- ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut
- aliquip ex ea commodo consequat.
+
diff --git a/apps/builder/cypress/tests/theme/customCss.ts b/apps/builder/cypress/tests/theme/customCss.ts
new file mode 100644
index 0000000000..2fb1da2d4d
--- /dev/null
+++ b/apps/builder/cypress/tests/theme/customCss.ts
@@ -0,0 +1,26 @@
+import { getIframeBody } from 'cypress/support'
+
+describe('Custom CSS settings', () => {
+ beforeEach(() => {
+ cy.task('seed')
+ cy.signOut()
+ })
+
+ it('should reflect changes in real time', () => {
+ cy.loadTypebotFixtureInDatabase('typebots/theme/theme.json')
+ cy.signIn('test2@gmail.com')
+ cy.visit('/typebots/typebot4/theme')
+ cy.findByRole('button', { name: 'Custom CSS' }).click()
+
+ cy.findByTestId('code-editor').type(
+ '.typebot-button {background-color: green}',
+ {
+ parseSpecialCharSequences: false,
+ }
+ )
+ getIframeBody()
+ .findByTestId('button')
+ .should('have.css', 'background-color')
+ .should('eq', 'rgb(0, 128, 0)')
+ })
+})
diff --git a/apps/builder/package.json b/apps/builder/package.json
index 90a536f5ea..54d22bb582 100644
--- a/apps/builder/package.json
+++ b/apps/builder/package.json
@@ -13,6 +13,7 @@
"@chakra-ui/css-reset": "^1.1.1",
"@chakra-ui/react": "^1.7.4",
"@codemirror/basic-setup": "^0.19.1",
+ "@codemirror/lang-css": "^0.19.3",
"@codemirror/lang-json": "^0.19.1",
"@codemirror/text": "^0.19.6",
"@dnd-kit/core": "^4.0.3",
diff --git a/packages/bot-engine/src/components/TypebotViewer.tsx b/packages/bot-engine/src/components/TypebotViewer.tsx
index 33cf000416..1330c2ede3 100644
--- a/packages/bot-engine/src/components/TypebotViewer.tsx
+++ b/packages/bot-engine/src/components/TypebotViewer.tsx
@@ -48,6 +48,7 @@ export const TypebotViewer = ({
{phoneNumberInputStyle}
{phoneSyle}
{style}
+ {typebot.theme?.customCss}
}
style={{ width: '100%', height: '100%', border: 'none' }}
diff --git a/packages/models/src/typebot/theme.ts b/packages/models/src/typebot/theme.ts
index fb027497b5..93c6f25553 100644
--- a/packages/models/src/typebot/theme.ts
+++ b/packages/models/src/typebot/theme.ts
@@ -1,6 +1,7 @@
export type Theme = {
general?: GeneralTheme
chat?: ChatTheme
+ customCss?: string
}
export type GeneralTheme = {
diff --git a/yarn.lock b/yarn.lock
index e8a5e8f917..42aa11a5e4 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -811,7 +811,7 @@
"@codemirror/state" "^0.19.0"
"@codemirror/view" "^0.19.23"
-"@codemirror/highlight@^0.19.0":
+"@codemirror/highlight@^0.19.0", "@codemirror/highlight@^0.19.6":
version "0.19.7"
resolved "https://registry.yarnpkg.com/@codemirror/highlight/-/highlight-0.19.7.tgz#91a0c9994c759f5f153861e3aae74ff9e7c7c35b"
integrity sha512-3W32hBCY0pbbv/xidismw+RDMKuIag+fo4kZIbD7WoRj+Ttcaxjf+vP6RttRHXLaaqbWh031lTeON8kMlDhMYw==
@@ -831,6 +831,17 @@
"@codemirror/state" "^0.19.2"
"@codemirror/view" "^0.19.0"
+"@codemirror/lang-css@^0.19.3":
+ version "0.19.3"
+ resolved "https://registry.yarnpkg.com/@codemirror/lang-css/-/lang-css-0.19.3.tgz#7a17adf78c6fcdab4ad5ee4e360631c41e949e4a"
+ integrity sha512-tyCUJR42/UlfOPLb94/p7dN+IPsYSIzHbAHP2KQHANj0I+Orqp+IyIOS++M8TuCX4zkWh9dvi8s92yy/Tn8Ifg==
+ dependencies:
+ "@codemirror/autocomplete" "^0.19.0"
+ "@codemirror/highlight" "^0.19.6"
+ "@codemirror/language" "^0.19.0"
+ "@codemirror/state" "^0.19.0"
+ "@lezer/css" "^0.15.2"
+
"@codemirror/lang-json@^0.19.1":
version "0.19.1"
resolved "https://registry.yarnpkg.com/@codemirror/lang-json/-/lang-json-0.19.1.tgz#616588d1422529965243c10af6c44ad0b9134fb0"
@@ -1338,6 +1349,13 @@
resolved "https://registry.yarnpkg.com/@lezer/common/-/common-0.15.11.tgz#965b5067036305f12e8a3efc344076850be1d3a8"
integrity sha512-vv0nSdIaVCRcJ8rPuDdsrNVfBOYe/4Szr/LhF929XyDmBndLDuWiCCHooGlGlJfzELyO608AyDhVsuX/ZG36NA==
+"@lezer/css@^0.15.2":
+ version "0.15.2"
+ resolved "https://registry.yarnpkg.com/@lezer/css/-/css-0.15.2.tgz#e96995da67df90bb4b191aaa8a486349cca5d8e7"
+ integrity sha512-tnMOMZY0Zs6JQeVjqfmREYMV0GnmZR1NitndLWioZMD6mA7VQF/PPKPmJX1f+ZgVZQc5Am0df9mX3aiJnNJlKQ==
+ dependencies:
+ "@lezer/lr" "^0.15.0"
+
"@lezer/json@^0.15.0":
version "0.15.0"
resolved "https://registry.yarnpkg.com/@lezer/json/-/json-0.15.0.tgz#b96c1161eb8514e05f4eaaec95c68376e76e539f"