2
0

docs(share): 📝 Add code blocks in embed instructions

This commit is contained in:
Baptiste Arnaud
2022-02-10 08:08:58 +01:00
parent c66827b606
commit 276f1c1e90
23 changed files with 1166 additions and 304 deletions

View File

@@ -0,0 +1,38 @@
import { FlexProps } from '@chakra-ui/layout'
import prettier from 'prettier/standalone'
import parserHtml from 'prettier/parser-html'
import { BubbleParams } from 'typebot-js'
import { parseInitBubbleCode, typebotJsHtml } from '../params'
import { useTypebot } from 'contexts/TypebotContext'
import { CodeEditor } from 'components/shared/CodeEditor'
type ChatEmbedCodeProps = {
withStarterVariables?: boolean
onCopied?: () => void
} & Pick<BubbleParams, 'button' | 'proactiveMessage'>
export const ChatEmbedCode = ({
proactiveMessage,
button,
}: ChatEmbedCodeProps & FlexProps) => {
const { typebot } = useTypebot()
const snippet = prettier.format(
createSnippet({
publishId: typebot?.publicId ?? '',
button,
proactiveMessage,
}),
{
parser: 'html',
plugins: [parserHtml],
}
)
return <CodeEditor value={snippet} lang="html" isReadOnly />
}
const createSnippet = (params: BubbleParams): string => {
const jsCode = parseInitBubbleCode(params)
return `${typebotJsHtml}
<script>${jsCode}</script>`
}

View File

@@ -0,0 +1,159 @@
import {
StackProps,
Stack,
Heading,
HStack,
Input,
Flex,
FormControl,
FormLabel,
NumberInput,
NumberInputField,
NumberInputStepper,
NumberIncrementStepper,
NumberDecrementStepper,
Switch,
Text,
Tag,
} from '@chakra-ui/react'
import { ColorPicker } from 'components/theme/GeneralSettings/ColorPicker'
import { useTypebot } from 'contexts/TypebotContext'
import { useState, useEffect } from 'react'
import { BubbleParams } from 'typebot-js'
type ChatEmbedSettingsProps = {
onUpdateSettings: (
windowSettings: Pick<BubbleParams, 'button' | 'proactiveMessage'>
) => void
}
export const ChatEmbedSettings = ({
onUpdateSettings,
...props
}: ChatEmbedSettingsProps & StackProps) => {
const { typebot } = useTypebot()
const [proactiveMessageChecked, setProactiveMessageChecked] = useState(false)
const [rememberProMessageChecked] = useState(true)
const [customIconInputValue, setCustomIconInputValue] = useState('')
const [inputValues, setInputValues] = useState({
messageDelay: '0',
messageContent: 'I have a question for you!',
})
const [bubbleColor, setBubbleColor] = useState(
typebot?.theme.chat.buttons.backgroundColor ?? '#0042DA'
)
useEffect(() => {
if (proactiveMessageChecked) {
onUpdateSettings({
button: {
color: bubbleColor,
iconUrl: customIconInputValue,
},
proactiveMessage: {
delay: parseInt(inputValues.messageDelay) * 1000,
textContent: inputValues.messageContent,
rememberClose: rememberProMessageChecked,
},
})
} else {
onUpdateSettings({
button: {
color: bubbleColor,
iconUrl: customIconInputValue,
},
proactiveMessage: undefined,
})
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [
inputValues,
bubbleColor,
rememberProMessageChecked,
customIconInputValue,
proactiveMessageChecked,
])
return (
<Stack {...props}>
<Heading fontSize="md" fontWeight="semibold">
Chat bubble settings
</Heading>
<Flex justify="space-between" align="center" mb="4">
<Text>Button color</Text>
<ColorPicker
initialColor={bubbleColor}
onColorChange={setBubbleColor}
/>
</Flex>
<HStack>
<Text flexShrink={0}>
Custom button icon <Tag>Optional</Tag>
</Text>
<Input
placeholder={'Paste image link (.png, .svg)'}
value={customIconInputValue}
onChange={(e) => setCustomIconInputValue(e.target.value)}
/>
</HStack>
<Flex alignItems="center">
<FormControl
display="flex"
alignItems="center"
w="full"
justifyContent="space-between"
pr={1}
>
<FormLabel htmlFor="fullscreen-option" mb="1">
Enable popup message?
</FormLabel>
<Switch
id="fullscreen-option"
onChange={() =>
setProactiveMessageChecked(!proactiveMessageChecked)
}
isChecked={proactiveMessageChecked}
/>
</FormControl>
</Flex>
{proactiveMessageChecked && (
<>
<Flex justify="space-between" align="center" pl="4" mb="2">
<Text>Appearance delay</Text>
<NumberInput
onChange={(messageDelay) =>
setInputValues({
...inputValues,
messageDelay,
})
}
value={inputValues.messageDelay}
min={0}
>
<NumberInputField />
<NumberInputStepper>
<NumberIncrementStepper />
<NumberDecrementStepper />
</NumberInputStepper>
</NumberInput>
</Flex>
<Flex justify="space-between" align="center" pl="4" mb="2">
<Text>Message content</Text>
<Input
type="text"
onChange={(e) =>
setInputValues({
...inputValues,
messageContent: e.target.value,
})
}
value={inputValues.messageContent}
/>
</Flex>
</>
)}
</Stack>
)
}

View File

@@ -0,0 +1,56 @@
import { FlexProps } from '@chakra-ui/react'
import parserHtml from 'prettier/parser-html'
import prettier from 'prettier/standalone'
import { parseInitContainerCode, typebotJsHtml } from '../params'
import { IframeParams } from 'typebot-js'
import { useTypebot } from 'contexts/TypebotContext'
import { CodeEditor } from 'components/shared/CodeEditor'
type ContainerEmbedCodeProps = {
widthLabel: string
heightLabel: string
withStarterVariables?: boolean
onCopied?: () => void
}
export const ContainerEmbedCode = ({
widthLabel,
heightLabel,
}: ContainerEmbedCodeProps & FlexProps) => {
const { typebot } = useTypebot()
const snippet = prettier.format(
parseSnippet({
publishId: typebot?.publicId ?? '',
heightLabel,
widthLabel,
}),
{
parser: 'html',
plugins: [parserHtml],
}
)
return <CodeEditor value={snippet} lang="html" isReadOnly />
}
type SnippetProps = IframeParams &
Pick<ContainerEmbedCodeProps, 'widthLabel' | 'heightLabel'>
const parseSnippet = ({
publishId,
customDomain,
backgroundColor,
hiddenVariables,
...embedProps
}: SnippetProps): string => {
const jsCode = parseInitContainerCode({
customDomain,
hiddenVariables,
backgroundColor,
publishId,
})
return `${typebotJsHtml}
<div id="typebot-container" style="width: ${embedProps.widthLabel}; height: ${embedProps.heightLabel};"></div>
<script>${jsCode}</script>`
}

View File

@@ -0,0 +1,120 @@
import {
StackProps,
Stack,
Flex,
Heading,
FormControl,
FormLabel,
Switch,
Input,
HStack,
Text,
} from '@chakra-ui/react'
import { DropdownList } from 'components/shared/DropdownList'
import { useState, useEffect } from 'react'
type StandardEmbedWindowSettingsProps = {
onUpdateWindowSettings: (windowSettings: {
heightLabel: string
widthLabel: string
}) => void
}
export const StandardEmbedWindowSettings = ({
onUpdateWindowSettings,
...props
}: StandardEmbedWindowSettingsProps & StackProps) => {
const [fullscreen, setFullscreen] = useState(false)
const [inputValues, setInputValues] = useState({
widthValue: '100',
widthType: '%',
heightValue: '600',
heightType: 'px',
})
useEffect(() => {
onUpdateWindowSettings({
widthLabel: fullscreen
? '100%'
: inputValues.widthValue + inputValues.widthType,
heightLabel: fullscreen
? '100vh'
: inputValues.heightValue + inputValues.heightType,
})
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [inputValues, fullscreen])
const handleWidthTypeSelect = (widthType: string) =>
setInputValues({ ...inputValues, widthType })
const handleHeightTypeSelect = (heightType: string) =>
setInputValues({ ...inputValues, heightType })
return (
<Stack {...props}>
<Flex alignItems="center" justifyContent="space-between">
<Heading fontSize="md" fontWeight="semibold" style={{ flexShrink: 0 }}>
Window settings
</Heading>
<FormControl
display="flex"
alignItems="center"
w="full"
justifyContent="flex-end"
>
<FormLabel htmlFor="fullscreen-option" mb="1">
Set to fullscreen?
</FormLabel>
<Switch
id="fullscreen-option"
onChange={() => setFullscreen(!fullscreen)}
isChecked={fullscreen}
/>
</FormControl>
</Flex>
{!fullscreen && (
<>
<Flex justify="space-between" align="center" mb="2">
<Text>Width</Text>
<HStack>
<Input
onChange={(e) =>
setInputValues({
...inputValues,
widthValue: e.target.value,
})
}
w="70px"
value={inputValues.widthValue}
/>
<DropdownList<string>
items={['px', '%']}
onItemSelect={handleWidthTypeSelect}
currentItem={inputValues.widthType}
/>
</HStack>
</Flex>
<Flex justify="space-between" align="center" mb="2">
<Text>Height</Text>
<HStack>
<Input
onChange={(e) =>
setInputValues({
...inputValues,
heightValue: e.target.value,
})
}
w="70px"
value={inputValues.heightValue}
/>
<DropdownList<string>
items={['px', '%']}
onItemSelect={handleHeightTypeSelect}
currentItem={inputValues.heightType}
/>
</HStack>
</Flex>
</>
)}
</Stack>
)
}

View File

@@ -0,0 +1,19 @@
import { FlexProps } from '@chakra-ui/react'
import { CodeEditor } from 'components/shared/CodeEditor'
import { useTypebot } from 'contexts/TypebotContext'
type Props = {
widthLabel: string
heightLabel: string
onCopied?: () => void
}
export const IframeEmbedCode = ({
widthLabel,
heightLabel,
}: Props & FlexProps) => {
const { typebot } = useTypebot()
const src = `https://${typebot?.publicId}.typebot.io`
const code = `<iframe src="${src}" width="${widthLabel}" height="${heightLabel}" />`
return <CodeEditor value={code} lang="html" isReadOnly />
}

View File

@@ -0,0 +1,34 @@
import { FlexProps } from '@chakra-ui/layout'
import { CodeEditor } from 'components/shared/CodeEditor'
import { useTypebot } from 'contexts/TypebotContext'
import parserHtml from 'prettier/parser-html'
import prettier from 'prettier/standalone'
import { PopupParams } from 'typebot-js'
import { parseInitPopupCode, typebotJsHtml } from '../params'
type PopupEmbedCodeProps = {
delay: number
withStarterVariables?: boolean
onCopied?: () => void
}
export const PopupEmbedCode = ({ delay }: PopupEmbedCodeProps & FlexProps) => {
const { typebot } = useTypebot()
const snippet = prettier.format(
createSnippet({
publishId: typebot?.publicId ?? '',
delay,
}),
{
parser: 'html',
plugins: [parserHtml],
}
)
return <CodeEditor value={snippet} lang="html" isReadOnly />
}
const createSnippet = (params: PopupParams): string => {
const jsCode = parseInitPopupCode(params)
return `${typebotJsHtml}
<script>${jsCode}</script>`
}

View File

@@ -0,0 +1,55 @@
import {
StackProps,
Stack,
Flex,
Heading,
NumberInput,
NumberInputField,
NumberInputStepper,
NumberIncrementStepper,
NumberDecrementStepper,
} from '@chakra-ui/react'
import { useState, useEffect } from 'react'
import { PopupParams } from 'typebot-js'
type PopupEmbedSettingsProps = {
onUpdateSettings: (windowSettings: Pick<PopupParams, 'delay'>) => void
}
export const PopupEmbedSettings = ({
onUpdateSettings,
...props
}: PopupEmbedSettingsProps & StackProps) => {
const [inputValue, setInputValue] = useState(0)
useEffect(() => {
onUpdateSettings({
delay: inputValue * 1000,
})
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [inputValue])
return (
<Stack {...props}>
<Flex alignItems="center" justifyContent="space-between">
<Heading fontSize="md" fontWeight="semibold">
Popup settings
</Heading>
</Flex>
<Flex justify="space-between" align="center" mb="2">
<p>Appearance delay</p>
<NumberInput
onChange={(_, val) => setInputValue(val)}
value={inputValue}
min={0}
>
<NumberInputField />
<NumberInputStepper>
<NumberIncrementStepper />
<NumberDecrementStepper />
</NumberInputStepper>
</NumberInput>
</Flex>
</Stack>
)
}

View File

@@ -0,0 +1,154 @@
import { FlexProps } from '@chakra-ui/react'
import React from 'react'
import { BubbleParams, IframeParams, PopupParams } from 'typebot-js'
import {
parseInitBubbleCode,
parseInitContainerCode,
parseInitPopupCode,
} from './params'
import parserBabel from 'prettier/parser-babel'
import prettier from 'prettier/standalone'
import { CodeEditor } from 'components/shared/CodeEditor'
import { useTypebot } from 'contexts/TypebotContext'
type StandardReactDivProps = { widthLabel: string; heightLabel: string }
export const StandardReactDiv = ({
widthLabel,
heightLabel,
}: StandardReactDivProps) => {
const { typebot } = useTypebot()
const snippet = prettier.format(
parseContainerSnippet({
publishId: typebot?.publicId ?? '',
heightLabel,
widthLabel,
}),
{
parser: 'babel',
plugins: [parserBabel],
}
)
return <CodeEditor value={snippet} lang="js" isReadOnly />
}
type SnippetProps = IframeParams &
Pick<StandardReactDivProps, 'widthLabel' | 'heightLabel'>
const parseContainerSnippet = ({
publishId,
customDomain,
backgroundColor,
hiddenVariables,
...embedProps
}: SnippetProps): string => {
const jsCode = parseInitContainerCode({
publishId,
customDomain,
backgroundColor,
hiddenVariables,
})
return `import {initContainer} from "typebot-js";
const Component = () => {
useEffect(()=> {
${jsCode}
}, [])
return <div id="typebot-container" style={{width: "${embedProps.widthLabel}", height: "${embedProps.heightLabel}"}} />
}`
}
type PopupEmbedCodeProps = {
delay: number
withStarterVariables?: boolean
}
export const PopupReactCode = ({ delay }: PopupEmbedCodeProps & FlexProps) => {
const { typebot } = useTypebot()
const snippet = prettier.format(
parsePopupSnippet({
publishId: typebot?.publicId ?? '',
delay,
}),
{
parser: 'babel',
plugins: [parserBabel],
}
)
return <CodeEditor value={snippet} lang="js" isReadOnly />
}
const parsePopupSnippet = ({
publishId,
customDomain,
backgroundColor,
hiddenVariables,
delay,
}: PopupParams): string => {
const jsCode = parseInitPopupCode({
publishId,
customDomain,
backgroundColor,
hiddenVariables,
delay,
})
return `import {initPopup} from "typebot-js";
const Component = () => {
useEffect(()=> {
${jsCode}
}, [])
return <></>;
}`
}
type ChatEmbedCodeProps = {
withStarterVariables?: boolean
} & Pick<BubbleParams, 'button' | 'proactiveMessage'>
export const ChatReactCode = ({
proactiveMessage,
button,
}: ChatEmbedCodeProps & FlexProps) => {
const { typebot } = useTypebot()
const snippet = prettier.format(
parseBubbleSnippet({
publishId: typebot?.publicId ?? '',
button,
proactiveMessage,
}),
{
parser: 'babel',
plugins: [parserBabel],
}
)
return <CodeEditor value={snippet} lang="js" isReadOnly />
}
const parseBubbleSnippet = ({
publishId,
customDomain,
backgroundColor,
hiddenVariables,
proactiveMessage,
button,
}: BubbleParams): string => {
const jsCode = parseInitBubbleCode({
publishId,
customDomain,
backgroundColor,
hiddenVariables,
proactiveMessage,
button,
})
return `import {initBubble} from "typebot-js";
const Component = () => {
useEffect(()=> {
${jsCode}
}, [])
return <></>
}`
}

View File

@@ -0,0 +1,142 @@
import {
BubbleParams,
ButtonParams,
IframeParams,
PopupParams,
ProactiveMessageParams,
} from 'typebot-js'
import parserBabel from 'prettier/parser-babel'
import prettier from 'prettier/standalone'
const parseStringParam = (fieldName: string, fieldValue?: string) =>
fieldValue ? `${fieldName}: "${fieldValue}",` : ``
const parseNonStringParam = (
fieldName: string,
fieldValue?: number | boolean
) => (fieldValue ? `${fieldName}: ${fieldValue},` : ``)
const parseCustomDomain = (domain?: string): string =>
parseStringParam('customDomain', domain)
const parseHiddenVariables = (
variables: { [key: string]: string | undefined } | undefined
): string => (variables ? `hiddenVariables: ${JSON.stringify(variables)},` : ``)
const parseBackgroundColor = (bgColor?: string): string =>
parseStringParam('backgroundColor', bgColor)
const parseDelay = (delay?: number) => parseNonStringParam('delay', delay)
const parseButton = (button?: ButtonParams): string => {
if (!button) return ''
const iconUrlString = parseStringParam('iconUrl', button.iconUrl)
const buttonColorstring = parseStringParam('color', button.color)
return `button: {${iconUrlString}${buttonColorstring}},`
}
const parseProactiveMessage = (
proactiveMessage?: ProactiveMessageParams
): string => {
if (!proactiveMessage) return ``
const { avatarUrl, textContent, delay, rememberClose } = proactiveMessage
const avatarUrlString = parseStringParam('avatarUrl', avatarUrl)
const textContentString = parseStringParam('textContent', textContent)
const rememberCloseString = parseNonStringParam(
'rememberClose',
rememberClose
)
const delayString = parseNonStringParam('delay', delay)
return `proactiveMessage: {${avatarUrlString}${textContentString}${rememberCloseString}${delayString}},`
}
const parseIframeParams = ({
customDomain,
hiddenVariables,
backgroundColor,
}: Pick<
IframeParams,
'customDomain' | 'hiddenVariables' | 'backgroundColor'
>) => ({
customDomainString: parseCustomDomain(customDomain),
hiddenVariablesString: parseHiddenVariables(hiddenVariables),
bgColorString: parseBackgroundColor(backgroundColor),
})
const parsePopupParams = ({ delay }: Pick<PopupParams, 'delay'>) => ({
delayString: parseDelay(delay),
})
const parseBubbleParams = ({
button,
proactiveMessage,
}: Pick<BubbleParams, 'button' | 'proactiveMessage'>) => ({
proactiveMessageString: parseProactiveMessage(proactiveMessage),
buttonString: parseButton(button),
})
export const parseInitContainerCode = ({
publishId,
customDomain,
backgroundColor,
hiddenVariables,
}: IframeParams) => {
const { customDomainString, hiddenVariablesString, bgColorString } =
parseIframeParams({
customDomain,
hiddenVariables,
backgroundColor,
})
return prettier.format(
`Typebot.initContainer("typebot-container", {
publishId: "${publishId}",${bgColorString}${customDomainString}${hiddenVariablesString}
});`,
{ parser: 'babel', plugins: [parserBabel] }
)
}
export const parseInitPopupCode = ({
publishId,
customDomain,
hiddenVariables,
backgroundColor,
delay,
}: PopupParams) => {
const { customDomainString, hiddenVariablesString, bgColorString } =
parseIframeParams({
customDomain,
hiddenVariables,
backgroundColor,
})
const { delayString } = parsePopupParams({ delay })
return prettier.format(
`var typebotCommands = Typebot.initPopup({publishId: "${publishId}",${delayString}${bgColorString}${customDomainString}${hiddenVariablesString}});`,
{ parser: 'babel', plugins: [parserBabel] }
)
}
export const parseInitBubbleCode = ({
publishId,
customDomain,
hiddenVariables,
backgroundColor,
button,
proactiveMessage,
}: BubbleParams) => {
const { customDomainString, hiddenVariablesString, bgColorString } =
parseIframeParams({
customDomain,
hiddenVariables,
backgroundColor,
})
const { buttonString, proactiveMessageString } = parseBubbleParams({
button,
proactiveMessage,
})
return prettier.format(
`var typebotCommands = Typebot.initBubble({publishId: "${publishId}",${bgColorString}${customDomainString}${hiddenVariablesString}${proactiveMessageString}${buttonString}});`,
{ parser: 'babel', plugins: [parserBabel] }
)
}
export const typebotJsHtml = `<script src="https://unpkg.com/typebot-js@2.0.20"></script>`

View File

@@ -21,6 +21,7 @@ import {
ReactModal, ReactModal,
NotionModal, NotionModal,
IframeModal, IframeModal,
WixModal,
} from './modals' } from './modals'
export type ModalProps = { export type ModalProps = {
@@ -82,7 +83,7 @@ export const integrationsList = [
<EmbedButton <EmbedButton
logo={<WixLogo height={100} width="90px" />} logo={<WixLogo height={100} width="90px" />}
label="Wix" label="Wix"
Modal={WebflowModal} Modal={WixModal}
{...props} {...props}
/> />
), ),
@@ -128,7 +129,7 @@ export const integrationsList = [
), ),
(props: Pick<ModalProps, 'publicId' | 'isPublished'>) => ( (props: Pick<ModalProps, 'publicId' | 'isPublished'>) => (
<EmbedButton <EmbedButton
logo={<IframeLogo height={100} width={80} />} logo={<IframeLogo height={100} width="70px" />}
label="Iframe" label="Iframe"
Modal={IframeModal} Modal={IframeModal}
{...props} {...props}
@@ -136,7 +137,7 @@ export const integrationsList = [
), ),
(props: Pick<ModalProps, 'publicId' | 'isPublished'>) => ( (props: Pick<ModalProps, 'publicId' | 'isPublished'>) => (
<EmbedButton <EmbedButton
logo={<OtherLogo height={100} width={80} />} logo={<OtherLogo height={100} width="70px" />}
label="Other" label="Other"
Modal={JavascriptModal} Modal={JavascriptModal}
{...props} {...props}

View File

@@ -1,14 +1,27 @@
import { OrderedList, ListItem, Tag } from '@chakra-ui/react' import { OrderedList, ListItem, Tag } from '@chakra-ui/react'
import { ChatEmbedCode } from 'components/share/codeSnippets/Chat/EmbedCode'
import { ChatEmbedSettings } from 'components/share/codeSnippets/Chat/EmbedSettings'
import { StandardEmbedWindowSettings } from 'components/share/codeSnippets/Container/EmbedSettings'
import {
parseInitContainerCode,
typebotJsHtml,
} from 'components/share/codeSnippets/params'
import { PopupEmbedCode } from 'components/share/codeSnippets/Popup/EmbedCode'
import { PopupEmbedSettings } from 'components/share/codeSnippets/Popup/EmbedSettings'
import { CodeEditor } from 'components/shared/CodeEditor'
import { useState } from 'react' import { useState } from 'react'
import { BubbleParams } from 'typebot-js'
import { ModalProps } from '../../EmbedButton'
type GtmInstructionsProps = { type GtmInstructionsProps = {
type: 'standard' | 'popup' | 'bubble' type: 'standard' | 'popup' | 'bubble'
publicId: string
} }
export const GtmInstructions = ({ type }: GtmInstructionsProps) => { export const GtmInstructions = ({ type, publicId }: GtmInstructionsProps) => {
switch (type) { switch (type) {
case 'standard': { case 'standard': {
return <StandardInstructions /> return <StandardInstructions publicId={publicId} />
} }
case 'popup': { case 'popup': {
return <PopupInstructions /> return <PopupInstructions />
@@ -19,23 +32,21 @@ export const GtmInstructions = ({ type }: GtmInstructionsProps) => {
} }
} }
const StandardInstructions = () => { const StandardInstructions = ({ publicId }: Pick<ModalProps, 'publicId'>) => {
// const [windowSizes, setWindowSizes] = useState({ const [windowSizes, setWindowSizes] = useState({
// height: '100%', height: '100%',
// width: '100%', width: '100%',
// }) })
// const jsCode = parseInitContainerCode({ const jsCode = parseInitContainerCode({
// publishId: chatbot?.publishId ?? '', publishId: publicId,
// backgroundColor: chatbot?.themeColors.chatbotBackground.value, })
// customDomain: chatbot?.customDomains[0], const headCode = `${typebotJsHtml}
// }) <script>
// const headCode = `${typebotJsHtml} ${jsCode}
// <script> </script>`
// ${jsCode}
// </script>`
// const elementCode = `<div id="typebot-container" style="background-color: ${backgroundColor}; height: ${windowSizes.height}; width: ${windowSizes.width}"></div>` const elementCode = `<div id="typebot-container" style="height: ${windowSizes.height}; width: ${windowSizes.width}"></div>`
return ( return (
<OrderedList spacing={2} mb={4}> <OrderedList spacing={2} mb={4}>
<ListItem> <ListItem>
@@ -46,16 +57,12 @@ const StandardInstructions = () => {
</ListItem> </ListItem>
<ListItem> <ListItem>
Paste the code below: Paste the code below:
{/* <CodeEditor <CodeEditor value={headCode} mt={2} isReadOnly lang="html" />
code={headCode}
mt={2}
onCopied={() => sendGtmCopyEvent('standard')}
/> */}
</ListItem> </ListItem>
<ListItem> <ListItem>
On your webpage, you need to have an element on which the typebot will On your webpage, you need to have an element on which the typebot will
go. It needs to have the id <Tag>typebot-container</Tag>: go. It needs to have the id <Tag>typebot-container</Tag>:
{/* <StandardEmbedWindowSettings <StandardEmbedWindowSettings
my={4} my={4}
onUpdateWindowSettings={(sizes) => onUpdateWindowSettings={(sizes) =>
setWindowSizes({ setWindowSizes({
@@ -64,14 +71,14 @@ const StandardInstructions = () => {
}) })
} }
/> />
<CodeBlock code={elementCode} mt={2} /> */} <CodeEditor value={elementCode} mt={2} isReadOnly lang="html" />
</ListItem> </ListItem>
</OrderedList> </OrderedList>
) )
} }
const PopupInstructions = () => { const PopupInstructions = () => {
// const [inputValue, setInputValue] = useState(0) const [inputValue, setInputValue] = useState(0)
return ( return (
<OrderedList spacing={2} mb={4}> <OrderedList spacing={2} mb={4}>
@@ -83,29 +90,26 @@ const PopupInstructions = () => {
</ListItem> </ListItem>
<ListItem> <ListItem>
Paste the code below: Paste the code below:
{/* <PopupEmbedSettings <PopupEmbedSettings
mb={4} my={4}
onUpdateSettings={(settings) => setInputValue(settings.delay ?? 0)} onUpdateSettings={(settings) => setInputValue(settings.delay ?? 0)}
/> />
<PopupEmbedCode <PopupEmbedCode delay={inputValue} />
delay={inputValue}
onCopied={() => sendGtmCopyEvent('popup')}
/> */}
</ListItem> </ListItem>
</OrderedList> </OrderedList>
) )
} }
const BubbleInstructions = () => { const BubbleInstructions = () => {
// const [inputValues, setInputValues] = useState< const [inputValues, setInputValues] = useState<
// Pick<BubbleParams, 'proactiveMessage' | 'button'> Pick<BubbleParams, 'proactiveMessage' | 'button'>
// >({ >({
// proactiveMessage: undefined, proactiveMessage: undefined,
// button: { button: {
// color: '', color: '',
// iconUrl: '', iconUrl: '',
// }, },
// }) })
return ( return (
<OrderedList spacing={2} mb={4}> <OrderedList spacing={2} mb={4}>
@@ -117,14 +121,10 @@ const BubbleInstructions = () => {
</ListItem> </ListItem>
<ListItem> <ListItem>
Paste the code below: Paste the code below:
{/* <ChatEmbedSettings <ChatEmbedSettings
onUpdateSettings={(settings) => setInputValues({ ...settings })} onUpdateSettings={(settings) => setInputValues({ ...settings })}
/> />
<ChatEmbedCode <ChatEmbedCode my={4} {...inputValues} />
mt={4}
{...inputValues}
onCopied={() => sendGtmCopyEvent('bubble')}
/> */}
</ListItem> </ListItem>
</OrderedList> </OrderedList>
) )

View File

@@ -18,7 +18,12 @@ import { capitalize } from 'utils'
import { PublishFirstInfo } from 'components/shared/Info' import { PublishFirstInfo } from 'components/shared/Info'
import { GtmInstructions } from './GtmInstructions' import { GtmInstructions } from './GtmInstructions'
export const GtmModal = ({ isOpen, onClose, isPublished }: ModalProps) => { export const GtmModal = ({
isOpen,
onClose,
isPublished,
publicId,
}: ModalProps) => {
const [chosenEmbedType, setChosenEmbedType] = useState< const [chosenEmbedType, setChosenEmbedType] = useState<
'standard' | 'popup' | 'bubble' | undefined 'standard' | 'popup' | 'bubble' | undefined
>() >()
@@ -53,7 +58,7 @@ export const GtmModal = ({ isOpen, onClose, isPublished }: ModalProps) => {
{!chosenEmbedType ? ( {!chosenEmbedType ? (
<ChooseEmbedTypeList onSelectEmbedType={setChosenEmbedType} /> <ChooseEmbedTypeList onSelectEmbedType={setChosenEmbedType} />
) : ( ) : (
<GtmInstructions type={chosenEmbedType} /> <GtmInstructions type={chosenEmbedType} publicId={publicId} />
)} )}
</ModalBody> </ModalBody>
<ModalFooter /> <ModalFooter />

View File

@@ -9,16 +9,13 @@ import {
ModalFooter, ModalFooter,
Text, Text,
} from '@chakra-ui/react' } from '@chakra-ui/react'
import { StandardEmbedWindowSettings } from 'components/share/codeSnippets/Container/EmbedSettings'
import { IframeEmbedCode } from 'components/share/codeSnippets/Iframe/EmbedCode'
import { PublishFirstInfo } from 'components/shared/Info' import { PublishFirstInfo } from 'components/shared/Info'
import { useState } from 'react' import { useState } from 'react'
import { ModalProps } from '../EmbedButton' import { ModalProps } from '../EmbedButton'
export const IframeModal = ({ export const IframeModal = ({ isPublished, isOpen, onClose }: ModalProps) => {
isPublished,
publicId,
isOpen,
onClose,
}: ModalProps) => {
const [inputValues, setInputValues] = useState({ const [inputValues, setInputValues] = useState({
heightLabel: '100%', heightLabel: '100%',
widthLabel: '100%', widthLabel: '100%',
@@ -33,6 +30,12 @@ export const IframeModal = ({
<ModalBody as={Stack} spacing={4}> <ModalBody as={Stack} spacing={4}>
{!isPublished && <PublishFirstInfo />} {!isPublished && <PublishFirstInfo />}
<Text>Paste this anywhere in your HTML code:</Text> <Text>Paste this anywhere in your HTML code:</Text>
<StandardEmbedWindowSettings
onUpdateWindowSettings={(settings) =>
setInputValues({ ...settings })
}
/>
<IframeEmbedCode {...inputValues} />
</ModalBody> </ModalBody>
<ModalFooter /> <ModalFooter />
</ModalContent> </ModalContent>

View File

@@ -1,4 +1,12 @@
import { Stack, Tag, Text } from '@chakra-ui/react' import { Stack, Tag, Text } from '@chakra-ui/react'
import { ChatEmbedCode } from 'components/share/codeSnippets/Chat/EmbedCode'
import { ChatEmbedSettings } from 'components/share/codeSnippets/Chat/EmbedSettings'
import { ContainerEmbedCode } from 'components/share/codeSnippets/Container/EmbedCode'
import { StandardEmbedWindowSettings } from 'components/share/codeSnippets/Container/EmbedSettings'
import { PopupEmbedCode } from 'components/share/codeSnippets/Popup/EmbedCode'
import { PopupEmbedSettings } from 'components/share/codeSnippets/Popup/EmbedSettings'
import { useState } from 'react'
import { BubbleParams } from 'typebot-js'
type JavascriptInstructionsProps = { type JavascriptInstructionsProps = {
type: 'standard' | 'popup' | 'bubble' type: 'standard' | 'popup' | 'bubble'
@@ -21,75 +29,61 @@ export const JavascriptInstructions = ({
} }
const StandardInstructions = () => { const StandardInstructions = () => {
// const [inputValues, setInputValues] = useState({ const [inputValues, setInputValues] = useState({
// heightLabel: '100%', heightLabel: '100%',
// widthLabel: '100%', widthLabel: '100%',
// }) })
return ( return (
<Stack> <Stack spacing={4}>
<Text> <Text>
Paste this anywhere in the <Tag>body</Tag> Paste this anywhere in the <Tag>body</Tag>
</Text> </Text>
{/* <StandardEmbedWindowSettings <StandardEmbedWindowSettings
onUpdateWindowSettings={(settings) => setInputValues({ ...settings })} onUpdateWindowSettings={(settings) => setInputValues({ ...settings })}
/> />
<ContainerEmbedCode <ContainerEmbedCode withStarterVariables={true} {...inputValues} mt={4} />
withStarterVariables={true}
{...inputValues}
mt={4}
onCopied={() => sendJsCopyEvent('standard')}
/> */}
</Stack> </Stack>
) )
} }
const PopupInstructions = () => { const PopupInstructions = () => {
// const [inputValue, setInputValue] = useState(0) const [inputValue, setInputValue] = useState(0)
return ( return (
<Stack> <Stack spacing={4}>
<Text> <Text>
Paste this anywhere in the <Tag>body</Tag> Paste this anywhere in the <Tag>body</Tag>
</Text> </Text>
{/* <StandardEmbedWindowSettings <PopupEmbedSettings
onUpdateWindowSettings={(settings) => setInputValues({ ...settings })} mb={4}
onUpdateSettings={(settings) => setInputValue(settings.delay ?? 0)}
/> />
<ContainerEmbedCode <PopupEmbedCode delay={inputValue} />
withStarterVariables={true}
{...inputValues}
mt={4}
onCopied={() => sendJsCopyEvent('standard')}
/> */}
</Stack> </Stack>
) )
} }
const BubbleInstructions = () => { const BubbleInstructions = () => {
// const [inputValues, setInputValues] = useState< const [inputValues, setInputValues] = useState<
// Pick<BubbleParams, 'proactiveMessage' | 'button'> Pick<BubbleParams, 'proactiveMessage' | 'button'>
// >({ >({
// proactiveMessage: undefined, proactiveMessage: undefined,
// button: { button: {
// color: '', color: '',
// iconUrl: '', iconUrl: '',
// }, },
// }) })
return ( return (
<Stack> <Stack spacing={4}>
<Text> <Text>
Paste this anywhere in the <Tag>body</Tag> Paste this anywhere in the <Tag>body</Tag>
</Text> </Text>
{/* <StandardEmbedWindowSettings <ChatEmbedSettings
onUpdateWindowSettings={(settings) => setInputValues({ ...settings })} onUpdateSettings={(settings) => setInputValues({ ...settings })}
/> />
<ContainerEmbedCode <ChatEmbedCode {...inputValues} />
withStarterVariables={true}
{...inputValues}
mt={4}
onCopied={() => sendJsCopyEvent('standard')}
/> */}
</Stack> </Stack>
) )
} }

View File

@@ -1,5 +1,15 @@
import { Stack, Text } from '@chakra-ui/react' import { Stack, Text } from '@chakra-ui/react'
import { ChatEmbedSettings } from 'components/share/codeSnippets/Chat/EmbedSettings'
import { StandardEmbedWindowSettings } from 'components/share/codeSnippets/Container/EmbedSettings'
import { PopupEmbedSettings } from 'components/share/codeSnippets/Popup/EmbedSettings'
import {
ChatReactCode,
PopupReactCode,
StandardReactDiv,
} from 'components/share/codeSnippets/ReactCode'
import { CodeEditor } from 'components/shared/CodeEditor' import { CodeEditor } from 'components/shared/CodeEditor'
import { useState } from 'react'
import { BubbleParams } from 'typebot-js'
type Props = { type Props = {
type: 'standard' | 'popup' | 'bubble' type: 'standard' | 'popup' | 'bubble'
@@ -20,58 +30,57 @@ export const ReactInstructions = ({ type }: Props) => {
} }
const StandardInstructions = () => { const StandardInstructions = () => {
// const [inputValues, setInputValues] = useState({ const [inputValues, setInputValues] = useState({
// heightLabel: '100%', heightLabel: '100%',
// widthLabel: '100%', widthLabel: '100%',
// }) })
return ( return (
<Stack spacing={4}> <Stack spacing={4}>
{/* <InstallPackageInstruction /> */} <InstallPackageInstruction />
{/* <StandardEmbedWindowSettings <StandardEmbedWindowSettings
onUpdateWindowSettings={(settings) => setInputValues({ ...settings })} onUpdateWindowSettings={(settings) => setInputValues({ ...settings })}
/> */} />
{/* <Text>{t('insert-the-typebot-container')}</Text> <Text>Insert the typebot container</Text>
<StandardReactDiv {...inputValues} /> */} <StandardReactDiv {...inputValues} />
</Stack> </Stack>
) )
} }
const PopupInstructions = () => { const PopupInstructions = () => {
// const [inputValue, setInputValue] = useState(0) const [inputValue, setInputValue] = useState(0)
return ( return (
<Stack spacing={4}> <Stack spacing={4}>
{/* <InstallPackageInstruction /> <InstallPackageInstruction />
<PopupEmbedSettings <PopupEmbedSettings
onUpdateSettings={(settings) => setInputValue(settings.delay ?? 0)} onUpdateSettings={(settings) => setInputValue(settings.delay ?? 0)}
/> />
<Text>{t('initialize-the-typebot')}</Text> <Text>Initialize the typebot</Text>
<PopupReactCode withStarterVariables={true} delay={inputValue} /> */} <PopupReactCode withStarterVariables={true} delay={inputValue} />
</Stack> </Stack>
) )
} }
const BubbleInstructions = () => { const BubbleInstructions = () => {
// const { t } = useTranslation() const [inputValues, setInputValues] = useState<
// const [inputValues, setInputValues] = useState< Pick<BubbleParams, 'proactiveMessage' | 'button'>
// Pick<BubbleParams, 'proactiveMessage' | 'button'> >({
// >({ proactiveMessage: undefined,
// proactiveMessage: undefined, button: {
// button: { color: '',
// color: '', iconUrl: '',
// iconUrl: '', },
// }, })
// })
return ( return (
<Stack spacing={4}> <Stack spacing={4}>
{/* <InstallPackageInstruction /> <InstallPackageInstruction />
<ChatEmbedSettings <ChatEmbedSettings
onUpdateSettings={(settings) => setInputValues({ ...settings })} onUpdateSettings={(settings) => setInputValues({ ...settings })}
/> />
<Text>{t('initialize-the-typebot')}</Text> <Text>Initialize the typebot</Text>
<ChatReactCode withStarterVariables={true} {...inputValues} mt={4} /> */} <ChatReactCode withStarterVariables={true} {...inputValues} mt={4} />
</Stack> </Stack>
) )
} }

View File

@@ -1,13 +1,32 @@
import { OrderedList, ListItem, Tag } from '@chakra-ui/react' import { OrderedList, ListItem, Tag } from '@chakra-ui/react'
import { ChatEmbedCode } from 'components/share/codeSnippets/Chat/EmbedCode'
import { ChatEmbedSettings } from 'components/share/codeSnippets/Chat/EmbedSettings'
import { StandardEmbedWindowSettings } from 'components/share/codeSnippets/Container/EmbedSettings'
import {
parseInitContainerCode,
typebotJsHtml,
} from 'components/share/codeSnippets/params'
import { PopupEmbedCode } from 'components/share/codeSnippets/Popup/EmbedCode'
import { PopupEmbedSettings } from 'components/share/codeSnippets/Popup/EmbedSettings'
import { CodeEditor } from 'components/shared/CodeEditor'
import { useState } from 'react'
import { BubbleParams } from 'typebot-js'
import { ModalProps } from '../../EmbedButton'
import parserHtml from 'prettier/parser-html'
import prettier from 'prettier/standalone'
type ShopifyInstructionsProps = { type ShopifyInstructionsProps = {
type: 'standard' | 'popup' | 'bubble' type: 'standard' | 'popup' | 'bubble'
publicId: string
} }
export const ShopifyInstructions = ({ type }: ShopifyInstructionsProps) => { export const ShopifyInstructions = ({
type,
publicId,
}: ShopifyInstructionsProps) => {
switch (type) { switch (type) {
case 'standard': { case 'standard': {
return <StandardInstructions /> return <StandardInstructions publicId={publicId} />
} }
case 'popup': { case 'popup': {
return <PopupInstructions /> return <PopupInstructions />
@@ -18,24 +37,30 @@ export const ShopifyInstructions = ({ type }: ShopifyInstructionsProps) => {
} }
} }
const StandardInstructions = () => { const StandardInstructions = ({ publicId }: Pick<ModalProps, 'publicId'>) => {
// const backgroundColor = chatbot?.themeColors.siteBackground.value const [windowSizes, setWindowSizes] = useState({
// const [windowSizes, setWindowSizes] = useState({ height: '100%',
// height: '100%', width: '100%',
// width: '100%', })
// })
// const jsCode = parseInitContainerCode({ const jsCode = parseInitContainerCode({
// publishId: chatbot?.publishId ?? '', publishId: publicId,
// customDomain: chatbot?.customDomains[0], })
// backgroundColor: chatbot?.themeColors.chatbotBackground.value, const headCode = prettier.format(
// }) `${typebotJsHtml}<script>${jsCode}</script>`,
// const headCode = `${typebotJsHtml} {
// <script> parser: 'html',
// ${jsCode} plugins: [parserHtml],
// </script>` }
)
// const elementCode = `<div id="typebot-container" style="background-color: ${backgroundColor}; height: ${windowSizes.height}; width: ${windowSizes.width}"></div>` const elementCode = prettier.format(
`<div id="typebot-container" style="height: ${windowSizes.height}; width: ${windowSizes.width}"></div>`,
{
parser: 'html',
plugins: [parserHtml],
}
)
return ( return (
<OrderedList spacing={2} mb={4}> <OrderedList spacing={2} mb={4}>
@@ -46,17 +71,13 @@ const StandardInstructions = () => {
<ListItem> <ListItem>
In <Tag>Layout {'>'} theme.liquid</Tag> file, paste this code just In <Tag>Layout {'>'} theme.liquid</Tag> file, paste this code just
before the closing <Tag>head</Tag> tag: before the closing <Tag>head</Tag> tag:
{/* <CodeBlock <CodeEditor value={headCode} mt={2} lang="html" isReadOnly />
code={headCode}
mt={2}
onCopied={() => sendShopifyCopyEvent('standard')}
/> */}
</ListItem> </ListItem>
<ListItem> <ListItem>
Then, you can place an element on which the typebot will go in any file Then, you can place an element on which the typebot will go in any file
in the <Tag>body</Tag> tags. It needs to have the id{' '} in the <Tag>body</Tag> tags. It needs to have the id{' '}
<Tag>typebot-container</Tag>: <Tag>typebot-container</Tag>:
{/* <StandardEmbedWindowSettings <StandardEmbedWindowSettings
my={4} my={4}
onUpdateWindowSettings={(sizes) => onUpdateWindowSettings={(sizes) =>
setWindowSizes({ setWindowSizes({
@@ -65,14 +86,14 @@ const StandardInstructions = () => {
}) })
} }
/> />
<CodeBlock code={elementCode} mt={2} /> */} <CodeEditor value={elementCode} mt={2} lang="html" isReadOnly />
</ListItem> </ListItem>
</OrderedList> </OrderedList>
) )
} }
const PopupInstructions = () => { const PopupInstructions = () => {
// const [inputValue, setInputValue] = useState(0) const [inputValue, setInputValue] = useState(0)
return ( return (
<OrderedList spacing={2} mb={4}> <OrderedList spacing={2} mb={4}>
@@ -83,29 +104,26 @@ const PopupInstructions = () => {
<ListItem> <ListItem>
In <Tag>Layout {'>'} theme.liquid</Tag> file, paste this code just In <Tag>Layout {'>'} theme.liquid</Tag> file, paste this code just
before the closing <Tag>head</Tag> tag: before the closing <Tag>head</Tag> tag:
{/* <PopupEmbedSettings <PopupEmbedSettings
mb={4} my="4"
onUpdateSettings={(settings) => setInputValue(settings.delay ?? 0)} onUpdateSettings={(settings) => setInputValue(settings.delay ?? 0)}
/> />
<PopupEmbedCode <PopupEmbedCode delay={inputValue} />
delay={inputValue}
onCopied={() => sendShopifyCopyEvent('popup')}
/> */}
</ListItem> </ListItem>
</OrderedList> </OrderedList>
) )
} }
const BubbleInstructions = () => { const BubbleInstructions = () => {
// const [inputValues, setInputValues] = useState< const [inputValues, setInputValues] = useState<
// Pick<BubbleParams, 'proactiveMessage' | 'button'> Pick<BubbleParams, 'proactiveMessage' | 'button'>
// >({ >({
// proactiveMessage: undefined, proactiveMessage: undefined,
// button: { button: {
// color: '', color: '',
// iconUrl: '', iconUrl: '',
// }, },
// }) })
return ( return (
<OrderedList spacing={2} mb={4}> <OrderedList spacing={2} mb={4}>
@@ -116,14 +134,11 @@ const BubbleInstructions = () => {
<ListItem> <ListItem>
In <Tag>Layout {'>'} theme.liquid</Tag> file, paste this code just In <Tag>Layout {'>'} theme.liquid</Tag> file, paste this code just
before the closing <Tag>head</Tag> tag: before the closing <Tag>head</Tag> tag:
{/* <ChatEmbedSettings <ChatEmbedSettings
onUpdateSettings={(settings) => setInputValues({ ...settings })} my="4"
/> onUpdateSettings={(settings) => setInputValues({ ...settings })}
<ChatEmbedCode />
mt={4} <ChatEmbedCode mt={4} {...inputValues} />
{...inputValues}
onCopied={() => sendShopifyCopyEvent('bubble')}
/> */}
</ListItem> </ListItem>
</OrderedList> </OrderedList>
) )

View File

@@ -18,7 +18,12 @@ import { capitalize } from 'utils'
import { PublishFirstInfo } from 'components/shared/Info' import { PublishFirstInfo } from 'components/shared/Info'
import { ShopifyInstructions } from './ShopifyInstructions' import { ShopifyInstructions } from './ShopifyInstructions'
export const ShopifyModal = ({ isOpen, onClose, isPublished }: ModalProps) => { export const ShopifyModal = ({
isOpen,
onClose,
isPublished,
publicId,
}: ModalProps) => {
const [chosenEmbedType, setChosenEmbedType] = useState< const [chosenEmbedType, setChosenEmbedType] = useState<
'standard' | 'popup' | 'bubble' | undefined 'standard' | 'popup' | 'bubble' | undefined
>() >()
@@ -53,7 +58,7 @@ export const ShopifyModal = ({ isOpen, onClose, isPublished }: ModalProps) => {
{!chosenEmbedType ? ( {!chosenEmbedType ? (
<ChooseEmbedTypeList onSelectEmbedType={setChosenEmbedType} /> <ChooseEmbedTypeList onSelectEmbedType={setChosenEmbedType} />
) : ( ) : (
<ShopifyInstructions type={chosenEmbedType} /> <ShopifyInstructions type={chosenEmbedType} publicId={publicId} />
)} )}
</ModalBody> </ModalBody>
<ModalFooter /> <ModalFooter />

View File

@@ -1,4 +1,11 @@
import { OrderedList, ListItem, Tag, Text, Stack } from '@chakra-ui/react' import { OrderedList, ListItem, Tag, Text, Stack } from '@chakra-ui/react'
import { ChatEmbedCode } from 'components/share/codeSnippets/Chat/EmbedCode'
import { ChatEmbedSettings } from 'components/share/codeSnippets/Chat/EmbedSettings'
import { ContainerEmbedCode } from 'components/share/codeSnippets/Container/EmbedCode'
import { PopupEmbedCode } from 'components/share/codeSnippets/Popup/EmbedCode'
import { PopupEmbedSettings } from 'components/share/codeSnippets/Popup/EmbedSettings'
import { useState } from 'react'
import { BubbleParams } from 'typebot-js'
type WebflowInstructionsProps = { type WebflowInstructionsProps = {
type: 'standard' | 'popup' | 'bubble' type: 'standard' | 'popup' | 'bubble'
@@ -21,8 +28,22 @@ export const WebflowInstructions = ({ type }: WebflowInstructionsProps) => {
} }
const StandardInstructions = () => ( const StandardInstructions = () => (
<Stack> <OrderedList spacing={2} mb={4}>
<Text>In the Webflow editor:</Text> <ListItem>
Press <Tag>A</Tag> to open the <Tag>Add elements</Tag> panel
</ListItem>
<ListItem>
Add an <Tag>embed</Tag> element from the <Tag>components</Tag>
section and paste this code:
<ContainerEmbedCode widthLabel="100%" heightLabel="100%" my={4} />
</ListItem>
</OrderedList>
)
const PopupInstructions = () => {
const [inputValue, setInputValue] = useState(0)
return (
<OrderedList spacing={2} mb={4}> <OrderedList spacing={2} mb={4}>
<ListItem> <ListItem>
Press <Tag>A</Tag> to open the <Tag>Add elements</Tag> panel Press <Tag>A</Tag> to open the <Tag>Add elements</Tag> panel
@@ -30,78 +51,41 @@ const StandardInstructions = () => (
<ListItem> <ListItem>
Add an <Tag>embed</Tag> element from the <Tag>components</Tag> Add an <Tag>embed</Tag> element from the <Tag>components</Tag>
section and paste this code: section and paste this code:
{/* <ContainerEmbedCode <PopupEmbedSettings
widthLabel="100%" onUpdateSettings={(settings) => setInputValue(settings.delay ?? 0)}
heightLabel="100%" my={4}
mt={4} />
onCopied={() => sendWebflowCopyEvent('standard')} <PopupEmbedCode delay={inputValue} mt={4} />
/> */}
</ListItem> </ListItem>
</OrderedList> </OrderedList>
</Stack>
)
const PopupInstructions = () => {
// const [inputValue, setInputValue] = useState(0)
return (
<Stack>
<Text>In the Webflow editor</Text>
<OrderedList spacing={2} mb={4}>
<ListItem>
Press <Tag>A</Tag> to open the <Tag>Add elements</Tag> panel
</ListItem>
<ListItem>
Add an <Tag>embed</Tag> element from the <Tag>components</Tag>
section and paste this code:
{/* <PopupEmbedSettings
onUpdateSettings={(settings) => setInputValue(settings.delay ?? 0)}
mt={4}
/>
<PopupEmbedCode
delay={inputValue}
mt={4}
onCopied={() => sendWebflowCopyEvent('popup')}
/> */}
</ListItem>
</OrderedList>
</Stack>
) )
} }
const BubbleInstructions = () => { const BubbleInstructions = () => {
// const [inputValues, setInputValues] = useState< const [inputValues, setInputValues] = useState<
// Pick<BubbleParams, 'proactiveMessage' | 'button'> Pick<BubbleParams, 'proactiveMessage' | 'button'>
// >({ >({
// proactiveMessage: undefined, proactiveMessage: undefined,
// button: { button: {
// color: '', color: '',
// iconUrl: '', iconUrl: '',
// }, },
// }) })
return ( return (
<Stack> <OrderedList spacing={2} mb={4}>
<Text>In the Webflow editor</Text> <ListItem>
<OrderedList spacing={2} mb={4}> Press <Tag>A</Tag> to open the <Tag>Add elements</Tag> panel
<ListItem> </ListItem>
Press <Tag>A</Tag> to open the <Tag>Add elements</Tag> panel <ListItem>
</ListItem> Add an <Tag>embed</Tag> element from the <Tag>components</Tag>
<ListItem> section and paste this code:
Add an <Tag>embed</Tag> element from the <Tag>components</Tag> <ChatEmbedSettings
section and paste this code: onUpdateSettings={(settings) => setInputValues({ ...settings })}
{/* <ChatEmbedSettings my={4}
onUpdateSettings={(settings) => setInputValues({ ...settings })} />
mt={4} <ChatEmbedCode withStarterVariables={true} {...inputValues} my={4} />
/> </ListItem>
<ChatEmbedCode </OrderedList>
withStarterVariables={true}
{...inputValues}
mt={4}
onCopied={() => sendWebflowCopyEvent('bubble')}
/> */}
</ListItem>
</OrderedList>
</Stack>
) )
} }

View File

@@ -1,5 +1,11 @@
import { ListItem, OrderedList, Tag } from '@chakra-ui/react' import { ListItem, OrderedList, Tag } from '@chakra-ui/react'
import { ChatEmbedCode } from 'components/share/codeSnippets/Chat/EmbedCode'
import { ChatEmbedSettings } from 'components/share/codeSnippets/Chat/EmbedSettings'
import { ContainerEmbedCode } from 'components/share/codeSnippets/Container/EmbedCode'
import { PopupEmbedCode } from 'components/share/codeSnippets/Popup/EmbedCode'
import { PopupEmbedSettings } from 'components/share/codeSnippets/Popup/EmbedSettings'
import { useState } from 'react' import { useState } from 'react'
import { BubbleParams } from 'typebot-js'
type WixInstructionsProps = { type WixInstructionsProps = {
type: 'standard' | 'popup' | 'bubble' type: 'standard' | 'popup' | 'bubble'
@@ -21,24 +27,23 @@ export const WixInstructions = ({ type }: WixInstructionsProps) => {
const StandardInstructions = () => { const StandardInstructions = () => {
return ( return (
<> <OrderedList spacing={2} mb={4}>
<OrderedList spacing={2} mb={4}> <ListItem>
<ListItem> In the Wix Website Editor:
In the Wix Website Editor: <Tag>
<Tag> Add {'>'} Embed {'>'} Embed a Widget
Add {'>'} Embed {'>'} Embed a Widget </Tag>
</Tag> </ListItem>
</ListItem> <ListItem>
<ListItem> Click on <Tag>Enter code</Tag> and paste this code:
Click on <Tag>Enter code</Tag> and paste this code: </ListItem>
</ListItem> <ContainerEmbedCode widthLabel="100%" heightLabel="100%" />
</OrderedList> </OrderedList>
</>
) )
} }
const PopupInstructions = () => { const PopupInstructions = () => {
// const [inputValue, setInputValue] = useState(0) const [inputValue, setInputValue] = useState(0)
return ( return (
<> <>
@@ -52,45 +57,49 @@ const PopupInstructions = () => {
<ListItem> <ListItem>
Click <Tag>+ Add Custom Code</Tag> at the top right. Click <Tag>+ Add Custom Code</Tag> at the top right.
</ListItem> </ListItem>
<ListItem>Paste this snippet in the code box:</ListItem> <ListItem>
Paste this snippet in the code box:
<PopupEmbedSettings
onUpdateSettings={(settings) => setInputValue(settings.delay ?? 0)}
my={4}
/>
<PopupEmbedCode delay={inputValue} />
</ListItem>
</OrderedList> </OrderedList>
</> </>
) )
} }
const BubbleInstructions = () => { const BubbleInstructions = () => {
// const [inputValues, setInputValues] = useState< const [inputValues, setInputValues] = useState<
// Pick<BubbleParams, 'proactiveMessage' | 'button'> Pick<BubbleParams, 'proactiveMessage' | 'button'>
// >({ >({
// proactiveMessage: undefined, proactiveMessage: undefined,
// button: { button: {
// color: '', color: '',
// iconUrl: '', iconUrl: '',
// }, },
// }) })
return ( return (
<> <OrderedList spacing={2} mb={4}>
<OrderedList spacing={2} mb={4}> <ListItem>
<ListItem> Go to <Tag>Settings</Tag> in your dashboard on Wix
Go to <Tag>Settings</Tag> in your dashboard on Wix </ListItem>
</ListItem> <ListItem>
<ListItem> Click on <Tag>Custom Code</Tag> under <Tag>Advanced</Tag>
Click on <Tag>Custom Code</Tag> under <Tag>Advanced</Tag> </ListItem>
</ListItem> <ListItem>
<ListItem> Click <Tag>+ Add Custom Code</Tag> at the top right.
Click <Tag>+ Add Custom Code</Tag> at the top right. </ListItem>
</ListItem> <ListItem>
<ListItem>Paste this snippet in the code box:</ListItem> Paste this snippet in the code box:{' '}
</OrderedList> <ChatEmbedSettings
{/* <ChatEmbedSettings my="4"
onUpdateSettings={(settings) => setInputValues({ ...settings })} onUpdateSettings={(settings) => setInputValues({ ...settings })}
/> />
<ChatEmbedCode <ChatEmbedCode {...inputValues} />
mt={4} </ListItem>
{...inputValues} </OrderedList>
onCopied={() => sendWixCopyEvent('bubble')}
/> */}
</>
) )
} }

View File

@@ -2,11 +2,13 @@ import { Box, BoxProps } from '@chakra-ui/react'
import { EditorState, EditorView, basicSetup } from '@codemirror/basic-setup' import { EditorState, EditorView, basicSetup } from '@codemirror/basic-setup'
import { json } from '@codemirror/lang-json' import { json } from '@codemirror/lang-json'
import { css } from '@codemirror/lang-css' import { css } from '@codemirror/lang-css'
import { javascript } from '@codemirror/lang-javascript'
import { html } from '@codemirror/lang-html'
import { useEffect, useRef, useState } from 'react' import { useEffect, useRef, useState } from 'react'
type Props = { type Props = {
value: string value: string
lang?: 'css' | 'json' lang?: 'css' | 'json' | 'js' | 'html'
onChange?: (value: string) => void onChange?: (value: string) => void
isReadOnly?: boolean isReadOnly?: boolean
} }
@@ -24,7 +26,11 @@ export const CodeEditor = ({
useEffect(() => { useEffect(() => {
if (!editorView.current || !isReadOnly) return if (!editorView.current || !isReadOnly) return
editorView.current.dispatch({ editorView.current.dispatch({
changes: { from: 0, insert: value }, changes: {
from: 0,
to: editorView.current.state.doc.length,
insert: value,
},
}) })
// eslint-disable-next-line react-hooks/exhaustive-deps // eslint-disable-next-line react-hooks/exhaustive-deps
}, [value]) }, [value])
@@ -36,6 +42,14 @@ export const CodeEditor = ({
}, [plainTextValue]) }, [plainTextValue])
useEffect(() => { useEffect(() => {
const editor = initEditor(value)
return () => {
editor?.destroy()
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [])
const initEditor = (value: string) => {
if (!editorContainer.current) return if (!editorContainer.current) return
const updateListenerExtension = EditorView.updateListener.of((update) => { const updateListenerExtension = EditorView.updateListener.of((update) => {
if (update.docChanged && onChange) if (update.docChanged && onChange)
@@ -48,6 +62,8 @@ export const CodeEditor = ({
] ]
if (lang === 'json') extensions.push(json()) if (lang === 'json') extensions.push(json())
if (lang === 'css') extensions.push(css()) if (lang === 'css') extensions.push(css())
if (lang === 'js') extensions.push(javascript())
if (lang === 'html') extensions.push(html())
const editor = new EditorView({ const editor = new EditorView({
state: EditorState.create({ state: EditorState.create({
extensions, extensions,
@@ -58,13 +74,8 @@ export const CodeEditor = ({
changes: { from: 0, insert: value }, changes: { from: 0, insert: value },
}) })
editorView.current = editor editorView.current = editor
return () => { return editor
editor.destroy() }
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [])
return ( return <Box ref={editorContainer} data-testid="code-editor" {...props} />
<Box ref={editorContainer} h="200px" data-testid="code-editor" {...props} />
)
} }

View File

@@ -15,6 +15,8 @@
"@chakra-ui/react": "^1.8.1", "@chakra-ui/react": "^1.8.1",
"@codemirror/basic-setup": "^0.19.1", "@codemirror/basic-setup": "^0.19.1",
"@codemirror/lang-css": "^0.19.3", "@codemirror/lang-css": "^0.19.3",
"@codemirror/lang-html": "^0.19.4",
"@codemirror/lang-javascript": "^0.19.7",
"@codemirror/lang-json": "^0.19.1", "@codemirror/lang-json": "^0.19.1",
"@codemirror/text": "^0.19.6", "@codemirror/text": "^0.19.6",
"@emotion/react": "^11.7.1", "@emotion/react": "^11.7.1",
@@ -69,7 +71,8 @@
"swr": "^1.2.0", "swr": "^1.2.0",
"use-debounce": "^7.0.1", "use-debounce": "^7.0.1",
"use-immer": "^0.6.0", "use-immer": "^0.6.0",
"utils": "*" "utils": "*",
"typebot-js": "2.0.21"
}, },
"devDependencies": { "devDependencies": {
"@playwright/test": "^1.18.1", "@playwright/test": "^1.18.1",
@@ -79,6 +82,7 @@
"@types/node": "^16.11.9", "@types/node": "^16.11.9",
"@types/nprogress": "^0.2.0", "@types/nprogress": "^0.2.0",
"@types/papaparse": "^5.3.1", "@types/papaparse": "^5.3.1",
"@types/prettier": "^2.4.4",
"@types/qs": "^6.9.7", "@types/qs": "^6.9.7",
"@types/react": "^17.0.38", "@types/react": "^17.0.38",
"@types/react-table": "^7.7.9", "@types/react-table": "^7.7.9",

View File

@@ -1,5 +1,4 @@
import { ItemBase, ItemType } from '.' import { ItemBase, ItemType } from '.'
import { Item } from './item'
import { StepBase } from './steps' import { StepBase } from './steps'
export type InputStep = export type InputStep =

View File

@@ -1110,7 +1110,7 @@
"@codemirror/state" "^0.19.0" "@codemirror/state" "^0.19.0"
"@codemirror/view" "^0.19.23" "@codemirror/view" "^0.19.23"
"@codemirror/highlight@^0.19.0", "@codemirror/highlight@^0.19.6": "@codemirror/highlight@^0.19.0", "@codemirror/highlight@^0.19.6", "@codemirror/highlight@^0.19.7":
version "0.19.7" version "0.19.7"
resolved "https://registry.yarnpkg.com/@codemirror/highlight/-/highlight-0.19.7.tgz#91a0c9994c759f5f153861e3aae74ff9e7c7c35b" resolved "https://registry.yarnpkg.com/@codemirror/highlight/-/highlight-0.19.7.tgz#91a0c9994c759f5f153861e3aae74ff9e7c7c35b"
integrity sha512-3W32hBCY0pbbv/xidismw+RDMKuIag+fo4kZIbD7WoRj+Ttcaxjf+vP6RttRHXLaaqbWh031lTeON8kMlDhMYw== integrity sha512-3W32hBCY0pbbv/xidismw+RDMKuIag+fo4kZIbD7WoRj+Ttcaxjf+vP6RttRHXLaaqbWh031lTeON8kMlDhMYw==
@@ -1130,7 +1130,7 @@
"@codemirror/state" "^0.19.2" "@codemirror/state" "^0.19.2"
"@codemirror/view" "^0.19.0" "@codemirror/view" "^0.19.0"
"@codemirror/lang-css@^0.19.3": "@codemirror/lang-css@^0.19.0", "@codemirror/lang-css@^0.19.3":
version "0.19.3" version "0.19.3"
resolved "https://registry.yarnpkg.com/@codemirror/lang-css/-/lang-css-0.19.3.tgz#7a17adf78c6fcdab4ad5ee4e360631c41e949e4a" 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== integrity sha512-tyCUJR42/UlfOPLb94/p7dN+IPsYSIzHbAHP2KQHANj0I+Orqp+IyIOS++M8TuCX4zkWh9dvi8s92yy/Tn8Ifg==
@@ -1141,6 +1141,33 @@
"@codemirror/state" "^0.19.0" "@codemirror/state" "^0.19.0"
"@lezer/css" "^0.15.2" "@lezer/css" "^0.15.2"
"@codemirror/lang-html@^0.19.4":
version "0.19.4"
resolved "https://registry.yarnpkg.com/@codemirror/lang-html/-/lang-html-0.19.4.tgz#e6eec28462f18842a0e108732a214a7416b5e333"
integrity sha512-GpiEikNuCBeFnS+/TJSeanwqaOfNm8Kkp9WpVNEPZCLyW1mAMCuFJu/3xlWYeWc778Hc3vJqGn3bn+cLNubgCA==
dependencies:
"@codemirror/autocomplete" "^0.19.0"
"@codemirror/highlight" "^0.19.6"
"@codemirror/lang-css" "^0.19.0"
"@codemirror/lang-javascript" "^0.19.0"
"@codemirror/language" "^0.19.0"
"@codemirror/state" "^0.19.0"
"@lezer/common" "^0.15.0"
"@lezer/html" "^0.15.0"
"@codemirror/lang-javascript@^0.19.0", "@codemirror/lang-javascript@^0.19.7":
version "0.19.7"
resolved "https://registry.yarnpkg.com/@codemirror/lang-javascript/-/lang-javascript-0.19.7.tgz#84581ef6abf2a16d78f017ffc96c2d6227de5eb5"
integrity sha512-DL9f3JLqOEHH9cIwEqqjnP5bkjdVXeECksLtV+/MbPm+l4H+AG+PkwZaJQ2oR1GfPZKh8MVSIE94aGWNkJP8WQ==
dependencies:
"@codemirror/autocomplete" "^0.19.0"
"@codemirror/highlight" "^0.19.7"
"@codemirror/language" "^0.19.0"
"@codemirror/lint" "^0.19.0"
"@codemirror/state" "^0.19.0"
"@codemirror/view" "^0.19.0"
"@lezer/javascript" "^0.15.1"
"@codemirror/lang-json@^0.19.1": "@codemirror/lang-json@^0.19.1":
version "0.19.1" version "0.19.1"
resolved "https://registry.yarnpkg.com/@codemirror/lang-json/-/lang-json-0.19.1.tgz#616588d1422529965243c10af6c44ad0b9134fb0" resolved "https://registry.yarnpkg.com/@codemirror/lang-json/-/lang-json-0.19.1.tgz#616588d1422529965243c10af6c44ad0b9134fb0"
@@ -1633,6 +1660,20 @@
dependencies: dependencies:
"@lezer/lr" "^0.15.0" "@lezer/lr" "^0.15.0"
"@lezer/html@^0.15.0":
version "0.15.0"
resolved "https://registry.yarnpkg.com/@lezer/html/-/html-0.15.0.tgz#572c9444bc39c1afc0529a70e089abf7254edf5d"
integrity sha512-ErmgP/Vv0AhYJvs/Ekb9oue4IzBHemKLi7K8tJ0jgS+20Y8FGC9foK6knCXtEHqdPaxVGQH9PVp7gecLnzLd9Q==
dependencies:
"@lezer/lr" "^0.15.0"
"@lezer/javascript@^0.15.1":
version "0.15.3"
resolved "https://registry.yarnpkg.com/@lezer/javascript/-/javascript-0.15.3.tgz#833a4c5650bae07805b9af88de6706368844dc55"
integrity sha512-8jA2NpOfpWwSPZxRhd9BxK2ZPvGd7nLE3LFTJ5AbMhXAzMHeMjneV6GEVd7dAIee85dtap0jdb6bgOSO0+lfwA==
dependencies:
"@lezer/lr" "^0.15.0"
"@lezer/json@^0.15.0": "@lezer/json@^0.15.0":
version "0.15.0" version "0.15.0"
resolved "https://registry.yarnpkg.com/@lezer/json/-/json-0.15.0.tgz#b96c1161eb8514e05f4eaaec95c68376e76e539f" resolved "https://registry.yarnpkg.com/@lezer/json/-/json-0.15.0.tgz#b96c1161eb8514e05f4eaaec95c68376e76e539f"
@@ -2208,6 +2249,11 @@
resolved "https://registry.yarnpkg.com/@types/parse-json/-/parse-json-4.0.0.tgz#2f8bb441434d163b35fb8ffdccd7138927ffb8c0" resolved "https://registry.yarnpkg.com/@types/parse-json/-/parse-json-4.0.0.tgz#2f8bb441434d163b35fb8ffdccd7138927ffb8c0"
integrity sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA== integrity sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==
"@types/prettier@^2.4.4":
version "2.4.4"
resolved "https://registry.yarnpkg.com/@types/prettier/-/prettier-2.4.4.tgz#5d9b63132df54d8909fce1c3f8ca260fdd693e17"
integrity sha512-ReVR2rLTV1kvtlWFyuot+d1pkpG2Fw/XKE3PDAdj57rbM97ttSp9JZ2UsP+2EHTylra9cUf6JA7tGwW1INzUrA==
"@types/prop-types@*": "@types/prop-types@*":
version "15.7.4" version "15.7.4"
resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.4.tgz#fcf7205c25dff795ee79af1e30da2c9790808f11" resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.4.tgz#fcf7205c25dff795ee79af1e30da2c9790808f11"
@@ -8061,7 +8107,7 @@ type-fest@^0.21.3:
resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.21.3.tgz#d260a24b0198436e133fa26a524a6d65fa3b2e37" resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.21.3.tgz#d260a24b0198436e133fa26a524a6d65fa3b2e37"
integrity sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w== integrity sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==
typebot-js@^2.0.21: typebot-js@2.0.21, typebot-js@^2.0.21:
version "2.0.21" version "2.0.21"
resolved "https://registry.yarnpkg.com/typebot-js/-/typebot-js-2.0.21.tgz#1211ef4ffbf8f69facf538721073ec17660283b9" resolved "https://registry.yarnpkg.com/typebot-js/-/typebot-js-2.0.21.tgz#1211ef4ffbf8f69facf538721073ec17660283b9"
integrity sha512-7a0vODc1MLYe2u9TtaO7u0Sz9V9+3Tk+YeY2cXjDgWEhFWNcUPyBZOJZMB5EDir5/togTMTIYr/TCm6fyGRi2Q== integrity sha512-7a0vODc1MLYe2u9TtaO7u0Sz9V9+3Tk+YeY2cXjDgWEhFWNcUPyBZOJZMB5EDir5/togTMTIYr/TCm6fyGRi2Q==