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.
- package/.github/workflows/npm-publish.yml +21 -0
- package/dist/App.d.ts +10 -0
- package/dist/App.js +22 -0
- package/dist/App.js.map +1 -0
- package/dist/Canva.d.ts +11 -0
- package/dist/Canva.js +10 -0
- package/dist/Canva.js.map +1 -0
- package/dist/Components/Answers.d.ts +8 -0
- package/dist/Components/Answers.js +18 -0
- package/dist/Components/Answers.js.map +1 -0
- package/dist/Components/Arrow.d.ts +13 -0
- package/dist/Components/Arrow.js +54 -0
- package/dist/Components/Arrow.js.map +1 -0
- package/dist/Components/Bubble.d.ts +6 -0
- package/dist/Components/Bubble.js +5 -0
- package/dist/Components/Bubble.js.map +1 -0
- package/dist/Components/Button.d.ts +9 -0
- package/dist/Components/Button.js +5 -0
- package/dist/Components/Button.js.map +1 -0
- package/dist/Components/Input.d.ts +12 -0
- package/dist/Components/Input.js +12 -0
- package/dist/Components/Input.js.map +1 -0
- package/dist/Components/Question.d.ts +18 -0
- package/dist/Components/Question.js +93 -0
- package/dist/Components/Question.js.map +1 -0
- package/dist/Components/Select.d.ts +13 -0
- package/dist/Components/Select.js +24 -0
- package/dist/Components/Select.js.map +1 -0
- package/dist/Components/SideBar.d.ts +12 -0
- package/dist/Components/SideBar.js +18 -0
- package/dist/Components/SideBar.js.map +1 -0
- package/dist/CurrentQuestionHook.d.ts +10 -0
- package/dist/CurrentQuestionHook.js +12 -0
- package/dist/CurrentQuestionHook.js.map +1 -0
- package/dist/TQuestion.d.ts +23 -0
- package/dist/TQuestion.js +2 -0
- package/dist/TQuestion.js.map +1 -0
- package/dist/UI.d.ts +20 -0
- package/dist/UI.js +116 -0
- package/dist/UI.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -0
- package/dist/main.d.ts +1 -0
- package/dist/main.js +108 -0
- package/dist/main.js.map +1 -0
- package/dist/utils.d.ts +2 -0
- package/dist/utils.js +2 -0
- package/dist/utils.js.map +1 -0
- package/eslint.config.js +26 -0
- package/index.html +12 -0
- package/package.json +38 -0
- package/src/App.tsx +43 -0
- package/src/Canva.tsx +23 -0
- package/src/Components/Answers.tsx +27 -0
- package/src/Components/Arrow.tsx +60 -0
- package/src/Components/Bubble.tsx +13 -0
- package/src/Components/Button.tsx +14 -0
- package/src/Components/Input.tsx +25 -0
- package/src/Components/Question.tsx +104 -0
- package/src/Components/Select.tsx +45 -0
- package/src/Components/SideBar.tsx +31 -0
- package/src/CurrentQuestionHook.tsx +22 -0
- package/src/TQuestion.ts +23 -0
- package/src/UI.tsx +138 -0
- package/src/index.ts +7 -0
- package/src/main.tsx +114 -0
- package/src/utils.ts +3 -0
- package/tsconfig.app.json +28 -0
- package/tsconfig.json +16 -0
- package/tsconfig.node.json +26 -0
- 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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"}
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -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
|
package/dist/main.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"main.js","sourceRoot":"","sources":["../src/main.tsx"],"names":[],"mappings":"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"}
|
package/dist/utils.d.ts
ADDED
package/dist/utils.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils.js","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":""}
|
package/eslint.config.js
ADDED
|
@@ -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,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
|
+
}
|