@ -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:*",
|
||||
|
638
apps/builder/public/bots/onboarding-dark.json
Normal file
638
apps/builder/public/bots/onboarding-dark.json
Normal file
@ -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": "<div>Welcome 👋</div>",
|
||||
"richText": [
|
||||
{ "type": "p", "children": [{ "text": "Welcome 👋" }] }
|
||||
],
|
||||
"plainText": "Welcome 👋"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "cl1267y1u000f2e6d4rlglv6g",
|
||||
"type": "text",
|
||||
"groupId": "cl1267q1z000d2e6d949f2ge4",
|
||||
"content": {
|
||||
"html": "<div>What's your name?</div>",
|
||||
"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": "<div>Welcome {{Name}} 👋</div>",
|
||||
"richText": [
|
||||
{ "type": "p", "children": [{ "text": "Welcome {{Name}} 👋" }] }
|
||||
],
|
||||
"plainText": "Welcome {{Name}} 👋"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "cl126hb9m000l2e6d5qk3mohn",
|
||||
"type": "text",
|
||||
"groupId": "cl126ixoq000p2e6dfbz9sype",
|
||||
"content": {
|
||||
"html": "<div>I'm super pumped that you've decided to try out Typebot 😍</div>",
|
||||
"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": "<div>You are small steps away from meaningful, hyper-personalized experience for your users</div>",
|
||||
"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": "<div>Let's get you set up for your Typebot journey.</div>",
|
||||
"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": "<div>Do you work for a specific company?</div>",
|
||||
"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": "<div>What type of forms are you planning to build with Typebot?</div>",
|
||||
"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": "<div>Thank you for answering those questions!</div>",
|
||||
"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": "<div>You can reach out to me using the contact bubble on the bottom right corner 🤓</div>",
|
||||
"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": "<div>Let's create your first typebot...</div>",
|
||||
"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": "<div>What else?</div>",
|
||||
"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
|
||||
}
|
BIN
apps/builder/public/images/dark-mode.png
Normal file
BIN
apps/builder/public/images/dark-mode.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 115 KiB |
BIN
apps/builder/public/images/light-mode.png
Normal file
BIN
apps/builder/public/images/light-mode.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 8.0 KiB |
BIN
apps/builder/public/images/system-mode.png
Normal file
BIN
apps/builder/public/images/system-mode.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 122 KiB |
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { AlertProps, Alert, AlertIcon } from '@chakra-ui/react'
|
||||
|
||||
export const AlertInfo = (props: AlertProps) => (
|
||||
<Alert status="info" bgColor={'blue.50'} rounded="md" {...props}>
|
||||
<Alert status="info" rounded="md" {...props}>
|
||||
<AlertIcon />
|
||||
{props.children}
|
||||
</Alert>
|
||||
|
@ -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<BoxProps, 'onChange'>) => {
|
||||
const isDark = useColorMode().colorMode === 'dark'
|
||||
const editorContainer = useRef<HTMLDivElement | null>(null)
|
||||
const editorView = useRef<EditorView | null>(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 (
|
||||
<HStack align="flex-end" spacing={0}>
|
||||
<HStack
|
||||
align="flex-end"
|
||||
spacing={0}
|
||||
borderWidth={'1px'}
|
||||
borderRadius="md"
|
||||
bg={useColorModeValue('#FCFCFC', '#2D2F3F')}
|
||||
>
|
||||
<Box
|
||||
w={isVariableButtonDisplayed ? 'calc(100% - 32px)' : '100%'}
|
||||
ref={editorContainer}
|
||||
|
@ -5,6 +5,7 @@ import {
|
||||
PopoverTrigger,
|
||||
PopoverContent,
|
||||
Flex,
|
||||
useColorModeValue,
|
||||
} from '@chakra-ui/react'
|
||||
import React from 'react'
|
||||
import { EmojiOrImageIcon } from './EmojiOrImageIcon'
|
||||
@ -23,6 +24,8 @@ export const EditableEmojiOrImageIcon = ({
|
||||
onChangeIcon,
|
||||
boxSize,
|
||||
}: Props) => {
|
||||
const bg = useColorModeValue('gray.100', 'gray.700')
|
||||
|
||||
return (
|
||||
<Popover isLazy>
|
||||
{({ 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"
|
||||
>
|
||||
|
@ -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<number>(0)
|
||||
const { onOpen, onClose, isOpen } = useDisclosure()
|
||||
const [inputValue, setInputValue] = useState(selectedItem ?? '')
|
||||
@ -172,13 +174,13 @@ export const SearchableDropdown = ({
|
||||
offset={[0, 0]}
|
||||
isLazy
|
||||
>
|
||||
<PopoverTrigger>
|
||||
<PopoverAnchor>
|
||||
<HStack spacing={0} align={'flex-end'} w="full">
|
||||
<Input
|
||||
ref={inputRef}
|
||||
value={inputValue}
|
||||
onChange={onInputChange}
|
||||
onClick={onOpen}
|
||||
onFocus={onOpen}
|
||||
type="text"
|
||||
onKeyUp={handleKeyUp}
|
||||
{...inputProps}
|
||||
@ -190,7 +192,7 @@ export const SearchableDropdown = ({
|
||||
/>
|
||||
)}
|
||||
</HStack>
|
||||
</PopoverTrigger>
|
||||
</PopoverAnchor>
|
||||
<PopoverContent
|
||||
maxH="35vh"
|
||||
overflowY="scroll"
|
||||
@ -215,9 +217,7 @@ export const SearchableDropdown = ({
|
||||
colorScheme="gray"
|
||||
role="menuitem"
|
||||
variant="ghost"
|
||||
bgColor={
|
||||
keyboardFocusIndex === idx ? 'gray.200' : 'transparent'
|
||||
}
|
||||
bg={keyboardFocusIndex === idx ? bg : 'transparent'}
|
||||
justifyContent="flex-start"
|
||||
>
|
||||
{typeof item === 'string' ? item : item.label}
|
||||
|
@ -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<HTMLInputElement>(null)
|
||||
const createVariableItemRef = useRef<HTMLButtonElement | null>(null)
|
||||
const itemsRef = useRef<(HTMLButtonElement | null)[]>([])
|
||||
|
||||
@ -80,7 +83,6 @@ export const VariableSearchInput = ({
|
||||
const onInputChange = (e: ChangeEvent<HTMLInputElement>) => {
|
||||
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]}
|
||||
>
|
||||
<PopoverTrigger>
|
||||
<PopoverAnchor>
|
||||
<Input
|
||||
data-testid="variables-input"
|
||||
ref={inputRef}
|
||||
value={inputValue}
|
||||
onChange={onInputChange}
|
||||
onClick={onOpen}
|
||||
onFocus={onOpen}
|
||||
onKeyUp={handleKeyUp}
|
||||
placeholder={inputProps.placeholder ?? 'Select a variable'}
|
||||
{...inputProps}
|
||||
/>
|
||||
</PopoverTrigger>
|
||||
</PopoverAnchor>
|
||||
<PopoverContent
|
||||
maxH="35vh"
|
||||
overflowY="scroll"
|
||||
@ -207,7 +209,7 @@ export const VariableSearchInput = ({
|
||||
variant="ghost"
|
||||
justifyContent="flex-start"
|
||||
leftIcon={<PlusIcon />}
|
||||
bgColor={keyboardFocusIndex === 0 ? 'gray.200' : 'transparent'}
|
||||
bgColor={keyboardFocusIndex === 0 ? bg : 'transparent'}
|
||||
>
|
||||
Create "{inputValue}"
|
||||
</Button>
|
||||
@ -232,9 +234,7 @@ export const VariableSearchInput = ({
|
||||
variant="ghost"
|
||||
justifyContent="space-between"
|
||||
bgColor={
|
||||
keyboardFocusIndex === indexInList
|
||||
? 'gray.200'
|
||||
: 'transparent'
|
||||
keyboardFocusIndex === indexInList ? bg : 'transparent'
|
||||
}
|
||||
>
|
||||
{item.name}
|
||||
|
@ -106,7 +106,6 @@ export const TextBox = ({
|
||||
onKeyUp={handleKeyUp}
|
||||
onClick={handleKeyUp}
|
||||
onChange={handleChange}
|
||||
bgColor={'white'}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
|
@ -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) => (
|
||||
<RadioGroup onChange={onChange} defaultValue={defaultValue}>
|
||||
<HStack spacing={4} w="full" align="stretch">
|
||||
{appearanceData.map((option) => (
|
||||
<VStack
|
||||
key={option.value}
|
||||
as="label"
|
||||
htmlFor={option.label}
|
||||
cursor="pointer"
|
||||
borderWidth="1px"
|
||||
borderRadius="md"
|
||||
w="full"
|
||||
spacing={2}
|
||||
justifyContent="space-between"
|
||||
pb={6}
|
||||
>
|
||||
<VStack spacing={4}>
|
||||
<Image
|
||||
src={option.image}
|
||||
alt="Theme preview"
|
||||
borderTopRadius="md"
|
||||
/>
|
||||
<Stack>
|
||||
<Text fontWeight="bold">{option.label}</Text>
|
||||
</Stack>
|
||||
</VStack>
|
||||
|
||||
<Radio value={option.value} id={option.label} />
|
||||
</VStack>
|
||||
))}
|
||||
</HStack>
|
||||
</RadioGroup>
|
||||
)
|
@ -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: <MouseIcon boxSize="35px" />,
|
||||
},
|
||||
{
|
||||
value: GraphNavigation.TRACKPAD,
|
||||
label: 'Trackpad',
|
||||
description: 'Move the board using 2 fingers and zoom in/out by pinching',
|
||||
icon: <LaptopIcon boxSize="35px" />,
|
||||
},
|
||||
]
|
||||
|
||||
type Props = {
|
||||
defaultValue: string
|
||||
onChange: (value: string) => void
|
||||
}
|
||||
export const GraphNavigationRadioGroup = ({
|
||||
defaultValue,
|
||||
onChange,
|
||||
}: Props) => (
|
||||
<RadioGroup onChange={onChange} defaultValue={defaultValue}>
|
||||
<HStack spacing={4} w="full" align="stretch">
|
||||
{graphNavigationData.map((option) => (
|
||||
<VStack
|
||||
key={option.value}
|
||||
as="label"
|
||||
htmlFor={option.label}
|
||||
cursor="pointer"
|
||||
borderWidth="1px"
|
||||
borderRadius="md"
|
||||
w="full"
|
||||
p="6"
|
||||
spacing={6}
|
||||
justifyContent="space-between"
|
||||
>
|
||||
<VStack spacing={6}>
|
||||
{option.icon}
|
||||
<Stack>
|
||||
<Text fontWeight="bold">{option.label}</Text>
|
||||
<Text>{option.description}</Text>
|
||||
</Stack>
|
||||
</VStack>
|
||||
|
||||
<Radio value={option.value} id={option.label} />
|
||||
</VStack>
|
||||
))}
|
||||
</HStack>
|
||||
</RadioGroup>
|
||||
)
|
@ -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 (
|
||||
<Stack spacing={12}>
|
||||
<Stack spacing={6}>
|
||||
<Heading size="md">Editor Navigation</Heading>
|
||||
<GraphNavigationRadioGroup
|
||||
defaultValue={user?.graphNavigation ?? GraphNavigation.TRACKPAD}
|
||||
onChange={changeGraphNavigation}
|
||||
/>
|
||||
</Stack>
|
||||
<Stack spacing={6}>
|
||||
<Heading size="md">Appearance</Heading>
|
||||
<AppearanceRadioGroup
|
||||
defaultValue={user?.preferredAppAppearance ?? 'system'}
|
||||
onChange={changeAppearance}
|
||||
/>
|
||||
</Stack>
|
||||
</Stack>
|
||||
)
|
||||
}
|
2
apps/builder/src/features/account/components/index.ts
Normal file
2
apps/builder/src/features/account/components/index.ts
Normal file
@ -0,0 +1,2 @@
|
||||
export * from './MyAccountForm'
|
||||
export * from './UserPreferenceForm/UserPreferencesForm'
|
@ -1,3 +1,3 @@
|
||||
export { UserProvider, useUser } from './UserProvider'
|
||||
export type { ApiTokenFromServer } from './types'
|
||||
export { MyAccountForm } from './components/MyAccountForm'
|
||||
export * from './components'
|
||||
|
@ -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 }) => {
|
||||
<Flex
|
||||
w="full"
|
||||
pos="relative"
|
||||
bgColor="gray.50"
|
||||
bgColor={useColorModeValue('white', 'gray.850')}
|
||||
backgroundImage={useColorModeValue(
|
||||
'radial-gradient(#c6d0e1 1px, transparent 0)',
|
||||
'radial-gradient(#2f2f39 1px, transparent 0)'
|
||||
)}
|
||||
backgroundSize="40px 40px"
|
||||
backgroundPosition="-19px -19px"
|
||||
h="full"
|
||||
justifyContent="center"
|
||||
>
|
||||
|
@ -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 (
|
||||
<SimpleGrid columns={{ base: 1, md: 3 }} spacing="6" {...props}>
|
||||
<Stat bgColor="white" p="4" rounded="md" boxShadow="md">
|
||||
<Stat bgColor={bg} p="4" rounded="md" boxShadow="md">
|
||||
<StatLabel>Views</StatLabel>
|
||||
{stats ? (
|
||||
<StatNumber>{stats.totalViews}</StatNumber>
|
||||
@ -23,7 +26,7 @@ export const StatsCards = ({
|
||||
<Skeleton w="50%" h="10px" mt="2" />
|
||||
)}
|
||||
</Stat>
|
||||
<Stat bgColor="white" p="4" rounded="md" boxShadow="md">
|
||||
<Stat bgColor={bg} p="4" rounded="md" boxShadow="md">
|
||||
<StatLabel>Starts</StatLabel>
|
||||
{stats ? (
|
||||
<StatNumber>{stats.totalStarts}</StatNumber>
|
||||
@ -31,7 +34,7 @@ export const StatsCards = ({
|
||||
<Skeleton w="50%" h="10px" mt="2" />
|
||||
)}
|
||||
</Stat>
|
||||
<Stat bgColor="white" p="4" rounded="md" boxShadow="md">
|
||||
<Stat bgColor={bg} p="4" rounded="md" boxShadow="md">
|
||||
<StatLabel>Completion rate</StatLabel>
|
||||
{stats ? (
|
||||
<StatNumber>
|
||||
|
@ -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: [],
|
||||
|
@ -44,7 +44,7 @@ export const CurrentSubscriptionContent = ({
|
||||
const isSubscribed = (plan === Plan.STARTER || plan === Plan.PRO) && stripeId
|
||||
|
||||
return (
|
||||
<Stack spacing="2">
|
||||
<Stack spacing="4">
|
||||
<Heading fontSize="3xl">Subscription</Heading>
|
||||
<HStack data-testid="current-subscription">
|
||||
<Text>Current workspace subscription: </Text>
|
||||
@ -70,7 +70,7 @@ export const CurrentSubscriptionContent = ({
|
||||
|
||||
{isSubscribed && !isCancelling && (
|
||||
<>
|
||||
<Stack spacing="1">
|
||||
<Stack spacing="4">
|
||||
<Text fontSize="sm">
|
||||
Need to change payment method or billing information? Head over to
|
||||
your billing portal:
|
||||
|
@ -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"
|
||||
>
|
||||
<Flex justifyContent="center">
|
||||
@ -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 }}
|
||||
|
@ -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<HTMLDivElement | null>(null)
|
||||
const rememberedSelection = useRef<BaseSelection | null>(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'),
|
||||
},
|
||||
}}
|
||||
>
|
||||
<ToolBar onVariablesButtonClick={() => setIsVariableDropdownOpen(true)} />
|
||||
<Plate
|
||||
id={id}
|
||||
editableProps={{
|
||||
style: editorStyle,
|
||||
style: editorStyle(useColorModeValue('white', colors.gray[850])),
|
||||
autoFocus: true,
|
||||
onFocus: () => {
|
||||
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}
|
||||
>
|
||||
|
@ -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 (
|
||||
<HStack
|
||||
bgColor={'white'}
|
||||
bgColor={useColorModeValue('white', 'gray.850')}
|
||||
borderTopRadius="md"
|
||||
p={2}
|
||||
w="full"
|
||||
|
@ -126,7 +126,8 @@ export const WebhookSettings = ({
|
||||
const handleTestRequestClick = async () => {
|
||||
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(
|
||||
|
@ -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) && (
|
||||
<HStack p="4">
|
||||
<SkeletonCircle boxSize="32px" />
|
||||
<SkeletonText width="200px" noOfLines={2} />
|
||||
<HStack p="4" justifyContent="space-between">
|
||||
<HStack>
|
||||
<SkeletonCircle boxSize="32px" />
|
||||
<Skeleton width="230px" h="10px" />
|
||||
</HStack>
|
||||
<Skeleton width="80px" h="10px" />
|
||||
</HStack>
|
||||
)}
|
||||
</Stack>
|
||||
|
@ -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<Typebot>()
|
||||
@ -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) => {
|
||||
/>
|
||||
<ModalOverlay />
|
||||
<ModalContent h="85vh">
|
||||
<ModalBody>
|
||||
<ModalBody p="10">
|
||||
{typebot && (
|
||||
<TypebotViewer
|
||||
apiHost={getViewerUrl({ isBuilder: true })}
|
||||
@ -125,6 +129,7 @@ export const OnboardingModal = ({ totalTypebots }: Props) => {
|
||||
Name: user?.name?.split(' ')[0] ?? undefined,
|
||||
}}
|
||||
onNewAnswer={handleNewAnswer}
|
||||
style={{ borderRadius: '0.25rem' }}
|
||||
/>
|
||||
)}
|
||||
</ModalBody>
|
||||
|
@ -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 = ({
|
||||
<Flex pos="relative">
|
||||
<HStack
|
||||
borderWidth="1px"
|
||||
borderColor="gray.200"
|
||||
borderColor={useColorModeValue('gray.200', 'gray.800')}
|
||||
rounded="lg"
|
||||
flex="1"
|
||||
cursor={'grab'}
|
||||
opacity={isMouseDown || isDisabled ? '0.4' : '1'}
|
||||
onMouseDown={handleMouseDown}
|
||||
bgColor="gray.50"
|
||||
bgColor={useColorModeValue('gray.50', 'gray.850')}
|
||||
px="4"
|
||||
py="2"
|
||||
_hover={{ shadow: 'md' }}
|
||||
transition="box-shadow 200ms"
|
||||
_hover={useColorModeValue({ shadow: 'md' }, { bgColor: 'gray.800' })}
|
||||
transition="box-shadow 200ms, background-color 200ms"
|
||||
pointerEvents={isDisabled ? 'none' : 'auto'}
|
||||
>
|
||||
{!isMouseDown ? (
|
||||
@ -46,38 +52,9 @@ export const BlockCard = ({
|
||||
<BlockIcon type={type} />
|
||||
<BlockTypeLabel type={type} />
|
||||
</>
|
||||
) : (
|
||||
<Text color="white" userSelect="none">
|
||||
Placeholder
|
||||
</Text>
|
||||
)}
|
||||
) : null}
|
||||
</HStack>
|
||||
</Flex>
|
||||
</Tooltip>
|
||||
)
|
||||
}
|
||||
|
||||
export const BlockCardOverlay = ({
|
||||
type,
|
||||
...props
|
||||
}: StackProps & { type: BlockType }) => {
|
||||
return (
|
||||
<HStack
|
||||
borderWidth="1px"
|
||||
rounded="lg"
|
||||
cursor={'grabbing'}
|
||||
w="147px"
|
||||
transition="none"
|
||||
pointerEvents="none"
|
||||
px="4"
|
||||
py="2"
|
||||
bgColor="white"
|
||||
shadow="xl"
|
||||
zIndex={2}
|
||||
{...props}
|
||||
>
|
||||
<BlockIcon type={type} />
|
||||
<BlockTypeLabel type={type} />
|
||||
</HStack>
|
||||
)
|
||||
}
|
||||
|
@ -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 (
|
||||
<HStack
|
||||
borderWidth="1px"
|
||||
rounded="lg"
|
||||
cursor={'grabbing'}
|
||||
w="147px"
|
||||
transition="none"
|
||||
pointerEvents="none"
|
||||
px="4"
|
||||
py="2"
|
||||
borderColor={useColorModeValue('gray.200', 'gray.800')}
|
||||
bgColor={useColorModeValue('gray.50', 'gray.850')}
|
||||
shadow="xl"
|
||||
zIndex={2}
|
||||
{...props}
|
||||
>
|
||||
<BlockIcon type={type} />
|
||||
<BlockTypeLabel type={type} />
|
||||
</HStack>
|
||||
)
|
||||
}
|
@ -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 <TextBubbleIcon {...props} />
|
||||
return <TextBubbleIcon color={blue} {...props} />
|
||||
case BubbleBlockType.IMAGE:
|
||||
return <ImageBubbleIcon {...props} />
|
||||
return <ImageBubbleIcon color={blue} {...props} />
|
||||
case BubbleBlockType.VIDEO:
|
||||
return <VideoBubbleIcon {...props} />
|
||||
return <VideoBubbleIcon color={blue} {...props} />
|
||||
case BubbleBlockType.EMBED:
|
||||
return <EmbedBubbleIcon {...props} />
|
||||
return <EmbedBubbleIcon color={blue} {...props} />
|
||||
case BubbleBlockType.AUDIO:
|
||||
return <AudioBubbleIcon {...props} />
|
||||
return <AudioBubbleIcon color={blue} {...props} />
|
||||
case InputBlockType.TEXT:
|
||||
return <TextInputIcon {...props} />
|
||||
return <TextInputIcon color={orange} {...props} />
|
||||
case InputBlockType.NUMBER:
|
||||
return <NumberInputIcon {...props} />
|
||||
return <NumberInputIcon color={orange} {...props} />
|
||||
case InputBlockType.EMAIL:
|
||||
return <EmailInputIcon {...props} />
|
||||
return <EmailInputIcon color={orange} {...props} />
|
||||
case InputBlockType.URL:
|
||||
return <UrlInputIcon {...props} />
|
||||
return <UrlInputIcon color={orange} {...props} />
|
||||
case InputBlockType.DATE:
|
||||
return <DateInputIcon {...props} />
|
||||
return <DateInputIcon color={orange} {...props} />
|
||||
case InputBlockType.PHONE:
|
||||
return <PhoneInputIcon {...props} />
|
||||
return <PhoneInputIcon color={orange} {...props} />
|
||||
case InputBlockType.CHOICE:
|
||||
return <ButtonsInputIcon {...props} />
|
||||
return <ButtonsInputIcon color={orange} {...props} />
|
||||
case InputBlockType.PAYMENT:
|
||||
return <PaymentInputIcon {...props} />
|
||||
return <PaymentInputIcon color={orange} {...props} />
|
||||
case InputBlockType.RATING:
|
||||
return <RatingInputIcon {...props} />
|
||||
return <RatingInputIcon color={orange} {...props} />
|
||||
case InputBlockType.FILE:
|
||||
return <FileInputIcon {...props} />
|
||||
return <FileInputIcon color={orange} {...props} />
|
||||
case LogicBlockType.SET_VARIABLE:
|
||||
return <SetVariableIcon {...props} />
|
||||
return <SetVariableIcon color={purple} {...props} />
|
||||
case LogicBlockType.CONDITION:
|
||||
return <ConditionIcon {...props} />
|
||||
return <ConditionIcon color={purple} {...props} />
|
||||
case LogicBlockType.REDIRECT:
|
||||
return <RedirectIcon {...props} />
|
||||
return <RedirectIcon color={purple} {...props} />
|
||||
case LogicBlockType.CODE:
|
||||
return <CodeIcon {...props} />
|
||||
return <CodeIcon color={purple} {...props} />
|
||||
case LogicBlockType.TYPEBOT_LINK:
|
||||
return <TypebotLinkIcon {...props} />
|
||||
return <TypebotLinkIcon color={purple} {...props} />
|
||||
case IntegrationBlockType.GOOGLE_SHEETS:
|
||||
return <GoogleSheetsLogo {...props} />
|
||||
case IntegrationBlockType.GOOGLE_ANALYTICS:
|
||||
|
@ -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 ? <LockedIcon /> : <UnlockedIcon />}
|
||||
aria-label={isLocked ? 'Unlock' : 'Lock'}
|
||||
size="sm"
|
||||
variant="outline"
|
||||
onClick={handleLockClick}
|
||||
/>
|
||||
</Tooltip>
|
||||
</Flex>
|
||||
|
||||
<Stack>
|
||||
<Text fontSize="sm" fontWeight="semibold" color="gray.600">
|
||||
<Text fontSize="sm" fontWeight="semibold">
|
||||
Bubbles
|
||||
</Text>
|
||||
<SimpleGrid columns={2} spacing="3">
|
||||
@ -123,7 +124,7 @@ export const BlocksSideBar = () => {
|
||||
</Stack>
|
||||
|
||||
<Stack>
|
||||
<Text fontSize="sm" fontWeight="semibold" color="gray.600">
|
||||
<Text fontSize="sm" fontWeight="semibold">
|
||||
Inputs
|
||||
</Text>
|
||||
<SimpleGrid columns={2} spacing="3">
|
||||
@ -134,7 +135,7 @@ export const BlocksSideBar = () => {
|
||||
</Stack>
|
||||
|
||||
<Stack>
|
||||
<Text fontSize="sm" fontWeight="semibold" color="gray.600">
|
||||
<Text fontSize="sm" fontWeight="semibold">
|
||||
Logic
|
||||
</Text>
|
||||
<SimpleGrid columns={2} spacing="3">
|
||||
@ -145,7 +146,7 @@ export const BlocksSideBar = () => {
|
||||
</Stack>
|
||||
|
||||
<Stack>
|
||||
<Text fontSize="sm" fontWeight="semibold" color="gray.600">
|
||||
<Text fontSize="sm" fontWeight="semibold">
|
||||
Integrations
|
||||
</Text>
|
||||
<SimpleGrid columns={2} spacing="3">
|
||||
|
@ -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 (
|
||||
<Menu>
|
||||
<MenuButton
|
||||
as={IconButton}
|
||||
bgColor="white"
|
||||
icon={<MoreVerticalIcon transform={'rotate(90deg)'} />}
|
||||
isLoading={isDownloading}
|
||||
size="sm"
|
||||
shadow="lg"
|
||||
{...props}
|
||||
/>
|
||||
<MenuList>
|
||||
<MenuItem icon={<SettingsIcon />} onClick={onOpen}>
|
||||
Editor settings
|
||||
</MenuItem>
|
||||
<MenuItem icon={<DownloadIcon />} onClick={downloadFlow}>
|
||||
Export flow
|
||||
</MenuItem>
|
||||
</MenuList>
|
||||
<EditorSettingsModal isOpen={isOpen} onClose={onClose} />
|
||||
</Menu>
|
||||
<Flex
|
||||
bgColor={useColorModeValue('white', 'gray.900')}
|
||||
rounded="md"
|
||||
{...props}
|
||||
>
|
||||
<Menu>
|
||||
<MenuButton
|
||||
as={IconButton}
|
||||
icon={<MoreVerticalIcon transform={'rotate(90deg)'} />}
|
||||
isLoading={isDownloading}
|
||||
size="sm"
|
||||
shadow="lg"
|
||||
bgColor={useColorModeValue('white', undefined)}
|
||||
/>
|
||||
<MenuList>
|
||||
<MenuItem icon={<SettingsIcon />} onClick={onOpen}>
|
||||
Editor settings
|
||||
</MenuItem>
|
||||
<MenuItem icon={<DownloadIcon />} onClick={downloadFlow}>
|
||||
Export flow
|
||||
</MenuItem>
|
||||
</MenuList>
|
||||
<EditorSettingsModal isOpen={isOpen} onClose={onClose} />
|
||||
</Menu>
|
||||
</Flex>
|
||||
)
|
||||
}
|
||||
|
@ -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 = () => {
|
||||
</GraphProvider>
|
||||
</GraphDndProvider>
|
||||
) : (
|
||||
<Flex
|
||||
justify="center"
|
||||
align="center"
|
||||
boxSize="full"
|
||||
bgColor="rgba(255, 255, 255, 0.5)"
|
||||
>
|
||||
<Flex justify="center" align="center" boxSize="full">
|
||||
<Spinner color="gray" />
|
||||
</Flex>
|
||||
)}
|
||||
|
@ -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<string>(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: <MouseIcon boxSize="35px" />,
|
||||
},
|
||||
{
|
||||
value: GraphNavigation.TRACKPAD,
|
||||
label: 'Trackpad',
|
||||
description: 'Move the board using 2 fingers and zoom in/out by pinching',
|
||||
icon: <LaptopIcon boxSize="35px" />,
|
||||
},
|
||||
]
|
||||
|
||||
return (
|
||||
<Stack spacing={6}>
|
||||
<Heading size="md">Editor Navigation</Heading>
|
||||
<RadioGroup onChange={changeEditorNavigation} value={value}>
|
||||
<HStack spacing={4} w="full" align="stretch">
|
||||
{options.map((option) => (
|
||||
<VStack
|
||||
key={option.value}
|
||||
as="label"
|
||||
htmlFor={option.label}
|
||||
cursor="pointer"
|
||||
borderWidth="1px"
|
||||
borderRadius="md"
|
||||
w="full"
|
||||
p="6"
|
||||
spacing={6}
|
||||
justifyContent="space-between"
|
||||
>
|
||||
<VStack spacing={6}>
|
||||
{option.icon}
|
||||
<Stack>
|
||||
<Text fontWeight="bold">{option.label}</Text>
|
||||
<Text>{option.description}</Text>
|
||||
</Stack>
|
||||
</VStack>
|
||||
|
||||
<Radio value={option.value} id={option.label} />
|
||||
</VStack>
|
||||
))}
|
||||
</HStack>
|
||||
</RadioGroup>
|
||||
</Stack>
|
||||
)
|
||||
}
|
@ -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 (
|
||||
<Modal isOpen={isOpen} onClose={onClose} size="xl">
|
||||
<ModalOverlay />
|
||||
<ModalContent>
|
||||
<ModalCloseButton />
|
||||
<ModalBody pt="12" pb="8" px="8">
|
||||
<EditorSettingsForm
|
||||
defaultGraphNavigation={
|
||||
user?.graphNavigation ?? GraphNavigation.TRACKPAD
|
||||
}
|
||||
/>
|
||||
</ModalBody>
|
||||
</ModalContent>
|
||||
</Modal>
|
||||
)
|
||||
}
|
||||
export const EditorSettingsModal = ({ isOpen, onClose }: Props) => (
|
||||
<Modal isOpen={isOpen} onClose={onClose} size="xl">
|
||||
<ModalOverlay />
|
||||
<ModalContent>
|
||||
<ModalCloseButton />
|
||||
<ModalBody pt="12" pb="8" px="8">
|
||||
<UserPreferencesForm />
|
||||
</ModalBody>
|
||||
</ModalContent>
|
||||
</Modal>
|
||||
)
|
||||
|
@ -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' }}
|
||||
/>
|
||||
<Accordion allowToggle>
|
||||
<AccordionItem>
|
||||
@ -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' }}
|
||||
/>
|
||||
<iframe
|
||||
width="100%"
|
||||
height="315"
|
||||
src="https://www.youtube.com/embed/ZuyDwFLRbfQ"
|
||||
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' }}
|
||||
/>
|
||||
</AccordionPanel>
|
||||
</AccordionItem>
|
||||
|
@ -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 = () => {
|
||||
>
|
||||
<Fade in={isResizeHandleVisible}>
|
||||
<ResizeHandle
|
||||
isDark={isDark}
|
||||
pos="absolute"
|
||||
left="-7.5px"
|
||||
top={`calc(50% - ${headerHeight}px)`}
|
||||
@ -107,6 +111,7 @@ export const PreviewDrawer = () => {
|
||||
onNewLog={handleNewLog}
|
||||
startGroupId={startPreviewAtGroup}
|
||||
isPreview
|
||||
style={{ borderRadius: '10px' }}
|
||||
/>
|
||||
</Flex>
|
||||
)}
|
||||
@ -115,20 +120,26 @@ export const PreviewDrawer = () => {
|
||||
)
|
||||
}
|
||||
|
||||
const ResizeHandle = (props: FlexProps) => {
|
||||
const ResizeHandle = (props: FlexProps & { isDark: boolean }) => {
|
||||
return (
|
||||
<Flex
|
||||
w="15px"
|
||||
h="50px"
|
||||
borderWidth={'1px'}
|
||||
bgColor={'white'}
|
||||
bgColor={props.isDark ? 'gray.800' : 'white'}
|
||||
cursor={'col-resize'}
|
||||
justifyContent={'center'}
|
||||
align={'center'}
|
||||
borderRadius={'sm'}
|
||||
{...props}
|
||||
>
|
||||
<Box w="2px" bgColor={'gray.300'} h="70%" mr="0.5" />
|
||||
<Box w="2px" bgColor={'gray.300'} h="70%" />
|
||||
<Box
|
||||
w="2px"
|
||||
bgColor={props.isDark ? 'gray.600' : 'gray.300'}
|
||||
h="70%"
|
||||
mr="0.5"
|
||||
/>
|
||||
<Box w="2px" bgColor={props.isDark ? 'gray.600' : 'gray.300'} h="70%" />
|
||||
</Flex>
|
||||
)
|
||||
}
|
||||
|
@ -39,7 +39,7 @@ export const EditableTypebotName = ({
|
||||
fontSize="14px"
|
||||
minW="30px"
|
||||
minH="20px"
|
||||
bgColor={currentName === '' ? 'gray.100' : 'white'}
|
||||
bgColor={currentName === '' ? 'gray.100' : 'inherit'}
|
||||
/>
|
||||
<EditableInput fontSize="14px" />
|
||||
</Editable>
|
||||
|
@ -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}
|
||||
>
|
||||
<HStack
|
||||
@ -201,6 +202,7 @@ export const TypebotHeader = () => {
|
||||
<CollaborationMenuButton isLoading={isNotDefined(typebot)} />
|
||||
{router.pathname.includes('/edit') && isNotDefined(rightPanel) && (
|
||||
<Button
|
||||
colorScheme="gray"
|
||||
onClick={handlePreviewClick}
|
||||
isLoading={isNotDefined(typebot)}
|
||||
size="sm"
|
||||
|
@ -1,7 +1,6 @@
|
||||
export { TypebotProvider, useTypebot } from './providers/TypebotProvider'
|
||||
export { TypebotHeader } from './components/TypebotHeader'
|
||||
export { EditTypebotPage } from './components/EditTypebotPage'
|
||||
export { EditorSettingsForm } from './components/EditorSettingsForm'
|
||||
export { headerHeight } from './constants'
|
||||
export { BlockIcon } from './components/BlocksSideBar/BlockIcon'
|
||||
export { RightPanel, useEditor } from './providers/EditorProvider'
|
||||
|
@ -15,6 +15,7 @@ import {
|
||||
SkeletonText,
|
||||
SkeletonCircle,
|
||||
WrapItem,
|
||||
useColorModeValue,
|
||||
} from '@chakra-ui/react'
|
||||
import { FolderIcon, MoreVerticalIcon } from '@/components/icons'
|
||||
import { ConfirmModal } from '@/components/ConfirmModal'
|
||||
@ -118,7 +119,9 @@ export const FolderButton = ({
|
||||
onSubmit={onRenameSubmit}
|
||||
>
|
||||
<EditablePreview
|
||||
_hover={{ bgColor: 'gray.300' }}
|
||||
_hover={{
|
||||
bg: useColorModeValue('gray.100', 'gray.700'),
|
||||
}}
|
||||
px="2"
|
||||
textAlign="center"
|
||||
/>
|
||||
|
@ -102,7 +102,6 @@ export const TypebotButton = ({
|
||||
display="flex"
|
||||
flexDir="column"
|
||||
variant="outline"
|
||||
color="gray.800"
|
||||
w="225px"
|
||||
h="270px"
|
||||
mr={{ sm: 6 }}
|
||||
|
@ -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) => {
|
||||
<path
|
||||
data-testid="edge"
|
||||
d={path}
|
||||
stroke={isPreviewing ? colors.blue[400] : colors.gray[400]}
|
||||
stroke={
|
||||
isPreviewing
|
||||
? colors.blue[400]
|
||||
: isDark
|
||||
? colors.gray[700]
|
||||
: colors.gray[400]
|
||||
}
|
||||
strokeWidth="2px"
|
||||
markerEnd={isPreviewing ? 'url(#blue-arrow)' : 'url(#arrow)'}
|
||||
fill="none"
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { chakra } from '@chakra-ui/react'
|
||||
import { chakra, useColorMode } from '@chakra-ui/react'
|
||||
import { colors } from '@/lib/theme'
|
||||
import { Edge as EdgeProps } from 'models'
|
||||
import React from 'react'
|
||||
@ -17,72 +17,75 @@ export const Edges = ({
|
||||
edges,
|
||||
answersCounts,
|
||||
onUnlockProPlanClick,
|
||||
}: Props) => (
|
||||
<chakra.svg
|
||||
width="full"
|
||||
height="full"
|
||||
overflow="visible"
|
||||
pos="absolute"
|
||||
left="0"
|
||||
top="0"
|
||||
shapeRendering="geometricPrecision"
|
||||
>
|
||||
<DrawingEdge />
|
||||
{edges.map((edge) => (
|
||||
<Edge key={edge.id} edge={edge} />
|
||||
))}
|
||||
{answersCounts?.map((answerCount) => (
|
||||
<DropOffEdge
|
||||
key={answerCount.groupId}
|
||||
answersCounts={answersCounts}
|
||||
groupId={answerCount.groupId}
|
||||
onUnlockProPlanClick={onUnlockProPlanClick}
|
||||
/>
|
||||
))}
|
||||
<marker
|
||||
id={'arrow'}
|
||||
refX="8"
|
||||
refY="4"
|
||||
orient="auto"
|
||||
viewBox="0 0 20 20"
|
||||
markerUnits="userSpaceOnUse"
|
||||
markerWidth="20"
|
||||
markerHeight="20"
|
||||
}: Props) => {
|
||||
const isDark = useColorMode().colorMode === 'dark'
|
||||
return (
|
||||
<chakra.svg
|
||||
width="full"
|
||||
height="full"
|
||||
overflow="visible"
|
||||
pos="absolute"
|
||||
left="0"
|
||||
top="0"
|
||||
shapeRendering="geometricPrecision"
|
||||
>
|
||||
<path
|
||||
d="M7.07138888,5.50174526 L2.43017246,7.82235347 C1.60067988,8.23709976 0.592024983,7.90088146 0.177278692,7.07138888 C0.0606951226,6.83822174 0,6.58111307 0,6.32042429 L0,1.67920787 C0,0.751806973 0.751806973,0 1.67920787,0 C1.93989666,0 2.19700532,0.0606951226 2.43017246,0.177278692 L7,3 C7.82949258,3.41474629 8.23709976,3.92128809 7.82235347,4.75078067 C7.6598671,5.07575341 7.39636161,5.33925889 7.07138888,5.50174526 Z"
|
||||
fill={colors.gray[400]}
|
||||
/>
|
||||
</marker>
|
||||
<marker
|
||||
id={'blue-arrow'}
|
||||
refX="8"
|
||||
refY="4"
|
||||
orient="auto"
|
||||
viewBox="0 0 20 20"
|
||||
markerUnits="userSpaceOnUse"
|
||||
markerWidth="20"
|
||||
markerHeight="20"
|
||||
>
|
||||
<path
|
||||
d="M7.07138888,5.50174526 L2.43017246,7.82235347 C1.60067988,8.23709976 0.592024983,7.90088146 0.177278692,7.07138888 C0.0606951226,6.83822174 0,6.58111307 0,6.32042429 L0,1.67920787 C0,0.751806973 0.751806973,0 1.67920787,0 C1.93989666,0 2.19700532,0.0606951226 2.43017246,0.177278692 L7,3 C7.82949258,3.41474629 8.23709976,3.92128809 7.82235347,4.75078067 C7.6598671,5.07575341 7.39636161,5.33925889 7.07138888,5.50174526 Z"
|
||||
fill={colors.blue[400]}
|
||||
/>
|
||||
</marker>
|
||||
<marker
|
||||
id={'red-arrow'}
|
||||
refX="8"
|
||||
refY="4"
|
||||
orient="auto"
|
||||
viewBox="0 0 20 20"
|
||||
markerUnits="userSpaceOnUse"
|
||||
markerWidth="20"
|
||||
markerHeight="20"
|
||||
>
|
||||
<path
|
||||
d="M7.07138888,5.50174526 L2.43017246,7.82235347 C1.60067988,8.23709976 0.592024983,7.90088146 0.177278692,7.07138888 C0.0606951226,6.83822174 0,6.58111307 0,6.32042429 L0,1.67920787 C0,0.751806973 0.751806973,0 1.67920787,0 C1.93989666,0 2.19700532,0.0606951226 2.43017246,0.177278692 L7,3 C7.82949258,3.41474629 8.23709976,3.92128809 7.82235347,4.75078067 C7.6598671,5.07575341 7.39636161,5.33925889 7.07138888,5.50174526 Z"
|
||||
fill="#e53e3e"
|
||||
/>
|
||||
</marker>
|
||||
</chakra.svg>
|
||||
)
|
||||
<DrawingEdge />
|
||||
{edges.map((edge) => (
|
||||
<Edge key={edge.id} edge={edge} />
|
||||
))}
|
||||
{answersCounts?.map((answerCount) => (
|
||||
<DropOffEdge
|
||||
key={answerCount.groupId}
|
||||
answersCounts={answersCounts}
|
||||
groupId={answerCount.groupId}
|
||||
onUnlockProPlanClick={onUnlockProPlanClick}
|
||||
/>
|
||||
))}
|
||||
<marker
|
||||
id={'arrow'}
|
||||
refX="8"
|
||||
refY="4"
|
||||
orient="auto"
|
||||
viewBox="0 0 20 20"
|
||||
markerUnits="userSpaceOnUse"
|
||||
markerWidth="20"
|
||||
markerHeight="20"
|
||||
>
|
||||
<path
|
||||
d="M7.07138888,5.50174526 L2.43017246,7.82235347 C1.60067988,8.23709976 0.592024983,7.90088146 0.177278692,7.07138888 C0.0606951226,6.83822174 0,6.58111307 0,6.32042429 L0,1.67920787 C0,0.751806973 0.751806973,0 1.67920787,0 C1.93989666,0 2.19700532,0.0606951226 2.43017246,0.177278692 L7,3 C7.82949258,3.41474629 8.23709976,3.92128809 7.82235347,4.75078067 C7.6598671,5.07575341 7.39636161,5.33925889 7.07138888,5.50174526 Z"
|
||||
fill={isDark ? colors.gray[600] : colors.gray[400]}
|
||||
/>
|
||||
</marker>
|
||||
<marker
|
||||
id={'blue-arrow'}
|
||||
refX="8"
|
||||
refY="4"
|
||||
orient="auto"
|
||||
viewBox="0 0 20 20"
|
||||
markerUnits="userSpaceOnUse"
|
||||
markerWidth="20"
|
||||
markerHeight="20"
|
||||
>
|
||||
<path
|
||||
d="M7.07138888,5.50174526 L2.43017246,7.82235347 C1.60067988,8.23709976 0.592024983,7.90088146 0.177278692,7.07138888 C0.0606951226,6.83822174 0,6.58111307 0,6.32042429 L0,1.67920787 C0,0.751806973 0.751806973,0 1.67920787,0 C1.93989666,0 2.19700532,0.0606951226 2.43017246,0.177278692 L7,3 C7.82949258,3.41474629 8.23709976,3.92128809 7.82235347,4.75078067 C7.6598671,5.07575341 7.39636161,5.33925889 7.07138888,5.50174526 Z"
|
||||
fill={colors.blue[400]}
|
||||
/>
|
||||
</marker>
|
||||
<marker
|
||||
id={'red-arrow'}
|
||||
refX="8"
|
||||
refY="4"
|
||||
orient="auto"
|
||||
viewBox="0 0 20 20"
|
||||
markerUnits="userSpaceOnUse"
|
||||
markerWidth="20"
|
||||
markerHeight="20"
|
||||
>
|
||||
<path
|
||||
d="M7.07138888,5.50174526 L2.43017246,7.82235347 C1.60067988,8.23709976 0.592024983,7.90088146 0.177278692,7.07138888 C0.0606951226,6.83822174 0,6.58111307 0,6.32042429 L0,1.67920787 C0,0.751806973 0.751806973,0 1.67920787,0 C1.93989666,0 2.19700532,0.0606951226 2.43017246,0.177278692 L7,3 C7.82949258,3.41474629 8.23709976,3.92128809 7.82235347,4.75078067 C7.6598671,5.07575341 7.39636161,5.33925889 7.07138888,5.50174526 Z"
|
||||
fill="#e53e3e"
|
||||
/>
|
||||
</marker>
|
||||
</chakra.svg>
|
||||
)
|
||||
}
|
||||
|
@ -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"
|
||||
>
|
||||
<Flex
|
||||
@ -72,8 +80,8 @@ export const SourceEndpoint = ({
|
||||
borderColor={
|
||||
previewingEdge?.from.blockId === source.blockId &&
|
||||
previewingEdge.from.itemId === source.itemId
|
||||
? 'blue.300'
|
||||
: 'blue.200'
|
||||
? connectedColor
|
||||
: color
|
||||
}
|
||||
/>
|
||||
</Flex>
|
||||
|
@ -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 {
|
||||
NodePosition,
|
||||
useBlockDnd,
|
||||
useDragDistance,
|
||||
useGraph,
|
||||
} from '../../../providers'
|
||||
import { ContextMenu } from '@/components/ContextMenu'
|
||||
import { setMultipleRefs } from '@/utils/helpers'
|
||||
import { TextBubbleEditor } from '@/features/blocks/bubbles/textBubble'
|
||||
import {
|
||||
NodePosition,
|
||||
useGraph,
|
||||
useBlockDnd,
|
||||
useDragDistance,
|
||||
} from '../../../providers'
|
||||
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 = ({
|
||||
<ContextMenu<HTMLDivElement>
|
||||
renderMenu={() => <BlockNodeContextMenu indices={indices} />}
|
||||
>
|
||||
{(ref, isOpened) => (
|
||||
{(ref, isContextMenuOpened) => (
|
||||
<Popover
|
||||
placement="left"
|
||||
isLazy
|
||||
@ -186,12 +190,18 @@ export const BlockNode = ({
|
||||
flex="1"
|
||||
userSelect="none"
|
||||
p="3"
|
||||
borderWidth={isOpened || isPreviewing ? '2px' : '1px'}
|
||||
borderColor={isOpened || isPreviewing ? 'blue.400' : 'gray.200'}
|
||||
margin={isOpened || isPreviewing ? '-1px' : 0}
|
||||
borderWidth={
|
||||
isContextMenuOpened || isPreviewing ? '2px' : '1px'
|
||||
}
|
||||
borderColor={
|
||||
isContextMenuOpened || isPreviewing
|
||||
? previewingBorderColor
|
||||
: borderColor
|
||||
}
|
||||
margin={isContextMenuOpened || isPreviewing ? '-1px' : 0}
|
||||
rounded="lg"
|
||||
cursor={'pointer'}
|
||||
bgColor="gray.50"
|
||||
bg={bg}
|
||||
align="flex-start"
|
||||
w="full"
|
||||
transition="border-color 0.2s"
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { BlockIcon } from '@/features/editor'
|
||||
import { StackProps, HStack } from '@chakra-ui/react'
|
||||
import { StackProps, HStack, useColorModeValue } from '@chakra-ui/react'
|
||||
import { StartBlock, Block, BlockIndices } from 'models'
|
||||
import { BlockNodeContent } from './BlockNodeContent/BlockNodeContent'
|
||||
|
||||
@ -13,7 +13,8 @@ export const BlockNodeOverlay = ({
|
||||
p="3"
|
||||
borderWidth="1px"
|
||||
rounded="lg"
|
||||
bgColor="white"
|
||||
borderColor={useColorModeValue('gray.200', 'gray.800')}
|
||||
bgColor={useColorModeValue('gray.50', 'gray.850')}
|
||||
cursor={'grab'}
|
||||
w="264px"
|
||||
pointerEvents="none"
|
||||
|
@ -10,6 +10,8 @@ import { useEffect, useRef, useState } from 'react'
|
||||
import { useTypebot } from '@/features/editor'
|
||||
import { BlockNode } from './BlockNode'
|
||||
import { BlockNodeOverlay } from './BlockNodeOverlay'
|
||||
import { PlaceholderNode } from '../PlaceholderNode'
|
||||
import { isDefined } from 'utils'
|
||||
|
||||
type Props = {
|
||||
groupId: string
|
||||
@ -49,7 +51,7 @@ export const BlockNodesList = ({
|
||||
const isDraggingOnCurrentGroup =
|
||||
(draggedBlock || draggedBlockType) && mouseOverGroup?.id === groupId
|
||||
const showSortPlaceholders =
|
||||
!isStartGroup && (draggedBlock || draggedBlockType)
|
||||
!isStartGroup && isDefined(draggedBlock || draggedBlockType)
|
||||
|
||||
useEffect(() => {
|
||||
if (mouseOverGroup?.id !== groupId) setExpandedPlaceholderIndex(undefined)
|
||||
@ -126,17 +128,10 @@ export const BlockNodesList = ({
|
||||
transition="none"
|
||||
pointerEvents={isReadOnly || isStartGroup ? 'none' : 'auto'}
|
||||
>
|
||||
<Flex
|
||||
ref={handlePushElementRef(0)}
|
||||
h={
|
||||
showSortPlaceholders && expandedPlaceholderIndex === 0
|
||||
? '50px'
|
||||
: '2px'
|
||||
}
|
||||
bgColor={'gray.300'}
|
||||
visibility={showSortPlaceholders ? 'visible' : 'hidden'}
|
||||
rounded="lg"
|
||||
transition={showSortPlaceholders ? 'height 200ms' : 'none'}
|
||||
<PlaceholderNode
|
||||
isVisible={showSortPlaceholders}
|
||||
isExpanded={expandedPlaceholderIndex === 0}
|
||||
onRef={handlePushElementRef(0)}
|
||||
/>
|
||||
{typebot &&
|
||||
blocks.map((block, idx) => (
|
||||
@ -148,17 +143,10 @@ export const BlockNodesList = ({
|
||||
isConnectable={blocks.length - 1 === idx}
|
||||
onMouseDown={handleBlockMouseDown(idx)}
|
||||
/>
|
||||
<Flex
|
||||
ref={handlePushElementRef(idx + 1)}
|
||||
h={
|
||||
showSortPlaceholders && expandedPlaceholderIndex === idx + 1
|
||||
? '50px'
|
||||
: '2px'
|
||||
}
|
||||
bgColor={'gray.300'}
|
||||
visibility={showSortPlaceholders ? 'visible' : 'hidden'}
|
||||
rounded="lg"
|
||||
transition={showSortPlaceholders ? 'height 200ms' : 'none'}
|
||||
<PlaceholderNode
|
||||
isVisible={showSortPlaceholders}
|
||||
isExpanded={expandedPlaceholderIndex === idx + 1}
|
||||
onRef={handlePushElementRef(idx + 1)}
|
||||
/>
|
||||
</Stack>
|
||||
))}
|
||||
|
@ -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={() => <GroupNodeContextMenu groupIndex={groupIndex} />}
|
||||
isDisabled={isReadOnly || isStartGroup}
|
||||
>
|
||||
{(ref, isOpened) => (
|
||||
{(ref, isContextMenuOpened) => (
|
||||
<Stack
|
||||
ref={setMultipleRefs([ref, groupRef])}
|
||||
data-testid="group"
|
||||
p="4"
|
||||
rounded="xl"
|
||||
bgColor="#ffffff"
|
||||
borderWidth="2px"
|
||||
bg={bg}
|
||||
borderWidth={
|
||||
isConnecting || isContextMenuOpened || isPreviewing ? '2px' : '1px'
|
||||
}
|
||||
borderColor={
|
||||
isConnecting || isOpened || isPreviewing ? 'blue.400' : '#ffffff'
|
||||
isConnecting || isContextMenuOpened || isPreviewing
|
||||
? previewingBorderColor
|
||||
: borderColor
|
||||
}
|
||||
w="300px"
|
||||
transition="border 300ms, box-shadow 200ms"
|
||||
@ -208,7 +217,9 @@ const NonMemoizedDraggableGroupNode = ({
|
||||
pr="8"
|
||||
>
|
||||
<EditablePreview
|
||||
_hover={{ bgColor: 'gray.200' }}
|
||||
_hover={{
|
||||
bg: editableHoverBg,
|
||||
}}
|
||||
px="1"
|
||||
userSelect={'none'}
|
||||
/>
|
||||
|
@ -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 = ({
|
||||
<ContextMenu<HTMLDivElement>
|
||||
renderMenu={() => <ItemNodeContextMenu indices={indices} />}
|
||||
>
|
||||
{(ref, isOpened) => (
|
||||
{(ref, isContextMenuOpened) => (
|
||||
<Flex
|
||||
data-testid="item"
|
||||
pos="relative"
|
||||
@ -74,10 +77,14 @@ export const ItemNode = ({
|
||||
_hover={{ shadow: 'md' }}
|
||||
transition="box-shadow 200ms, border-color 200ms"
|
||||
rounded="md"
|
||||
borderWidth={isOpened || isPreviewing ? '2px' : '1px'}
|
||||
borderColor={isOpened || isPreviewing ? 'blue.400' : 'gray.100'}
|
||||
margin={isOpened || isPreviewing ? '-1px' : 0}
|
||||
bgColor="white"
|
||||
bg={bg}
|
||||
borderWidth={isContextMenuOpened || isPreviewing ? '2px' : '1px'}
|
||||
borderColor={
|
||||
isContextMenuOpened || isPreviewing
|
||||
? previewingBorderColor
|
||||
: borderColor
|
||||
}
|
||||
margin={isContextMenuOpened || isPreviewing ? '-1px' : 0}
|
||||
w="full"
|
||||
>
|
||||
<ItemNodeContent
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { Flex, FlexProps } from '@chakra-ui/react'
|
||||
import { Flex, FlexProps, useColorModeValue } from '@chakra-ui/react'
|
||||
import { Item } from 'models'
|
||||
import React, { ReactNode } from 'react'
|
||||
|
||||
@ -12,9 +12,9 @@ export const ItemNodeOverlay = ({ item, ...props }: Props) => {
|
||||
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"
|
||||
|
@ -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 (
|
||||
<Stack flex={1} spacing={1} maxW="full" onClick={stopPropagating}>
|
||||
<Flex
|
||||
ref={handlePushElementRef(0)}
|
||||
h={showPlaceholders && expandedPlaceholderIndex === 0 ? '50px' : '2px'}
|
||||
bgColor={'gray.300'}
|
||||
visibility={showPlaceholders ? 'visible' : 'hidden'}
|
||||
rounded="lg"
|
||||
transition={showPlaceholders ? 'height 200ms' : 'none'}
|
||||
<PlaceholderNode
|
||||
isVisible={showPlaceholders}
|
||||
isExpanded={expandedPlaceholderIndex === 0}
|
||||
onRef={handlePushElementRef(0)}
|
||||
/>
|
||||
{block.items.map((item, idx) => (
|
||||
<Stack key={item.id} spacing={1}>
|
||||
@ -136,45 +142,14 @@ export const ItemNodesList = ({
|
||||
indices={{ groupIndex, blockIndex, itemIndex: idx }}
|
||||
onMouseDown={handleBlockMouseDown(idx)}
|
||||
/>
|
||||
<Flex
|
||||
ref={handlePushElementRef(idx + 1)}
|
||||
h={
|
||||
showPlaceholders && expandedPlaceholderIndex === idx + 1
|
||||
? '50px'
|
||||
: '2px'
|
||||
}
|
||||
bgColor={'gray.300'}
|
||||
visibility={showPlaceholders ? 'visible' : 'hidden'}
|
||||
rounded="lg"
|
||||
transition={showPlaceholders ? 'height 200ms' : 'none'}
|
||||
<PlaceholderNode
|
||||
isVisible={showPlaceholders}
|
||||
isExpanded={expandedPlaceholderIndex === idx + 1}
|
||||
onRef={handlePushElementRef(idx + 1)}
|
||||
/>
|
||||
</Stack>
|
||||
))}
|
||||
{isLastBlock && (
|
||||
<Flex
|
||||
px="4"
|
||||
py="2"
|
||||
borderWidth="1px"
|
||||
borderColor="gray.300"
|
||||
bgColor={'gray.50'}
|
||||
rounded="md"
|
||||
pos="relative"
|
||||
align="center"
|
||||
cursor="not-allowed"
|
||||
>
|
||||
<Text color="gray.500">
|
||||
{block.type === LogicBlockType.CONDITION ? 'Else' : 'Default'}
|
||||
</Text>
|
||||
<SourceEndpoint
|
||||
source={{
|
||||
groupId: block.groupId,
|
||||
blockId: block.id,
|
||||
}}
|
||||
pos="absolute"
|
||||
right="-49px"
|
||||
/>
|
||||
</Flex>
|
||||
)}
|
||||
{isLastBlock && <DefaultItemNode block={block} />}
|
||||
|
||||
{draggedItem && draggedItem.blockId === block.id && (
|
||||
<Portal>
|
||||
@ -189,14 +164,38 @@ export const ItemNodesList = ({
|
||||
w="220px"
|
||||
transformOrigin="0 0 0"
|
||||
>
|
||||
<ItemNode
|
||||
item={draggedItem}
|
||||
indices={{ groupIndex, blockIndex, itemIndex: 0 }}
|
||||
connectionDisabled
|
||||
/>
|
||||
<ItemNodeOverlay item={draggedItem} />
|
||||
</Flex>
|
||||
</Portal>
|
||||
)}
|
||||
</Stack>
|
||||
)
|
||||
}
|
||||
|
||||
const DefaultItemNode = ({ block }: { block: BlockWithItems }) => {
|
||||
return (
|
||||
<Flex
|
||||
px="4"
|
||||
py="2"
|
||||
borderWidth="1px"
|
||||
borderColor={useColorModeValue('gray.300', undefined)}
|
||||
bgColor={useColorModeValue('gray.50', 'gray.850')}
|
||||
rounded="md"
|
||||
pos="relative"
|
||||
align="center"
|
||||
cursor="not-allowed"
|
||||
>
|
||||
<Text color="gray.500">
|
||||
{block.type === LogicBlockType.CONDITION ? 'Else' : 'Default'}
|
||||
</Text>
|
||||
<SourceEndpoint
|
||||
source={{
|
||||
groupId: block.groupId,
|
||||
blockId: block.id,
|
||||
}}
|
||||
pos="absolute"
|
||||
right="-49px"
|
||||
/>
|
||||
</Flex>
|
||||
)
|
||||
}
|
||||
|
@ -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 (
|
||||
<Flex
|
||||
ref={onRef}
|
||||
h={isExpanded ? '50px' : '2px'}
|
||||
bgColor={useColorModeValue('gray.300', 'gray.700')}
|
||||
visibility={isVisible ? 'visible' : 'hidden'}
|
||||
rounded="lg"
|
||||
transition={isVisible ? 'height 200ms' : 'none'}
|
||||
/>
|
||||
)
|
||||
}
|
@ -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}
|
||||
/>
|
||||
<IconButton
|
||||
@ -33,7 +33,7 @@ export const ZoomButtons = ({
|
||||
aria-label={'Zoom out'}
|
||||
size="sm"
|
||||
onClick={onZoomOut}
|
||||
bgColor="white"
|
||||
bgColor={useColorModeValue('white', undefined)}
|
||||
borderTopRadius={0}
|
||||
/>
|
||||
</Stack>
|
||||
|
@ -111,7 +111,7 @@ export const ChatEmbedSettings = ({
|
||||
/>
|
||||
</HStack>
|
||||
<HStack justifyContent="space-between">
|
||||
<FormLabel htmlFor="custom-icon" mb="1" flexShrink={0}>
|
||||
<FormLabel htmlFor="custom-icon" mb="0" flexShrink={0}>
|
||||
Custom button icon?
|
||||
</FormLabel>
|
||||
<Switch
|
||||
@ -139,9 +139,8 @@ export const ChatEmbedSettings = ({
|
||||
alignItems="center"
|
||||
w="full"
|
||||
justifyContent="space-between"
|
||||
pr={1}
|
||||
>
|
||||
<FormLabel htmlFor="fullscreen-option" mb="1">
|
||||
<FormLabel htmlFor="fullscreen-option" mb="0">
|
||||
Enable popup message?
|
||||
</FormLabel>
|
||||
<Switch
|
||||
|
@ -2,18 +2,22 @@ import { Icon, IconProps } from '@chakra-ui/react'
|
||||
|
||||
export const NotionLogo = (props: IconProps) => (
|
||||
<Icon
|
||||
width="246"
|
||||
height="246"
|
||||
viewBox="0 0 246 246"
|
||||
fill="none"
|
||||
width="100"
|
||||
height="100"
|
||||
viewBox="0 0 100 100"
|
||||
fill="white"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
{...props}
|
||||
>
|
||||
<path
|
||||
d="M6.017 4.313l55.333 -4.087c6.797 -0.583 8.543 -0.19 12.817 2.917l17.663 12.443c2.913 2.14 3.883 2.723 3.883 5.053v68.243c0 4.277 -1.553 6.807 -6.99 7.193L24.467 99.967c-4.08 0.193 -6.023 -0.39 -8.16 -3.113L3.3 79.94c-2.333 -3.113 -3.3 -5.443 -3.3 -8.167V11.113c0 -3.497 1.553 -6.413 6.017 -6.8z"
|
||||
fill="#fff"
|
||||
/>
|
||||
<path
|
||||
fillRule="evenodd"
|
||||
clipRule="evenodd"
|
||||
d="M46.0982 43.7783C53.7102 49.9627 56.5657 49.4909 70.8599 48.5371L205.616 40.4456C208.474 40.4456 206.098 37.5944 205.144 37.1206L182.764 20.9415C178.476 17.6122 172.763 13.7995 161.813 14.7532L31.3283 24.2703C26.5695 24.7422 25.6191 27.1216 27.5142 29.0287L46.0982 43.7783ZM54.1887 75.1833V216.97C54.1887 224.59 57.9966 227.441 66.5672 226.97L214.664 218.4C223.239 217.929 224.194 212.688 224.194 206.497V65.6619C224.194 59.4818 221.817 56.1491 216.568 56.6248L61.805 65.6619C56.0934 66.1419 54.1883 68.9989 54.1883 75.1833H54.1887ZM200.39 82.789C201.339 87.0755 200.39 91.3581 196.095 91.84L188.96 93.2618V197.938C182.764 201.268 177.051 203.172 172.291 203.172C164.668 203.172 162.759 200.791 157.05 193.658L110.375 120.384V191.278L125.145 194.611C125.145 194.611 125.145 203.172 113.229 203.172L80.3785 205.077C79.4242 203.172 80.3785 198.418 83.7107 197.465L92.2832 195.089V101.353L80.3809 100.399C79.4261 96.1126 81.8036 89.932 88.4753 89.4525L123.716 87.0769L172.291 161.305V95.6407L159.906 94.2194C158.955 88.9792 162.759 85.1742 167.522 84.7023L200.39 82.789ZM20.3726 11.4244L156.097 1.42918C172.765 -0.000288379 177.053 0.957344 187.529 8.56689L230.854 39.0181C238.003 44.2545 240.386 45.6801 240.386 51.3884V218.4C240.386 228.867 236.572 235.057 223.242 236.005L65.624 245.523C55.6168 246 50.8541 244.574 45.6134 237.908L13.7082 196.513C7.99173 188.893 5.61426 183.192 5.61426 176.523V28.0715C5.61426 19.512 9.42842 12.3719 20.3726 11.4244V11.4244Z"
|
||||
fill="black"
|
||||
d="M61.35 0.227l-55.333 4.087C1.553 4.7 0 7.617 0 11.113v60.66c0 2.723 0.967 5.053 3.3 8.167l13.007 16.913c2.137 2.723 4.08 3.307 8.16 3.113l64.257 -3.89c5.433 -0.387 6.99 -2.917 6.99 -7.193V20.64c0 -2.21 -0.873 -2.847 -3.443 -4.733L74.167 3.143c-4.273 -3.107 -6.02 -3.5 -12.817 -2.917zM25.92 19.523c-5.247 0.353 -6.437 0.433 -9.417 -1.99L8.927 11.507c-0.77 -0.78 -0.383 -1.753 1.557 -1.947l53.193 -3.887c4.467 -0.39 6.793 1.167 8.54 2.527l9.123 6.61c0.39 0.197 1.36 1.36 0.193 1.36l-54.933 3.307 -0.68 0.047zM19.803 88.3V30.367c0 -2.53 0.777 -3.697 3.103 -3.893L86 22.78c2.14 -0.193 3.107 1.167 3.107 3.693v57.547c0 2.53 -0.39 4.67 -3.883 4.863l-60.377 3.5c-3.493 0.193 -5.043 -0.97 -5.043 -4.083zm59.6 -54.827c0.387 1.75 0 3.5 -1.75 3.7l-2.91 0.577v42.773c-2.527 1.36 -4.853 2.137 -6.797 2.137 -3.107 0 -3.883 -0.973 -6.21 -3.887l-19.03 -29.94v28.967l6.02 1.363s0 3.5 -4.857 3.5l-13.39 0.777c-0.39 -0.78 0 -2.723 1.357 -3.11l3.497 -0.97v-38.3L30.48 40.667c-0.39 -1.75 0.58 -4.277 3.3 -4.473l14.367 -0.967 19.8 30.327v-26.83l-5.047 -0.58c-0.39 -2.143 1.163 -3.7 3.103 -3.89l13.4 -0.78z"
|
||||
fill="#000"
|
||||
/>
|
||||
</Icon>
|
||||
)
|
||||
|
@ -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) => (
|
||||
<Icon
|
||||
width="512"
|
||||
height="512"
|
||||
viewBox="0 0 512 512"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
{...props}
|
||||
>
|
||||
<path
|
||||
d="M256 282C270.359 282 282 270.359 282 256C282 241.641 270.359 230 256 230C241.641 230 230 241.641 230 256C230 270.359 241.641 282 256 282Z"
|
||||
fill="black"
|
||||
/>
|
||||
<path
|
||||
d="M346 282C360.359 282 372 270.359 372 256C372 241.641 360.359 230 346 230C331.641 230 320 241.641 320 256C320 270.359 331.641 282 346 282Z"
|
||||
fill="black"
|
||||
/>
|
||||
<path
|
||||
d="M166 282C180.359 282 192 270.359 192 256C192 241.641 180.359 230 166 230C151.641 230 140 241.641 140 256C140 270.359 151.641 282 166 282Z"
|
||||
fill="black"
|
||||
/>
|
||||
<path
|
||||
d="M448 256C448 150 362 64 256 64C150 64 64 150 64 256C64 362 150 448 256 448C362 448 448 362 448 256Z"
|
||||
stroke="black"
|
||||
strokeWidth="32"
|
||||
strokeMiterlimit="10"
|
||||
/>
|
||||
</Icon>
|
||||
)
|
||||
export const OtherLogo = (props: IconProps) => {
|
||||
const stroke = useColorModeValue('black', colors.gray[200])
|
||||
return (
|
||||
<Icon
|
||||
width="512"
|
||||
height="512"
|
||||
viewBox="0 0 512 512"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
{...props}
|
||||
>
|
||||
<path
|
||||
d="M256 282C270.359 282 282 270.359 282 256C282 241.641 270.359 230 256 230C241.641 230 230 241.641 230 256C230 270.359 241.641 282 256 282Z"
|
||||
fill={stroke}
|
||||
/>
|
||||
<path
|
||||
d="M346 282C360.359 282 372 270.359 372 256C372 241.641 360.359 230 346 230C331.641 230 320 241.641 320 256C320 270.359 331.641 282 346 282Z"
|
||||
fill={stroke}
|
||||
/>
|
||||
<path
|
||||
d="M166 282C180.359 282 192 270.359 192 256C192 241.641 180.359 230 166 230C151.641 230 140 241.641 140 256C140 270.359 151.641 282 166 282Z"
|
||||
fill={stroke}
|
||||
/>
|
||||
<path
|
||||
d="M448 256C448 150 362 64 256 64C150 64 64 150 64 256C64 362 150 448 256 448C362 448 448 362 448 256Z"
|
||||
stroke={stroke}
|
||||
strokeWidth="32"
|
||||
strokeMiterlimit="10"
|
||||
/>
|
||||
</Icon>
|
||||
)
|
||||
}
|
||||
|
@ -1,29 +1,32 @@
|
||||
import { Icon, IconProps } from '@chakra-ui/react'
|
||||
import { Icon, IconProps, useColorModeValue } from '@chakra-ui/react'
|
||||
|
||||
export const WixLogo = (props: IconProps) => (
|
||||
<Icon
|
||||
width="311"
|
||||
height="121"
|
||||
viewBox="0 0 311 121"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
{...props}
|
||||
>
|
||||
<path
|
||||
d="M178 2.29971C172 5.29971 169.4 10.8997 169.4 26.0997C169.4 26.0997 172.4 23.0997 177.2 21.2997C180.7 19.9997 183.2 18.2997 185 16.9997C190.2 13.0997 191 8.39971 191 0.199713C190.9 0.199713 182.7 -0.300287 178 2.29971Z"
|
||||
fill="#FBBD71"
|
||||
/>
|
||||
<path
|
||||
d="M141.3 5.79963C136.1 10.0996 134.8 17.4996 134.8 17.4996L118 81.8996L104.2 29.1996C102.9 23.5996 100.3 16.6996 96.4 11.8996C91.6 5.79963 81.6 5.39963 80.4 5.39963C79.5 5.39963 69.6 5.79963 64.4 11.8996C60.5 16.6996 57.9 23.5996 56.6 29.1996L43.6 81.8996L26.8 17.4996C26.8 17.4996 25.5 10.5996 20.3 5.79963C12.1 -1.60037 0 0.199629 0 0.199629L32 120.7C32 120.7 42.4 121.6 47.6 119C54.5 115.5 58 113 61.9 96.4996C65.8 81.7996 76.2 38.9996 77 35.9996C77.4 34.6996 78.3 30.7996 80.9 30.7996C83.5 30.7996 84.4 34.2996 84.8 35.9996C85.7 38.9996 96 81.7996 99.9 96.4996C104.2 112.9 107.2 115.5 114.2 119C119.4 121.6 129.8 120.7 129.8 120.7L161.6 0.199629C161.6 0.199629 149.5 -1.50037 141.3 5.79963Z"
|
||||
fill="black"
|
||||
/>
|
||||
<path
|
||||
d="M190.9 19.5996C190.9 19.5996 188.7 22.5996 184.4 25.1996C181.4 26.8996 178.8 27.7996 175.8 29.4996C170.6 32.0996 169.3 34.6996 169.3 38.5996V39.8996V46.3996V47.6996V120.3C169.3 120.3 177.5 121.2 182.7 118.6C189.6 115.1 190.9 111.7 190.9 96.9996V24.3996V19.5996Z"
|
||||
fill="black"
|
||||
/>
|
||||
<path
|
||||
d="M270.4 60.7003L311 0.600311C311 0.600311 294.2 -2.39969 285.5 5.40031C279.9 10.2003 274.3 19.2003 274.3 19.2003L259.6 40.8003C258.7 42.1003 257.9 43.0003 256.6 43.0003C255.3 43.0003 254 41.7003 253.6 40.8003L238.9 19.2003C238.9 19.2003 232.9 10.6003 227.7 5.40031C219.1 -2.39969 202.2 0.600311 202.2 0.600311L241.5 60.6003L201.3 120.6C201.3 120.6 219 122.8 227.7 115C233.3 110.2 238.5 102 238.5 102L253.2 80.4003C254.1 79.1003 254.9 78.2003 256.2 78.2003C257.5 78.2003 258.8 79.5003 259.2 80.4003L273.9 102C273.9 102 279.5 110.2 284.7 115C293.3 122.8 310.6 120.6 310.6 120.6L270.4 60.7003Z"
|
||||
fill="black"
|
||||
/>
|
||||
</Icon>
|
||||
)
|
||||
export const WixLogo = (props: IconProps) => {
|
||||
const fill = useColorModeValue('black', 'white')
|
||||
return (
|
||||
<Icon
|
||||
width="311"
|
||||
height="121"
|
||||
viewBox="0 0 311 121"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
{...props}
|
||||
>
|
||||
<path
|
||||
d="M178 2.29971C172 5.29971 169.4 10.8997 169.4 26.0997C169.4 26.0997 172.4 23.0997 177.2 21.2997C180.7 19.9997 183.2 18.2997 185 16.9997C190.2 13.0997 191 8.39971 191 0.199713C190.9 0.199713 182.7 -0.300287 178 2.29971Z"
|
||||
fill="#FBBD71"
|
||||
/>
|
||||
<path
|
||||
d="M141.3 5.79963C136.1 10.0996 134.8 17.4996 134.8 17.4996L118 81.8996L104.2 29.1996C102.9 23.5996 100.3 16.6996 96.4 11.8996C91.6 5.79963 81.6 5.39963 80.4 5.39963C79.5 5.39963 69.6 5.79963 64.4 11.8996C60.5 16.6996 57.9 23.5996 56.6 29.1996L43.6 81.8996L26.8 17.4996C26.8 17.4996 25.5 10.5996 20.3 5.79963C12.1 -1.60037 0 0.199629 0 0.199629L32 120.7C32 120.7 42.4 121.6 47.6 119C54.5 115.5 58 113 61.9 96.4996C65.8 81.7996 76.2 38.9996 77 35.9996C77.4 34.6996 78.3 30.7996 80.9 30.7996C83.5 30.7996 84.4 34.2996 84.8 35.9996C85.7 38.9996 96 81.7996 99.9 96.4996C104.2 112.9 107.2 115.5 114.2 119C119.4 121.6 129.8 120.7 129.8 120.7L161.6 0.199629C161.6 0.199629 149.5 -1.50037 141.3 5.79963Z"
|
||||
fill={fill}
|
||||
/>
|
||||
<path
|
||||
d="M190.9 19.5996C190.9 19.5996 188.7 22.5996 184.4 25.1996C181.4 26.8996 178.8 27.7996 175.8 29.4996C170.6 32.0996 169.3 34.6996 169.3 38.5996V39.8996V46.3996V47.6996V120.3C169.3 120.3 177.5 121.2 182.7 118.6C189.6 115.1 190.9 111.7 190.9 96.9996V24.3996V19.5996Z"
|
||||
fill={fill}
|
||||
/>
|
||||
<path
|
||||
d="M270.4 60.7003L311 0.600311C311 0.600311 294.2 -2.39969 285.5 5.40031C279.9 10.2003 274.3 19.2003 274.3 19.2003L259.6 40.8003C258.7 42.1003 257.9 43.0003 256.6 43.0003C255.3 43.0003 254 41.7003 253.6 40.8003L238.9 19.2003C238.9 19.2003 232.9 10.6003 227.7 5.40031C219.1 -2.39969 202.2 0.600311 202.2 0.600311L241.5 60.6003L201.3 120.6C201.3 120.6 219 122.8 227.7 115C233.3 110.2 238.5 102 238.5 102L253.2 80.4003C254.1 79.1003 254.9 78.2003 256.2 78.2003C257.5 78.2003 258.8 79.5003 259.2 80.4003L273.9 102C273.9 102 279.5 110.2 284.7 115C293.3 122.8 310.6 120.6 310.6 120.6L270.4 60.7003Z"
|
||||
fill={fill}
|
||||
/>
|
||||
</Icon>
|
||||
)
|
||||
}
|
||||
|
@ -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) => (
|
||||
<Icon
|
||||
width="123"
|
||||
height="123"
|
||||
viewBox="0 0 123 123"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
{...props}
|
||||
>
|
||||
<path
|
||||
d="M8.70801 61.2601C8.70801 82.0621 20.797 100.039 38.327 108.558L13.258 39.8721C10.342 46.4081 8.70801 53.6411 8.70801 61.2601Z"
|
||||
fill="#464342"
|
||||
/>
|
||||
<path
|
||||
d="M96.7396 58.608C96.7396 52.113 94.4066 47.615 92.4056 44.114C89.7416 39.785 87.2446 36.119 87.2446 31.79C87.2446 26.959 90.9086 22.462 96.0696 22.462C96.3026 22.462 96.5236 22.491 96.7506 22.504C87.4006 13.938 74.9436 8.70801 61.2616 8.70801C42.9016 8.70801 26.7486 18.128 17.3516 32.396C18.5846 32.433 19.7466 32.459 20.7336 32.459C26.2306 32.459 34.7396 31.792 34.7396 31.792C37.5726 31.625 37.9066 35.786 35.0766 36.121C35.0766 36.121 32.2296 36.456 29.0616 36.622L48.1996 93.547L59.7006 59.054L51.5126 36.62C48.6826 36.454 46.0016 36.119 46.0016 36.119C43.1696 35.953 43.5016 31.623 46.3336 31.79C46.3336 31.79 55.0126 32.457 60.1766 32.457C65.6726 32.457 74.1826 31.79 74.1826 31.79C77.0176 31.623 77.3506 35.784 74.5196 36.119C74.5196 36.119 71.6666 36.454 68.5046 36.62L87.4966 93.114L92.7386 75.597C95.0106 68.328 96.7396 63.107 96.7396 58.608Z"
|
||||
fill="#464342"
|
||||
/>
|
||||
<path
|
||||
d="M62.184 65.8574L46.416 111.676C51.124 113.06 56.103 113.817 61.262 113.817C67.382 113.817 73.251 112.759 78.714 110.838C78.573 110.613 78.445 110.374 78.34 110.114L62.184 65.8574Z"
|
||||
fill="#464342"
|
||||
/>
|
||||
<path
|
||||
d="M107.376 36.0459C107.602 37.7199 107.73 39.5169 107.73 41.4499C107.73 46.7829 106.734 52.7779 103.734 60.2739L87.6807 106.687C103.305 97.5759 113.814 80.6489 113.814 61.2609C113.815 52.1239 111.481 43.5319 107.376 36.0459Z"
|
||||
fill="#464342"
|
||||
/>
|
||||
<path
|
||||
d="M61.262 0C27.483 0 0 27.481 0 61.26C0 95.043 27.483 122.523 61.262 122.523C95.04 122.523 122.527 95.043 122.527 61.26C122.526 27.481 95.04 0 61.262 0ZM61.262 119.715C29.032 119.715 2.809 93.492 2.809 61.26C2.809 29.03 29.031 2.809 61.262 2.809C93.491 2.809 119.712 29.03 119.712 61.26C119.712 93.492 93.491 119.715 61.262 119.715Z"
|
||||
fill="#464342"
|
||||
/>
|
||||
</Icon>
|
||||
)
|
||||
export const WordpressLogo = (props: react.IconProps) => {
|
||||
const fill = react.useColorModeValue('#464342', colors.gray[400])
|
||||
return (
|
||||
<react.Icon
|
||||
width="123"
|
||||
height="123"
|
||||
viewBox="0 0 123 123"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
{...props}
|
||||
>
|
||||
<path
|
||||
d="M8.70801 61.2601C8.70801 82.0621 20.797 100.039 38.327 108.558L13.258 39.8721C10.342 46.4081 8.70801 53.6411 8.70801 61.2601Z"
|
||||
fill={fill}
|
||||
/>
|
||||
<path
|
||||
d="M96.7396 58.608C96.7396 52.113 94.4066 47.615 92.4056 44.114C89.7416 39.785 87.2446 36.119 87.2446 31.79C87.2446 26.959 90.9086 22.462 96.0696 22.462C96.3026 22.462 96.5236 22.491 96.7506 22.504C87.4006 13.938 74.9436 8.70801 61.2616 8.70801C42.9016 8.70801 26.7486 18.128 17.3516 32.396C18.5846 32.433 19.7466 32.459 20.7336 32.459C26.2306 32.459 34.7396 31.792 34.7396 31.792C37.5726 31.625 37.9066 35.786 35.0766 36.121C35.0766 36.121 32.2296 36.456 29.0616 36.622L48.1996 93.547L59.7006 59.054L51.5126 36.62C48.6826 36.454 46.0016 36.119 46.0016 36.119C43.1696 35.953 43.5016 31.623 46.3336 31.79C46.3336 31.79 55.0126 32.457 60.1766 32.457C65.6726 32.457 74.1826 31.79 74.1826 31.79C77.0176 31.623 77.3506 35.784 74.5196 36.119C74.5196 36.119 71.6666 36.454 68.5046 36.62L87.4966 93.114L92.7386 75.597C95.0106 68.328 96.7396 63.107 96.7396 58.608Z"
|
||||
fill={fill}
|
||||
/>
|
||||
<path
|
||||
d="M62.184 65.8574L46.416 111.676C51.124 113.06 56.103 113.817 61.262 113.817C67.382 113.817 73.251 112.759 78.714 110.838C78.573 110.613 78.445 110.374 78.34 110.114L62.184 65.8574Z"
|
||||
fill={fill}
|
||||
/>
|
||||
<path
|
||||
d="M107.376 36.0459C107.602 37.7199 107.73 39.5169 107.73 41.4499C107.73 46.7829 106.734 52.7779 103.734 60.2739L87.6807 106.687C103.305 97.5759 113.814 80.6489 113.814 61.2609C113.815 52.1239 111.481 43.5319 107.376 36.0459Z"
|
||||
fill={fill}
|
||||
/>
|
||||
<path
|
||||
d="M61.262 0C27.483 0 0 27.481 0 61.26C0 95.043 27.483 122.523 61.262 122.523C95.04 122.523 122.527 95.043 122.527 61.26C122.526 27.481 95.04 0 61.262 0ZM61.262 119.715C29.032 119.715 2.809 93.492 2.809 61.26C2.809 29.03 29.031 2.809 61.262 2.809C93.491 2.809 119.712 29.03 119.712 61.26C119.712 93.492 93.491 119.715 61.262 119.715Z"
|
||||
fill={fill}
|
||||
/>
|
||||
</react.Icon>
|
||||
)
|
||||
}
|
||||
|
@ -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 = () => {
|
||||
<Flex
|
||||
pos="absolute"
|
||||
zIndex={2}
|
||||
bgColor="white"
|
||||
w="full"
|
||||
bg={useColorModeValue('white', 'gray.900')}
|
||||
justifyContent="center"
|
||||
h="60px"
|
||||
display={['none', 'flex']}
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { chakra, Fade, Button } from '@chakra-ui/react'
|
||||
import { chakra, Fade, Button, useColorModeValue } from '@chakra-ui/react'
|
||||
import { Cell as CellProps, flexRender } from '@tanstack/react-table'
|
||||
import { ExpandIcon } from '@/components/icons'
|
||||
import { memo } from 'react'
|
||||
@ -26,7 +26,7 @@ const Cell = ({
|
||||
px="4"
|
||||
py="2"
|
||||
border="1px"
|
||||
borderColor="gray.200"
|
||||
borderColor={useColorModeValue('gray.200', 'gray.700')}
|
||||
whiteSpace="nowrap"
|
||||
wordBreak="normal"
|
||||
overflow="hidden"
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { Box, BoxProps, chakra } from '@chakra-ui/react'
|
||||
import { Box, BoxProps, chakra, useColorModeValue } from '@chakra-ui/react'
|
||||
import { flexRender, HeaderGroup } from '@tanstack/react-table'
|
||||
import React from 'react'
|
||||
import { TableData } from '../../types'
|
||||
@ -8,6 +8,7 @@ type Props = {
|
||||
}
|
||||
|
||||
export const HeaderRow = ({ headerGroup }: Props) => {
|
||||
const borderColor = useColorModeValue('gray.200', 'gray.700')
|
||||
return (
|
||||
<tr key={headerGroup.id}>
|
||||
{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"
|
||||
|
@ -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"
|
||||
>
|
||||
<Flex ml="1">
|
||||
@ -28,7 +36,7 @@ export const LoadingRows = ({ totalColumns }: LoadingRowsProps) => {
|
||||
px="4"
|
||||
py="2"
|
||||
border="1px"
|
||||
borderColor="gray.200"
|
||||
borderColor={borderColor}
|
||||
>
|
||||
<Skeleton height="5px" w="full" />
|
||||
</chakra.td>
|
||||
|
@ -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<Record<string, boolean>>({})
|
||||
const [columnsVisibility, setColumnsVisibility] = useState<
|
||||
@ -204,7 +207,16 @@ export const ResultsTable = ({
|
||||
onColumnOrderChange={instance.setColumnOrder}
|
||||
/>
|
||||
</Flex>
|
||||
<Box className="table-wrapper" overflow="scroll" rounded="md">
|
||||
<Box
|
||||
overflow="scroll"
|
||||
rounded="md"
|
||||
data-testid="results-table"
|
||||
backgroundImage={`linear-gradient(to right, ${background}, ${background}), linear-gradient(to right, ${background}, ${background}),linear-gradient(to right, rgba(0, 0, 0, 0.1), rgba(255, 255, 255, 0)),linear-gradient(to left, rgba(0, 0, 0, 0.1), rgba(255, 255, 255, 0));`}
|
||||
backgroundPosition="left center, right center, left center, right center"
|
||||
backgroundRepeat="no-repeat"
|
||||
backgroundSize="30px 100%, 30px 100%, 15px 100%, 15px 100%"
|
||||
backgroundAttachment="local, local, scroll, scroll"
|
||||
>
|
||||
<chakra.table rounded="md">
|
||||
<thead>
|
||||
{instance.getHeaderGroups().map((headerGroup) => (
|
||||
@ -225,7 +237,13 @@ export const ResultsTable = ({
|
||||
/>
|
||||
))}
|
||||
{hasMore === true && (
|
||||
<LoadingRows totalColumns={columns.length - 1} />
|
||||
<LoadingRows
|
||||
totalColumns={
|
||||
resultHeader.filter(
|
||||
(header) => columnsVisibility[header.id] !== false
|
||||
).length + 1
|
||||
}
|
||||
/>
|
||||
)}
|
||||
</tbody>
|
||||
</chakra.table>
|
||||
|
@ -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)
|
||||
})
|
||||
|
@ -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={<ToolIcon color="blue.500" boxSize="25px" mr="2" />}
|
||||
leftIcon={
|
||||
<ToolIcon
|
||||
color={useColorModeValue('blue.500', 'blue.300')}
|
||||
boxSize="25px"
|
||||
mr="2"
|
||||
/>
|
||||
}
|
||||
onClick={() => handleCreateSubmit()}
|
||||
isLoading={isLoading}
|
||||
>
|
||||
@ -78,7 +91,13 @@ export const CreateNewTypebotButtons = () => {
|
||||
w="full"
|
||||
py="8"
|
||||
fontSize="lg"
|
||||
leftIcon={<TemplateIcon color="orange.500" boxSize="25px" mr="2" />}
|
||||
leftIcon={
|
||||
<TemplateIcon
|
||||
color={useColorModeValue('orange.500', 'orange.300')}
|
||||
boxSize="25px"
|
||||
mr="2"
|
||||
/>
|
||||
}
|
||||
onClick={onOpen}
|
||||
isLoading={isLoading}
|
||||
>
|
||||
@ -89,7 +108,13 @@ export const CreateNewTypebotButtons = () => {
|
||||
w="full"
|
||||
py="8"
|
||||
fontSize="lg"
|
||||
leftIcon={<DownloadIcon color="purple.500" boxSize="25px" mr="2" />}
|
||||
leftIcon={
|
||||
<DownloadIcon
|
||||
color={useColorModeValue('purple.500', 'purple.300')}
|
||||
boxSize="25px"
|
||||
mr="2"
|
||||
/>
|
||||
}
|
||||
isLoading={isLoading}
|
||||
onNewTypebot={handleCreateSubmit}
|
||||
>
|
||||
|
@ -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}
|
||||
|
@ -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 (
|
||||
<Menu placement="bottom-end" isLazy>
|
||||
<MenuButton _hover={{ backgroundColor: 'gray.100' }} borderRadius="md">
|
||||
<MenuButton
|
||||
_hover={{
|
||||
bg: useColorModeValue('gray.100', 'gray.700'),
|
||||
}}
|
||||
borderRadius="md"
|
||||
>
|
||||
<MemberIdentityContent
|
||||
email={email}
|
||||
name={name}
|
||||
|
@ -96,7 +96,7 @@ export const MembersList = () => {
|
||||
|
||||
return (
|
||||
<Stack w="full" spacing={3}>
|
||||
{!canInviteNewMember && (
|
||||
{true && (
|
||||
<UnlockPlanAlertInfo
|
||||
contentLabel={`
|
||||
Upgrade your plan to work with more team members, and unlock awesome
|
||||
|
@ -20,9 +20,8 @@ import { useState } from 'react'
|
||||
import { MembersList } from './MembersList'
|
||||
import { WorkspaceSettingsForm } from './WorkspaceSettingsForm'
|
||||
import { useWorkspace } from '../WorkspaceProvider'
|
||||
import { MyAccountForm } from '@/features/account'
|
||||
import { MyAccountForm, UserPreferencesForm } from '@/features/account'
|
||||
import { BillingContent } from '@/features/billing'
|
||||
import { EditorSettingsForm } from '@/features/editor'
|
||||
|
||||
type Props = {
|
||||
isOpen: boolean
|
||||
@ -177,9 +176,7 @@ const SettingsContent = ({
|
||||
case 'my-account':
|
||||
return <MyAccountForm />
|
||||
case 'user-settings':
|
||||
return (
|
||||
<EditorSettingsForm defaultGraphNavigation={defaultGraphNavigation} />
|
||||
)
|
||||
return <UserPreferencesForm />
|
||||
case 'workspace-settings':
|
||||
return <WorkspaceSettingsForm onClose={onClose} />
|
||||
case 'members':
|
||||
|
@ -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(
|
||||
[
|
||||
|
@ -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,
|
||||
})
|
||||
|
@ -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"
|
||||
/>
|
||||
<meta name="google" content="notranslate" />
|
||||
{/* eslint-disable-next-line @next/next/no-sync-scripts */}
|
||||
<script src="/__env.js" />
|
||||
</Head>
|
||||
<body>
|
||||
<ColorModeScript initialColorMode={customTheme.config.initialColorMode} />
|
||||
<Main />
|
||||
<NextScript />
|
||||
</body>
|
||||
|
Reference in New Issue
Block a user