chatbot-editor 1.0.0 → 1.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -6,5 +6,5 @@ interface AppProps {
6
6
  export?: (questions: TQuestion[]) => void;
7
7
  import?: () => Promise<TQuestion[]>;
8
8
  }
9
- export default function App(props: AppProps): React.JSX.Element;
9
+ export default function ChatbotEditor(props: AppProps): React.JSX.Element;
10
10
  export {};
@@ -3,11 +3,11 @@ import Canva from "./Canva";
3
3
  import { useState } from "react";
4
4
  import { CurrentQuestionProvider } from "./CurrentQuestionHook";
5
5
  import React from "react";
6
- export default function App(props) {
6
+ export default function ChatbotEditor(props) {
7
7
  const [questions, setQuestions] = useState([]);
8
8
  const [reloadArrow, setReloadArrow] = useState(false);
9
9
  return (React.createElement(CurrentQuestionProvider, null,
10
- React.createElement("div", { className: "relative h-screen w-screen overflow-hidden" },
10
+ React.createElement("div", { className: "relative h-full w-full overflow-hidden" },
11
11
  React.createElement(Canva, { questions: questions, setQuestions: setQuestions, reloadArrow: reloadArrow, setReloadArrow: setReloadArrow }),
12
12
  React.createElement(UI, { setReloadArrow: setReloadArrow, questions: questions, addQuestion: (initPos) => {
13
13
  let idQuestion = "question";
@@ -19,4 +19,4 @@ export default function App(props) {
19
19
  setQuestions(prev => [...prev, { id: idQuestion, text: "Text", position: initPos }]);
20
20
  }, editQuestion: (id, data) => setQuestions(prev => prev.map(v => v.id === id ? data : v)), deleteQuestion: id => setQuestions(prev => prev.filter(v => v.id !== id)), setQuestions: setQuestions, save: props.save, load: props.load, export: props.export, import: props.import }))));
21
21
  }
22
- //# sourceMappingURL=App.js.map
22
+ //# sourceMappingURL=ChatbotEditor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ChatbotEditor.js","sourceRoot":"","sources":["../src/ChatbotEditor.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,MAAM,CAAC;AACtB,OAAO,KAAK,MAAM,SAAS,CAAC;AAC5B,OAAO,EAAC,QAAQ,EAAC,MAAM,OAAO,CAAC;AAE/B,OAAO,EAAC,uBAAuB,EAAC,MAAM,uBAAuB,CAAC;AAC9D,OAAO,KAAK,MAAM,OAAO,CAAC;AAS1B,MAAM,CAAC,OAAO,UAAU,aAAa,CAAC,KAAe;IACpD,MAAM,CAAC,SAAS,EAAE,YAAY,CAAC,GAAG,QAAQ,CAAc,EAAE,CAAC,CAAC;IAC5D,MAAM,CAAC,WAAW,EAAE,cAAc,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC;IACtD,OAAO,CACN,oBAAC,uBAAuB;QACvB,6BAAK,SAAS,EAAE,wCAAwC;YACvD,oBAAC,KAAK,IAAC,SAAS,EAAE,SAAS,EAAE,YAAY,EAAE,YAAY,EAAE,WAAW,EAAE,WAAW,EAAE,cAAc,EAAE,cAAc,GAAG;YACpH,oBAAC,EAAE,IAAC,cAAc,EAAE,cAAc,EAAE,SAAS,EAAE,SAAS,EAAE,WAAW,EAAE,CAAC,OAA+B,EAAE,EAAE;oBAC1G,IAAI,UAAU,GAAG,UAAU,CAAC;oBAC5B,IAAI,CAAC,GAAG,CAAC,CAAC;oBACV,OAAM,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,UAAU,CAAC,EAAE,CAAC;wBAChD,CAAC,EAAE,CAAC;wBACJ,UAAU,GAAG,WAAW,CAAC,EAAE,CAAC;oBAC7B,CAAC;oBACD,YAAY,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,GAAG,IAAI,EAAE,EAAC,EAAE,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,OAAO,EAAC,CAAC,CAAC,CAAC;gBACpF,CAAC,EAAE,YAAY,EAAE,CAAC,EAAE,EAAE,IAAI,EAAE,EAAE,CAC7B,YAAY,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAE3D,cAAc,EAAE,EAAE,CAAC,EAAE,CAAC,YAAY,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,EACzE,YAAY,EAAE,YAAY,EAC1B,IAAI,EAAE,KAAK,CAAC,IAAI,EAChB,IAAI,EAAE,KAAK,CAAC,IAAI,EAChB,MAAM,EAAE,KAAK,CAAC,MAAM,EACpB,MAAM,EAAE,KAAK,CAAC,MAAM,GACnB,CACG,CACmB,CAC1B,CAAA;AACF,CAAC"}
@@ -2,7 +2,7 @@ import { clsx } from "clsx";
2
2
  import { BsCheck, BsX } from "react-icons/bs";
3
3
  import React from "react";
4
4
  export default function SideBar(props) {
5
- return (React.createElement("div", { className: clsx("fixed transition w-1/3 h-screen top-0 left-0 bg-stone-900 z-50 flex flex-col", props.display && "translate-x-0" || "-translate-x-full") },
5
+ return (React.createElement("div", { className: clsx("fixed transition w-1/3 h-full top-0 left-0 bg-stone-900 z-50 flex flex-col", props.display && "translate-x-0" || "-translate-x-full") },
6
6
  React.createElement("div", { className: "flex justify-end" },
7
7
  React.createElement("button", { className: "mx-2 my-1 p-1 rounded cursor-pointer border border-stone-200/30 aspect-square w-8", onClick: () => {
8
8
  props.setDisplay(false);
@@ -1 +1 @@
1
- {"version":3,"file":"SideBar.js","sourceRoot":"","sources":["../../src/Components/SideBar.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAC,IAAI,EAAC,MAAM,MAAM,CAAC;AAC1B,OAAO,EAAC,OAAO,EAAE,GAAG,EAAC,MAAM,gBAAgB,CAAC;AAC5C,OAAO,KAAK,MAAM,OAAO,CAAC;AAU1B,MAAM,CAAC,OAAO,UAAU,OAAO,CAAC,KAAmB;IAClD,OAAO,CACN,6BAAK,SAAS,EAAE,IAAI,CAAC,8EAA8E,EAAE,KAAK,CAAC,OAAO,IAAI,eAAe,IAAI,mBAAmB,CAAC;QAC5J,6BAAK,SAAS,EAAE,kBAAkB;YACjC,gCAAQ,SAAS,EAAE,mFAAmF,EAAE,OAAO,EAAE,GAAG,EAAE;oBACrH,KAAK,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC;oBACxB,IAAG,KAAK,CAAC,OAAO,EAAE,CAAC;wBAClB,KAAK,CAAC,OAAO,EAAE,CAAC;oBAClB,CAAC;gBAAA,CAAC;gBACD,oBAAC,GAAG,IAAC,SAAS,EAAE,SAAS,GAAG,CACpB;YACR,KAAK,CAAC,UAAU,IAAI,gCAAQ,SAAS,EAAE,mFAAmF,EAAE,OAAO,EAAE,GAAG,EAAE,CAAC,KAAK,CAAC,UAAU,IAAI,KAAK,CAAC,UAAU,EAAE;gBAAE,oBAAC,OAAO,IAAC,SAAS,EAAE,SAAS,GAAG,CAAS,CACxN;QACN,6BAAK,SAAS,EAAE,0BAA0B,IAAG,KAAK,CAAC,QAAQ,CAAO,CAC7D,CACN,CAAA;AACF,CAAC"}
1
+ {"version":3,"file":"SideBar.js","sourceRoot":"","sources":["../../src/Components/SideBar.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAC,IAAI,EAAC,MAAM,MAAM,CAAC;AAC1B,OAAO,EAAC,OAAO,EAAE,GAAG,EAAC,MAAM,gBAAgB,CAAC;AAC5C,OAAO,KAAK,MAAM,OAAO,CAAC;AAU1B,MAAM,CAAC,OAAO,UAAU,OAAO,CAAC,KAAmB;IAClD,OAAO,CACN,6BAAK,SAAS,EAAE,IAAI,CAAC,4EAA4E,EAAE,KAAK,CAAC,OAAO,IAAI,eAAe,IAAI,mBAAmB,CAAC;QAC1J,6BAAK,SAAS,EAAE,kBAAkB;YACjC,gCAAQ,SAAS,EAAE,mFAAmF,EAAE,OAAO,EAAE,GAAG,EAAE;oBACrH,KAAK,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC;oBACxB,IAAG,KAAK,CAAC,OAAO,EAAE,CAAC;wBAClB,KAAK,CAAC,OAAO,EAAE,CAAC;oBAClB,CAAC;gBAAA,CAAC;gBACD,oBAAC,GAAG,IAAC,SAAS,EAAE,SAAS,GAAG,CACpB;YACR,KAAK,CAAC,UAAU,IAAI,gCAAQ,SAAS,EAAE,mFAAmF,EAAE,OAAO,EAAE,GAAG,EAAE,CAAC,KAAK,CAAC,UAAU,IAAI,KAAK,CAAC,UAAU,EAAE;gBAAE,oBAAC,OAAO,IAAC,SAAS,EAAE,SAAS,GAAG,CAAS,CACxN;QACN,6BAAK,SAAS,EAAE,0BAA0B,IAAG,KAAK,CAAC,QAAQ,CAAO,CAC7D,CACN,CAAA;AACF,CAAC"}
package/dist/index.d.ts CHANGED
@@ -1,3 +1,3 @@
1
- import App from "./App";
1
+ import ChatbotEditor from "./ChatbotEditor";
2
2
  import type TQuestion from "./TQuestion.ts";
3
- export { App, type TQuestion };
3
+ export { ChatbotEditor, type TQuestion };
package/dist/index.js CHANGED
@@ -1,3 +1,3 @@
1
- import App from "./App";
2
- export { App };
1
+ import ChatbotEditor from "./ChatbotEditor";
2
+ export { ChatbotEditor };
3
3
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,GAAG,MAAM,OAAO,CAAC;AAGxB,OAAO,EACN,GAAG,EAEH,CAAA"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,aAAa,MAAM,iBAAiB,CAAC;AAG5C,OAAO,EACN,aAAa,EAEb,CAAA"}
package/dist/main.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import { StrictMode } from 'react';
2
2
  import { createRoot } from 'react-dom/client';
3
3
  import './index.css';
4
- import App from "./App";
4
+ import ChatbotEditor from "./ChatbotEditor";
5
5
  import React from "react";
6
6
  const save = (questions) => {
7
7
  const save = questions.map(q => {
@@ -104,5 +104,5 @@ const importFile = async () => {
104
104
  return p;
105
105
  };
106
106
  createRoot(document.getElementById('root')).render(React.createElement(StrictMode, null,
107
- React.createElement(App, { save: save, load: load, export: download, import: importFile })));
107
+ React.createElement(ChatbotEditor, { save: save, load: load, export: download, import: importFile })));
108
108
  //# sourceMappingURL=main.js.map
package/dist/main.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"main.js","sourceRoot":"","sources":["../src/main.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"main.js","sourceRoot":"","sources":["../src/main.tsx"],"names":[],"mappings":"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"}
package/index.css ADDED
@@ -0,0 +1,2 @@
1
+ /*! tailwindcss v4.1.18 | MIT License | https://tailwindcss.com */
2
+ @layer properties{@supports (((-webkit-hyphens:none)) and (not (margin-trim:inline))) or ((-moz-orient:inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-translate-x:0;--tw-translate-y:0;--tw-translate-z:0;--tw-border-style:solid;--tw-font-weight:initial;--tw-scale-x:1;--tw-scale-y:1;--tw-scale-z:1}}}@layer theme{:root,:host{--font-sans:ui-sans-serif,system-ui,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji";--font-mono:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;--color-orange-100:oklch(95.4% .038 75.164);--color-orange-500:oklch(70.5% .213 47.604);--color-green-800:oklch(44.8% .119 151.328);--color-violet-900:oklch(38% .189 293.745);--color-neutral-400:oklch(70.8% 0 0);--color-neutral-800:oklch(26.9% 0 0);--color-neutral-900:oklch(20.5% 0 0);--color-neutral-950:oklch(14.5% 0 0);--color-stone-100:oklch(97% .001 106.424);--color-stone-200:oklch(92.3% .003 48.717);--color-stone-400:oklch(70.9% .01 56.259);--color-stone-500:oklch(55.3% .013 58.071);--color-stone-600:oklch(44.4% .011 73.639);--color-stone-700:oklch(37.4% .01 67.558);--color-stone-800:oklch(26.8% .007 34.298);--color-stone-900:oklch(21.6% .006 56.043);--color-stone-950:oklch(14.7% .004 49.25);--color-white:#fff;--spacing:.25rem;--text-lg:1.125rem;--text-lg--line-height:calc(1.75/1.125);--font-weight-bold:700;--radius-lg:.5rem;--default-transition-duration:.15s;--default-transition-timing-function:cubic-bezier(.4,0,.2,1);--default-font-family:var(--font-sans);--default-mono-font-family:var(--font-mono)}}@layer base{*,:after,:before,::backdrop{box-sizing:border-box;border:0 solid;margin:0;padding:0}::file-selector-button{box-sizing:border-box;border:0 solid;margin:0;padding:0}html,:host{-webkit-text-size-adjust:100%;tab-size:4;line-height:1.5;font-family:var(--default-font-family,ui-sans-serif,system-ui,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji");font-feature-settings:var(--default-font-feature-settings,normal);font-variation-settings:var(--default-font-variation-settings,normal);-webkit-tap-highlight-color:transparent}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:var(--default-mono-font-family,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace);font-feature-settings:var(--default-mono-font-feature-settings,normal);font-variation-settings:var(--default-mono-font-variation-settings,normal);font-size:1em}small{font-size:80%}sub,sup{vertical-align:baseline;font-size:75%;line-height:0;position:relative}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}:-moz-focusring{outline:auto}progress{vertical-align:baseline}summary{display:list-item}ol,ul,menu{list-style:none}img,svg,video,canvas,audio,iframe,embed,object{vertical-align:middle;display:block}img,video{max-width:100%;height:auto}button,input,select,optgroup,textarea{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}::file-selector-button{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}:where(select:is([multiple],[size])) optgroup{font-weight:bolder}:where(select:is([multiple],[size])) optgroup option{padding-inline-start:20px}::file-selector-button{margin-inline-end:4px}::placeholder{opacity:1}@supports (not ((-webkit-appearance:-apple-pay-button))) or (contain-intrinsic-size:1px){::placeholder{color:currentColor}@supports (color:color-mix(in lab, red, red)){::placeholder{color:color-mix(in oklab,currentcolor 50%,transparent)}}}textarea{resize:vertical}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-date-and-time-value{min-height:1lh;text-align:inherit}::-webkit-datetime-edit{display:inline-flex}::-webkit-datetime-edit-fields-wrapper{padding:0}::-webkit-datetime-edit{padding-block:0}::-webkit-datetime-edit-year-field{padding-block:0}::-webkit-datetime-edit-month-field{padding-block:0}::-webkit-datetime-edit-day-field{padding-block:0}::-webkit-datetime-edit-hour-field{padding-block:0}::-webkit-datetime-edit-minute-field{padding-block:0}::-webkit-datetime-edit-second-field{padding-block:0}::-webkit-datetime-edit-millisecond-field{padding-block:0}::-webkit-datetime-edit-meridiem-field{padding-block:0}::-webkit-calendar-picker-indicator{line-height:1}:-moz-ui-invalid{box-shadow:none}button,input:where([type=button],[type=reset],[type=submit]){appearance:button}::file-selector-button{appearance:button}::-webkit-inner-spin-button{height:auto}::-webkit-outer-spin-button{height:auto}[hidden]:where(:not([hidden=until-found])){display:none!important}}@layer components;@layer utilities{.pointer-events-none{pointer-events:none}.visible{visibility:visible}.absolute{position:absolute}.fixed{position:fixed}.relative{position:relative}.top-0{top:calc(var(--spacing)*0)}.top-1{top:calc(var(--spacing)*1)}.top-2{top:calc(var(--spacing)*2)}.top-3{top:calc(var(--spacing)*3)}.top-full{top:100%}.-right-3{right:calc(var(--spacing)*-3)}.-right-5{right:calc(var(--spacing)*-5)}.-right-7{right:calc(var(--spacing)*-7)}.-right-15{right:calc(var(--spacing)*-15)}.right-8{right:calc(var(--spacing)*8)}.-left-4{left:calc(var(--spacing)*-4)}.left-0{left:calc(var(--spacing)*0)}.-z-20{z-index:calc(20*-1)}.z-0{z-index:0}.z-10{z-index:10}.z-50{z-index:50}.container{width:100%}@media (min-width:40rem){.container{max-width:40rem}}@media (min-width:48rem){.container{max-width:48rem}}@media (min-width:64rem){.container{max-width:64rem}}@media (min-width:80rem){.container{max-width:80rem}}@media (min-width:96rem){.container{max-width:96rem}}.m-1{margin:calc(var(--spacing)*1)}.mx-1{margin-inline:calc(var(--spacing)*1)}.mx-2{margin-inline:calc(var(--spacing)*2)}.my-1{margin-block:calc(var(--spacing)*1)}.-mt-2{margin-top:calc(var(--spacing)*-2)}.-mb-2{margin-bottom:calc(var(--spacing)*-2)}.flex{display:flex}.hidden{display:none}.aspect-square{aspect-ratio:1}.h-0{height:calc(var(--spacing)*0)}.h-4{height:calc(var(--spacing)*4)}.h-6{height:calc(var(--spacing)*6)}.h-8{height:calc(var(--spacing)*8)}.h-64{height:calc(var(--spacing)*64)}.h-full{height:100%}.max-h-32{max-height:calc(var(--spacing)*32)}.min-h-8{min-height:calc(var(--spacing)*8)}.min-h-full{min-height:100%}.w-0{width:calc(var(--spacing)*0)}.w-1\/3{width:33.3333%}.w-4{width:calc(var(--spacing)*4)}.w-6{width:calc(var(--spacing)*6)}.w-8{width:calc(var(--spacing)*8)}.w-16{width:calc(var(--spacing)*16)}.w-50{width:calc(var(--spacing)*50)}.w-full{width:100%}.max-w-full{max-width:100%}.min-w-full{min-width:100%}.grow{flex-grow:1}.-translate-x-full{--tw-translate-x:-100%;translate:var(--tw-translate-x)var(--tw-translate-y)}.translate-x-0{--tw-translate-x:calc(var(--spacing)*0);translate:var(--tw-translate-x)var(--tw-translate-y)}.cursor-pointer{cursor:pointer}.flex-col{flex-direction:column}.items-center{align-items:center}.items-end{align-items:flex-end}.justify-between{justify-content:space-between}.justify-center{justify-content:center}.justify-end{justify-content:flex-end}.gap-1{gap:calc(var(--spacing)*1)}.gap-1\.5{gap:calc(var(--spacing)*1.5)}.gap-2{gap:calc(var(--spacing)*2)}.overflow-auto{overflow:auto}.overflow-hidden{overflow:hidden}.overflow-visible{overflow:visible}.overflow-x-hidden{overflow-x:hidden}.overflow-y-auto{overflow-y:auto}.rounded{border-radius:.25rem}.rounded-full{border-radius:3.40282e38px}.rounded-lg{border-radius:var(--radius-lg)}.rounded-t-lg{border-top-left-radius:var(--radius-lg);border-top-right-radius:var(--radius-lg)}.rounded-b-lg{border-bottom-right-radius:var(--radius-lg);border-bottom-left-radius:var(--radius-lg)}.border{border-style:var(--tw-border-style);border-width:1px}.border-2{border-style:var(--tw-border-style);border-width:2px}.border-green-800{border-color:var(--color-green-800)}.border-neutral-400\/20{border-color:#a1a1a133}@supports (color:color-mix(in lab, red, red)){.border-neutral-400\/20{border-color:color-mix(in oklab,var(--color-neutral-400)20%,transparent)}}.border-stone-200\/30{border-color:#e7e5e44d}@supports (color:color-mix(in lab, red, red)){.border-stone-200\/30{border-color:color-mix(in oklab,var(--color-stone-200)30%,transparent)}}.border-violet-900{border-color:var(--color-violet-900)}.bg-green-800{background-color:var(--color-green-800)}.bg-neutral-800{background-color:var(--color-neutral-800)}.bg-neutral-900{background-color:var(--color-neutral-900)}.bg-neutral-950{background-color:var(--color-neutral-950)}.bg-stone-700{background-color:var(--color-stone-700)}.bg-stone-800{background-color:var(--color-stone-800)}.bg-stone-900{background-color:var(--color-stone-900)}.bg-stone-950{background-color:var(--color-stone-950)}.bg-violet-900{background-color:var(--color-violet-900)}.stroke-stone-600{stroke:var(--color-stone-600)}.p-1{padding:calc(var(--spacing)*1)}.p-2{padding:calc(var(--spacing)*2)}.px-2{padding-inline:calc(var(--spacing)*2)}.px-4{padding-inline:calc(var(--spacing)*4)}.py-1{padding-block:calc(var(--spacing)*1)}.py-2{padding-block:calc(var(--spacing)*2)}.pt-1{padding-top:calc(var(--spacing)*1)}.pt-2{padding-top:calc(var(--spacing)*2)}.pb-1{padding-bottom:calc(var(--spacing)*1)}.pb-2{padding-bottom:calc(var(--spacing)*2)}.pb-8{padding-bottom:calc(var(--spacing)*8)}.text-center{text-align:center}.font-mono{font-family:var(--font-mono)}.font-sans{font-family:var(--font-sans)}.text-lg{font-size:var(--text-lg);line-height:var(--tw-leading,var(--text-lg--line-height))}.font-bold{--tw-font-weight:var(--font-weight-bold);font-weight:var(--font-weight-bold)}.text-nowrap{text-wrap:nowrap}.text-ellipsis{text-overflow:ellipsis}.text-orange-100{color:var(--color-orange-100)}.text-orange-500{color:var(--color-orange-500)}.text-stone-100{color:var(--color-stone-100)}.text-stone-200{color:var(--color-stone-200)}.text-stone-500{color:var(--color-stone-500)}.text-white{color:var(--color-white)}.transition{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to,opacity,box-shadow,transform,translate,scale,rotate,filter,-webkit-backdrop-filter,backdrop-filter,display,content-visibility,overlay,pointer-events;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}@media (hover:hover){.hover\:scale-105:hover{--tw-scale-x:105%;--tw-scale-y:105%;--tw-scale-z:105%;scale:var(--tw-scale-x)var(--tw-scale-y)}.hover\:bg-stone-900:hover{background-color:var(--color-stone-900)}}.disabled\:cursor-default:disabled{cursor:default}.disabled\:bg-neutral-800:disabled{background-color:var(--color-neutral-800)}.disabled\:bg-neutral-900:disabled{background-color:var(--color-neutral-900)}.disabled\:text-stone-400:disabled{color:var(--color-stone-400)}@media (hover:hover){.disabled\:hover\:scale-100:disabled:hover{--tw-scale-x:100%;--tw-scale-y:100%;--tw-scale-z:100%;scale:var(--tw-scale-x)var(--tw-scale-y)}}}.workspace{position:relative}.workspace:before{background-image:radial-gradient(var(--color-neutral-800)10%,transparent 10%);content:"";pointer-events:none;background-size:20px 20px;width:100%;height:100%;display:block;position:fixed}@property --tw-translate-x{syntax:"*";inherits:false;initial-value:0}@property --tw-translate-y{syntax:"*";inherits:false;initial-value:0}@property --tw-translate-z{syntax:"*";inherits:false;initial-value:0}@property --tw-border-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-font-weight{syntax:"*";inherits:false}@property --tw-scale-x{syntax:"*";inherits:false;initial-value:1}@property --tw-scale-y{syntax:"*";inherits:false;initial-value:1}@property --tw-scale-z{syntax:"*";inherits:false;initial-value:1}
package/package.json CHANGED
@@ -4,6 +4,10 @@
4
4
  "repository": "MacaronFR/chatbot-editor",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
7
+ "files": [
8
+ "/dist",
9
+ "/index.css"
10
+ ],
7
11
  "types": "dist/index.d.ts",
8
12
  "scripts": {
9
13
  "dev": "vite",
@@ -34,5 +38,5 @@
34
38
  "typescript-eslint": "^8.46.4",
35
39
  "vite": "^7.2.4"
36
40
  },
37
- "version": "1.0.0"
41
+ "version": "1.0.2"
38
42
  }
@@ -1,21 +0,0 @@
1
- name: publish on npm
2
- on:
3
- release:
4
- types:
5
- - published
6
-
7
- jobs:
8
- publish-npm:
9
- runs-on: ubuntu-latest
10
- steps:
11
- - uses: actions/checkout@v4
12
- - uses: actions/setup-node@v4
13
- with:
14
- node version: 20
15
- registry-url: https://registry.npmjs.org/
16
- - run: npm install
17
- - run: npm version ${{ github.event.release.name }} --git-tag-version=false
18
- - run: npm run build
19
- - run: npm publish
20
- env:
21
- NODE_AUTH_TOKEN: ${{secrets.NPM_TOKEN}}
package/dist/App.js.map DELETED
@@ -1 +0,0 @@
1
- {"version":3,"file":"App.js","sourceRoot":"","sources":["../src/App.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,MAAM,CAAC;AACtB,OAAO,KAAK,MAAM,SAAS,CAAC;AAC5B,OAAO,EAAC,QAAQ,EAAC,MAAM,OAAO,CAAC;AAE/B,OAAO,EAAC,uBAAuB,EAAC,MAAM,uBAAuB,CAAC;AAC9D,OAAO,KAAK,MAAM,OAAO,CAAC;AAS1B,MAAM,CAAC,OAAO,UAAU,GAAG,CAAC,KAAe;IAC1C,MAAM,CAAC,SAAS,EAAE,YAAY,CAAC,GAAG,QAAQ,CAAc,EAAE,CAAC,CAAC;IAC5D,MAAM,CAAC,WAAW,EAAE,cAAc,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC;IACtD,OAAO,CACN,oBAAC,uBAAuB;QACvB,6BAAK,SAAS,EAAE,4CAA4C;YAC3D,oBAAC,KAAK,IAAC,SAAS,EAAE,SAAS,EAAE,YAAY,EAAE,YAAY,EAAE,WAAW,EAAE,WAAW,EAAE,cAAc,EAAE,cAAc,GAAG;YACpH,oBAAC,EAAE,IAAC,cAAc,EAAE,cAAc,EAAE,SAAS,EAAE,SAAS,EAAE,WAAW,EAAE,CAAC,OAA+B,EAAE,EAAE;oBAC1G,IAAI,UAAU,GAAG,UAAU,CAAC;oBAC5B,IAAI,CAAC,GAAG,CAAC,CAAC;oBACV,OAAM,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,UAAU,CAAC,EAAE,CAAC;wBAChD,CAAC,EAAE,CAAC;wBACJ,UAAU,GAAG,WAAW,CAAC,EAAE,CAAC;oBAC7B,CAAC;oBACD,YAAY,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,GAAG,IAAI,EAAE,EAAC,EAAE,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,OAAO,EAAC,CAAC,CAAC,CAAC;gBACpF,CAAC,EAAE,YAAY,EAAE,CAAC,EAAE,EAAE,IAAI,EAAE,EAAE,CAC7B,YAAY,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAE3D,cAAc,EAAE,EAAE,CAAC,EAAE,CAAC,YAAY,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,EACzE,YAAY,EAAE,YAAY,EAC1B,IAAI,EAAE,KAAK,CAAC,IAAI,EAChB,IAAI,EAAE,KAAK,CAAC,IAAI,EAChB,MAAM,EAAE,KAAK,CAAC,MAAM,EACpB,MAAM,EAAE,KAAK,CAAC,MAAM,GACnB,CACG,CACmB,CAC1B,CAAA;AACF,CAAC"}
package/eslint.config.js DELETED
@@ -1,26 +0,0 @@
1
- import js from '@eslint/js'
2
- import globals from 'globals'
3
- import reactHooks, {rules} from 'eslint-plugin-react-hooks'
4
- import reactRefresh from 'eslint-plugin-react-refresh'
5
- import tseslint from 'typescript-eslint'
6
- import { defineConfig, globalIgnores } from 'eslint/config'
7
-
8
- export default defineConfig([
9
- globalIgnores(['dist']),
10
- {
11
- files: ['**/*.{ts,tsx}'],
12
- extends: [
13
- js.configs.recommended,
14
- tseslint.configs.recommended,
15
- reactHooks.configs.flat.recommended,
16
- reactRefresh.configs.vite,
17
- ],
18
- languageOptions: {
19
- ecmaVersion: 2020,
20
- globals: globals.browser,
21
- },
22
- rules: {
23
- "react-hooks/set-state-in-effect": "off"
24
- },
25
- }
26
- ]);
package/index.html DELETED
@@ -1,12 +0,0 @@
1
- <!doctype html>
2
- <html lang="en">
3
- <head>
4
- <meta charset="UTF-8" />
5
- <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
- <title>chatbot-editor</title>
7
- </head>
8
- <body>
9
- <div id="root"></div>
10
- <script type="module" src="/src/main.tsx"></script>
11
- </body>
12
- </html>
package/src/App.tsx DELETED
@@ -1,43 +0,0 @@
1
- import UI from "./UI";
2
- import Canva from "./Canva";
3
- import {useState} from "react";
4
- import type TQuestion from "./TQuestion.ts";
5
- import {CurrentQuestionProvider} from "./CurrentQuestionHook";
6
- import React from "react";
7
-
8
- interface AppProps {
9
- save?: (questions: TQuestion[]) => void;
10
- load?: () => Promise<TQuestion[]>;
11
- export?: (questions: TQuestion[]) => void;
12
- import?: () => Promise<TQuestion[]>;
13
- }
14
-
15
- export default function App(props: AppProps) {
16
- const [questions, setQuestions] = useState<TQuestion[]>([]);
17
- const [reloadArrow, setReloadArrow] = useState(false);
18
- return (
19
- <CurrentQuestionProvider>
20
- <div className={"relative h-screen w-screen overflow-hidden"}>
21
- <Canva questions={questions} setQuestions={setQuestions} reloadArrow={reloadArrow} setReloadArrow={setReloadArrow}/>
22
- <UI setReloadArrow={setReloadArrow} questions={questions} addQuestion={(initPos: {x: number, y: number}) => {
23
- let idQuestion = "question";
24
- let i = 0;
25
- while(questions.find(v => v.id === idQuestion)) {
26
- i++;
27
- idQuestion = `question${i}`;
28
- }
29
- setQuestions(prev => [...prev, {id: idQuestion, text: "Text", position: initPos}]);
30
- }} editQuestion={(id, data) =>
31
- setQuestions(prev => prev.map(v => v.id === id ? data : v))
32
- }
33
- deleteQuestion={id => setQuestions(prev => prev.filter(v => v.id !== id))}
34
- setQuestions={setQuestions}
35
- save={props.save}
36
- load={props.load}
37
- export={props.export}
38
- import={props.import}
39
- />
40
- </div>
41
- </CurrentQuestionProvider>
42
- )
43
- }
package/src/Canva.tsx DELETED
@@ -1,23 +0,0 @@
1
- import React from "react";
2
- import Question from "./Components/Question";
3
- import type TQuestion from "./TQuestion.ts";
4
- import type {SetState} from "./utils.ts";
5
- import {useEffect} from "react";
6
-
7
- interface CanvaProps {
8
- questions: TQuestion[];
9
- setQuestions: SetState<TQuestion[]>;
10
- reloadArrow: boolean;
11
- setReloadArrow: SetState<boolean>;
12
- }
13
-
14
- export default function Canva(props: CanvaProps) {
15
- useEffect(() => {
16
- props.setReloadArrow(prev => !prev);
17
- }, [props.questions, props.setReloadArrow]);
18
- return (
19
- <div className={"min-w-full min-h-full bg-neutral-950 workspace overflow-auto"}>
20
- {props.questions.map((v, i) => <Question {...v} key={i} reloadArrow={props.reloadArrow} setReloadArrow={props.setReloadArrow}/>)}
21
- </div>
22
- )
23
- }
@@ -1,27 +0,0 @@
1
- import React from "react";
2
- import Arrow from "./Arrow";
3
- import {useEffect, useMemo, useRef, useState} from "react";
4
- import {CiWarning} from "react-icons/ci";
5
-
6
- interface AnswersProps {
7
- text: string;
8
- next: string;
9
- reloadArrows: boolean;
10
- }
11
-
12
- export default function Answers(props: AnswersProps) {
13
- const container = useRef<HTMLDivElement>(null);
14
- const [pos, setPos] = useState({x: 0, y: 0});
15
- useEffect(() => {
16
- setPos(container.current!.getBoundingClientRect());
17
- }, [props.reloadArrows]);
18
- const destPos = useMemo(() => {
19
- return document.getElementById(props.next)?.getBoundingClientRect();
20
- }, [props.next, props.reloadArrows]);
21
- return (
22
- <div className={"rounded bg-stone-700 w-16 px-2 py-1 text-nowrap text-ellipsis relative"} ref={container}>
23
- <p className={"text-ellipsis text-nowrap overflow-hidden max-w-full"} title={props.text}>{props.text}</p>
24
- {destPos && <Arrow from={{x: 64, y: 16}} to={{x: destPos.x - pos.x - 1, y: destPos.y - pos.y + 20}}/> || <CiWarning className={"text-orange-500 absolute -right-5 top-2"}/>}
25
- </div>
26
- )
27
- }
@@ -1,60 +0,0 @@
1
- import React from "react";
2
- import {useMemo, useRef} from "react";
3
-
4
- interface ArrowProps {
5
- from: {x: number, y: number},
6
- to: {x: number, y: number}
7
- }
8
-
9
- export default function Arrow(props: ArrowProps) {
10
- const ref = useRef<SVGSVGElement>(null);
11
- const [width, height] = useMemo(() => [
12
- Math.abs(props.from.x - props.to.x) + (props.from.x + 20 <= props.to.x - 20 ? 0 : 40),
13
- Math.abs(props.from.y - props.to.y)
14
- ], [props.from, props.to]);
15
- const [start] = useMemo(() => [
16
- {x: props.from.x + 20 < props.to.x - 20 ? 0 : -20, y: 0}
17
- ], [props.from, props.to]);
18
- const [left, top] = useMemo(() =>
19
- [
20
- props.from.x + 20 <= props.to.x - 20 ? props.from.x : props.to.x - 20,
21
- props.from.y < props.to.y ? props.from.y : props.to.y
22
- ],
23
- [props.from, props.to]
24
- );
25
- const [from, to] = useMemo(() => [
26
- {x: props.from.x + 20 < props.to.x - 20 ? 0 : (props.from.x < props.to.x ? (props.from.x === props.to.x ? 0 : -20) : width - 40), y: props.from.y < props.to.y ? 0 : height},
27
- {x: props.from.x + 20 < props.to.x - 20 ? width : (props.from.x + 20 === props.to.x - 20 ? 20 : 0), y: props.from.y < props.to.y ? height : 0},
28
- ], [props.from, props.to, width, height]);
29
- const path = useMemo(() => {
30
- let p = `M${from.x} ${from.y} L${from.x + 16} ${from.y}`;
31
- if(from.x + 20 < to.x - 20) {
32
- if(from.y < to.y) {
33
- p += ` L${(to.x - from.x) / 2 - 4} ${from.y} Q${(to.x - from.x) / 2 - 4} ${from.y} ${(to.x - from.x) / 2} ${from.y + 4} L${(to.x - from.x) / 2} ${to.y - 4} Q${(to.x - from.x) / 2} ${to.y - 4} ${(to.x - from.x) / 2 + 4} ${to.y}`;
34
- } else if(from.y > to.y) {
35
- p += ` L${(to.x - from.x) / 2 - 4} ${from.y} Q${(to.x - from.x) / 2 - 4} ${from.y} ${(to.x - from.x) / 2} ${from.y - 4} L${(to.x - from.x) / 2} ${to.y + 4} Q${(to.x - from.x) / 2} ${to.y + 4} ${(to.x - from.x) / 2 + 4} ${to.y}`;
36
- }
37
- } else if(from.x + 20 > to.x - 20) {
38
- if(from.y < to.y) {
39
- p += ` Q${from.x + 16} ${from.y} ${from.x + 20} ${from.y + 4} L${from.x + 20} ${to.y - 44} Q${from.x + 20} ${to.y - 44} ${from.x + 16} ${to.y - 40} L${to.x-16} ${to.y - 40} Q${to.x-16} ${to.y - 40} ${to.x-20} ${to.y - 36}`;
40
- p += ` L${to.x - 20} ${to.y - 4} Q${to.x - 20} ${to.y - 4} ${to.x - 16} ${to.y}`;
41
- } else if(from.y > to.y) {
42
- p += ` Q${from.x + 16} ${from.y} ${from.x + 20} ${from.y - 4} L${from.x + 20} ${from.y - 36} Q${from.x + 20} ${from.y - 36} ${from.x + 16} ${from.y -40} L${to.x-16} ${from.y - 40} Q${to.x-16} ${from.y - 40} ${to.x-20} ${from.y - 44}`;
43
- p += ` L${to.x - 20} ${to.y + 4} Q${to.x - 20} ${to.y + 4} ${to.x - 16} ${to.y}`;
44
- }
45
- } else {
46
- if(from.y < to.y) {
47
- p += ` Q${from.x + 16} ${from.y} ${from.x + 20} ${from.y + 4} L${from.x + 20} ${to.y - 4} Q${from.x + 20} ${to.y - 4} ${from.x + 24} ${to.y}`;
48
- } else if(from.y > to.y) {
49
- p += ` Q${from.x + 16} ${from.y} ${from.x + 20} ${from.y - 4} L${from.x + 20} ${to.y + 4} Q${from.x + 20} ${to.y + 4} ${from.x + 24} ${to.y}`;
50
- }
51
- }
52
- p += ` L${to.x} ${to.y}`
53
- return p;
54
- }, [from, to]);
55
- return (
56
- <svg ref={ref} viewBox={`${start.x} ${start.y} ${width} ${height}`} width={width} height={height} className={"absolute -z-20 stroke-stone-600 pointer-events-none"} style={{left: left, top: top}}>
57
- <path d={path} fill={"none"} strokeWidth={"2"}/>
58
- </svg>
59
- )
60
- }
@@ -1,13 +0,0 @@
1
- import React from "react";
2
-
3
- interface BubbleProps {
4
- text: string;
5
- }
6
-
7
- export default function Bubble(props: BubbleProps) {
8
- return (
9
- <div className={"text-orange-100 py-2 px-4 rounded bg-stone-800"}>
10
- {props.text}
11
- </div>
12
- )
13
- }
@@ -1,14 +0,0 @@
1
- import {type ReactNode} from "react";
2
- import React from "react";
3
-
4
- interface ButtonProps {
5
- children: ReactNode;
6
- disabled?: boolean;
7
- onClick?: (e: React.MouseEvent) => void;
8
- }
9
-
10
- export default function Button(props: ButtonProps) {
11
- return (
12
- <button className={"bg-stone-800 rounded-lg py-1 px-2 text-lg cursor-pointer transition hover:scale-105 disabled:hover:scale-100 disabled:cursor-default disabled:text-stone-400 disabled:bg-neutral-800"} onClick={props.onClick} disabled={props.disabled}>{props.children}</button>
13
- )
14
- }
@@ -1,25 +0,0 @@
1
- import * as React from "react";
2
- import {useMemo} from "react";
3
- import {clsx} from "clsx";
4
-
5
- interface InputProps {
6
- value: string;
7
- onChange: (e: React.ChangeEvent<HTMLInputElement>) => void;
8
- type?: React.HTMLInputTypeAttribute;
9
- label?: React.ReactNode;
10
- disabled?: boolean;
11
- id?: string;
12
- className?: string;
13
- }
14
-
15
- export default function Input(props: InputProps) {
16
- const id = useMemo(() => {
17
- return props.id ?? (Math.random().toString(36).substring(2, 15) + Math.random().toString(36).substring(2, 15));
18
- }, [props.id]);
19
- return (
20
- <div className={clsx("flex flex-col", props.className)}>
21
- {props.label && <label className={clsx("px-2 pt-1 rounded-t-lg pb-2 -mb-2", props.disabled === true && "text-stone-500 bg-neutral-950" || "bg-stone-950")} htmlFor={id}>{props.label}</label>}
22
- <input type={props.type} value={props.value} onChange={props.onChange} id={id} className={"bg-stone-800 rounded-lg py-1 px-2 text-lg disabled:bg-neutral-900"} disabled={props.disabled}/>
23
- </div>
24
- )
25
- }
@@ -1,104 +0,0 @@
1
- import {useCallback, useEffect, useMemo, useRef, useState} from "react";
2
- import Bubble from "./Bubble";
3
- import Answers from "./Answers";
4
- import {useCurrentQuestion} from "../CurrentQuestionHook";
5
- import * as React from "react";
6
- import Arrow from "./Arrow";
7
- import type {SetState} from "../utils.ts";
8
- import type {TAction, TAnswers} from "../TQuestion.ts";
9
- import {CiWarning} from "react-icons/ci";
10
-
11
- interface QuestionProps {
12
- id: string;
13
- text: string | string[];
14
- goto?: string;
15
- answers?: TAnswers[];
16
- action?: TAction;
17
- reloadArrow: boolean;
18
- setReloadArrow: SetState<boolean>;
19
- position: {x: number, y: number};
20
- }
21
-
22
- export default function Question(props: QuestionProps) {
23
- const container = useRef<HTMLDivElement>(null);
24
- const [position, setPosition] = useState(props.position);
25
- const [clicked, setClicked] = useState(false);
26
- const [, setOpen] = useState(false);
27
- const [, setQuestion] = useCurrentQuestion();
28
- const onMouseDown = useCallback((e: React.MouseEvent) => {
29
- if(e.button !== 0) return;
30
- setClicked(true);
31
- setOpen(true);
32
- }, []);
33
- const onMouseUp = useCallback((e: MouseEvent) => {
34
- if(e.button !== 0) return;
35
- if(e.target !== container.current && (container.current && !container.current.contains(e.target as Node))) return;
36
- setClicked(false);
37
- setOpen(prev => {
38
- if(prev) {
39
- setQuestion(props);
40
- }
41
- return true;
42
- })
43
- }, [props, setQuestion]);
44
- const onMouseMove = useCallback((e: MouseEvent) => {
45
- setOpen(false);
46
- setPosition(prev => {
47
- return {
48
- x: prev.x + e.movementX,
49
- y: prev.y + e.movementY
50
- }
51
- });
52
- props.setReloadArrow(prev => !prev);
53
- }, [setPosition, props]);
54
- useEffect(() => {
55
- if(clicked) {
56
- document.addEventListener("mousemove", onMouseMove);
57
- }
58
- return () => {
59
- document.removeEventListener("mousemove", onMouseMove)
60
- }
61
- }, [clicked, onMouseMove]);
62
- useEffect(() => {
63
- document.addEventListener("mouseup", onMouseUp);
64
- return () => document.removeEventListener("mouseup", onMouseUp);
65
- }, [onMouseUp]);
66
- const gotoPosition = useMemo(() => {
67
- let pos: {x: number, y: number} | undefined = undefined;
68
- if(props.goto || props.action?.goto) {
69
- const toElement = document.getElementById(props.goto ?? props.action?.goto ?? "");
70
- if(toElement) {
71
- pos = {x: toElement.offsetLeft, y: toElement.offsetTop};
72
- pos.x -= (position.x - position.x % 20);
73
- pos.y -= (position.y - position.y % 20);
74
- pos.y += 18
75
- } else {
76
- pos = undefined;
77
- }
78
- }
79
- return pos;
80
- }, [props.goto, props.action?.goto, position, props.reloadArrow]);
81
- return (
82
- <div id={props.id} className={"w-50 h-64 bg-stone-900 border border-neutral-400/20 rounded z-10 absolute flex flex-col gap-1 pb-1"} style={{top: position.y - (position.y % 20), left: position.x - (position.x % 20)}} onMouseDown={onMouseDown} ref={container}>
83
- <h2 title={props.id} className={"text-stone-100 m-1 min-h-8 bg-neutral-900 px-2 py-1 font-mono overflow-hidden text-ellipsis"}>{props.id}</h2>
84
- <div className={"p-1 flex flex-col gap-1 max-h-32 overflow-x-hidden overflow-y-auto"}>
85
- { typeof props.text === "string" ? <Bubble text={props.text}/> : props.text.map((v, i) => <Bubble text={v} key={i}/>)}
86
- </div>
87
- <div className={"absolute -right-15 top-1 flex flex-col gap-1.5"}>
88
- {props.answers?.map((v, i) => <Answers text={v.text} key={i} next={v.next} reloadArrows={props.reloadArrow}/>)}
89
- </div>
90
- {props.id === "start" && <div className={"absolute top-2 -left-4 w-6 h-6 rounded-full border-2 border-green-800 text-center flex items-center justify-center"}><div className={"bg-green-800 w-4 h-4 rounded-full"}/></div>}
91
- {(props.goto || props.action?.goto) && <div>
92
- <div className={"absolute top-2 -right-3 w-6 h-6 rounded-full border-2 border-violet-900 text-center flex justify-center items-center"}><div className={"bg-violet-900 w-4 h-4 rounded-full"}/></div>
93
- {gotoPosition && <Arrow from={{x: 200, y: 20}} to={gotoPosition}/> || <CiWarning className={"text-orange-500 absolute top-3 -right-7"}/>}
94
- </div>}
95
- <div className={"grow"}/>
96
- { props.action && <div className={"font-mono text-stone-200 px-4 mx-1 rounded bg-neutral-800 overflow-hidden"}>
97
- <p className={"font-sans"}>Action</p>
98
- {props.action.action === "set" && <p><span>{props.action.property}</span> == {props.action.value}</p> }
99
- {props.action.action === "ask" && <p><span>{props.action.property}</span> == user input</p> }
100
- {props.action.action === "end" && <p>Chatbot end</p> }
101
- </div>}
102
- </div>
103
- )
104
- }
@@ -1,45 +0,0 @@
1
- import * as React from "react";
2
- import {useMemo, useRef, useState} from "react";
3
- import {clsx} from "clsx";
4
- import {BsChevronDown} from "react-icons/bs";
5
-
6
- export interface Option {
7
- value: string;
8
- label: React.ReactNode;
9
- }
10
-
11
- interface SelectProps {
12
- options: Option[];
13
- id?: string;
14
- value: string;
15
- onChange: (v: string) => void;
16
- }
17
-
18
- export default function Select(props: SelectProps) {
19
- const select = useRef<HTMLSelectElement | null>(null);
20
- const id = useMemo(() => {
21
- return props.id ?? (Math.random().toString(36).substring(2, 15) + Math.random().toString(36).substring(2, 15));
22
- }, [props.id]);
23
- const [visible, setVisible] = useState(false);
24
- return (
25
- <label htmlFor={id}>
26
- <div className={"relative bg-stone-800 rounded-lg h-8 flex justify-between items-center px-2"} onClick={() => setVisible(prev => !prev)}>
27
- <p>{props.options.find(o => o.value == props.value)?.label ?? props.value}</p>
28
- <button><BsChevronDown/></button>
29
- <div className={clsx("absolute bg-stone-800 pt-2 -mt-2 z-0 w-full rounded-b-lg top-full left-0", visible || "hidden")}>
30
- {props.options.map((v, i) =>
31
- <p key={i} className={"p-1 hover:bg-stone-900"} onClick={() => {
32
- if(select.current) {
33
- select.current.value = v.value;
34
- props.onChange(v.value);
35
- }
36
- }}>{v.label}</p>
37
- )}
38
- </div>
39
- </div>
40
- <select className={"hidden"} id={id} onChange={e => props.onChange(e.target.value)} value={props.value} ref={select}>
41
- {props.options.map((v, i) => <option value={v.value} key={i}>{v.label}</option>)}
42
- </select>
43
- </label>
44
- )
45
- }
@@ -1,31 +0,0 @@
1
- import {type ReactNode} from "react";
2
- import type {SetState} from "../utils.ts";
3
- import {clsx} from "clsx";
4
- import {BsCheck, BsX} from "react-icons/bs";
5
- import React from "react";
6
-
7
- interface SideBarProps {
8
- display: boolean;
9
- setDisplay: SetState<boolean>;
10
- children: ReactNode;
11
- onClose?: () => void;
12
- onValidate?: () => void;
13
- }
14
-
15
- export default function SideBar(props: SideBarProps) {
16
- return (
17
- <div className={clsx("fixed transition w-1/3 h-screen top-0 left-0 bg-stone-900 z-50 flex flex-col", props.display && "translate-x-0" || "-translate-x-full")}>
18
- <div className={"flex justify-end"}>
19
- <button className={"mx-2 my-1 p-1 rounded cursor-pointer border border-stone-200/30 aspect-square w-8"} onClick={() => {
20
- props.setDisplay(false);
21
- if(props.onClose) {
22
- props.onClose();
23
- }}}>
24
- <BsX className={"w-6 h-6"}/>
25
- </button>
26
- {props.onValidate && <button className={"mx-2 my-1 p-1 rounded cursor-pointer border border-stone-200/30 aspect-square w-8"} onClick={() => props.onValidate && props.onValidate()}><BsCheck className={"w-6 h-6"}/></button>}
27
- </div>
28
- <div className={"p-2 grow overflow-hidden"}>{props.children}</div>
29
- </div>
30
- )
31
- }
@@ -1,22 +0,0 @@
1
- import React from "react";
2
- import {createContext, type ReactNode, useContext, useState} from "react";
3
- import type TQuestion from "./TQuestion.ts";
4
- import type {SetState} from "./utils.ts";
5
-
6
- const CurrentQuestionContext = createContext<[TQuestion | null, SetState<TQuestion | null>]>([null, () => {}]);
7
-
8
- interface CurrentQuestionProviderProps {
9
- children: ReactNode;
10
- }
11
-
12
- export function CurrentQuestionProvider(props: CurrentQuestionProviderProps) {
13
- const [question, setQuestion] = useState<TQuestion | null>(null);
14
- return <CurrentQuestionContext.Provider value={[question, setQuestion]}>
15
- {props.children}
16
- </CurrentQuestionContext.Provider>
17
- }
18
-
19
- // eslint-disable-next-line react-refresh/only-export-components
20
- export function useCurrentQuestion() {
21
- return useContext(CurrentQuestionContext);
22
- }
package/src/TQuestion.ts DELETED
@@ -1,23 +0,0 @@
1
- export default interface TQuestion {
2
- id: string;
3
- text: string | string[];
4
- answers?: TAnswers[];
5
- goto?: string;
6
- action?: TAction;
7
- position: {x: number, y: number};
8
- }
9
-
10
- export interface TAnswers {
11
- text: string;
12
- next: string;
13
- action?: TAction
14
- }
15
-
16
- export interface TAction {
17
- action: TActionValue
18
- property?: string;
19
- value?: any;
20
- goto?: string;
21
- }
22
-
23
- export type TActionValue = "set" | "ask" | "end";
package/src/UI.tsx DELETED
@@ -1,138 +0,0 @@
1
- import SideBar from "./Components/SideBar";
2
- import {useEffect, useState} from "react";
3
- import {useCurrentQuestion} from "./CurrentQuestionHook";
4
- import type TQuestion from "./TQuestion.ts";
5
- import type { TAnswers, TAction } from "./TQuestion.ts";
6
- import type {SetState} from "./utils.ts";
7
- import Button from "./Components/Button";
8
- import Input from "./Components/Input";
9
- import {clsx} from "clsx";
10
- import Select from "./Components/Select";
11
- import {BsPlus} from "react-icons/bs";
12
- import {LuSave} from "react-icons/lu";
13
- import {MdOutlineFileOpen} from "react-icons/md";
14
- import {BiDownload, BiUpload} from "react-icons/bi";
15
- import React from "react";
16
-
17
- interface UIProps {
18
- questions: TQuestion[];
19
- setQuestions: SetState<TQuestion[]>;
20
- addQuestion: (initPos: {x: number, y: number}) => void;
21
- editQuestion: (id: string, data: TQuestion) => void;
22
- deleteQuestion: (id: string) => void;
23
- setReloadArrow: SetState<boolean>;
24
- save?: (questions: TQuestion[]) => void;
25
- load?: () => Promise<TQuestion[]>;
26
- export?: (questions: TQuestion[]) => void;
27
- import?: () => Promise<TQuestion[]>;
28
- }
29
-
30
- export default function UI(props: UIProps) {
31
- const [question, setQuestion] = useCurrentQuestion();
32
- const [id, setId] = useState("");
33
- const [goto, setGoto] = useState<string>();
34
- const [text, setText] = useState<string[]>([""]);
35
- const [answers, setAnswers] = useState<TAnswers[]>([]);
36
- const [action, setAction] = useState<TAction | undefined>(undefined);
37
- useEffect(() => {
38
- if(question) {
39
- setId(question.id);
40
- if(typeof question.text === "string") {
41
- setText([question.text]);
42
- } else {
43
- setText(question.text);
44
- }
45
- setGoto(question.goto);
46
- setAnswers(question.answers ?? []);
47
- setAction(question.action);
48
- }
49
- }, [question]);
50
- return (
51
- <div className={"fixed top-0 left-0 w-0 h-0 overflow-visible text-white z-10"}>
52
- <SideBar display={question !== null} setDisplay={(value) => { if(typeof value === "function") value = value(question !== null); if(!value) setQuestion(null) }} onClose={() => setQuestion(null)} onValidate={() => {
53
- const t = text.length === 1 ? text[0] : text;
54
- props.editQuestion(question?.id ?? "", {id: id, text: t, goto: goto, answers: answers, position: {x: 0, y: 0}, action: action});
55
- setQuestion(null);
56
- }}>
57
- <div className={"flex flex-col gap-2 h-full pb-8 overflow-y-auto overflow-x-hidden"}>
58
- <Input type={"text"} value={id} onChange={(e) => setId(e.target.value)} label={"ID"}/>
59
- <div className={"bg-stone-950 p-2 rounded-lg flex flex-col gap-1"}>
60
- <p className={"text-lg font-bold "}>Text</p>
61
- {text.map((value, index) => <div className={"flex gap-1"} key={index}>
62
- <Input type={"text"} value={value} onChange={(e) => setText(prev => prev.map((v, i) => i === index ? e.target.value : v))}/>
63
- <Button onClick={() => setText(prev => prev.filter((_, i) => i !== index))}>-</Button>
64
- </div>)}
65
- <Button onClick={() => setText(prev => [...prev, ""])}>+</Button>
66
- </div>
67
- <div className={"bg-stone-950 p-2 rounded-lg flex flex-col gap-1"}>
68
- <p className={"text-lg font-bold"}>Answers</p>
69
- {answers.map((value, index) => <div className={"flex ga flex-col p-1"} key={index}>
70
- <div className={"flex gap-1 items-end"}>
71
- <Input type={"text"} value={value.text} onChange={(e) => setAnswers(prev => prev.map((v, i) => i === index ? {...v, text: e.target.value} : v))} label={"Text"}/>
72
- <Input type={"text"} value={value.next} onChange={(e) => setAnswers(prev => prev.map((v, i) => i === index ? {...v, next: e.target.value} : v))} label={"Next"}/>
73
- <Button onClick={() => setAnswers(prev => prev.filter((_, i) => i !== index))}>-</Button>
74
- </div>
75
- <div className={"flex flex-col gap-1"}>
76
- <p>Action</p>
77
- <Select options={[{value: "none", label: "None"}, {value: "set", label: "Set"}]} value={value.action?.action ?? "none"} onChange={ (v) => v === "none" ?
78
- setAnswers(prev => prev.map((v, i) => i === index ? {...v, action: undefined} : v)) :
79
- setAnswers(prev => prev.map((v, i) => i === index ? {...v, action: {action: "set"}} : v))
80
- }/>
81
- <Input className={clsx(value.action === undefined && "hidden")} label={"Property"} value={value.action?.property ?? ""} onChange={e => setAnswers(prev => prev.map((v, i) => i === index ? {...v, action: {action: value.action!.action, property: e.target.value, value: value.action?.value}} : v))}/>
82
- <Input className={clsx(value.action === undefined && "hidden")} label={"Value"} value={value.action?.value ?? ""} onChange={e => setAnswers(prev => prev.map((v, i) => i === index ? {...v, action: {action: value.action!.action, value: e.target.value, property: value.action?.property}} : v))}/>
83
- </div>
84
- </div>)}
85
- <Button disabled={goto !== undefined} onClick={() => setAnswers(prev => [...prev, {text: "", next: ""}])}>+</Button>
86
- </div>
87
- <div className={"bg-stone-950 p-2 rounded-lg flex flex-col gap-1"}>
88
- <p className={"text-lg font-bold"}>Action</p>
89
- <Select options={[{value: "ask", label: "Ask"}, {value: "set", label: "Set"}, {value: "end", label: "End"}, {value: "none", label: "None"}]} value={action?.action ?? "none"} onChange={(v) => {
90
- switch (v) {
91
- case "ask":
92
- setAction(prev => ({action: "ask", property: prev?.property, value: undefined}));
93
- break;
94
- case "end":
95
- setAction({action: "end", property: undefined, value: undefined});
96
- break;
97
- case "set":
98
- setAction(prev => ({action: "set", property: prev?.property, value: prev?.value}));
99
- break;
100
- case "none":
101
- setAction(undefined);
102
- break;
103
- }
104
- }}/>
105
- <Input className={clsx((action === undefined || action.action === "end") && "hidden")} type={"text"} label={"Property"} value={action?.property ?? ""} onChange={(e) => setAction(prev => prev ? ({...prev, property: e.target.value === "" ? undefined : e.target.value}) : undefined)}/>
106
- <Input className={clsx((action === undefined || action.action !== "set") && "hidden")} type={"text"} label={"Value"} value={action?.value ?? ""} onChange={(e) => setAction(prev => prev ? ({...prev, value: e.target.value === "" ? undefined : e.target.value}) : undefined)}/>
107
- <Input className={clsx((action === undefined || action.action !== "ask") && "hidden")} type={"text"} label={"Goto"} value={action?.goto ?? ""} onChange={(e) => setAction(prev => prev ? ({...prev, goto: e.target.value === "" ? undefined : e.target.value}) : undefined)}/>
108
- </div>
109
- <Input disabled={answers.length !== 0} type={"text"} label={"Goto"} value={goto ?? ""} onChange={(e) => setGoto(e.target.value === "" ? undefined : e.target.value)}/>
110
- <div className={"grow"}/>
111
- <Button onClick={() => {
112
- props.deleteQuestion(question?.id ?? "")
113
- setQuestion(null);
114
- }}>Delete</Button>
115
- </div>
116
- </SideBar>
117
- <div className={"p-2 fixed right-8 top-0 flex gap-2"}>
118
- <Button onClick={() => props.addQuestion({x: 20, y: 20})}><BsPlus className={"w-6 h-6"}/></Button>
119
- {props.save && <Button onClick={() => props.save && props.save(props.questions)}><LuSave className={"w-6 h-6"}/></Button>}
120
- {props.load && <Button onClick={async () => {
121
- if(props.load) {
122
- const questions = await props.load();
123
- props.setQuestions(questions);
124
- props.setReloadArrow(prev => !prev);
125
- }
126
- }}><MdOutlineFileOpen className={"w-6 h-6"}/></Button>}
127
- {props.export && <Button onClick={() => props.export && props.export(props.questions)}><BiDownload className={"w-6 h-6"}/></Button>}
128
- { props.import &&<Button onClick={async () => {
129
- if(props.import) {
130
- const questions = await props.import();
131
- props.setQuestions(questions);
132
- props.setReloadArrow(prev => !prev);
133
- }
134
- }}><BiUpload className={"w-6 h-6"}/></Button>}
135
- </div>
136
- </div>
137
- )
138
- }
package/src/index.ts DELETED
@@ -1,7 +0,0 @@
1
- import App from "./App";
2
- import type TQuestion from "./TQuestion.ts";
3
-
4
- export {
5
- App,
6
- type TQuestion
7
- }
package/src/main.tsx DELETED
@@ -1,114 +0,0 @@
1
- import {StrictMode} from 'react'
2
- import {createRoot} from 'react-dom/client'
3
- import './index.css'
4
- import App from "./App";
5
- import type TQuestion from "./TQuestion.ts";
6
- import type { TAction, TAnswers } from "./TQuestion.ts";
7
- import React from "react";
8
-
9
- const save = (questions: TQuestion[]) => {
10
- const save = questions.map(q => {
11
- const pos = document.getElementById(q.id)!.getBoundingClientRect();
12
- q.position.x = pos.x;
13
- q.position.y = pos.y;
14
- return q;
15
- });
16
- const file = URL.createObjectURL(new Blob([JSON.stringify(save)], {type: "application/json"}));
17
- const a = document.createElement("a");
18
- a.href = file;
19
- a.download = "questions.json";
20
- a.click();
21
- URL.revokeObjectURL(file);
22
- };
23
-
24
- const download = (questions: TQuestion[]) => {
25
- const result = {} as Record<string, {question: string | string[], goto?: string, answers: TAnswers[] | undefined, action?: TAction}>;
26
- questions.forEach(q => result[q.id] = {
27
- question: q.text,
28
- goto: q.goto,
29
- action: q.action,
30
- answers: q.answers
31
- });
32
- const file = URL.createObjectURL(new Blob([JSON.stringify(result)], {type: "application/json"}));
33
- const a = document.createElement("a");
34
- a.href = file;
35
- a.download = "questions.json";
36
- a.click();
37
- URL.revokeObjectURL(file);
38
- };
39
-
40
- const load = async () => {
41
- const fileLoader = document.createElement("input");
42
- fileLoader.type = "file";
43
- fileLoader.accept = ".json";
44
- const p = new Promise<TQuestion[]>((resolve, reject) => {
45
- fileLoader.addEventListener("change", () => {
46
- if(fileLoader.files?.length === 1) {
47
- fileLoader.files[0].text().then(v => {
48
- const questions = JSON.parse(v);
49
- if(typeof questions === "object" && questions instanceof Array) {
50
- const validate = questions.filter(q => {
51
- return typeof q["id"] === "string" && typeof q["text"] === "string" && typeof q["position"] === "object" && typeof q["position"]["x"] === "number" && typeof q["position"]["y"] === "number"
52
- });
53
- if(validate.length !== questions.length) {
54
- console.error("Invalid file format");
55
- return;
56
- }
57
- resolve(questions as TQuestion[]);
58
- } else {
59
- reject("Invalid file format");
60
- }
61
- }).catch(reject);
62
- } else {
63
- reject("You must select only one file");
64
- }
65
- });
66
- });
67
- fileLoader.click();
68
- return p;
69
- }
70
-
71
- const importFile = async () => {
72
- const fileLoader = document.createElement("input");
73
- fileLoader.type = "file";
74
- fileLoader.accept = ".json";
75
- const p = new Promise<TQuestion[]>((resolve, reject) => {
76
- fileLoader.addEventListener("change", () => {
77
- if (fileLoader.files?.length === 1) {
78
- fileLoader.files[0].text().then(v => {
79
- const questions = JSON.parse(v);
80
- if (typeof questions === "object") {
81
- const validate = Object.values<any>(questions).filter(q => {
82
- return typeof q["question"] === "string" || (typeof q["question"] === "object" && q["question"] instanceof Array)
83
- });
84
- if (validate.length !== Object.values(questions).length) {
85
- reject("Invalid file format");
86
- return;
87
- }
88
- const tmp = Object.keys(questions).map((id, index) => {
89
- return {
90
- id: id,
91
- text: questions[id]["question"],
92
- goto: questions[id]["goto"] ?? undefined,
93
- answers: questions[id]["answers"] ?? [],
94
- position: {x: index % 5 * 260 + 20, y: Math.floor(index / 5) * 300 + 20},
95
- action: questions[id]["action"] ?? undefined
96
- } as TQuestion;
97
- });
98
- resolve(tmp);
99
- } else {
100
- reject("Invalid file format");
101
- }
102
- }).catch(reject);
103
- }
104
- });
105
- });
106
- fileLoader.click();
107
- return p;
108
- }
109
-
110
- createRoot(document.getElementById('root')!).render(
111
- <StrictMode>
112
- <App save={save} load={load} export={download} import={importFile}/>
113
- </StrictMode>,
114
- )
package/src/utils.ts DELETED
@@ -1,3 +0,0 @@
1
- import * as React from "react";
2
-
3
- export type SetState<T> = React.Dispatch<React.SetStateAction<T>>;
package/tsconfig.app.json DELETED
@@ -1,28 +0,0 @@
1
- {
2
- "compilerOptions": {
3
- "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
4
- "target": "ES2022",
5
- "useDefineForClassFields": true,
6
- "lib": ["ES2022", "DOM", "DOM.Iterable"],
7
- "module": "ESNext",
8
- "types": ["vite/client"],
9
- "skipLibCheck": true,
10
-
11
- /* Bundler mode */
12
- "moduleResolution": "bundler",
13
- "allowImportingTsExtensions": true,
14
- "verbatimModuleSyntax": true,
15
- "moduleDetection": "force",
16
- "noEmit": true,
17
- "jsx": "react-jsx",
18
-
19
- /* Linting */
20
- "strict": true,
21
- "noUnusedLocals": true,
22
- "noUnusedParameters": true,
23
- "erasableSyntaxOnly": true,
24
- "noFallthroughCasesInSwitch": true,
25
- "noUncheckedSideEffectImports": true
26
- },
27
- "include": ["src"]
28
- }
package/tsconfig.json DELETED
@@ -1,16 +0,0 @@
1
- {
2
- "include": ["src"],
3
- "compilerOptions": {
4
- "target": "ES2022",
5
- "module": "ESNext",
6
- "declaration": true,
7
- "sourceMap": true,
8
- "outDir": "dist",
9
- "esModuleInterop": true,
10
- "forceConsistentCasingInFileNames": true,
11
- "strict": true,
12
- "skipLibCheck": true,
13
- "jsx": "react",
14
- "moduleResolution": "bundler"
15
- }
16
- }
@@ -1,26 +0,0 @@
1
- {
2
- "compilerOptions": {
3
- "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo",
4
- "target": "ES2023",
5
- "lib": ["ES2023"],
6
- "module": "ESNext",
7
- "types": ["node"],
8
- "skipLibCheck": true,
9
-
10
- /* Bundler mode */
11
- "moduleResolution": "bundler",
12
- "allowImportingTsExtensions": true,
13
- "verbatimModuleSyntax": true,
14
- "moduleDetection": "force",
15
- "noEmit": true,
16
-
17
- /* Linting */
18
- "strict": true,
19
- "noUnusedLocals": true,
20
- "noUnusedParameters": true,
21
- "erasableSyntaxOnly": true,
22
- "noFallthroughCasesInSwitch": true,
23
- "noUncheckedSideEffectImports": true
24
- },
25
- "include": ["vite.config.ts"]
26
- }
package/vite.config.ts DELETED
@@ -1,8 +0,0 @@
1
- import { defineConfig } from 'vite'
2
- import react from '@vitejs/plugin-react'
3
- import tailwindcss from "@tailwindcss/vite"
4
-
5
- // https://vite.dev/config/
6
- export default defineConfig({
7
- plugins: [react(), tailwindcss()],
8
- })