diff --git a/apps/builder/package.json b/apps/builder/package.json index 6b2744f9f6..97e2038ece 100644 --- a/apps/builder/package.json +++ b/apps/builder/package.json @@ -12,8 +12,10 @@ "test:report": "pnpm playwright show-report" }, "dependencies": { + "@chakra-ui/anatomy": "^2.1.0", "@chakra-ui/css-reset": "2.0.10", "@chakra-ui/react": "2.4.4", + "@chakra-ui/theme-tools": "^2.0.14", "@codemirror/lang-css": "6.0.1", "@codemirror/lang-html": "6.4.0", "@codemirror/lang-javascript": "6.1.2", @@ -51,6 +53,7 @@ "bot-engine": "workspace:*", "browser-image-compression": "2.0.0", "canvas-confetti": "1.6.0", + "chakra-react-select": "^4.4.3", "codemirror": "6.0.1", "cuid": "2.1.8", "deep-object-diff": "1.1.9", @@ -87,6 +90,7 @@ "styled-components": "5.3.6", "svg-round-corners": "0.4.1", "swr": "2.0.0", + "thememirror": "^2.0.1", "tinycolor2": "1.4.2", "trpc-openapi": "1.0.0", "typebot-js": "workspace:*", diff --git a/apps/builder/public/bots/onboarding-dark.json b/apps/builder/public/bots/onboarding-dark.json new file mode 100644 index 0000000000..8cb11c23f8 --- /dev/null +++ b/apps/builder/public/bots/onboarding-dark.json @@ -0,0 +1,638 @@ +{ + "id": "cl128l5vx007509il86n74oer", + "createdAt": "2022-03-22T14:33:05.037Z", + "updatedAt": "2022-03-22T16:33:37.928Z", + "name": "Onboarding", + "publishedTypebotId": "cl128n64i00092e69wenv1dlx", + "folderId": null, + "groups": [ + { + "id": "cl1265zct0000mb1a6bir36w7", + "blocks": [ + { + "id": "cl1265zct0001mb1afel460do", + "type": "start", + "label": "Start", + "groupId": "cl1265zct0000mb1a6bir36w7", + "outgoingEdgeId": "cl1266kt100082e6d1wks5dtp" + } + ], + "title": "Start", + "graphCoordinates": { "x": 0, "y": 0 } + }, + { + "id": "cl1266bah00032e6dgdnj4vgz", + "blocks": [ + { + "id": "cl1266bam00042e6dm0gn22vy", + "type": "Condition", + "items": [ + { + "id": "cl1266bam00052e6dn1sdjnax", + "type": 1, + "blockId": "cl1266bam00042e6dm0gn22vy", + "content": { + "comparisons": [ + { + "id": "cl1266cg600062e6d76qwk74v", + "variableId": "cl126f4hf000i2e6d8zvzc3t1", + "comparisonOperator": "Is set" + } + ], + "logicalOperator": "AND" + }, + "outgoingEdgeId": "cl12bk3j6000c2e69bak89ja9" + } + ], + "groupId": "cl1266bah00032e6dgdnj4vgz", + "outgoingEdgeId": "cl12bnfyd000g2e69g7lr3czq" + } + ], + "title": "Group #1", + "graphCoordinates": { "x": 266, "y": 162 } + }, + { + "id": "cl1267q1z000d2e6d949f2ge4", + "blocks": [ + { + "id": "cl1267q2c000e2e6dynjeg83n", + "type": "text", + "groupId": "cl1267q1z000d2e6d949f2ge4", + "content": { + "html": "
Welcome 👋
", + "richText": [ + { "type": "p", "children": [{ "text": "Welcome 👋" }] } + ], + "plainText": "Welcome 👋" + } + }, + { + "id": "cl1267y1u000f2e6d4rlglv6g", + "type": "text", + "groupId": "cl1267q1z000d2e6d949f2ge4", + "content": { + "html": "
What's your name?
", + "richText": [ + { "type": "p", "children": [{ "text": "What's your name?" }] } + ], + "plainText": "What's your name?" + } + }, + { + "id": "cl126820m000g2e6dfleq78bt", + "type": "text input", + "groupId": "cl1267q1z000d2e6d949f2ge4", + "options": { + "isLong": false, + "labels": { + "button": "Send", + "placeholder": "Type your answer..." + }, + "variableId": "cl126f4hf000i2e6d8zvzc3t1" + } + }, + { + "id": "cl1289y1s00142e6dvbkpvbje", + "type": "Code", + "groupId": "cl1267q1z000d2e6d949f2ge4", + "options": { + "name": "Store Name in DB", + "content": "postMessage({from: \"typebot\", action: \"storeName\", content: {{Name}}}, \"*\")" + }, + "outgoingEdgeId": "cl12bk56s000d2e69oll3nqxm" + } + ], + "title": "Group #3", + "graphCoordinates": { "x": 269, "y": 381 } + }, + { + "id": "cl126ixoq000p2e6dfbz9sype", + "blocks": [ + { + "id": "cl1266v6f000a2e6db7wj3ux7", + "type": "text", + "groupId": "cl126ixoq000p2e6dfbz9sype", + "content": { + "html": "
Welcome {{Name}} 👋
", + "richText": [ + { "type": "p", "children": [{ "text": "Welcome {{Name}} 👋" }] } + ], + "plainText": "Welcome {{Name}} 👋" + } + }, + { + "id": "cl126hb9m000l2e6d5qk3mohn", + "type": "text", + "groupId": "cl126ixoq000p2e6dfbz9sype", + "content": { + "html": "
I'm super pumped that you've decided to try out Typebot 😍
", + "richText": [ + { + "type": "p", + "children": [ + { + "text": "I'm super pumped that you've decided to try out Typebot 😍" + } + ] + } + ], + "plainText": "I'm super pumped that you've decided to try out Typebot 😍" + } + }, + { + "id": "cl126hpw1000m2e6dneousygl", + "type": "text", + "groupId": "cl126ixoq000p2e6dfbz9sype", + "content": { + "html": "
You are small steps away from meaningful, hyper-personalized experience for your users
", + "richText": [ + { + "type": "p", + "children": [ + { + "text": "You are small steps away from meaningful, hyper-personalized experience for your users" + } + ] + } + ], + "plainText": "You are small steps away from meaningful, hyper-personalized experience for your users" + } + }, + { + "id": "cl126guhd000k2e6d6ypkex9z", + "type": "text", + "groupId": "cl126ixoq000p2e6dfbz9sype", + "content": { + "html": "
Let's get you set up for your Typebot journey.
", + "richText": [ + { + "type": "p", + "children": [ + { "text": "Let's get you set up for your Typebot journey." } + ] + } + ], + "plainText": "Let's get you set up for your Typebot journey." + } + }, + { + "id": "cl126ixp9000q2e6dslh0zypi", + "type": "text", + "groupId": "cl126ixoq000p2e6dfbz9sype", + "content": { + "html": "
Do you work for a specific company?
", + "richText": [ + { + "type": "p", + "children": [{ "text": "Do you work for a specific company?" }] + } + ], + "plainText": "Do you work for a specific company?" + } + }, + { + "id": "cl126jb2q000r2e6dgqlnxnt8", + "type": "choice input", + "items": [ + { + "id": "cl126jb2q000s2e6dm60yq5p2", + "type": 0, + "blockId": "cl126jb2q000r2e6dgqlnxnt8", + "content": "Yes", + "outgoingEdgeId": "cl126jsoo000x2e6ditu7dgf8" + }, + { + "id": "cl126jc5a000t2e6dqv91w7j6", + "type": 0, + "blockId": "cl126jb2q000r2e6dgqlnxnt8", + "content": "No", + "outgoingEdgeId": "cl126l5tx00122e6dmisci6h5" + } + ], + "groupId": "cl126ixoq000p2e6dfbz9sype", + "options": { "buttonLabel": "Send", "isMultipleChoice": false } + } + ], + "title": "Group #5", + "graphCoordinates": { "x": 614, "y": 244 } + }, + { + "id": "cl126jioj000u2e6dqssno3hv", + "blocks": [ + { + "id": "cl126jioz000v2e6dwrk1f2cb", + "type": "text input", + "groupId": "cl126jioj000u2e6dqssno3hv", + "options": { + "isLong": false, + "labels": { + "button": "Send", + "placeholder": "Type the company name..." + }, + "variableId": "cl126jqww000w2e6dq9yv4ifq" + } + }, + { + "id": "cl12890kw00132e6dp9v5dexm", + "type": "Code", + "groupId": "cl126jioj000u2e6dqssno3hv", + "options": { + "name": "Store company in DB", + "content": "postMessage({from: \"typebot\", action: \"storeCompany\", content: {{Company}}}, \"*\")" + }, + "outgoingEdgeId": "cl128ag8i00162e6dufv3tgo0" + } + ], + "title": "Group #6", + "graphCoordinates": { "x": 969, "y": 308 } + }, + { + "id": "cl126krbp00102e6dnjelmfa1", + "blocks": [ + { + "id": "cl126krck00112e6d1m6ctxpn", + "type": "text", + "groupId": "cl126krbp00102e6dnjelmfa1", + "content": { + "html": "
What type of forms are you planning to build with Typebot?
", + "richText": [ + { + "type": "p", + "children": [ + { + "text": "What type of forms are you planning to build with Typebot?" + } + ] + } + ], + "plainText": "What type of forms are you planning to build with Typebot?" + } + }, + { + "id": "cl126lb8v00142e6duv5qe08l", + "type": "choice input", + "items": [ + { + "id": "cl126onz9001g2e6dk0nbjeu6", + "type": 0, + "blockId": "cl126lb8v00142e6duv5qe08l", + "content": "Lead qualification" + }, + { + "id": "cl126lm6c00172e6d1pfvdiju", + "type": 0, + "blockId": "cl126lb8v00142e6duv5qe08l", + "content": "Customer support" + }, + { + "id": "cl126orr2001h2e6d0fqs7737", + "type": 0, + "blockId": "cl126lb8v00142e6duv5qe08l", + "content": "Customer research" + }, + { + "id": "cl126oudu001i2e6dktwi7qwv", + "type": 0, + "blockId": "cl126lb8v00142e6duv5qe08l", + "content": "User onboarding" + }, + { + "id": "cl126luv500192e6dl317ssyr", + "type": 0, + "blockId": "cl126lb8v00142e6duv5qe08l", + "content": "Quizzes" + }, + { + "id": "cl126lz8q001a2e6d8b9lb3b5", + "type": 0, + "blockId": "cl126lb8v00142e6duv5qe08l", + "content": "Content distribution" + }, + { + "id": "cl126nf7k001d2e6dg2zczjgz", + "type": 0, + "blockId": "cl126lb8v00142e6duv5qe08l", + "content": "FAQ" + }, + { + "id": "cl126ngy8001e2e6ddfo5s9fm", + "type": 0, + "blockId": "cl126lb8v00142e6duv5qe08l", + "content": "Other" + } + ], + "groupId": "cl126krbp00102e6dnjelmfa1", + "options": { + "variableId": "cl126mo3t001b2e6dvyi16bkd", + "buttonLabel": "Send", + "isMultipleChoice": true + } + }, + { + "id": "cl128ain900172e6d1osj4u90", + "type": "Code", + "groupId": "cl126krbp00102e6dnjelmfa1", + "options": { + "name": "Store categories in DB", + "content": "postMessage({from: \"typebot\", action: \"storeCategories\", content: {{Categories}}}, \"*\")" + }, + "outgoingEdgeId": "cl128azam00182e6dct61k7v5" + } + ], + "title": "Group #6", + "graphCoordinates": { "x": 1218, "y": 510 } + }, + { + "id": "cl126p75m001j2e6d73qmes0m", + "blocks": [ + { + "id": "cl126p76d001k2e6dbhnf2ysq", + "type": "text", + "groupId": "cl126p75m001j2e6d73qmes0m", + "content": { + "html": "
Thank you for answering those questions!
", + "richText": [ + { + "type": "p", + "children": [ + { "text": "Thank you for answering those questions!" } + ] + } + ], + "plainText": "Thank you for answering those questions!" + } + }, + { + "id": "cl128375600112e6d4l0jtuyf", + "type": "Code", + "groupId": "cl126p75m001j2e6d73qmes0m", + "options": { + "name": "Shoot confettis", + "content": "postMessage({from: \"typebot\", action: \"shootConfettis\"}, \"*\")" + } + }, + { + "id": "cl126rfy6001t2e6d21gcb6b0", + "type": "image", + "groupId": "cl126p75m001j2e6d73qmes0m", + "content": { + "url": "https://media4.giphy.com/media/l0amJzVHIAfl7jMDos/giphy.gif?cid=fe3852a3i4c33635xdtj3nesr9uq4zteujaab6b0jr42gpxx&rid=giphy.gif&ct=g" + } + }, + { + "id": "cl126txta001y2e6dtxrbsnek", + "type": "text", + "groupId": "cl126p75m001j2e6d73qmes0m", + "content": { + "html": "
You can reach out to me using the contact bubble on the bottom right corner 🤓
", + "richText": [ + { + "type": "p", + "children": [ + { + "text": "You can reach out to me using the contact bubble on the bottom right corner 🤓" + } + ] + } + ], + "plainText": "You can reach out to me using the contact bubble on the bottom right corner 🤓" + } + }, + { + "id": "cl12buyly00172e6991bz38ch", + "groupId": "cl126p75m001j2e6d73qmes0m", + "type": "text", + "content": { + "html": "
Let's create your first typebot...
", + "richText": [ + { + "type": "p", + "children": [{ "text": "Let's create your first typebot..." }] + } + ], + "plainText": "Let's create your first typebot..." + } + }, + { + "id": "cl12bwpi800182e69kcivnp1s", + "groupId": "cl126p75m001j2e6d73qmes0m", + "type": "Code", + "options": { + "name": "Go to typebot creation", + "content": "setTimeout(() => {window.location.href = \"https://app.typebot.io/typebots/create?isFirstBot=true\"}, 4000)" + } + } + ], + "title": "Group #7", + "graphCoordinates": { "x": 1612, "y": 1103 } + }, + { + "id": "cl126pv6w001n2e6dp0qkvthu", + "blocks": [ + { + "id": "cl127yxym000b2e6d9hksxo6h", + "type": "text", + "groupId": "cl126pv6w001n2e6dp0qkvthu", + "content": { + "html": "
What else?
", + "richText": [ + { "type": "p", "children": [{ "text": "What else?" }] } + ], + "plainText": "What else?" + } + }, + { + "id": "cl126pv7n001o2e6dajltc4qz", + "type": "text input", + "groupId": "cl126pv6w001n2e6dp0qkvthu", + "options": { + "isLong": false, + "labels": { "button": "Send", "placeholder": "Type your answer" }, + "variableId": "cl126q38p001q2e6d0hj23f6b" + } + }, + { + "id": "cl128b34o00192e6dqjxs3cxf", + "type": "Code", + "groupId": "cl126pv6w001n2e6dp0qkvthu", + "options": { + "name": "Store Other categories in DB", + "content": "postMessage({from: \"typebot\", action: \"storeOtherCategories\", content: {{Other categories}}}, \"*\")" + }, + "outgoingEdgeId": "cl128c0fu001a2e6droq69g6z" + } + ], + "title": "Group #8", + "graphCoordinates": { "x": 1943, "y": 895 } + }, + { + "id": "cl1278gx9002v2e6d4kf3v89s", + "blocks": [ + { + "id": "cl1278gyk002w2e6d744eb87n", + "type": "Condition", + "items": [ + { + "id": "cl1278gyk002x2e6dwmpzs3nf", + "type": 1, + "blockId": "cl1278gyk002w2e6d744eb87n", + "content": { + "comparisons": [ + { + "id": "cl1278irq002y2e6dv4965diw", + "value": "Other", + "variableId": "cl126mo3t001b2e6dvyi16bkd", + "comparisonOperator": "Contains" + } + ], + "logicalOperator": "AND" + }, + "outgoingEdgeId": "cl1278r3b002z2e6d6d6rk9dh" + } + ], + "groupId": "cl1278gx9002v2e6d4kf3v89s", + "outgoingEdgeId": "cl1278trd00312e6dxmzhcmmn" + } + ], + "title": "Group #13", + "graphCoordinates": { "x": 1585, "y": 792 } + } + ], + "variables": [ + { "id": "cl126f4hf000i2e6d8zvzc3t1", "name": "Name" }, + { "id": "cl126jqww000w2e6dq9yv4ifq", "name": "Company" }, + { "id": "cl126mo3t001b2e6dvyi16bkd", "name": "Categories" }, + { "id": "cl126q38p001q2e6d0hj23f6b", "name": "Other categories" } + ], + "edges": [ + { + "id": "cl1266kt100082e6d1wks5dtp", + "to": { "groupId": "cl1266bah00032e6dgdnj4vgz" }, + "from": { + "blockId": "cl1265zct0001mb1afel460do", + "groupId": "cl1265zct0000mb1a6bir36w7" + } + }, + { + "id": "cl126jsoo000x2e6ditu7dgf8", + "to": { "groupId": "cl126jioj000u2e6dqssno3hv" }, + "from": { + "itemId": "cl126jb2q000s2e6dm60yq5p2", + "blockId": "cl126jb2q000r2e6dgqlnxnt8", + "groupId": "cl126ixoq000p2e6dfbz9sype" + } + }, + { + "id": "cl126l5tx00122e6dmisci6h5", + "to": { "groupId": "cl126krbp00102e6dnjelmfa1" }, + "from": { + "itemId": "cl126jc5a000t2e6dqv91w7j6", + "blockId": "cl126jb2q000r2e6dgqlnxnt8", + "groupId": "cl126ixoq000p2e6dfbz9sype" + } + }, + { + "id": "cl1278r3b002z2e6d6d6rk9dh", + "to": { "groupId": "cl126pv6w001n2e6dp0qkvthu" }, + "from": { + "itemId": "cl1278gyk002x2e6dwmpzs3nf", + "blockId": "cl1278gyk002w2e6d744eb87n", + "groupId": "cl1278gx9002v2e6d4kf3v89s" + } + }, + { + "id": "cl1278trd00312e6dxmzhcmmn", + "to": { "groupId": "cl126p75m001j2e6d73qmes0m" }, + "from": { + "blockId": "cl1278gyk002w2e6d744eb87n", + "groupId": "cl1278gx9002v2e6d4kf3v89s" + } + }, + { + "id": "cl128ag8i00162e6dufv3tgo0", + "to": { "groupId": "cl126krbp00102e6dnjelmfa1" }, + "from": { + "blockId": "cl12890kw00132e6dp9v5dexm", + "groupId": "cl126jioj000u2e6dqssno3hv" + } + }, + { + "id": "cl128azam00182e6dct61k7v5", + "to": { "groupId": "cl1278gx9002v2e6d4kf3v89s" }, + "from": { + "blockId": "cl128ain900172e6d1osj4u90", + "groupId": "cl126krbp00102e6dnjelmfa1" + } + }, + { + "id": "cl128c0fu001a2e6droq69g6z", + "to": { "groupId": "cl126p75m001j2e6d73qmes0m" }, + "from": { + "blockId": "cl128b34o00192e6dqjxs3cxf", + "groupId": "cl126pv6w001n2e6dp0qkvthu" + } + }, + { + "from": { + "groupId": "cl1266bah00032e6dgdnj4vgz", + "blockId": "cl1266bam00042e6dm0gn22vy", + "itemId": "cl1266bam00052e6dn1sdjnax" + }, + "to": { "groupId": "cl126ixoq000p2e6dfbz9sype" }, + "id": "cl12bk3j6000c2e69bak89ja9" + }, + { + "from": { + "groupId": "cl1267q1z000d2e6d949f2ge4", + "blockId": "cl1289y1s00142e6dvbkpvbje" + }, + "to": { + "groupId": "cl126ixoq000p2e6dfbz9sype", + "blockId": "cl126hb9m000l2e6d5qk3mohn" + }, + "id": "cl12bk56s000d2e69oll3nqxm" + }, + { + "from": { + "groupId": "cl1266bah00032e6dgdnj4vgz", + "blockId": "cl1266bam00042e6dm0gn22vy" + }, + "to": { "groupId": "cl1267q1z000d2e6d949f2ge4" }, + "id": "cl12bnfyd000g2e69g7lr3czq" + } + ], + "theme": { + "chat": { + "inputs": { + "color": "#ffffff", + "backgroundColor": "#1e293b", + "placeholderColor": "#9095A0" + }, + "buttons": { "color": "#ffffff", "backgroundColor": "#1a5fff" }, + "hostBubbles": { "color": "#ffffff", "backgroundColor": "#1e293b" }, + "guestBubbles": { "color": "#FFFFFF", "backgroundColor": "#FF8E21" }, + "hostAvatar": { + "isEnabled": true, + "url": "https://s3.eu-west-3.amazonaws.com/typebot/public/typebots/cl0s4zy9m247009l1ybkoojxe/me-square.png" + } + }, + "general": { + "font": "Open Sans", + "background": { "type": "Color", "content": "#171923" } + }, + "customCss": ".typebot-button {box-shadow: inset 0 1px 0 0 rgb(255 255 255/0.2)}" + }, + "settings": { + "general": { + "isBrandingEnabled": true, + "isInputPrefillEnabled": true, + "isNewResultOnRefreshEnabled": false + }, + "metadata": { + "description": "Build beautiful conversational forms and embed them directly in your applications without a line of code. Triple your response rate and collect answers that has more value compared to a traditional form." + }, + "typingEmulation": { "speed": 300, "enabled": true, "maxDelay": 1.5 } + }, + "publicId": "typebot-onboarding", + "customDomain": null +} diff --git a/apps/builder/public/images/dark-mode.png b/apps/builder/public/images/dark-mode.png new file mode 100644 index 0000000000..cbc025c555 Binary files /dev/null and b/apps/builder/public/images/dark-mode.png differ diff --git a/apps/builder/public/images/light-mode.png b/apps/builder/public/images/light-mode.png new file mode 100644 index 0000000000..9b909ed256 Binary files /dev/null and b/apps/builder/public/images/light-mode.png differ diff --git a/apps/builder/public/images/system-mode.png b/apps/builder/public/images/system-mode.png new file mode 100644 index 0000000000..e53c09220f Binary files /dev/null and b/apps/builder/public/images/system-mode.png differ diff --git a/apps/builder/src/assets/styles/codeMirror.css b/apps/builder/src/assets/styles/codeMirror.css index 67cf4647c4..76f3b6dba8 100644 --- a/apps/builder/src/assets/styles/codeMirror.css +++ b/apps/builder/src/assets/styles/codeMirror.css @@ -1,9 +1,9 @@ .cm-editor { outline: 0px solid transparent !important; height: 100%; + border-radius: 1rem; } .cm-scroller { border-radius: 5px; - border: 1px solid #e5e7eb; } diff --git a/apps/builder/src/assets/styles/plate.css b/apps/builder/src/assets/styles/plate.css index cf36697c2a..d2499a7d7f 100644 --- a/apps/builder/src/assets/styles/plate.css +++ b/apps/builder/src/assets/styles/plate.css @@ -10,9 +10,6 @@ text-decoration: underline; } -.slate-ToolbarButton-active { - color: blue !important; -} .slate-ToolbarButton-active > svg { stroke-width: 2px; } @@ -22,7 +19,6 @@ } .slate-a { - color: blue !important; text-decoration: underline; } diff --git a/apps/builder/src/components/AlertInfo.tsx b/apps/builder/src/components/AlertInfo.tsx index 800259646e..44fcd112c9 100644 --- a/apps/builder/src/components/AlertInfo.tsx +++ b/apps/builder/src/components/AlertInfo.tsx @@ -1,7 +1,7 @@ import { AlertProps, Alert, AlertIcon } from '@chakra-ui/react' export const AlertInfo = (props: AlertProps) => ( - + {props.children} diff --git a/apps/builder/src/components/CodeEditor.tsx b/apps/builder/src/components/CodeEditor.tsx index 0bb14c6918..966a0607f8 100644 --- a/apps/builder/src/components/CodeEditor.tsx +++ b/apps/builder/src/components/CodeEditor.tsx @@ -1,4 +1,10 @@ -import { Box, BoxProps, HStack } from '@chakra-ui/react' +import { + Box, + BoxProps, + HStack, + useColorMode, + useColorModeValue, +} from '@chakra-ui/react' import { EditorView, basicSetup } from 'codemirror' import { EditorState } from '@codemirror/state' import { json, jsonParseLinter } from '@codemirror/lang-json' @@ -11,6 +17,7 @@ import { linter, LintSource } from '@codemirror/lint' import { VariablesButton } from '@/features/variables' import { Variable } from 'models' import { env } from 'utils' +import { espresso, dracula } from 'thememirror' const linterExtension = linter(jsonParseLinter() as unknown as LintSource) @@ -33,6 +40,7 @@ export const CodeEditor = ({ debounceTimeout = 1000, ...props }: Props & Omit) => { + const isDark = useColorMode().colorMode === 'dark' const editorContainer = useRef(null) const editorView = useRef(null) const [, setPlainTextValue] = useState(value) @@ -84,6 +92,7 @@ export const CodeEditor = ({ updateListenerExtension, basicSetup, EditorState.readOnly.of(isReadOnly), + isDark ? dracula : espresso, ] if (lang === 'json') { extensions.push(json()) @@ -130,7 +139,13 @@ export const CodeEditor = ({ } return ( - + { + const bg = useColorModeValue('gray.100', 'gray.700') + return ( {({ onClose }: { onClose: () => void }) => ( @@ -32,7 +35,9 @@ export const EditableEmojiOrImageIcon = ({ cursor="pointer" p="2" rounded="md" - _hover={{ bgColor: 'gray.100' }} + _hover={{ + bg, + }} transition="background-color 0.2s" data-testid="editable-icon" > diff --git a/apps/builder/src/components/SearchableDropdown.tsx b/apps/builder/src/components/SearchableDropdown.tsx index 00a00c0b11..3260dcad3f 100644 --- a/apps/builder/src/components/SearchableDropdown.tsx +++ b/apps/builder/src/components/SearchableDropdown.tsx @@ -3,12 +3,13 @@ import { useOutsideClick, Flex, Popover, - PopoverTrigger, Input, PopoverContent, Button, InputProps, HStack, + useColorModeValue, + PopoverAnchor, } from '@chakra-ui/react' import { Variable } from 'models' import { useState, useRef, useEffect, ChangeEvent, ReactNode } from 'react' @@ -32,6 +33,7 @@ export const SearchableDropdown = ({ onValueChange, ...inputProps }: Props) => { + const bg = useColorModeValue('gray.200', 'gray.700') const [carretPosition, setCarretPosition] = useState(0) const { onOpen, onClose, isOpen } = useDisclosure() const [inputValue, setInputValue] = useState(selectedItem ?? '') @@ -172,13 +174,13 @@ export const SearchableDropdown = ({ offset={[0, 0]} isLazy > - + )} - + {typeof item === 'string' ? item : item.label} diff --git a/apps/builder/src/components/VariableSearchInput.tsx b/apps/builder/src/components/VariableSearchInput.tsx index ee0f193418..eb725eee2a 100644 --- a/apps/builder/src/components/VariableSearchInput.tsx +++ b/apps/builder/src/components/VariableSearchInput.tsx @@ -1,6 +1,5 @@ import { useDisclosure, - useOutsideClick, Flex, Popover, PopoverTrigger, @@ -10,6 +9,9 @@ import { InputProps, IconButton, HStack, + useColorModeValue, + PopoverAnchor, + useOutsideClick, } from '@chakra-ui/react' import { EditIcon, PlusIcon, TrashIcon } from '@/components/icons' import { useTypebot } from '@/features/editor' @@ -35,6 +37,7 @@ export const VariableSearchInput = ({ debounceTimeout = 1000, ...inputProps }: Props) => { + const bg = useColorModeValue('gray.200', 'gray.700') const { onOpen, onClose, isOpen } = useDisclosure() const { typebot, createVariable, deleteVariable, updateVariable } = useTypebot() @@ -56,7 +59,7 @@ export const VariableSearchInput = ({ number | undefined >() const dropdownRef = useRef(null) - const inputRef = useRef(null) + const inputRef = useRef(null) const createVariableItemRef = useRef(null) const itemsRef = useRef<(HTMLButtonElement | null)[]>([]) @@ -80,7 +83,6 @@ export const VariableSearchInput = ({ const onInputChange = (e: ChangeEvent) => { setInputValue(e.target.value) debounced(e.target.value) - onOpen() if (e.target.value === '') { onSelectVariable(undefined) setFilteredItems([...variables.slice(0, 50)]) @@ -175,18 +177,18 @@ export const VariableSearchInput = ({ isLazy offset={[0, 2]} > - + - + } - bgColor={keyboardFocusIndex === 0 ? 'gray.200' : 'transparent'} + bgColor={keyboardFocusIndex === 0 ? bg : 'transparent'} > Create "{inputValue}" @@ -232,9 +234,7 @@ export const VariableSearchInput = ({ variant="ghost" justifyContent="space-between" bgColor={ - keyboardFocusIndex === indexInList - ? 'gray.200' - : 'transparent' + keyboardFocusIndex === indexInList ? bg : 'transparent' } > {item.name} diff --git a/apps/builder/src/components/inputs/TextBox.tsx b/apps/builder/src/components/inputs/TextBox.tsx index e715fa09c2..e713cbb680 100644 --- a/apps/builder/src/components/inputs/TextBox.tsx +++ b/apps/builder/src/components/inputs/TextBox.tsx @@ -106,7 +106,6 @@ export const TextBox = ({ onKeyUp={handleKeyUp} onClick={handleKeyUp} onChange={handleChange} - bgColor={'white'} {...props} /> ) diff --git a/apps/builder/src/features/account/components/UserPreferenceForm/AppearanceRadioGroup.tsx b/apps/builder/src/features/account/components/UserPreferenceForm/AppearanceRadioGroup.tsx new file mode 100644 index 0000000000..307b63e688 --- /dev/null +++ b/apps/builder/src/features/account/components/UserPreferenceForm/AppearanceRadioGroup.tsx @@ -0,0 +1,66 @@ +import { + RadioGroup, + HStack, + VStack, + Stack, + Radio, + Image, + Text, +} from '@chakra-ui/react' + +const appearanceData = [ + { + value: 'light', + label: 'Light', + image: '/images/light-mode.png', + }, + { + value: 'dark', + label: 'Dark', + image: '/images/dark-mode.png', + }, + { + value: 'system', + label: 'System', + image: '/images/system-mode.png', + }, +] + +type Props = { + defaultValue: string + onChange: (value: string) => void +} + +export const AppearanceRadioGroup = ({ defaultValue, onChange }: Props) => ( + + + {appearanceData.map((option) => ( + + + Theme preview + + {option.label} + + + + + + ))} + + +) diff --git a/apps/builder/src/features/account/components/UserPreferenceForm/GraphNavigationRadioGroup.tsx b/apps/builder/src/features/account/components/UserPreferenceForm/GraphNavigationRadioGroup.tsx new file mode 100644 index 0000000000..f5b71e887c --- /dev/null +++ b/apps/builder/src/features/account/components/UserPreferenceForm/GraphNavigationRadioGroup.tsx @@ -0,0 +1,64 @@ +import { MouseIcon, LaptopIcon } from '@/components/icons' +import { + HStack, + Radio, + RadioGroup, + Stack, + VStack, + Text, +} from '@chakra-ui/react' +import { GraphNavigation } from 'db' + +const graphNavigationData = [ + { + value: GraphNavigation.MOUSE, + label: 'Mouse', + description: + 'Move by dragging the board and zoom in/out using the scroll wheel', + icon: , + }, + { + value: GraphNavigation.TRACKPAD, + label: 'Trackpad', + description: 'Move the board using 2 fingers and zoom in/out by pinching', + icon: , + }, +] + +type Props = { + defaultValue: string + onChange: (value: string) => void +} +export const GraphNavigationRadioGroup = ({ + defaultValue, + onChange, +}: Props) => ( + + + {graphNavigationData.map((option) => ( + + + {option.icon} + + {option.label} + {option.description} + + + + + + ))} + + +) diff --git a/apps/builder/src/features/account/components/UserPreferenceForm/UserPreferencesForm.tsx b/apps/builder/src/features/account/components/UserPreferenceForm/UserPreferencesForm.tsx new file mode 100644 index 0000000000..514b3f3eb7 --- /dev/null +++ b/apps/builder/src/features/account/components/UserPreferenceForm/UserPreferencesForm.tsx @@ -0,0 +1,44 @@ +import { Stack, Heading, useColorMode } from '@chakra-ui/react' +import { useUser } from '@/features/account' +import { GraphNavigation } from 'db' +import React, { useEffect } from 'react' +import { GraphNavigationRadioGroup } from './GraphNavigationRadioGroup' +import { AppearanceRadioGroup } from './AppearanceRadioGroup' + +export const UserPreferencesForm = () => { + const { setColorMode } = useColorMode() + const { saveUser, user } = useUser() + + useEffect(() => { + if (!user?.graphNavigation) + saveUser({ graphNavigation: GraphNavigation.TRACKPAD }) + }, [saveUser, user?.graphNavigation]) + + const changeGraphNavigation = async (value: string) => { + await saveUser({ graphNavigation: value as GraphNavigation }) + } + + const changeAppearance = async (value: string) => { + setColorMode(value) + await saveUser({ preferredAppAppearance: value }) + } + + return ( + + + Editor Navigation + + + + Appearance + + + + ) +} diff --git a/apps/builder/src/features/account/components/index.ts b/apps/builder/src/features/account/components/index.ts new file mode 100644 index 0000000000..1ac04e4843 --- /dev/null +++ b/apps/builder/src/features/account/components/index.ts @@ -0,0 +1,2 @@ +export * from './MyAccountForm' +export * from './UserPreferenceForm/UserPreferencesForm' diff --git a/apps/builder/src/features/account/index.ts b/apps/builder/src/features/account/index.ts index e1212c7954..9c50f21b02 100644 --- a/apps/builder/src/features/account/index.ts +++ b/apps/builder/src/features/account/index.ts @@ -1,3 +1,3 @@ export { UserProvider, useUser } from './UserProvider' export type { ApiTokenFromServer } from './types' -export { MyAccountForm } from './components/MyAccountForm' +export * from './components' diff --git a/apps/builder/src/features/analytics/components/AnalyticsGraphContainer.tsx b/apps/builder/src/features/analytics/components/AnalyticsGraphContainer.tsx index dcdaed8e30..d166bfb645 100644 --- a/apps/builder/src/features/analytics/components/AnalyticsGraphContainer.tsx +++ b/apps/builder/src/features/analytics/components/AnalyticsGraphContainer.tsx @@ -1,4 +1,9 @@ -import { Flex, Spinner, useDisclosure } from '@chakra-ui/react' +import { + Flex, + Spinner, + useColorModeValue, + useDisclosure, +} from '@chakra-ui/react' import { useToast } from '@/hooks/useToast' import { useTypebot } from '@/features/editor' import { Stats } from 'models' @@ -24,7 +29,13 @@ export const AnalyticsGraphContainer = ({ stats }: { stats?: Stats }) => { diff --git a/apps/builder/src/features/analytics/components/StatsCards.tsx b/apps/builder/src/features/analytics/components/StatsCards.tsx index 7eb32e611f..7660139743 100644 --- a/apps/builder/src/features/analytics/components/StatsCards.tsx +++ b/apps/builder/src/features/analytics/components/StatsCards.tsx @@ -5,6 +5,7 @@ import { Stat, StatLabel, StatNumber, + useColorModeValue, } from '@chakra-ui/react' import { Stats } from 'models' import React from 'react' @@ -13,9 +14,11 @@ export const StatsCards = ({ stats, ...props }: { stats?: Stats } & GridProps) => { + const bg = useColorModeValue('white', 'gray.900') + return ( - + Views {stats ? ( {stats.totalViews} @@ -23,7 +26,7 @@ export const StatsCards = ({ )} - + Starts {stats ? ( {stats.totalStarts} @@ -31,7 +34,7 @@ export const StatsCards = ({ )} - + Completion rate {stats ? ( diff --git a/apps/builder/src/features/auth/constants.ts b/apps/builder/src/features/auth/constants.ts index efd1e73b97..68ad70e92f 100644 --- a/apps/builder/src/features/auth/constants.ts +++ b/apps/builder/src/features/auth/constants.ts @@ -8,6 +8,7 @@ export const mockedUser: User = { createdAt: new Date(), emailVerified: null, graphNavigation: 'TRACKPAD', + preferredAppAppearance: null, image: 'https://avatars.githubusercontent.com/u/16015833?v=4', lastActivityAt: new Date(), onboardingCategories: [], diff --git a/apps/builder/src/features/billing/components/BillingContent/CurrentSubscriptionContent.tsx b/apps/builder/src/features/billing/components/BillingContent/CurrentSubscriptionContent.tsx index 3234c90159..1e3cca667c 100644 --- a/apps/builder/src/features/billing/components/BillingContent/CurrentSubscriptionContent.tsx +++ b/apps/builder/src/features/billing/components/BillingContent/CurrentSubscriptionContent.tsx @@ -44,7 +44,7 @@ export const CurrentSubscriptionContent = ({ const isSubscribed = (plan === Plan.STARTER || plan === Plan.PRO) && stripeId return ( - + Subscription Current workspace subscription: @@ -70,7 +70,7 @@ export const CurrentSubscriptionContent = ({ {isSubscribed && !isCancelling && ( <> - + Need to change payment method or billing information? Head over to your billing portal: diff --git a/apps/builder/src/features/billing/components/ChangePlanForm/ProPlanContent.tsx b/apps/builder/src/features/billing/components/ChangePlanForm/ProPlanContent.tsx index 20a1ea92ea..8bfc48dc0b 100644 --- a/apps/builder/src/features/billing/components/ChangePlanForm/ProPlanContent.tsx +++ b/apps/builder/src/features/billing/components/ChangePlanForm/ProPlanContent.tsx @@ -12,6 +12,7 @@ import { Tooltip, Flex, Tag, + useColorModeValue, } from '@chakra-ui/react' import { ChevronLeftIcon } from '@/components/icons' import { useWorkspace } from '@/features/workspace' @@ -126,7 +127,7 @@ export const ProPlanContent = ({ flex="1" flexShrink={0} borderWidth="1px" - borderColor="blue.500" + borderColor={useColorModeValue('blue.500', 'blue.300')} rounded="lg" > @@ -134,6 +135,7 @@ export const ProPlanContent = ({ pos="absolute" top="-10px" colorScheme="blue" + bg={useColorModeValue('blue.500', 'blue.400')} variant="solid" fontWeight="semibold" style={{ marginTop: 0 }} diff --git a/apps/builder/src/features/blocks/bubbles/textBubble/components/TextBubbleEditor/TextBubbleEditor.tsx b/apps/builder/src/features/blocks/bubbles/textBubble/components/TextBubbleEditor/TextBubbleEditor.tsx index 4ee1f71f79..4557c06666 100644 --- a/apps/builder/src/features/blocks/bubbles/textBubble/components/TextBubbleEditor/TextBubbleEditor.tsx +++ b/apps/builder/src/features/blocks/bubbles/textBubble/components/TextBubbleEditor/TextBubbleEditor.tsx @@ -1,6 +1,7 @@ import { Flex, Stack, + useColorModeValue, useEventListener, useOutsideClick, } from '@chakra-ui/react' @@ -20,6 +21,7 @@ import { ReactEditor } from 'slate-react' import { serializeHtml } from '@udecode/plate-serializer-html' import { parseHtmlStringToPlainText } from '../../utils' import { VariableSearchInput } from '@/components/VariableSearchInput' +import { colors } from '@/lib/theme' type TextBubbleEditorContentProps = { id: string @@ -32,6 +34,7 @@ const TextBubbleEditorContent = ({ textEditorValue, onClose, }: TextBubbleEditorContentProps) => { + const variableInputBg = useColorModeValue('white', 'gray.900') const editor = usePlateEditorRef() const varDropdownRef = useRef(null) const rememberedSelection = useRef(null) @@ -112,12 +115,27 @@ const TextBubbleEditorContent = ({ pos="relative" spacing={0} cursor="text" + sx={{ + '.slate-ToolbarButton-active': { + color: useColorModeValue('blue.500', 'blue.300') + ' !important', + }, + '.PlateFloatingLink___StyledFloatingLinkInsertRoot-sc-1bralnd-8': { + backgroundColor: useColorModeValue('white', 'gray.800'), + borderWidth: 1, + }, + '.PlateFloatingLink___StyledDiv2-sc-1bralnd-2': { + backgroundColor: useColorModeValue('gray.200', 'gray.600'), + }, + '.slate-a': { + color: useColorModeValue('blue.500', 'blue.300'), + }, + }} > setIsVariableDropdownOpen(true)} /> { if (editor.children.length === 0) return @@ -138,7 +156,7 @@ const TextBubbleEditorContent = ({ ref={varDropdownRef} shadow="lg" rounded="md" - bgColor="white" + bg={variableInputBg} w="250px" zIndex={10} > diff --git a/apps/builder/src/features/blocks/bubbles/textBubble/components/TextBubbleEditor/ToolBar.tsx b/apps/builder/src/features/blocks/bubbles/textBubble/components/TextBubbleEditor/ToolBar.tsx index cc85e88ffc..eec504bb12 100644 --- a/apps/builder/src/features/blocks/bubbles/textBubble/components/TextBubbleEditor/ToolBar.tsx +++ b/apps/builder/src/features/blocks/bubbles/textBubble/components/TextBubbleEditor/ToolBar.tsx @@ -1,4 +1,9 @@ -import { StackProps, HStack, IconButton } from '@chakra-ui/react' +import { + StackProps, + HStack, + IconButton, + useColorModeValue, +} from '@chakra-ui/react' import { MARK_BOLD, MARK_ITALIC, @@ -27,7 +32,7 @@ export const ToolBar = ({ onVariablesButtonClick, ...props }: Props) => { } return ( { if (!typebot || !localWebhook) return setIsTestResponseLoading(true) - await Promise.all([updateWebhook(localWebhook.id, localWebhook), save()]) + await updateWebhook(localWebhook.id, localWebhook) + await save() const { data, error } = await executeWebhook( typebot.id, convertVariablesForTestToVariables( diff --git a/apps/builder/src/features/collaboration/components/CollaborationMenuButton/CollaborationList.tsx b/apps/builder/src/features/collaboration/components/CollaborationMenuButton/CollaborationList.tsx index 29ecfc06b4..0314d32b55 100644 --- a/apps/builder/src/features/collaboration/components/CollaborationMenuButton/CollaborationList.tsx +++ b/apps/builder/src/features/collaboration/components/CollaborationMenuButton/CollaborationList.tsx @@ -12,6 +12,7 @@ import { Text, Tag, Flex, + Skeleton, } from '@chakra-ui/react' import { ChevronLeftIcon } from '@/components/icons' import { useToast } from '@/hooks/useToast' @@ -205,9 +206,12 @@ export const CollaborationList = () => { /> ))} {(isCollaboratorsLoading || isInvitationsLoading) && ( - - - + + + + + + )} diff --git a/apps/builder/src/features/dashboard/components/OnboardingModal.tsx b/apps/builder/src/features/dashboard/components/OnboardingModal.tsx index 5e95abd366..41f16d9ca9 100644 --- a/apps/builder/src/features/dashboard/components/OnboardingModal.tsx +++ b/apps/builder/src/features/dashboard/components/OnboardingModal.tsx @@ -4,6 +4,7 @@ import { ModalBody, ModalContent, ModalOverlay, + useColorModeValue, useDisclosure, } from '@chakra-ui/react' import { TypebotViewer } from 'bot-engine' @@ -18,6 +19,10 @@ import { parseTypebotToPublicTypebot } from '@/features/publish' type Props = { totalTypebots: number } export const OnboardingModal = ({ totalTypebots }: Props) => { + const botPath = useColorModeValue( + '/bots/onboarding.json', + '/bots/onboarding-dark.json' + ) const { user, saveUser } = useUser() const { isOpen, onOpen, onClose } = useDisclosure() const [typebot, setTypebot] = useState() @@ -30,7 +35,6 @@ export const OnboardingModal = ({ totalTypebots }: Props) => { useEffect(() => { fetchTemplate() - // eslint-disable-next-line react-hooks/exhaustive-deps }, []) @@ -73,7 +77,7 @@ export const OnboardingModal = ({ totalTypebots }: Props) => { } const fetchTemplate = async () => { - const { data, error } = await sendRequest(`/bots/onboarding.json`) + const { data, error } = await sendRequest(botPath) if (error) return showToast({ title: error.name, description: error.message }) setTypebot(data as Typebot) @@ -116,7 +120,7 @@ export const OnboardingModal = ({ totalTypebots }: Props) => { /> - + {typebot && ( { Name: user?.name?.split(' ')[0] ?? undefined, }} onNewAnswer={handleNewAnswer} + style={{ borderRadius: '0.25rem' }} /> )} diff --git a/apps/builder/src/features/editor/components/BlocksSideBar/BlockCard.tsx b/apps/builder/src/features/editor/components/BlocksSideBar/BlockCard.tsx index 2dda039b95..7fbf8e1117 100644 --- a/apps/builder/src/features/editor/components/BlocksSideBar/BlockCard.tsx +++ b/apps/builder/src/features/editor/components/BlocksSideBar/BlockCard.tsx @@ -1,5 +1,11 @@ -import { Flex, HStack, StackProps, Text, Tooltip } from '@chakra-ui/react' -import { BlockType, DraggableBlockType } from 'models' +import { + Flex, + HStack, + Text, + Tooltip, + useColorModeValue, +} from '@chakra-ui/react' +import { DraggableBlockType } from 'models' import { useBlockDnd } from '@/features/graph' import React, { useEffect, useState } from 'react' import { BlockIcon } from './BlockIcon' @@ -28,17 +34,17 @@ export const BlockCard = ({ {!isMouseDown ? ( @@ -46,38 +52,9 @@ export const BlockCard = ({ - ) : ( - - Placeholder - - )} + ) : null} ) } - -export const BlockCardOverlay = ({ - type, - ...props -}: StackProps & { type: BlockType }) => { - return ( - - - - - ) -} diff --git a/apps/builder/src/features/editor/components/BlocksSideBar/BlockCardOverlay.tsx b/apps/builder/src/features/editor/components/BlocksSideBar/BlockCardOverlay.tsx new file mode 100644 index 0000000000..ccefb7e9b7 --- /dev/null +++ b/apps/builder/src/features/editor/components/BlocksSideBar/BlockCardOverlay.tsx @@ -0,0 +1,30 @@ +import { StackProps, HStack, useColorModeValue } from '@chakra-ui/react' +import { BlockType } from 'models' +import { BlockIcon } from './BlockIcon' +import { BlockTypeLabel } from './BlockTypeLabel' + +export const BlockCardOverlay = ({ + type, + ...props +}: StackProps & { type: BlockType }) => { + return ( + + + + + ) +} diff --git a/apps/builder/src/features/editor/components/BlocksSideBar/BlockIcon.tsx b/apps/builder/src/features/editor/components/BlocksSideBar/BlockIcon.tsx index e6d7b99d8c..f58c04fc89 100644 --- a/apps/builder/src/features/editor/components/BlocksSideBar/BlockIcon.tsx +++ b/apps/builder/src/features/editor/components/BlocksSideBar/BlockIcon.tsx @@ -1,4 +1,4 @@ -import { IconProps } from '@chakra-ui/react' +import { IconProps, useColorModeValue } from '@chakra-ui/react' import { BubbleBlockType, InputBlockType, @@ -40,47 +40,50 @@ import { AudioBubbleIcon } from '@/features/blocks/bubbles/audio' type BlockIconProps = { type: BlockType } & IconProps export const BlockIcon = ({ type, ...props }: BlockIconProps) => { + const blue = useColorModeValue('blue.500', 'blue.300') + const orange = useColorModeValue('orange.500', 'orange.300') + const purple = useColorModeValue('purple.500', 'purple.300') switch (type) { case BubbleBlockType.TEXT: - return + return case BubbleBlockType.IMAGE: - return + return case BubbleBlockType.VIDEO: - return + return case BubbleBlockType.EMBED: - return + return case BubbleBlockType.AUDIO: - return + return case InputBlockType.TEXT: - return + return case InputBlockType.NUMBER: - return + return case InputBlockType.EMAIL: - return + return case InputBlockType.URL: - return + return case InputBlockType.DATE: - return + return case InputBlockType.PHONE: - return + return case InputBlockType.CHOICE: - return + return case InputBlockType.PAYMENT: - return + return case InputBlockType.RATING: - return + return case InputBlockType.FILE: - return + return case LogicBlockType.SET_VARIABLE: - return + return case LogicBlockType.CONDITION: - return + return case LogicBlockType.REDIRECT: - return + return case LogicBlockType.CODE: - return + return case LogicBlockType.TYPEBOT_LINK: - return + return case IntegrationBlockType.GOOGLE_SHEETS: return case IntegrationBlockType.GOOGLE_ANALYTICS: diff --git a/apps/builder/src/features/editor/components/BlocksSideBar/BlocksSideBar.tsx b/apps/builder/src/features/editor/components/BlocksSideBar/BlocksSideBar.tsx index cba9d8114e..892cc76bae 100644 --- a/apps/builder/src/features/editor/components/BlocksSideBar/BlocksSideBar.tsx +++ b/apps/builder/src/features/editor/components/BlocksSideBar/BlocksSideBar.tsx @@ -8,6 +8,7 @@ import { IconButton, Tooltip, Fade, + useColorModeValue, } from '@chakra-ui/react' import { BubbleBlockType, @@ -18,9 +19,10 @@ import { } from 'models' import { useBlockDnd } from '@/features/graph' import React, { useState } from 'react' -import { BlockCard, BlockCardOverlay } from './BlockCard' +import { BlockCard } from './BlockCard' import { LockedIcon, UnlockedIcon } from '@/components/icons' import { headerHeight } from '../../constants' +import { BlockCardOverlay } from './BlockCardOverlay' export const BlocksSideBar = () => { const { setDraggedBlockType, draggedBlockType } = useBlockDnd() @@ -93,7 +95,7 @@ export const BlocksSideBar = () => { pt="2" pb="10" px="4" - bgColor="white" + bgColor={useColorModeValue('white', 'gray.900')} spacing={6} userSelect="none" overflowY="scroll" @@ -105,14 +107,13 @@ export const BlocksSideBar = () => { icon={isLocked ? : } aria-label={isLocked ? 'Unlock' : 'Lock'} size="sm" - variant="outline" onClick={handleLockClick} /> - + Bubbles @@ -123,7 +124,7 @@ export const BlocksSideBar = () => { - + Inputs @@ -134,7 +135,7 @@ export const BlocksSideBar = () => { - + Logic @@ -145,7 +146,7 @@ export const BlocksSideBar = () => { - + Integrations diff --git a/apps/builder/src/features/editor/components/BoardMenuButton.tsx b/apps/builder/src/features/editor/components/BoardMenuButton.tsx index 4c07cfb50c..39efe71789 100644 --- a/apps/builder/src/features/editor/components/BoardMenuButton.tsx +++ b/apps/builder/src/features/editor/components/BoardMenuButton.tsx @@ -1,10 +1,12 @@ import { + Flex, + FlexProps, IconButton, Menu, MenuButton, - MenuButtonProps, MenuItem, MenuList, + useColorModeValue, useDisclosure, } from '@chakra-ui/react' import assert from 'assert' @@ -21,7 +23,7 @@ import { isNotDefined } from 'utils' import { EditorSettingsModal } from './EditorSettingsModal' import { parseDefaultPublicId } from '@/features/publish' -export const BoardMenuButton = (props: MenuButtonProps) => { +export const BoardMenuButton = (props: FlexProps) => { const { query } = useRouter() const { typebot } = useTypebot() const { user } = useUser() @@ -55,25 +57,30 @@ export const BoardMenuButton = (props: MenuButtonProps) => { setIsDownloading(false) } return ( - - } - isLoading={isDownloading} - size="sm" - shadow="lg" - {...props} - /> - - } onClick={onOpen}> - Editor settings - - } onClick={downloadFlow}> - Export flow - - - - + + + } + isLoading={isDownloading} + size="sm" + shadow="lg" + bgColor={useColorModeValue('white', undefined)} + /> + + } onClick={onOpen}> + Editor settings + + } onClick={downloadFlow}> + Export flow + + + + + ) } diff --git a/apps/builder/src/features/editor/components/EditTypebotPage.tsx b/apps/builder/src/features/editor/components/EditTypebotPage.tsx index 71961fc872..7450f7abbe 100644 --- a/apps/builder/src/features/editor/components/EditTypebotPage.tsx +++ b/apps/builder/src/features/editor/components/EditTypebotPage.tsx @@ -5,7 +5,7 @@ import { GraphProvider, GroupsCoordinatesProvider, } from '@/features/graph' -import { Flex, Spinner } from '@chakra-ui/react' +import { Flex, Spinner, useColorModeValue } from '@chakra-ui/react' import { EditorProvider, useEditor, @@ -31,8 +31,11 @@ export const EditTypebotPage = () => { flex="1" pos="relative" h="full" - background="#f4f5f8" - backgroundImage="radial-gradient(#c6d0e1 1px, transparent 0)" + bgColor={useColorModeValue('#f4f5f8', 'gray.850')} + backgroundImage={useColorModeValue( + 'radial-gradient(#c6d0e1 1px, transparent 0)', + 'radial-gradient(#2f2f39 1px, transparent 0)' + )} backgroundSize="40px 40px" backgroundPosition="-19px -19px" > @@ -48,12 +51,7 @@ export const EditTypebotPage = () => { ) : ( - + )} diff --git a/apps/builder/src/features/editor/components/EditorSettingsForm.tsx b/apps/builder/src/features/editor/components/EditorSettingsForm.tsx deleted file mode 100644 index e6f4da5a7a..0000000000 --- a/apps/builder/src/features/editor/components/EditorSettingsForm.tsx +++ /dev/null @@ -1,77 +0,0 @@ -import { - Stack, - Heading, - HStack, - Text, - Radio, - RadioGroup, - VStack, -} from '@chakra-ui/react' -import { MouseIcon, LaptopIcon } from '@/components/icons' -import { useUser } from '@/features/account' -import { GraphNavigation } from 'db' -import React, { useState } from 'react' - -type Props = { - defaultGraphNavigation: GraphNavigation -} - -export const EditorSettingsForm = ({ defaultGraphNavigation }: Props) => { - const { saveUser } = useUser() - const [value, setValue] = useState(defaultGraphNavigation) - - const changeEditorNavigation = (value: string) => { - setValue(value) - saveUser({ graphNavigation: value as GraphNavigation }).then() - } - - const options = [ - { - value: GraphNavigation.MOUSE, - label: 'Mouse', - description: - 'Move by dragging the board and zoom in/out using the scroll wheel', - icon: , - }, - { - value: GraphNavigation.TRACKPAD, - label: 'Trackpad', - description: 'Move the board using 2 fingers and zoom in/out by pinching', - icon: , - }, - ] - - return ( - - Editor Navigation - - - {options.map((option) => ( - - - {option.icon} - - {option.label} - {option.description} - - - - - - ))} - - - - ) -} diff --git a/apps/builder/src/features/editor/components/EditorSettingsModal.tsx b/apps/builder/src/features/editor/components/EditorSettingsModal.tsx index d5513ea33e..dccfbbdd66 100644 --- a/apps/builder/src/features/editor/components/EditorSettingsModal.tsx +++ b/apps/builder/src/features/editor/components/EditorSettingsModal.tsx @@ -1,4 +1,4 @@ -import { useUser } from '@/features/account' +import { UserPreferencesForm } from '@/features/account' import { Modal, ModalBody, @@ -6,31 +6,21 @@ import { ModalContent, ModalOverlay, } from '@chakra-ui/react' -import { GraphNavigation } from 'db' import React from 'react' -import { EditorSettingsForm } from './EditorSettingsForm' type Props = { isOpen: boolean onClose: () => void } -export const EditorSettingsModal = ({ isOpen, onClose }: Props) => { - const { user } = useUser() - - return ( - - - - - - - - - - ) -} +export const EditorSettingsModal = ({ isOpen, onClose }: Props) => ( + + + + + + + + + +) diff --git a/apps/builder/src/features/editor/components/GettingStartedModal.tsx b/apps/builder/src/features/editor/components/GettingStartedModal.tsx index 812f7fb86d..c588c1185a 100644 --- a/apps/builder/src/features/editor/components/GettingStartedModal.tsx +++ b/apps/builder/src/features/editor/components/GettingStartedModal.tsx @@ -127,10 +127,9 @@ export const GettingStartedModal = () => { height="315" src="https://www.youtube.com/embed/jp3ggg_42-M" title="YouTube video player" - frameBorder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowFullScreen - style={{ borderRadius: '0.5rem' }} + style={{ borderRadius: '0.5rem', border: 'none' }} /> @@ -146,20 +145,18 @@ export const GettingStartedModal = () => { height="315" src="https://www.youtube.com/embed/6BudIC4GYNk" title="YouTube video player" - frameBorder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowFullScreen - style={{ borderRadius: '0.5rem' }} + style={{ borderRadius: '0.5rem', border: 'none' }} />