feat(theme): ✨ Add custom css settings
This commit is contained in:
@ -159,6 +159,7 @@ export const WebhookSettings = ({
|
||||
<AccordionPanel pb={4} as={Stack} spacing="6">
|
||||
<CodeEditor
|
||||
value={webhook?.body ?? ''}
|
||||
lang="json"
|
||||
onChange={handleBodyChange}
|
||||
/>
|
||||
</AccordionPanel>
|
||||
@ -181,7 +182,9 @@ export const WebhookSettings = ({
|
||||
<Button onClick={handleTestRequestClick} colorScheme="blue">
|
||||
Test the request
|
||||
</Button>
|
||||
{testResponse && <CodeEditor isReadOnly value={testResponse} />}
|
||||
{testResponse && (
|
||||
<CodeEditor isReadOnly lang="json" value={testResponse} />
|
||||
)}
|
||||
{(testResponse || options?.responseVariableMapping) && (
|
||||
<Accordion allowToggle allowMultiple>
|
||||
<AccordionItem>
|
||||
|
@ -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,
|
||||
})
|
||||
|
@ -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 (
|
||||
<CodeEditor
|
||||
value={customCss ?? ''}
|
||||
lang="css"
|
||||
onChange={onCustomCssChange}
|
||||
/>
|
||||
)
|
||||
}
|
@ -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 (
|
||||
<Stack
|
||||
flex="1"
|
||||
@ -55,21 +59,6 @@ export const SideMenu = () => {
|
||||
/>
|
||||
</AccordionPanel>
|
||||
</AccordionItem>
|
||||
<AccordionItem>
|
||||
<AccordionButton py={6}>
|
||||
<HStack flex="1" pl={2}>
|
||||
<LayoutIcon />
|
||||
<Heading fontSize="lg">Layout</Heading>
|
||||
</HStack>
|
||||
<AccordionIcon />
|
||||
</AccordionButton>
|
||||
<AccordionPanel pb={4}>
|
||||
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.
|
||||
</AccordionPanel>
|
||||
</AccordionItem>
|
||||
<AccordionItem>
|
||||
<AccordionButton py={6}>
|
||||
<HStack flex="1" pl={2}>
|
||||
@ -94,10 +83,10 @@ export const SideMenu = () => {
|
||||
<AccordionIcon />
|
||||
</AccordionButton>
|
||||
<AccordionPanel pb={4}>
|
||||
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.
|
||||
<CustomCssSettings
|
||||
customCss={typebot?.theme?.customCss}
|
||||
onCustomCssChange={handleCustomCssChange}
|
||||
/>
|
||||
</AccordionPanel>
|
||||
</AccordionItem>
|
||||
</Accordion>
|
||||
|
26
apps/builder/cypress/tests/theme/customCss.ts
Normal file
26
apps/builder/cypress/tests/theme/customCss.ts
Normal file
@ -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)')
|
||||
})
|
||||
})
|
@ -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",
|
||||
|
@ -48,6 +48,7 @@ export const TypebotViewer = ({
|
||||
{phoneNumberInputStyle}
|
||||
{phoneSyle}
|
||||
{style}
|
||||
{typebot.theme?.customCss}
|
||||
</style>
|
||||
}
|
||||
style={{ width: '100%', height: '100%', border: 'none' }}
|
||||
|
@ -1,6 +1,7 @@
|
||||
export type Theme = {
|
||||
general?: GeneralTheme
|
||||
chat?: ChatTheme
|
||||
customCss?: string
|
||||
}
|
||||
|
||||
export type GeneralTheme = {
|
||||
|
20
yarn.lock
20
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"
|
||||
|
Reference in New Issue
Block a user