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) => (
+
+
+
+
+ {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' }}
/>
VIDEO
diff --git a/apps/builder/src/features/editor/components/PreviewDrawer.tsx b/apps/builder/src/features/editor/components/PreviewDrawer.tsx
index 9c21ae643b..934106efd8 100644
--- a/apps/builder/src/features/editor/components/PreviewDrawer.tsx
+++ b/apps/builder/src/features/editor/components/PreviewDrawer.tsx
@@ -5,6 +5,7 @@ import {
Fade,
Flex,
FlexProps,
+ useColorMode,
useEventListener,
UseToastOptions,
VStack,
@@ -21,6 +22,7 @@ import { headerHeight } from '../constants'
import { parseTypebotToPublicTypebot } from '@/features/publish'
export const PreviewDrawer = () => {
+ const isDark = useColorMode().colorMode === 'dark'
const { typebot } = useTypebot()
const { setRightPanel, startPreviewAtGroup } = useEditor()
const { setPreviewingEdge } = useGraph()
@@ -68,7 +70,8 @@ export const PreviewDrawer = () => {
top={`0`}
h={`100%`}
w={`${width}px`}
- bgColor="white"
+ bgColor={isDark ? 'gray.900' : 'white'}
+ borderLeftWidth={'1px'}
shadow="lg"
borderLeftRadius={'lg'}
onMouseOver={() => setIsResizeHandleVisible(true)}
@@ -78,6 +81,7 @@ export const PreviewDrawer = () => {
>
{
onNewLog={handleNewLog}
startGroupId={startPreviewAtGroup}
isPreview
+ style={{ borderRadius: '10px' }}
/>
)}
@@ -115,20 +120,26 @@ export const PreviewDrawer = () => {
)
}
-const ResizeHandle = (props: FlexProps) => {
+const ResizeHandle = (props: FlexProps & { isDark: boolean }) => {
return (
-
-
+
+
)
}
diff --git a/apps/builder/src/features/editor/components/TypebotHeader/EditableTypebotName.tsx b/apps/builder/src/features/editor/components/TypebotHeader/EditableTypebotName.tsx
index b1d1965937..bd784a280f 100644
--- a/apps/builder/src/features/editor/components/TypebotHeader/EditableTypebotName.tsx
+++ b/apps/builder/src/features/editor/components/TypebotHeader/EditableTypebotName.tsx
@@ -39,7 +39,7 @@ export const EditableTypebotName = ({
fontSize="14px"
minW="30px"
minH="20px"
- bgColor={currentName === '' ? 'gray.100' : 'white'}
+ bgColor={currentName === '' ? 'gray.100' : 'inherit'}
/>
diff --git a/apps/builder/src/features/editor/components/TypebotHeader/TypebotHeader.tsx b/apps/builder/src/features/editor/components/TypebotHeader/TypebotHeader.tsx
index b1e681ba45..d8b9fdeec3 100644
--- a/apps/builder/src/features/editor/components/TypebotHeader/TypebotHeader.tsx
+++ b/apps/builder/src/features/editor/components/TypebotHeader/TypebotHeader.tsx
@@ -6,6 +6,7 @@ import {
Tooltip,
Spinner,
Text,
+ useColorModeValue,
} from '@chakra-ui/react'
import {
BuoyIcon,
@@ -66,7 +67,7 @@ export const TypebotHeader = () => {
h={`${headerHeight}px`}
zIndex={100}
pos="relative"
- bgColor="white"
+ bgColor={useColorModeValue('white', 'gray.900')}
flexShrink={0}
>
{
{router.pathname.includes('/edit') && isNotDefined(rightPanel) && (
diff --git a/apps/builder/src/features/folders/components/TypebotButton.tsx b/apps/builder/src/features/folders/components/TypebotButton.tsx
index 134d86ed3f..a0b3ff6291 100644
--- a/apps/builder/src/features/folders/components/TypebotButton.tsx
+++ b/apps/builder/src/features/folders/components/TypebotButton.tsx
@@ -102,7 +102,6 @@ export const TypebotButton = ({
display="flex"
flexDir="column"
variant="outline"
- color="gray.800"
w="225px"
h="270px"
mr={{ sm: 6 }}
diff --git a/apps/builder/src/features/graph/components/Edges/Edge.tsx b/apps/builder/src/features/graph/components/Edges/Edge.tsx
index 2bb0899c3d..c92e2de692 100644
--- a/apps/builder/src/features/graph/components/Edges/Edge.tsx
+++ b/apps/builder/src/features/graph/components/Edges/Edge.tsx
@@ -1,7 +1,7 @@
import { Coordinates, useGraph, useGroupsCoordinates } from '../../providers'
import React, { useEffect, useLayoutEffect, useMemo, useState } from 'react'
import { Edge as EdgeProps } from 'models'
-import { Portal, useDisclosure } from '@chakra-ui/react'
+import { color, Portal, useColorMode, useDisclosure } from '@chakra-ui/react'
import { useTypebot } from '@/features/editor'
import { EdgeMenu } from './EdgeMenu'
import { colors } from '@/lib/theme'
@@ -23,6 +23,7 @@ type Props = {
edge: EdgeProps
}
export const Edge = ({ edge }: Props) => {
+ const isDark = useColorMode().colorMode === 'dark'
const { deleteEdge } = useTypebot()
const {
previewingEdge,
@@ -141,7 +142,13 @@ export const Edge = ({ edge }: Props) => {
(
-
-
- {edges.map((edge) => (
-
- ))}
- {answersCounts?.map((answerCount) => (
-
- ))}
- {
+ const isDark = useColorMode().colorMode === 'dark'
+ return (
+
-
-
-
-
-
-
-
-
-
-)
+
+ {edges.map((edge) => (
+
+ ))}
+ {answersCounts?.map((answerCount) => (
+
+ ))}
+
+
+
+
+
+
+
+
+
+
+ )
+}
diff --git a/apps/builder/src/features/graph/components/Endpoints/SourceEndpoint.tsx b/apps/builder/src/features/graph/components/Endpoints/SourceEndpoint.tsx
index 23251cab75..8fdedc1a9f 100644
--- a/apps/builder/src/features/graph/components/Endpoints/SourceEndpoint.tsx
+++ b/apps/builder/src/features/graph/components/Endpoints/SourceEndpoint.tsx
@@ -1,4 +1,9 @@
-import { BoxProps, Flex, useEventListener } from '@chakra-ui/react'
+import {
+ BoxProps,
+ Flex,
+ useColorModeValue,
+ useEventListener,
+} from '@chakra-ui/react'
import { useGraph, useGroupsCoordinates } from '../../providers'
import { Source } from 'models'
import React, { useEffect, useRef, useState } from 'react'
@@ -9,6 +14,9 @@ export const SourceEndpoint = ({
}: BoxProps & {
source: Source
}) => {
+ const color = useColorModeValue('blue.200', 'blue.100')
+ const connectedColor = useColorModeValue('blue.300', 'blue.200')
+ const bg = useColorModeValue('gray.100', 'gray.700')
const [ranOnce, setRanOnce] = useState(false)
const { setConnectingIds, addSourceEndpoint, previewingEdge } = useGraph()
@@ -61,7 +69,7 @@ export const SourceEndpoint = ({
boxSize="20px"
justify="center"
align="center"
- bgColor="gray.100"
+ bg={bg}
rounded="full"
>
diff --git a/apps/builder/src/features/graph/components/Nodes/BlockNode/BlockNode.tsx b/apps/builder/src/features/graph/components/Nodes/BlockNode/BlockNode.tsx
index da74e8d686..4d89d063b8 100644
--- a/apps/builder/src/features/graph/components/Nodes/BlockNode/BlockNode.tsx
+++ b/apps/builder/src/features/graph/components/Nodes/BlockNode/BlockNode.tsx
@@ -3,6 +3,7 @@ import {
HStack,
Popover,
PopoverTrigger,
+ useColorModeValue,
useDisclosure,
useEventListener,
} from '@chakra-ui/react'
@@ -26,17 +27,17 @@ import { SourceEndpoint } from '../../Endpoints/SourceEndpoint'
import { useRouter } from 'next/router'
import { SettingsModal } from './SettingsPopoverContent/SettingsModal'
import { BlockSettings } from './SettingsPopoverContent/SettingsPopoverContent'
-import { TextBubbleEditor } from '../../../../blocks/bubbles/textBubble/components/TextBubbleEditor'
import { TargetEndpoint } from '../../Endpoints'
import { MediaBubblePopoverContent } from './MediaBubblePopoverContent'
+import { ContextMenu } from '@/components/ContextMenu'
+import { setMultipleRefs } from '@/utils/helpers'
+import { TextBubbleEditor } from '@/features/blocks/bubbles/textBubble'
import {
NodePosition,
+ useGraph,
useBlockDnd,
useDragDistance,
- useGraph,
} from '../../../providers'
-import { ContextMenu } from '@/components/ContextMenu'
-import { setMultipleRefs } from '@/utils/helpers'
import { hasDefaultConnector } from '../../../utils'
export const BlockNode = ({
@@ -50,6 +51,9 @@ export const BlockNode = ({
indices: { blockIndex: number; groupIndex: number }
onMouseDown?: (blockNodePosition: NodePosition, block: DraggableBlock) => void
}) => {
+ const bg = useColorModeValue('gray.50', 'gray.850')
+ const previewingBorderColor = useColorModeValue('blue.400', 'blue.300')
+ const borderColor = useColorModeValue('gray.200', 'gray.800')
const { query } = useRouter()
const {
setConnectingIds,
@@ -165,7 +169,7 @@ export const BlockNode = ({
renderMenu={() => }
>
- {(ref, isOpened) => (
+ {(ref, isContextMenuOpened) => (
{
if (mouseOverGroup?.id !== groupId) setExpandedPlaceholderIndex(undefined)
@@ -126,17 +128,10 @@ export const BlockNodesList = ({
transition="none"
pointerEvents={isReadOnly || isStartGroup ? 'none' : 'auto'}
>
-
{typebot &&
blocks.map((block, idx) => (
@@ -148,17 +143,10 @@ export const BlockNodesList = ({
isConnectable={blocks.length - 1 === idx}
onMouseDown={handleBlockMouseDown(idx)}
/>
-
))}
diff --git a/apps/builder/src/features/graph/components/Nodes/GroupNode/GroupNode.tsx b/apps/builder/src/features/graph/components/Nodes/GroupNode/GroupNode.tsx
index 341588e5a1..ccfa1631d0 100644
--- a/apps/builder/src/features/graph/components/Nodes/GroupNode/GroupNode.tsx
+++ b/apps/builder/src/features/graph/components/Nodes/GroupNode/GroupNode.tsx
@@ -4,6 +4,7 @@ import {
EditablePreview,
IconButton,
Stack,
+ useColorModeValue,
} from '@chakra-ui/react'
import React, { memo, useCallback, useEffect, useRef, useState } from 'react'
import { Group } from 'models'
@@ -52,6 +53,10 @@ const NonMemoizedDraggableGroupNode = ({
groupIndex,
onGroupDrag,
}: Props & { onGroupDrag: (newCoord: Coordinates) => void }) => {
+ const bg = useColorModeValue('white', 'gray.900')
+ const previewingBorderColor = useColorModeValue('blue.400', 'blue.300')
+ const borderColor = useColorModeValue('white', 'gray.800')
+ const editableHoverBg = useColorModeValue('gray.100', 'gray.700')
const {
connectingIds,
setConnectingIds,
@@ -172,16 +177,20 @@ const NonMemoizedDraggableGroupNode = ({
renderMenu={() => }
isDisabled={isReadOnly || isStartGroup}
>
- {(ref, isOpened) => (
+ {(ref, isContextMenuOpened) => (
diff --git a/apps/builder/src/features/graph/components/Nodes/ItemNode/ItemNode.tsx b/apps/builder/src/features/graph/components/Nodes/ItemNode/ItemNode.tsx
index 45359aee3a..75dcf9fd6e 100644
--- a/apps/builder/src/features/graph/components/Nodes/ItemNode/ItemNode.tsx
+++ b/apps/builder/src/features/graph/components/Nodes/ItemNode/ItemNode.tsx
@@ -1,4 +1,4 @@
-import { Flex } from '@chakra-ui/react'
+import { Flex, useColorModeValue } from '@chakra-ui/react'
import {
Coordinates,
useGraph,
@@ -30,6 +30,9 @@ export const ItemNode = ({
onMouseDown,
connectionDisabled,
}: Props) => {
+ const previewingBorderColor = useColorModeValue('blue.400', 'blue.300')
+ const borderColor = useColorModeValue('gray.200', 'gray.700')
+ const bg = useColorModeValue('white', undefined)
const { typebot } = useTypebot()
const { previewingEdge } = useGraph()
const [isMouseOver, setIsMouseOver] = useState(false)
@@ -59,7 +62,7 @@ export const ItemNode = ({
renderMenu={() => }
>
- {(ref, isOpened) => (
+ {(ref, isContextMenuOpened) => (
{
px="4"
py="2"
rounded="md"
- bgColor="white"
+ bgColor={useColorModeValue('white', 'gray.850')}
borderWidth="1px"
- borderColor={'gray.300'}
+ borderColor={useColorModeValue('gray.200', 'gray.700')}
w="212px"
pointerEvents="none"
shadow="lg"
diff --git a/apps/builder/src/features/graph/components/Nodes/ItemNode/ItemNodesList.tsx b/apps/builder/src/features/graph/components/Nodes/ItemNode/ItemNodesList.tsx
index a0423b291e..e23c35df6c 100644
--- a/apps/builder/src/features/graph/components/Nodes/ItemNode/ItemNodesList.tsx
+++ b/apps/builder/src/features/graph/components/Nodes/ItemNode/ItemNodesList.tsx
@@ -1,4 +1,11 @@
-import { Flex, Portal, Stack, Text, useEventListener } from '@chakra-ui/react'
+import {
+ Flex,
+ Portal,
+ Stack,
+ Text,
+ useColorModeValue,
+ useEventListener,
+} from '@chakra-ui/react'
import {
computeNearestPlaceholderIndex,
useBlockDnd,
@@ -10,6 +17,8 @@ import { BlockIndices, BlockWithItems, LogicBlockType, Item } from 'models'
import React, { useEffect, useRef, useState } from 'react'
import { ItemNode } from './ItemNode'
import { SourceEndpoint } from '../../Endpoints'
+import { ItemNodeOverlay } from './ItemNodeOverlay'
+import { PlaceholderNode } from '../PlaceholderNode'
type Props = {
block: BlockWithItems
@@ -121,13 +130,10 @@ export const ItemNodesList = ({
return (
-
{block.items.map((item, idx) => (
@@ -136,45 +142,14 @@ export const ItemNodesList = ({
indices={{ groupIndex, blockIndex, itemIndex: idx }}
onMouseDown={handleBlockMouseDown(idx)}
/>
-
))}
- {isLastBlock && (
-
-
- {block.type === LogicBlockType.CONDITION ? 'Else' : 'Default'}
-
-
-
- )}
+ {isLastBlock && }
{draggedItem && draggedItem.blockId === block.id && (
@@ -189,14 +164,38 @@ export const ItemNodesList = ({
w="220px"
transformOrigin="0 0 0"
>
-
+
)}
)
}
+
+const DefaultItemNode = ({ block }: { block: BlockWithItems }) => {
+ return (
+
+
+ {block.type === LogicBlockType.CONDITION ? 'Else' : 'Default'}
+
+
+
+ )
+}
diff --git a/apps/builder/src/features/graph/components/Nodes/PlaceholderNode.tsx b/apps/builder/src/features/graph/components/Nodes/PlaceholderNode.tsx
new file mode 100644
index 0000000000..0b7a44adc9
--- /dev/null
+++ b/apps/builder/src/features/graph/components/Nodes/PlaceholderNode.tsx
@@ -0,0 +1,21 @@
+import { Flex, useColorModeValue } from '@chakra-ui/react'
+import React from 'react'
+
+type Props = {
+ isVisible: boolean
+ isExpanded: boolean
+ onRef: (ref: HTMLDivElement) => void
+}
+
+export const PlaceholderNode = ({ isVisible, isExpanded, onRef }: Props) => {
+ return (
+
+ )
+}
diff --git a/apps/builder/src/features/graph/components/ZoomButtons.tsx b/apps/builder/src/features/graph/components/ZoomButtons.tsx
index 1fa885e681..41f75d9db4 100644
--- a/apps/builder/src/features/graph/components/ZoomButtons.tsx
+++ b/apps/builder/src/features/graph/components/ZoomButtons.tsx
@@ -1,4 +1,4 @@
-import { Stack, IconButton } from '@chakra-ui/react'
+import { Stack, IconButton, useColorModeValue } from '@chakra-ui/react'
import { PlusIcon, MinusIcon } from '@/components/icons'
import { headerHeight } from '@/features/editor'
@@ -14,7 +14,7 @@ export const ZoomButtons = ({
pos="fixed"
top={`calc(${headerHeight}px + 70px)`}
right="40px"
- bgColor="white"
+ bgColor={useColorModeValue('white', 'gray.900')}
rounded="md"
zIndex={1}
spacing="0"
@@ -25,7 +25,7 @@ export const ZoomButtons = ({
aria-label={'Zoom in'}
size="sm"
onClick={onZoomIn}
- bgColor="white"
+ bgColor={useColorModeValue('white', undefined)}
borderBottomRadius={0}
/>
diff --git a/apps/builder/src/features/publish/components/embeds/codeSnippets/Chat/EmbedSettings.tsx b/apps/builder/src/features/publish/components/embeds/codeSnippets/Chat/EmbedSettings.tsx
index 4349572cf8..6fd66ff934 100644
--- a/apps/builder/src/features/publish/components/embeds/codeSnippets/Chat/EmbedSettings.tsx
+++ b/apps/builder/src/features/publish/components/embeds/codeSnippets/Chat/EmbedSettings.tsx
@@ -111,7 +111,7 @@ export const ChatEmbedSettings = ({
/>
-
+
Custom button icon?
-
+
Enable popup message?
(
+
)
diff --git a/apps/builder/src/features/publish/components/embeds/logos/OtherLogo.tsx b/apps/builder/src/features/publish/components/embeds/logos/OtherLogo.tsx
index 3ce5d1cc12..af5eec5d05 100644
--- a/apps/builder/src/features/publish/components/embeds/logos/OtherLogo.tsx
+++ b/apps/builder/src/features/publish/components/embeds/logos/OtherLogo.tsx
@@ -1,31 +1,35 @@
-import { Icon, IconProps } from '@chakra-ui/react'
+import { colors } from '@/lib/theme'
+import { Icon, IconProps, useColorModeValue } from '@chakra-ui/react'
-export const OtherLogo = (props: IconProps) => (
-
-
-
-
-
-
-)
+export const OtherLogo = (props: IconProps) => {
+ const stroke = useColorModeValue('black', colors.gray[200])
+ return (
+
+
+
+
+
+
+ )
+}
diff --git a/apps/builder/src/features/publish/components/embeds/logos/WixLogo.tsx b/apps/builder/src/features/publish/components/embeds/logos/WixLogo.tsx
index 67bcfb1acc..cb8c134237 100644
--- a/apps/builder/src/features/publish/components/embeds/logos/WixLogo.tsx
+++ b/apps/builder/src/features/publish/components/embeds/logos/WixLogo.tsx
@@ -1,29 +1,32 @@
-import { Icon, IconProps } from '@chakra-ui/react'
+import { Icon, IconProps, useColorModeValue } from '@chakra-ui/react'
-export const WixLogo = (props: IconProps) => (
-
-
-
-
-
-
-)
+export const WixLogo = (props: IconProps) => {
+ const fill = useColorModeValue('black', 'white')
+ return (
+
+
+
+
+
+
+ )
+}
diff --git a/apps/builder/src/features/publish/components/embeds/logos/WordpressLogo.tsx b/apps/builder/src/features/publish/components/embeds/logos/WordpressLogo.tsx
index d70846dc86..8a0205ce57 100644
--- a/apps/builder/src/features/publish/components/embeds/logos/WordpressLogo.tsx
+++ b/apps/builder/src/features/publish/components/embeds/logos/WordpressLogo.tsx
@@ -1,33 +1,37 @@
-import { Icon, IconProps } from '@chakra-ui/react'
+import { colors } from '@/lib/theme'
+import * as react from '@chakra-ui/react'
-export const WordpressLogo = (props: IconProps) => (
-
-
-
-
-
-
-
-)
+export const WordpressLogo = (props: react.IconProps) => {
+ const fill = react.useColorModeValue('#464342', colors.gray[400])
+ return (
+
+
+
+
+
+
+
+ )
+}
diff --git a/apps/builder/src/features/results/components/ResultsPage.tsx b/apps/builder/src/features/results/components/ResultsPage.tsx
index 7071b738eb..04b052829f 100644
--- a/apps/builder/src/features/results/components/ResultsPage.tsx
+++ b/apps/builder/src/features/results/components/ResultsPage.tsx
@@ -5,7 +5,14 @@ import { useUsage } from '@/features/billing'
import { useTypebot, TypebotHeader } from '@/features/editor'
import { useWorkspace } from '@/features/workspace'
import { useToast } from '@/hooks/useToast'
-import { Flex, HStack, Button, Tag, Text } from '@chakra-ui/react'
+import {
+ Flex,
+ HStack,
+ Button,
+ Tag,
+ Text,
+ useColorModeValue,
+} from '@chakra-ui/react'
import Link from 'next/link'
import { useRouter } from 'next/router'
import { useMemo } from 'react'
@@ -121,8 +128,8 @@ export const ResultsPage = () => {
{
+ const borderColor = useColorModeValue('gray.200', 'gray.700')
return (
{headerGroup.headers.map((header) => {
@@ -18,7 +19,7 @@ export const HeaderRow = ({ headerGroup }: Props) => {
py="2"
pos="relative"
border="1px"
- borderColor="gray.200"
+ borderColor={borderColor}
fontWeight="normal"
whiteSpace="nowrap"
wordBreak="normal"
diff --git a/apps/builder/src/features/results/components/ResultsTable/LoadingRows.tsx b/apps/builder/src/features/results/components/ResultsTable/LoadingRows.tsx
index 7880f923eb..bfb8653523 100644
--- a/apps/builder/src/features/results/components/ResultsTable/LoadingRows.tsx
+++ b/apps/builder/src/features/results/components/ResultsTable/LoadingRows.tsx
@@ -1,4 +1,11 @@
-import { chakra, Checkbox, Flex, Skeleton } from '@chakra-ui/react'
+import {
+ chakra,
+ Checkbox,
+ Flex,
+ Skeleton,
+ useColorMode,
+ useColorModeValue,
+} from '@chakra-ui/react'
import React from 'react'
type LoadingRowsProps = {
@@ -6,6 +13,7 @@ type LoadingRowsProps = {
}
export const LoadingRows = ({ totalColumns }: LoadingRowsProps) => {
+ const borderColor = useColorModeValue('gray.200', 'gray.700')
return (
<>
{Array.from(Array(3)).map((_, idx) => (
@@ -14,7 +22,7 @@ export const LoadingRows = ({ totalColumns }: LoadingRowsProps) => {
px="2"
py="2"
border="1px"
- borderColor="gray.200"
+ borderColor={borderColor}
width="40px"
>
@@ -28,7 +36,7 @@ export const LoadingRows = ({ totalColumns }: LoadingRowsProps) => {
px="4"
py="2"
border="1px"
- borderColor="gray.200"
+ borderColor={borderColor}
>
diff --git a/apps/builder/src/features/results/components/ResultsTable/ResultsTable.tsx b/apps/builder/src/features/results/components/ResultsTable/ResultsTable.tsx
index 93c01983fe..22811b5dcf 100644
--- a/apps/builder/src/features/results/components/ResultsTable/ResultsTable.tsx
+++ b/apps/builder/src/features/results/components/ResultsTable/ResultsTable.tsx
@@ -6,6 +6,7 @@ import {
HStack,
Stack,
Text,
+ useColorModeValue,
} from '@chakra-ui/react'
import { AlignLeftTextIcon } from '@/components/icons'
import { ResultHeaderCell, ResultsTablePreferences } from 'models'
@@ -26,6 +27,7 @@ import { HeaderRow } from './HeaderRow'
import { CellValueType, TableData } from '../../types'
import { HeaderIcon, parseAccessor } from '../../utils'
import { IndeterminateCheckbox } from './IndeterminateCheckbox'
+import { colors } from '@/lib/theme'
type ResultsTableProps = {
resultHeader: ResultHeaderCell[]
@@ -46,6 +48,7 @@ export const ResultsTable = ({
onLogOpenIndex,
onResultExpandIndex,
}: ResultsTableProps) => {
+ const background = useColorModeValue('white', colors.gray[900])
const { updateTypebot } = useTypebot()
const [rowSelection, setRowSelection] = useState>({})
const [columnsVisibility, setColumnsVisibility] = useState<
@@ -204,7 +207,16 @@ export const ResultsTable = ({
onColumnOrderChange={instance.setColumnOrder}
/>
-
+
{instance.getHeaderGroups().map((headerGroup) => (
@@ -225,7 +237,13 @@ export const ResultsTable = ({
/>
))}
{hasMore === true && (
-
+ columnsVisibility[header.id] !== false
+ ).length + 1
+ }
+ />
)}
diff --git a/apps/builder/src/features/results/results.spec.ts b/apps/builder/src/features/results/results.spec.ts
index 95e8365001..e903d6ff43 100644
--- a/apps/builder/src/features/results/results.spec.ts
+++ b/apps/builder/src/features/results/results.spec.ts
@@ -159,7 +159,7 @@ const validateExportAll = (data: unknown[]) => {
const scrollToBottom = (page: Page) =>
page.evaluate(() => {
- const tableWrapper = document.querySelector('.table-wrapper')
+ const tableWrapper = document.querySelector('[data-testid="results-table"]')
if (!tableWrapper) return
tableWrapper.scrollTo(0, tableWrapper.scrollHeight)
})
diff --git a/apps/builder/src/features/templates/components/CreateNewTypebotButtons.tsx b/apps/builder/src/features/templates/components/CreateNewTypebotButtons.tsx
index 3bca539ad2..058dc2c1e3 100644
--- a/apps/builder/src/features/templates/components/CreateNewTypebotButtons.tsx
+++ b/apps/builder/src/features/templates/components/CreateNewTypebotButtons.tsx
@@ -1,4 +1,11 @@
-import { VStack, Heading, Stack, Button, useDisclosure } from '@chakra-ui/react'
+import {
+ VStack,
+ Heading,
+ Stack,
+ Button,
+ useDisclosure,
+ useColorModeValue,
+} from '@chakra-ui/react'
import { ToolIcon, TemplateIcon, DownloadIcon } from '@/components/icons'
import { Typebot } from 'models'
import { useRouter } from 'next/router'
@@ -67,7 +74,13 @@ export const CreateNewTypebotButtons = () => {
w="full"
py="8"
fontSize="lg"
- leftIcon={ }
+ leftIcon={
+
+ }
onClick={() => handleCreateSubmit()}
isLoading={isLoading}
>
@@ -78,7 +91,13 @@ export const CreateNewTypebotButtons = () => {
w="full"
py="8"
fontSize="lg"
- leftIcon={ }
+ leftIcon={
+
+ }
onClick={onOpen}
isLoading={isLoading}
>
@@ -89,7 +108,13 @@ export const CreateNewTypebotButtons = () => {
w="full"
py="8"
fontSize="lg"
- leftIcon={ }
+ leftIcon={
+
+ }
isLoading={isLoading}
onNewTypebot={handleCreateSubmit}
>
diff --git a/apps/builder/src/features/theme/components/GeneralSettings/BackgroundSelector/BackgroundTypeRadioButtons.tsx b/apps/builder/src/features/theme/components/GeneralSettings/BackgroundSelector/BackgroundTypeRadioButtons.tsx
index 6dae8f2980..041b80e4c8 100644
--- a/apps/builder/src/features/theme/components/GeneralSettings/BackgroundSelector/BackgroundTypeRadioButtons.tsx
+++ b/apps/builder/src/features/theme/components/GeneralSettings/BackgroundSelector/BackgroundTypeRadioButtons.tsx
@@ -2,6 +2,7 @@ import {
Box,
Flex,
HStack,
+ useColorModeValue,
useRadio,
useRadioGroup,
UseRadioProps,
@@ -57,9 +58,14 @@ export const RadioCard = (props: UseRadioProps & { children: ReactNode }) => {
borderWidth="1px"
borderRadius="md"
_checked={{
- bg: 'orange.400',
- color: 'white',
- borderColor: 'orange.400',
+ borderWidth: '2px',
+ borderColor: 'blue.400',
+ }}
+ _hover={{
+ bgColor: useColorModeValue('gray.100', 'gray.700'),
+ }}
+ _active={{
+ bgColor: useColorModeValue('gray.200', 'gray.600'),
}}
px={5}
py={2}
diff --git a/apps/builder/src/features/workspace/components/MembersList/MemberItem.tsx b/apps/builder/src/features/workspace/components/MembersList/MemberItem.tsx
index 4bfab1f1a9..e775f0f19f 100644
--- a/apps/builder/src/features/workspace/components/MembersList/MemberItem.tsx
+++ b/apps/builder/src/features/workspace/components/MembersList/MemberItem.tsx
@@ -8,6 +8,7 @@ import {
Stack,
Tag,
Text,
+ useColorModeValue,
} from '@chakra-ui/react'
import { WorkspaceRole } from 'db'
import React from 'react'
@@ -38,9 +39,15 @@ export const MemberItem = ({
}: Props) => {
const handleAdminClick = () => onSelectNewRole(WorkspaceRole.ADMIN)
const handleMemberClick = () => onSelectNewRole(WorkspaceRole.MEMBER)
+
return (
-
+
{
return (
- {!canInviteNewMember && (
+ {true && (
case 'user-settings':
- return (
-
- )
+ return
case 'workspace-settings':
return
case 'members':
diff --git a/apps/builder/src/lib/plate.tsx b/apps/builder/src/lib/plate.tsx
index ef9503f0de..a2b45c3077 100644
--- a/apps/builder/src/lib/plate.tsx
+++ b/apps/builder/src/lib/plate.tsx
@@ -7,12 +7,12 @@ import { createPlugins } from '@udecode/plate-core'
import { createLinkPlugin, ELEMENT_LINK } from '@udecode/plate-link'
import { PlateFloatingLink } from '@udecode/plate-ui-link'
-export const editorStyle: React.CSSProperties = {
+export const editorStyle = (backgroundColor: string): React.CSSProperties => ({
flex: 1,
padding: '1rem',
- backgroundColor: 'white',
+ backgroundColor,
borderRadius: '0.25rem',
-}
+})
export const platePlugins = createPlugins(
[
diff --git a/apps/builder/src/lib/theme.ts b/apps/builder/src/lib/theme.ts
index e2c71c5f04..86bbf273e7 100644
--- a/apps/builder/src/lib/theme.ts
+++ b/apps/builder/src/lib/theme.ts
@@ -1,22 +1,44 @@
-import { extendTheme } from '@chakra-ui/react'
+import {
+ createMultiStyleConfigHelpers,
+ defineStyleConfig,
+ extendTheme,
+ StyleFunctionProps,
+ type ThemeConfig,
+} from '@chakra-ui/react'
+import { mode } from '@chakra-ui/theme-tools'
+import {
+ alertAnatomy,
+ accordionAnatomy,
+ menuAnatomy,
+ modalAnatomy,
+ popoverAnatomy,
+ switchAnatomy,
+} from '@chakra-ui/anatomy'
+
+const config: ThemeConfig = {
+ initialColorMode: 'system',
+ useSystemColorMode: true,
+}
const fonts = {
- heading: 'Outfit',
- body: 'Open Sans',
+ heading:
+ "Outfit, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'",
+ body: "Open Sans, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'",
}
export const colors = {
gray: {
- 50: '#F9FAFB',
- 100: '#F3F4F6',
- 200: '#E5E7EB',
- 300: '#D1D5DB',
- 400: '#9CA3AF',
- 500: '#6B7280',
- 600: '#4B5563',
- 700: '#374151',
- 800: '#1F2937',
- 900: '#111827',
+ 50: '#fafafa',
+ 100: '#f4f4f5',
+ 200: '#e4e4e7',
+ 300: '#d4d4d8',
+ 400: '#a1a1aa',
+ 500: '#71717a',
+ 600: '#52525b',
+ 700: '#3f3f46',
+ 800: '#27272a',
+ 850: '#1f1f23',
+ 900: '#18181b',
},
blue: {
50: '#e0edff',
@@ -56,33 +78,137 @@ export const colors = {
},
}
+const Modal = createMultiStyleConfigHelpers(
+ modalAnatomy.keys
+).defineMultiStyleConfig({
+ baseStyle: ({ colorMode }) => ({
+ dialog: { bg: colorMode === 'dark' ? 'gray.800' : 'white' },
+ }),
+})
+
+const Popover = createMultiStyleConfigHelpers(
+ popoverAnatomy.keys
+).defineMultiStyleConfig({
+ baseStyle: ({ colorMode }) => ({
+ popper: {
+ width: 'fit-content',
+ maxWidth: 'fit-content',
+ },
+ content: {
+ bg: colorMode === 'dark' ? 'gray.800' : 'white',
+ },
+ }),
+})
+
+const Menu = createMultiStyleConfigHelpers(
+ menuAnatomy.keys
+).defineMultiStyleConfig({
+ baseStyle: ({ colorMode }) => ({
+ list: {
+ shadow: 'lg',
+ bg: colorMode === 'dark' ? 'gray.800' : 'white',
+ },
+ item: {
+ bg: colorMode === 'dark' ? 'gray.800' : 'white',
+ _hover: {
+ bg: colorMode === 'dark' ? 'gray.700' : 'gray.100',
+ },
+ },
+ }),
+})
+
+const Accordion = createMultiStyleConfigHelpers(
+ accordionAnatomy.keys
+).defineMultiStyleConfig({
+ baseStyle: ({ colorMode }) => ({
+ button: {
+ _hover: {
+ bg: colorMode === 'dark' ? 'gray.800' : 'gray.100',
+ },
+ },
+ }),
+})
+
+const Button = defineStyleConfig({
+ baseStyle: ({ colorMode }) => ({
+ bg: colorMode === 'dark' ? 'gray.800' : 'white',
+ }),
+ variants: {
+ solid: ({ colorMode, colorScheme }) => {
+ if (colorScheme !== 'blue') return {}
+ return {
+ bg: colorMode === 'dark' ? 'blue.400' : 'blue.500',
+ color: 'white',
+ _hover: {
+ bg: colorMode === 'dark' ? 'blue.500' : 'blue.600',
+ },
+ _active: {
+ bg: colorMode === 'dark' ? 'blue.600' : 'blue.700',
+ },
+ }
+ },
+ outline: {
+ bg: 'transparent',
+ },
+ ghost: {
+ bg: 'transparent',
+ },
+ },
+})
+
+const Alert = createMultiStyleConfigHelpers(
+ alertAnatomy.keys
+).defineMultiStyleConfig({
+ variants: {
+ subtle: ({ colorScheme, colorMode }) => {
+ if (colorScheme !== 'blue' || colorMode === 'dark') return {}
+ return {
+ container: {
+ bg: 'blue.50',
+ },
+ }
+ },
+ },
+})
+
+const Switch = createMultiStyleConfigHelpers(
+ switchAnatomy.keys
+).defineMultiStyleConfig({
+ baseStyle: ({ colorMode, colorScheme }) => ({
+ track: {
+ _checked: {
+ bg: colorMode === 'dark' ? `${colorScheme}.400` : `${colorScheme}.500`,
+ },
+ },
+ }),
+})
+
const components = {
+ Modal,
+ Popover,
+ Menu,
+ Button,
+ Accordion,
+ Alert,
+ Switch,
Spinner: {
defaultProps: {
colorScheme: 'blue',
},
},
NumberInput: {
- defaultProps: {
+ baseStyle: {
focusBorderColor: 'blue.200',
},
},
Input: {
- defaultProps: {
+ baseStyle: {
focusBorderColor: 'blue.200',
},
},
Textarea: {
- defaultProps: {
- focusBorderColor: 'blue.200',
- },
- },
- Popover: {
baseStyle: {
- popper: {
- width: 'fit-content',
- maxWidth: 'fit-content',
- },
+ focusBorderColor: 'blue.200',
},
},
Link: {
@@ -90,20 +216,25 @@ const components = {
_hover: { textDecoration: 'none' },
},
},
- Menu: {
- parts: ['list'],
- defaultProps: {
- list: {
- shadow: 'lg',
- },
- },
- },
Tooltip: {
- defaultProps: {
+ baseStyle: {
rounded: 'md',
- hasArrow: true,
},
},
}
-export const customTheme: any = extendTheme({ colors, fonts, components })
+const styles = {
+ global: (props: StyleFunctionProps) => ({
+ body: {
+ bg: mode('white', 'gray.900')(props),
+ },
+ }),
+}
+
+export const customTheme = extendTheme({
+ colors,
+ fonts,
+ components,
+ config,
+ styles,
+})
diff --git a/apps/builder/src/pages/_document.tsx b/apps/builder/src/pages/_document.tsx
index f9f374e329..5dccc71df9 100644
--- a/apps/builder/src/pages/_document.tsx
+++ b/apps/builder/src/pages/_document.tsx
@@ -1,4 +1,5 @@
-/* eslint-disable @next/next/no-sync-scripts */
+import { customTheme } from '@/lib/theme'
+import { ColorModeScript } from '@chakra-ui/react'
import { Html, Head, Main, NextScript } from 'next/document'
const Document = () => (
@@ -10,9 +11,11 @@ const Document = () => (
rel="stylesheet"
/>
+ {/* eslint-disable-next-line @next/next/no-sync-scripts */}
+
diff --git a/packages/db/prisma/migrations/20221219142712_add_app_appearance_preference/migration.sql b/packages/db/prisma/migrations/20221219142712_add_app_appearance_preference/migration.sql
new file mode 100644
index 0000000000..3ba8737983
--- /dev/null
+++ b/packages/db/prisma/migrations/20221219142712_add_app_appearance_preference/migration.sql
@@ -0,0 +1,2 @@
+-- AlterTable
+ALTER TABLE "User" ADD COLUMN "preferredAppAppearance" TEXT;
diff --git a/packages/db/prisma/schema.prisma b/packages/db/prisma/schema.prisma
index b86339f9cd..61a705f8b4 100644
--- a/packages/db/prisma/schema.prisma
+++ b/packages/db/prisma/schema.prisma
@@ -48,6 +48,7 @@ model User {
company String?
onboardingCategories String[]
graphNavigation GraphNavigation?
+ preferredAppAppearance String?
accounts Account[]
apiTokens ApiToken[]
CollaboratorsOnTypebots CollaboratorsOnTypebots[]
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index f844936166..d6889a268b 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -17,9 +17,11 @@ importers:
apps/builder:
specifiers:
'@babel/core': 7.20.5
+ '@chakra-ui/anatomy': ^2.1.0
'@chakra-ui/css-reset': 2.0.10
'@chakra-ui/react': 2.4.4
'@chakra-ui/styled-system': 2.5.0
+ '@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
@@ -71,6 +73,7 @@ importers:
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
db: workspace:*
@@ -114,6 +117,7 @@ importers:
superjson: ^1.12.0
svg-round-corners: 0.4.1
swr: 2.0.0
+ thememirror: ^2.0.1
tinycolor2: 1.4.2
trpc-openapi: 1.0.0
tsconfig: workspace:*
@@ -123,8 +127,10 @@ importers:
utils: workspace:*
zod: 3.20.2
dependencies:
+ '@chakra-ui/anatomy': 2.1.0
'@chakra-ui/css-reset': 2.0.10_hp5f5nkljdiwilp4rgxyefcplu
'@chakra-ui/react': 2.4.4_przcunyodmsiq2duiyjrphchze
+ '@chakra-ui/theme-tools': 2.0.14_egcizgpwtsioofm7hx34ab4iqi
'@codemirror/lang-css': 6.0.1_oaehsghbizwy4uu4eqfxbgnija
'@codemirror/lang-html': 6.4.0
'@codemirror/lang-javascript': 6.1.2
@@ -162,6 +168,7 @@ importers:
bot-engine: link:../../packages/bot-engine
browser-image-compression: 2.0.0
canvas-confetti: 1.6.0
+ chakra-react-select: 4.4.3_rimn5i5k53tiepfjihjwcsjnou
codemirror: 6.0.1_@lezer+common@1.0.2
cuid: 2.1.8
deep-object-diff: 1.1.9
@@ -198,6 +205,7 @@ importers:
styled-components: 5.3.6_7i5myeigehqah43i5u7wbekgba
svg-round-corners: 0.4.1
swr: 2.0.0_react@18.2.0
+ thememirror: 2.0.1_jxyczrmcrnl7x5ydpuf7hgjfya
tinycolor2: 1.4.2
trpc-openapi: 1.0.0_nuoe2uo2ngdjbmcrwljfpdxrve
typebot-js: link:../../packages/typebot-js
@@ -4387,12 +4395,22 @@ packages:
resolution: {integrity: sha512-buc8BXHmG9l82+OQXOFU3Kr2XQx9ys01U/Q9HMIrZ300iLc8HLMgh7dcCqgYzAzf4BkoQvDcXf5Y+CuEZ5JBYg==}
dev: false
+ /@floating-ui/core/1.0.4:
+ resolution: {integrity: sha512-FPFLbg2b06MIw1dqk2SOEMAMX3xlrreGjcui5OTxfBDtaKTmh0kioOVjT8gcfl58juawL/yF+S+gnq8aUYQx/Q==}
+ dev: false
+
/@floating-ui/dom/0.5.4:
resolution: {integrity: sha512-419BMceRLq0RrmTSDxn8hf9R3VCJv2K9PUfugh5JyEFmdjzDo+e8U5EdR8nzKq8Yj1htzLm3b6eQEEam3/rrtg==}
dependencies:
'@floating-ui/core': 0.7.3
dev: false
+ /@floating-ui/dom/1.0.12:
+ resolution: {integrity: sha512-HeG/wHoa2laUHlDX3xkzqlUqliAfa+zqV04LaKIwNCmCNaW2p0fQi4/Kd0LB4GdFoJ2UllLFq5gWnXAd67lg7w==}
+ dependencies:
+ '@floating-ui/core': 1.0.4
+ dev: false
+
/@floating-ui/react-dom-interactions/0.6.6_ib3m5ricvtkl2cll7qpr2f6lvq:
resolution: {integrity: sha512-qnao6UPjSZNHnXrF+u4/n92qVroQkx0Umlhy3Avk1oIebm/5ee6yvDm4xbHob0OjY7ya8WmUnV3rQlPwX3Atwg==}
peerDependencies:
@@ -6149,7 +6167,6 @@ packages:
resolution: {integrity: sha512-juKD/eiSM3/xZYzjuzH6ZwpP+/lejltmiS3QEzV/vmb/Q8+HfDmxu+Baga8UEMGBqV88Nbg4l2hY/K2DkyaLLA==}
dependencies:
'@types/react': 18.0.26
- dev: true
/@types/react/18.0.26:
resolution: {integrity: sha512-hCR3PJQsAIXyxhTNSiDFY//LhnMZWpNNr5etoCqx/iUfGc5gXWtQR2Phl908jVR6uPXacojQWTg4qRpkxTuGug==}
@@ -7897,6 +7914,34 @@ packages:
resolution: {integrity: sha512-vlNK021QdI7PNeiUh/lKkC/mNHHfV0m/Ad5JoI0TYtlBnJAslM/JIkm/tGC88bkLIwO6OQ5uV6ztS6kVAtCDlg==}
dev: false
+ /chakra-react-select/4.4.3_rimn5i5k53tiepfjihjwcsjnou:
+ resolution: {integrity: sha512-anDgJyYUpIapTmUbgXB+Iw5hJ90hOPvgoUPUaYdO5q9zY2VBFhQ1L0gBMqWAQxiKUmuHpwQypf8sPoVtd0b3KA==}
+ peerDependencies:
+ '@chakra-ui/form-control': ^2.0.0
+ '@chakra-ui/icon': ^3.0.0
+ '@chakra-ui/layout': ^2.0.0
+ '@chakra-ui/menu': ^2.0.0
+ '@chakra-ui/spinner': ^2.0.0
+ '@chakra-ui/system': ^2.0.0
+ '@emotion/react': ^11.8.1
+ react: ^18.0.0
+ react-dom: ^18.0.0
+ dependencies:
+ '@chakra-ui/form-control': 2.0.13_iuckyjetixsa6e5uo5ymtjguvq
+ '@chakra-ui/icon': 3.0.13_iuckyjetixsa6e5uo5ymtjguvq
+ '@chakra-ui/layout': 2.1.11_iuckyjetixsa6e5uo5ymtjguvq
+ '@chakra-ui/menu': 2.1.5_v3e3sxd2uk3a5ht2jlbmshfate
+ '@chakra-ui/spinner': 2.0.11_iuckyjetixsa6e5uo5ymtjguvq
+ '@chakra-ui/system': 2.3.5_dovxhg2tvkkxkdnqyoum6wzcxm
+ '@emotion/react': 11.10.5_xl5my4wapvq2ctl7qwehtbgorq
+ react: 18.2.0
+ react-dom: 18.2.0_react@18.2.0
+ react-select: 5.7.0_bkycudvrb3j3gvocoupj7qjewi
+ transitivePeerDependencies:
+ - '@babel/core'
+ - '@types/react'
+ dev: false
+
/chalk/2.4.2:
resolution: {integrity: sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==}
engines: {node: '>=4'}
@@ -13128,6 +13173,10 @@ packages:
fs-monkey: 1.0.3
dev: false
+ /memoize-one/6.0.0:
+ resolution: {integrity: sha512-rkpe71W0N0c0Xz6QD0eJETuWAJGnJ9afsl1srmwPrI+yBCkge5EycXXbYRyvL29zZVUWQCY7InPRCv3GDXuZNw==}
+ dev: false
+
/mensch/0.3.4:
resolution: {integrity: sha512-IAeFvcOnV9V0Yk+bFhYR07O3yNina9ANIN5MoXBKYJ/RLYPurd2d0yw14MDhpr9/momp0WofT1bPUh3hkzdi/g==}
@@ -15692,6 +15741,28 @@ packages:
react-dom: 18.2.0_react@18.2.0
dev: false
+ /react-select/5.7.0_bkycudvrb3j3gvocoupj7qjewi:
+ resolution: {integrity: sha512-lJGiMxCa3cqnUr2Jjtg9YHsaytiZqeNOKeibv6WF5zbK/fPegZ1hg3y/9P1RZVLhqBTs0PfqQLKuAACednYGhQ==}
+ peerDependencies:
+ react: ^16.8.0 || ^17.0.0 || ^18.0.0
+ react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0
+ dependencies:
+ '@babel/runtime': 7.20.6
+ '@emotion/cache': 11.10.5
+ '@emotion/react': 11.10.5_xl5my4wapvq2ctl7qwehtbgorq
+ '@floating-ui/dom': 1.0.12
+ '@types/react-transition-group': 4.4.5
+ memoize-one: 6.0.0
+ prop-types: 15.8.1
+ react: 18.2.0
+ react-dom: 18.2.0_react@18.2.0
+ react-transition-group: 4.4.5_biqbaboplfbrettd7655fr4n2y
+ use-isomorphic-layout-effect: 1.1.2_kzbn2opkn2327fwg5yzwzya5o4
+ transitivePeerDependencies:
+ - '@babel/core'
+ - '@types/react'
+ dev: false
+
/react-ssr-prepass/1.5.0_react@18.2.0:
resolution: {integrity: sha512-yFNHrlVEReVYKsLI5lF05tZoHveA5pGzjFbFJY/3pOqqjGOmMmqx83N4hIjN2n6E1AOa+eQEUxs3CgRnPmT0RQ==}
peerDependencies:
@@ -17287,6 +17358,18 @@ packages:
/text-table/0.2.0:
resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==}
+ /thememirror/2.0.1_jxyczrmcrnl7x5ydpuf7hgjfya:
+ resolution: {integrity: sha512-d5i6FVvWWPkwrm4cHLI3t9AT1OrkAt7Ig8dtdYSofgF7C/eiyNuq6zQzSTusWTde3jpW9WLvA9J/fzNKMUsd0w==}
+ peerDependencies:
+ '@codemirror/language': ^6.0.0
+ '@codemirror/state': ^6.0.0
+ '@codemirror/view': ^6.0.0
+ dependencies:
+ '@codemirror/language': 6.3.2
+ '@codemirror/state': 6.1.4
+ '@codemirror/view': 6.7.1
+ dev: false
+
/thenify-all/1.6.0:
resolution: {integrity: sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==}
engines: {node: '>=0.8'}