From 2b2b1c3d6d197df5b87a795d06e6f509ea162ab6 Mon Sep 17 00:00:00 2001 From: Baptiste Arnaud Date: Sat, 25 Feb 2023 10:16:57 +0100 Subject: [PATCH] :pencil: (embed) Add new script embed instructions --- .../publish/components/embeds/EmbedButton.tsx | 10 ++++ .../embeds/modals/Script/ScriptModal.tsx | 25 +++++++++ .../instructions/ScriptBubbleInstructions.tsx | 55 +++++++++++++++++++ .../instructions/ScriptInstructions.tsx | 21 +++++++ .../instructions/ScriptPopupInstructions.tsx | 34 ++++++++++++ .../ScriptStandardInstructions.tsx | 50 +++++++++++++++++ .../embeds/snippetParsers/shared.ts | 11 ++++ apps/docs/docs/embed/script.md | 5 ++ 8 files changed, 211 insertions(+) create mode 100644 apps/builder/src/features/publish/components/embeds/modals/Script/ScriptModal.tsx create mode 100644 apps/builder/src/features/publish/components/embeds/modals/Script/instructions/ScriptBubbleInstructions.tsx create mode 100644 apps/builder/src/features/publish/components/embeds/modals/Script/instructions/ScriptInstructions.tsx create mode 100644 apps/builder/src/features/publish/components/embeds/modals/Script/instructions/ScriptPopupInstructions.tsx create mode 100644 apps/builder/src/features/publish/components/embeds/modals/Script/instructions/ScriptStandardInstructions.tsx create mode 100644 apps/docs/docs/embed/script.md diff --git a/apps/builder/src/features/publish/components/embeds/EmbedButton.tsx b/apps/builder/src/features/publish/components/embeds/EmbedButton.tsx index 84242d0c8..c8aeb73f8 100644 --- a/apps/builder/src/features/publish/components/embeds/EmbedButton.tsx +++ b/apps/builder/src/features/publish/components/embeds/EmbedButton.tsx @@ -24,6 +24,8 @@ import { WixModal, } from './modals' import { OtherModal } from './modals/OtherModal' +import { ScriptIcon } from '@/features/blocks/logic/script' +import { ScriptModal } from './modals/Script/ScriptModal' export type ModalProps = { publicId: string @@ -112,6 +114,14 @@ export const integrationsList = [ {...props} /> ), + (props: Pick) => ( + } + label="Script" + Modal={ScriptModal} + {...props} + /> + ), (props: Pick) => ( } diff --git a/apps/builder/src/features/publish/components/embeds/modals/Script/ScriptModal.tsx b/apps/builder/src/features/publish/components/embeds/modals/Script/ScriptModal.tsx new file mode 100644 index 000000000..16a405a08 --- /dev/null +++ b/apps/builder/src/features/publish/components/embeds/modals/Script/ScriptModal.tsx @@ -0,0 +1,25 @@ +import React, { useState } from 'react' +import { ModalProps } from '../../EmbedButton' +import { EmbedModal } from '../../EmbedModal' +import { isDefined } from '@udecode/plate-common' +import { ScriptInstructions } from './instructions/ScriptInstructions' + +export const ScriptModal = ({ isOpen, onClose, isPublished }: ModalProps) => { + const [selectedEmbedType, setSelectedEmbedType] = useState< + 'standard' | 'popup' | 'bubble' | undefined + >() + return ( + + {isDefined(selectedEmbedType) && ( + + )} + + ) +} diff --git a/apps/builder/src/features/publish/components/embeds/modals/Script/instructions/ScriptBubbleInstructions.tsx b/apps/builder/src/features/publish/components/embeds/modals/Script/instructions/ScriptBubbleInstructions.tsx new file mode 100644 index 000000000..aa680f0c9 --- /dev/null +++ b/apps/builder/src/features/publish/components/embeds/modals/Script/instructions/ScriptBubbleInstructions.tsx @@ -0,0 +1,55 @@ +import { CodeEditor } from '@/components/CodeEditor' +import { useTypebot } from '@/features/editor' +import { isCloudProdInstance } from '@/utils/helpers' +import { Stack, Text } from '@chakra-ui/react' +import { BubbleProps } from '@typebot.io/js' +import { Typebot } from 'models' +import { useState } from 'react' +import { env, getViewerUrl } from 'utils' +import { BubbleSettings } from '../../../settings/BubbleSettings/BubbleSettings' +import { parseInlineScript, parseInitBubbleCode } from '../../../snippetParsers' + +export const parseDefaultBubbleTheme = (typebot?: Typebot) => ({ + button: { + backgroundColor: typebot?.theme.chat.buttons.backgroundColor, + iconColor: typebot?.theme.chat.buttons.color, + }, + previewMessage: { + backgroundColor: typebot?.theme.general.background.content ?? 'white', + textColor: 'black', + }, +}) + +export const ScriptBubbleInstructions = () => { + const { typebot } = useTypebot() + const [theme, setTheme] = useState( + parseDefaultBubbleTheme(typebot) + ) + const [previewMessage, setPreviewMessage] = + useState() + + const scriptSnippet = parseInlineScript( + parseInitBubbleCode({ + typebot: typebot?.publicId ?? '', + apiHost: isCloudProdInstance + ? undefined + : env('VIEWER_INTERNAL_URL') ?? getViewerUrl(), + theme, + previewMessage, + }) + ) + + return ( + + + Run this script to initialize the typebot: + + + ) +} diff --git a/apps/builder/src/features/publish/components/embeds/modals/Script/instructions/ScriptInstructions.tsx b/apps/builder/src/features/publish/components/embeds/modals/Script/instructions/ScriptInstructions.tsx new file mode 100644 index 000000000..11768fcfc --- /dev/null +++ b/apps/builder/src/features/publish/components/embeds/modals/Script/instructions/ScriptInstructions.tsx @@ -0,0 +1,21 @@ +import { ScriptBubbleInstructions } from './ScriptBubbleInstructions' +import { ScriptPopupInstructions } from './ScriptPopupInstructions' +import { ScriptStandardInstructions } from './ScriptStandardInstructions' + +type Props = { + type: 'standard' | 'popup' | 'bubble' +} + +export const ScriptInstructions = ({ type }: Props) => { + switch (type) { + case 'standard': { + return + } + case 'popup': { + return + } + case 'bubble': { + return + } + } +} diff --git a/apps/builder/src/features/publish/components/embeds/modals/Script/instructions/ScriptPopupInstructions.tsx b/apps/builder/src/features/publish/components/embeds/modals/Script/instructions/ScriptPopupInstructions.tsx new file mode 100644 index 000000000..f4f467054 --- /dev/null +++ b/apps/builder/src/features/publish/components/embeds/modals/Script/instructions/ScriptPopupInstructions.tsx @@ -0,0 +1,34 @@ +import { CodeEditor } from '@/components/CodeEditor' +import { useTypebot } from '@/features/editor' +import { isCloudProdInstance } from '@/utils/helpers' +import { Stack, Text } from '@chakra-ui/react' +import { useState } from 'react' +import { env, getViewerUrl } from 'utils' +import { PopupSettings } from '../../../settings/PopupSettings' +import { parseInitPopupCode } from '../../../snippetParsers' +import { parseInlineScript } from '../../../snippetParsers/shared' + +export const ScriptPopupInstructions = () => { + const { typebot } = useTypebot() + const [inputValue, setInputValue] = useState() + + const scriptSnippet = parseInlineScript( + parseInitPopupCode({ + typebot: typebot?.publicId ?? '', + apiHost: isCloudProdInstance + ? undefined + : env('VIEWER_INTERNAL_URL') ?? getViewerUrl(), + autoShowDelay: inputValue, + }) + ) + + return ( + + setInputValue(settings.autoShowDelay)} + /> + Run this script to initialize the typebot: + + + ) +} diff --git a/apps/builder/src/features/publish/components/embeds/modals/Script/instructions/ScriptStandardInstructions.tsx b/apps/builder/src/features/publish/components/embeds/modals/Script/instructions/ScriptStandardInstructions.tsx new file mode 100644 index 000000000..48ed4ea6e --- /dev/null +++ b/apps/builder/src/features/publish/components/embeds/modals/Script/instructions/ScriptStandardInstructions.tsx @@ -0,0 +1,50 @@ +import { CodeEditor } from '@/components/CodeEditor' +import { useTypebot } from '@/features/editor' +import { isCloudProdInstance } from '@/utils/helpers' +import { Stack, Code, Text } from '@chakra-ui/react' +import { useState } from 'react' +import { env, getViewerUrl } from 'utils' +import { StandardSettings } from '../../../settings/StandardSettings' +import { parseInitStandardCode } from '../../../snippetParsers/standard' +import { parseStandardElementCode } from '../../Javascript/JavascriptStandardSnippet' +import { parseInlineScript } from '../../../snippetParsers/shared' + +export const ScriptStandardInstructions = () => { + const { typebot } = useTypebot() + const [inputValues, setInputValues] = useState<{ + heightLabel: string + widthLabel?: string + }>({ + heightLabel: '100%', + widthLabel: '100%', + }) + + const standardElementSnippet = parseStandardElementCode( + inputValues.widthLabel, + inputValues.heightLabel + ) + + const scriptSnippet = parseInlineScript( + parseInitStandardCode({ + typebot: typebot?.publicId ?? '', + apiHost: isCloudProdInstance + ? undefined + : env('VIEWER_INTERNAL_URL') ?? getViewerUrl(), + }) + ) + + return ( + + setInputValues({ ...settings })} + /> + + Make sure you have this typebot-standard element in your{' '} + {''}: + + + Then, run this script to initialize the typebot: + + + ) +} diff --git a/apps/builder/src/features/publish/components/embeds/snippetParsers/shared.ts b/apps/builder/src/features/publish/components/embeds/snippetParsers/shared.ts index 48bd9c8aa..40b46f4b4 100644 --- a/apps/builder/src/features/publish/components/embeds/snippetParsers/shared.ts +++ b/apps/builder/src/features/publish/components/embeds/snippetParsers/shared.ts @@ -1,4 +1,6 @@ import { BotProps } from '@typebot.io/js' +import parserBabel from 'prettier/parser-babel' +import prettier from 'prettier/standalone' import { isDefined } from 'utils' export const parseStringParam = (fieldName: string, fieldValue?: string) => @@ -30,3 +32,12 @@ export const parseReactBotProps = ({ typebot, apiHost }: BotProps) => { } export const typebotImportUrl = `https://cdn.jsdelivr.net/npm/@typebot.io/js@0.0.14/dist/web.js` + +export const parseInlineScript = (script: string) => + prettier.format( + `const typebotInitScript = document.createElement("script"); + typebotInitScript.type = "module"; + typebotInitScript.innerHTML = \`${script}\`; + document.body.append(typebotInitScript);`, + { parser: 'babel', plugins: [parserBabel] } + ) diff --git a/apps/docs/docs/embed/script.md b/apps/docs/docs/embed/script.md new file mode 100644 index 000000000..2892c6cd4 --- /dev/null +++ b/apps/docs/docs/embed/script.md @@ -0,0 +1,5 @@ +# Script + +The script embed option is useful only if you don't have access to the HTML tree of your application or if your website builder only allows you to inline script snippets. + +Otherwise, it's preferable to follow [HTML & Javascript](./html-javascript) embed instructions because the script snippets are just scripts that will inject the code from the HTML & Javascript embed method.