chatbot-editor 1.0.0

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.
Files changed (72) hide show
  1. package/.github/workflows/npm-publish.yml +21 -0
  2. package/dist/App.d.ts +10 -0
  3. package/dist/App.js +22 -0
  4. package/dist/App.js.map +1 -0
  5. package/dist/Canva.d.ts +11 -0
  6. package/dist/Canva.js +10 -0
  7. package/dist/Canva.js.map +1 -0
  8. package/dist/Components/Answers.d.ts +8 -0
  9. package/dist/Components/Answers.js +18 -0
  10. package/dist/Components/Answers.js.map +1 -0
  11. package/dist/Components/Arrow.d.ts +13 -0
  12. package/dist/Components/Arrow.js +54 -0
  13. package/dist/Components/Arrow.js.map +1 -0
  14. package/dist/Components/Bubble.d.ts +6 -0
  15. package/dist/Components/Bubble.js +5 -0
  16. package/dist/Components/Bubble.js.map +1 -0
  17. package/dist/Components/Button.d.ts +9 -0
  18. package/dist/Components/Button.js +5 -0
  19. package/dist/Components/Button.js.map +1 -0
  20. package/dist/Components/Input.d.ts +12 -0
  21. package/dist/Components/Input.js +12 -0
  22. package/dist/Components/Input.js.map +1 -0
  23. package/dist/Components/Question.d.ts +18 -0
  24. package/dist/Components/Question.js +93 -0
  25. package/dist/Components/Question.js.map +1 -0
  26. package/dist/Components/Select.d.ts +13 -0
  27. package/dist/Components/Select.js +24 -0
  28. package/dist/Components/Select.js.map +1 -0
  29. package/dist/Components/SideBar.d.ts +12 -0
  30. package/dist/Components/SideBar.js +18 -0
  31. package/dist/Components/SideBar.js.map +1 -0
  32. package/dist/CurrentQuestionHook.d.ts +10 -0
  33. package/dist/CurrentQuestionHook.js +12 -0
  34. package/dist/CurrentQuestionHook.js.map +1 -0
  35. package/dist/TQuestion.d.ts +23 -0
  36. package/dist/TQuestion.js +2 -0
  37. package/dist/TQuestion.js.map +1 -0
  38. package/dist/UI.d.ts +20 -0
  39. package/dist/UI.js +116 -0
  40. package/dist/UI.js.map +1 -0
  41. package/dist/index.d.ts +3 -0
  42. package/dist/index.js +3 -0
  43. package/dist/index.js.map +1 -0
  44. package/dist/main.d.ts +1 -0
  45. package/dist/main.js +108 -0
  46. package/dist/main.js.map +1 -0
  47. package/dist/utils.d.ts +2 -0
  48. package/dist/utils.js +2 -0
  49. package/dist/utils.js.map +1 -0
  50. package/eslint.config.js +26 -0
  51. package/index.html +12 -0
  52. package/package.json +38 -0
  53. package/src/App.tsx +43 -0
  54. package/src/Canva.tsx +23 -0
  55. package/src/Components/Answers.tsx +27 -0
  56. package/src/Components/Arrow.tsx +60 -0
  57. package/src/Components/Bubble.tsx +13 -0
  58. package/src/Components/Button.tsx +14 -0
  59. package/src/Components/Input.tsx +25 -0
  60. package/src/Components/Question.tsx +104 -0
  61. package/src/Components/Select.tsx +45 -0
  62. package/src/Components/SideBar.tsx +31 -0
  63. package/src/CurrentQuestionHook.tsx +22 -0
  64. package/src/TQuestion.ts +23 -0
  65. package/src/UI.tsx +138 -0
  66. package/src/index.ts +7 -0
  67. package/src/main.tsx +114 -0
  68. package/src/utils.ts +3 -0
  69. package/tsconfig.app.json +28 -0
  70. package/tsconfig.json +16 -0
  71. package/tsconfig.node.json +26 -0
  72. package/vite.config.ts +8 -0
package/dist/UI.js ADDED
@@ -0,0 +1,116 @@
1
+ import SideBar from "./Components/SideBar";
2
+ import { useEffect, useState } from "react";
3
+ import { useCurrentQuestion } from "./CurrentQuestionHook";
4
+ import Button from "./Components/Button";
5
+ import Input from "./Components/Input";
6
+ import { clsx } from "clsx";
7
+ import Select from "./Components/Select";
8
+ import { BsPlus } from "react-icons/bs";
9
+ import { LuSave } from "react-icons/lu";
10
+ import { MdOutlineFileOpen } from "react-icons/md";
11
+ import { BiDownload, BiUpload } from "react-icons/bi";
12
+ import React from "react";
13
+ export default function UI(props) {
14
+ const [question, setQuestion] = useCurrentQuestion();
15
+ const [id, setId] = useState("");
16
+ const [goto, setGoto] = useState();
17
+ const [text, setText] = useState([""]);
18
+ const [answers, setAnswers] = useState([]);
19
+ const [action, setAction] = useState(undefined);
20
+ useEffect(() => {
21
+ if (question) {
22
+ setId(question.id);
23
+ if (typeof question.text === "string") {
24
+ setText([question.text]);
25
+ }
26
+ else {
27
+ setText(question.text);
28
+ }
29
+ setGoto(question.goto);
30
+ setAnswers(question.answers ?? []);
31
+ setAction(question.action);
32
+ }
33
+ }, [question]);
34
+ return (React.createElement("div", { className: "fixed top-0 left-0 w-0 h-0 overflow-visible text-white z-10" },
35
+ React.createElement(SideBar, { display: question !== null, setDisplay: (value) => { if (typeof value === "function")
36
+ value = value(question !== null); if (!value)
37
+ setQuestion(null); }, onClose: () => setQuestion(null), onValidate: () => {
38
+ const t = text.length === 1 ? text[0] : text;
39
+ props.editQuestion(question?.id ?? "", { id: id, text: t, goto: goto, answers: answers, position: { x: 0, y: 0 }, action: action });
40
+ setQuestion(null);
41
+ } },
42
+ React.createElement("div", { className: "flex flex-col gap-2 h-full pb-8 overflow-y-auto overflow-x-hidden" },
43
+ React.createElement(Input, { type: "text", value: id, onChange: (e) => setId(e.target.value), label: "ID" }),
44
+ React.createElement("div", { className: "bg-stone-950 p-2 rounded-lg flex flex-col gap-1" },
45
+ React.createElement("p", { className: "text-lg font-bold " }, "Text"),
46
+ text.map((value, index) => React.createElement("div", { className: "flex gap-1", key: index },
47
+ React.createElement(Input, { type: "text", value: value, onChange: (e) => setText(prev => prev.map((v, i) => i === index ? e.target.value : v)) }),
48
+ React.createElement(Button, { onClick: () => setText(prev => prev.filter((_, i) => i !== index)) }, "-"))),
49
+ React.createElement(Button, { onClick: () => setText(prev => [...prev, ""]) }, "+")),
50
+ React.createElement("div", { className: "bg-stone-950 p-2 rounded-lg flex flex-col gap-1" },
51
+ React.createElement("p", { className: "text-lg font-bold" }, "Answers"),
52
+ answers.map((value, index) => React.createElement("div", { className: "flex ga flex-col p-1", key: index },
53
+ React.createElement("div", { className: "flex gap-1 items-end" },
54
+ React.createElement(Input, { type: "text", value: value.text, onChange: (e) => setAnswers(prev => prev.map((v, i) => i === index ? { ...v, text: e.target.value } : v)), label: "Text" }),
55
+ React.createElement(Input, { type: "text", value: value.next, onChange: (e) => setAnswers(prev => prev.map((v, i) => i === index ? { ...v, next: e.target.value } : v)), label: "Next" }),
56
+ React.createElement(Button, { onClick: () => setAnswers(prev => prev.filter((_, i) => i !== index)) }, "-")),
57
+ React.createElement("div", { className: "flex flex-col gap-1" },
58
+ React.createElement("p", null, "Action"),
59
+ React.createElement(Select, { options: [{ value: "none", label: "None" }, { value: "set", label: "Set" }], value: value.action?.action ?? "none", onChange: (v) => v === "none" ?
60
+ setAnswers(prev => prev.map((v, i) => i === index ? { ...v, action: undefined } : v)) :
61
+ setAnswers(prev => prev.map((v, i) => i === index ? { ...v, action: { action: "set" } } : v)) }),
62
+ React.createElement(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)) }),
63
+ React.createElement(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)) })))),
64
+ React.createElement(Button, { disabled: goto !== undefined, onClick: () => setAnswers(prev => [...prev, { text: "", next: "" }]) }, "+")),
65
+ React.createElement("div", { className: "bg-stone-950 p-2 rounded-lg flex flex-col gap-1" },
66
+ React.createElement("p", { className: "text-lg font-bold" }, "Action"),
67
+ React.createElement(Select, { options: [{ value: "ask", label: "Ask" }, { value: "set", label: "Set" }, { value: "end", label: "End" }, { value: "none", label: "None" }], value: action?.action ?? "none", onChange: (v) => {
68
+ switch (v) {
69
+ case "ask":
70
+ setAction(prev => ({ action: "ask", property: prev?.property, value: undefined }));
71
+ break;
72
+ case "end":
73
+ setAction({ action: "end", property: undefined, value: undefined });
74
+ break;
75
+ case "set":
76
+ setAction(prev => ({ action: "set", property: prev?.property, value: prev?.value }));
77
+ break;
78
+ case "none":
79
+ setAction(undefined);
80
+ break;
81
+ }
82
+ } }),
83
+ React.createElement(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) }),
84
+ React.createElement(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) }),
85
+ React.createElement(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) })),
86
+ React.createElement(Input, { disabled: answers.length !== 0, type: "text", label: "Goto", value: goto ?? "", onChange: (e) => setGoto(e.target.value === "" ? undefined : e.target.value) }),
87
+ React.createElement("div", { className: "grow" }),
88
+ React.createElement(Button, { onClick: () => {
89
+ props.deleteQuestion(question?.id ?? "");
90
+ setQuestion(null);
91
+ } }, "Delete"))),
92
+ React.createElement("div", { className: "p-2 fixed right-8 top-0 flex gap-2" },
93
+ React.createElement(Button, { onClick: () => props.addQuestion({ x: 20, y: 20 }) },
94
+ React.createElement(BsPlus, { className: "w-6 h-6" })),
95
+ props.save && React.createElement(Button, { onClick: () => props.save && props.save(props.questions) },
96
+ React.createElement(LuSave, { className: "w-6 h-6" })),
97
+ props.load && React.createElement(Button, { onClick: async () => {
98
+ if (props.load) {
99
+ const questions = await props.load();
100
+ props.setQuestions(questions);
101
+ props.setReloadArrow(prev => !prev);
102
+ }
103
+ } },
104
+ React.createElement(MdOutlineFileOpen, { className: "w-6 h-6" })),
105
+ props.export && React.createElement(Button, { onClick: () => props.export && props.export(props.questions) },
106
+ React.createElement(BiDownload, { className: "w-6 h-6" })),
107
+ props.import && React.createElement(Button, { onClick: async () => {
108
+ if (props.import) {
109
+ const questions = await props.import();
110
+ props.setQuestions(questions);
111
+ props.setReloadArrow(prev => !prev);
112
+ }
113
+ } },
114
+ React.createElement(BiUpload, { className: "w-6 h-6" })))));
115
+ }
116
+ //# sourceMappingURL=UI.js.map
package/dist/UI.js.map ADDED
@@ -0,0 +1 @@
1
+ {"version":3,"file":"UI.js","sourceRoot":"","sources":["../src/UI.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import App from "./App";
2
+ import type TQuestion from "./TQuestion.ts";
3
+ export { App, type TQuestion };
package/dist/index.js ADDED
@@ -0,0 +1,3 @@
1
+ import App from "./App";
2
+ export { App };
3
+ //# sourceMappingURL=index.js.map
@@ -0,0 +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"}
package/dist/main.d.ts ADDED
@@ -0,0 +1 @@
1
+ import './index.css';
package/dist/main.js ADDED
@@ -0,0 +1,108 @@
1
+ import { StrictMode } from 'react';
2
+ import { createRoot } from 'react-dom/client';
3
+ import './index.css';
4
+ import App from "./App";
5
+ import React from "react";
6
+ const save = (questions) => {
7
+ const save = questions.map(q => {
8
+ const pos = document.getElementById(q.id).getBoundingClientRect();
9
+ q.position.x = pos.x;
10
+ q.position.y = pos.y;
11
+ return q;
12
+ });
13
+ const file = URL.createObjectURL(new Blob([JSON.stringify(save)], { type: "application/json" }));
14
+ const a = document.createElement("a");
15
+ a.href = file;
16
+ a.download = "questions.json";
17
+ a.click();
18
+ URL.revokeObjectURL(file);
19
+ };
20
+ const download = (questions) => {
21
+ const result = {};
22
+ questions.forEach(q => result[q.id] = {
23
+ question: q.text,
24
+ goto: q.goto,
25
+ action: q.action,
26
+ answers: q.answers
27
+ });
28
+ const file = URL.createObjectURL(new Blob([JSON.stringify(result)], { type: "application/json" }));
29
+ const a = document.createElement("a");
30
+ a.href = file;
31
+ a.download = "questions.json";
32
+ a.click();
33
+ URL.revokeObjectURL(file);
34
+ };
35
+ const load = async () => {
36
+ const fileLoader = document.createElement("input");
37
+ fileLoader.type = "file";
38
+ fileLoader.accept = ".json";
39
+ const p = new Promise((resolve, reject) => {
40
+ fileLoader.addEventListener("change", () => {
41
+ if (fileLoader.files?.length === 1) {
42
+ fileLoader.files[0].text().then(v => {
43
+ const questions = JSON.parse(v);
44
+ if (typeof questions === "object" && questions instanceof Array) {
45
+ const validate = questions.filter(q => {
46
+ return typeof q["id"] === "string" && typeof q["text"] === "string" && typeof q["position"] === "object" && typeof q["position"]["x"] === "number" && typeof q["position"]["y"] === "number";
47
+ });
48
+ if (validate.length !== questions.length) {
49
+ console.error("Invalid file format");
50
+ return;
51
+ }
52
+ resolve(questions);
53
+ }
54
+ else {
55
+ reject("Invalid file format");
56
+ }
57
+ }).catch(reject);
58
+ }
59
+ else {
60
+ reject("You must select only one file");
61
+ }
62
+ });
63
+ });
64
+ fileLoader.click();
65
+ return p;
66
+ };
67
+ const importFile = async () => {
68
+ const fileLoader = document.createElement("input");
69
+ fileLoader.type = "file";
70
+ fileLoader.accept = ".json";
71
+ const p = new Promise((resolve, reject) => {
72
+ fileLoader.addEventListener("change", () => {
73
+ if (fileLoader.files?.length === 1) {
74
+ fileLoader.files[0].text().then(v => {
75
+ const questions = JSON.parse(v);
76
+ if (typeof questions === "object") {
77
+ const validate = Object.values(questions).filter(q => {
78
+ return typeof q["question"] === "string" || (typeof q["question"] === "object" && q["question"] instanceof Array);
79
+ });
80
+ if (validate.length !== Object.values(questions).length) {
81
+ reject("Invalid file format");
82
+ return;
83
+ }
84
+ const tmp = Object.keys(questions).map((id, index) => {
85
+ return {
86
+ id: id,
87
+ text: questions[id]["question"],
88
+ goto: questions[id]["goto"] ?? undefined,
89
+ answers: questions[id]["answers"] ?? [],
90
+ position: { x: index % 5 * 260 + 20, y: Math.floor(index / 5) * 300 + 20 },
91
+ action: questions[id]["action"] ?? undefined
92
+ };
93
+ });
94
+ resolve(tmp);
95
+ }
96
+ else {
97
+ reject("Invalid file format");
98
+ }
99
+ }).catch(reject);
100
+ }
101
+ });
102
+ });
103
+ fileLoader.click();
104
+ return p;
105
+ };
106
+ createRoot(document.getElementById('root')).render(React.createElement(StrictMode, null,
107
+ React.createElement(App, { save: save, load: load, export: download, import: importFile })));
108
+ //# sourceMappingURL=main.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"main.js","sourceRoot":"","sources":["../src/main.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ import * as React from "react";
2
+ export type SetState<T> = React.Dispatch<React.SetStateAction<T>>;
package/dist/utils.js ADDED
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=utils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.js","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":""}
@@ -0,0 +1,26 @@
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 ADDED
@@ -0,0 +1,12 @@
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/package.json ADDED
@@ -0,0 +1,38 @@
1
+ {
2
+ "name": "chatbot-editor",
3
+ "description": "A chat bot editor made with React and TailwindCSS",
4
+ "repository": "MacaronFR/chatbot-editor",
5
+ "type": "module",
6
+ "main": "dist/index.js",
7
+ "types": "dist/index.d.ts",
8
+ "scripts": {
9
+ "dev": "vite",
10
+ "build": "rm -rf dist && tsc && tailwindcss -i src/index.css -o index.css --minify",
11
+ "prepublish": "npm run build"
12
+ },
13
+ "author": "Macaron",
14
+ "license": "ISC",
15
+ "dependencies": {
16
+ "@tailwindcss/cli": "^4.1.17",
17
+ "@tailwindcss/vite": "^4.1.17",
18
+ "clsx": "^2.1.1",
19
+ "react": "^19.2.0",
20
+ "react-dom": "^19.2.0",
21
+ "react-icons": "^5.5.0"
22
+ },
23
+ "devDependencies": {
24
+ "@eslint/js": "^9.39.1",
25
+ "@types/node": "^24.10.1",
26
+ "@types/react": "^19.2.5",
27
+ "@types/react-dom": "^19.2.3",
28
+ "@vitejs/plugin-react": "^5.1.1",
29
+ "eslint": "^9.39.1",
30
+ "eslint-plugin-react-hooks": "^7.0.1",
31
+ "eslint-plugin-react-refresh": "^0.4.24",
32
+ "globals": "^16.5.0",
33
+ "typescript": "~5.9.3",
34
+ "typescript-eslint": "^8.46.4",
35
+ "vite": "^7.2.4"
36
+ },
37
+ "version": "1.0.0"
38
+ }
package/src/App.tsx ADDED
@@ -0,0 +1,43 @@
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 ADDED
@@ -0,0 +1,23 @@
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
+ }
@@ -0,0 +1,27 @@
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
+ }
@@ -0,0 +1,60 @@
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
+ }
@@ -0,0 +1,13 @@
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
+ }
@@ -0,0 +1,14 @@
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
+ }
@@ -0,0 +1,25 @@
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
+ }