commit fef8e70f2353c54462ae0ba3dc08a6c70c42c43d
Author: root <root@hub.scroll.pub>
Date: 2024-12-28 14:02:45 +0000
Subject: Initial commit
diff --git a/body.html b/body.html
new file mode 100644
index 0000000..8b87b9c
--- /dev/null
+++ b/body.html
@@ -0,0 +1,18 @@
+<main class="dashboard">
+ <div class="canvas-container">
+ <canvas id="dashboardCanvas"></canvas>
+ </div>
+ <div class="controls">
+ <button id="addNode" aria-label="Add new node">+ Add Node</button>
+ </div>
+ <dialog id="editDialog">
+ <form>
+ <label for="nodeContent">Edit Node:</label>
+ <textarea id="nodeContent" rows="4"></textarea>
+ <div class="dialog-buttons">
+ <button type="submit">Save</button>
+ <button type="button" id="cancelEdit">Cancel</button>
+ </div>
+ </form>
+ </dialog>
+</main>
\ No newline at end of file
diff --git a/index.scroll b/index.scroll
new file mode 100644
index 0000000..b835e8d
--- /dev/null
+++ b/index.scroll
@@ -0,0 +1,8 @@
+buildHtml
+baseUrl https://nodedash.scroll.pub
+metaTags
+editButton /edit.html
+title NodeDash - Interactive 3D Dashboard
+style.css
+body.html
+script.js
\ No newline at end of file
diff --git a/prompt.json b/prompt.json
new file mode 100644
index 0000000..d019c75
--- /dev/null
+++ b/prompt.json
@@ -0,0 +1,25 @@
+{
+ "id": "07bdc191-1fc8-4c3f-b4ef-9d171f5b023b",
+ "object": "chat.completion",
+ "created": 1735394537,
+ "model": "deepseek-chat",
+ "choices": [
+ {
+ "index": 0,
+ "message": {
+ "role": "assistant",
+ "content": "---domain---\nnodedash.scroll.pub\n---index.scroll---\nbuildHtml\nbaseUrl https://nodedash.scroll.pub\nmetaTags\neditButton /edit.html\ntitle NodeDash - Interactive 3D Dashboard\nstyle.css\nbody.html\nscript.js\n---body.html---\n<main class=\"dashboard\">\n <div class=\"canvas-container\">\n <canvas id=\"dashboardCanvas\"></canvas>\n </div>\n <div class=\"controls\">\n <button id=\"addNode\" aria-label=\"Add new node\">+ Add Node</button>\n </div>\n <dialog id=\"editDialog\">\n <form>\n <label for=\"nodeContent\">Edit Node:</label>\n <textarea id=\"nodeContent\" rows=\"4\"></textarea>\n <div class=\"dialog-buttons\">\n <button type=\"submit\">Save</button>\n <button type=\"button\" id=\"cancelEdit\">Cancel</button>\n </div>\n </form>\n </dialog>\n</main>\n---style.css---\n:root {\n --primary-color: #6366f1;\n --secondary-color: #4f46e5;\n --background: #1e1e2f;\n --text-color: #f8fafc;\n --node-color: #3b82f6;\n}\n\n* {\n margin: 0;\n padding: 0;\n box-sizing: border-box;\n}\n\nbody {\n background-color: var(--background);\n color: var(--text-color);\n font-family: system-ui, -apple-system, sans-serif;\n min-height: 100vh;\n display: flex;\n flex-direction: column;\n}\n\n.dashboard {\n flex: 1;\n position: relative;\n}\n\n.canvas-container {\n width: 100%;\n height: 100vh;\n overflow: hidden;\n}\n\ncanvas {\n width: 100%;\n height: 100%;\n background: radial-gradient(circle at center, #2c2c44, #1e1e2f);\n}\n\n.controls {\n position: absolute;\n bottom: 2rem;\n right: 2rem;\n z-index: 10;\n}\n\nbutton {\n background-color: var(--primary-color);\n color: white;\n border: none;\n padding: 0.75rem 1.5rem;\n border-radius: 0.5rem;\n cursor: pointer;\n font-size: 1rem;\n transition: background-color 0.2s;\n}\n\nbutton:hover {\n background-color: var(--secondary-color);\n}\n\n#editDialog {\n background-color: var(--background);\n color: var(--text-color);\n border: 1px solid #333;\n border-radius: 0.5rem;\n padding: 1.5rem;\n max-width: 400px;\n}\n\n#editDialog::backdrop {\n background: rgba(0, 0, 0, 0.5);\n}\n\n.dialog-buttons {\n display: flex;\n gap: 1rem;\n margin-top: 1rem;\n}\n\ntextarea {\n width: 100%;\n padding: 0.5rem;\n border-radius: 0.25rem;\n border: 1px solid #333;\n background-color: #2c2c44;\n color: var(--text-color);\n resize: vertical;\n}\n\n@media (max-width: 768px) {\n .controls {\n bottom: 1rem;\n right: 1rem;\n }\n \n button {\n padding: 0.5rem 1rem;\n font-size: 0.9rem;\n }\n}\n---script.js---\nclass Node {\n constructor(x, y, content = 'New Node') {\n this.x = x;\n this.y = y;\n this.width = 150;\n this.height = 100;\n this.content = content;\n this.isDragging = false;\n }\n\n draw(ctx) {\n ctx.save();\n ctx.translate(this.x, this.y);\n \n // Node background\n ctx.fillStyle = '#3b82f6';\n ctx.beginPath();\n ctx.roundRect(0, 0, this.width, this.height, 12);\n ctx.fill();\n \n // Node content\n ctx.fillStyle = '#ffffff';\n ctx.font = '14px sans-serif';\n ctx.textAlign = 'center';\n ctx.textBaseline = 'middle';\n ctx.fillText(this.content, this.width/2, this.height/2);\n \n ctx.restore();\n }\n\n isPointInside(x, y) {\n return x > this.x && x < this.x + this.width &&\n y > this.y && y < this.y + this.height;\n }\n}\n\nclass Dashboard {\n constructor(canvas) {\n this.canvas = canvas;\n this.ctx = canvas.getContext('2d');\n this.nodes = [];\n this.selectedNode = null;\n this.isDragging = false;\n this.offsetX = 0;\n this.offsetY = 0;\n \n this.setupEventListeners();\n this.resizeCanvas();\n this.animate();\n }\n\n setupEventListeners() {\n this.canvas.addEventListener('mousedown', this.handleMouseDown.bind(this));\n this.canvas.addEventListener('mousemove', this.handleMouseMove.bind(this));\n this.canvas.addEventListener('mouseup', this.handleMouseUp.bind(this));\n this.canvas.addEventListener('dblclick', this.handleDoubleClick.bind(this));\n this.canvas.addEventListener('contextmenu', this.handleRightClick.bind(this));\n window.addEventListener('resize', this.resizeCanvas.bind(this));\n }\n\n handleMouseDown(e) {\n const rect = this.canvas.getBoundingClientRect();\n const x = e.clientX - rect.left;\n const y = e.clientY - rect.top;\n \n for (let node of this.nodes) {\n if (node.isPointInside(x, y)) {\n this.selectedNode = node;\n this.isDragging = true;\n this.offsetX = x - node.x;\n this.offsetY = y - node.y;\n break;\n }\n }\n }\n\n handleMouseMove(e) {\n if (this.isDragging && this.selectedNode) {\n const rect = this.canvas.getBoundingClientRect();\n const x = e.clientX - rect.left;\n const y = e.clientY - rect.top;\n \n this.selectedNode.x = x - this.offsetX;\n this.selectedNode.y = y - this.offsetY;\n }\n }\n\n handleMouseUp() {\n this.isDragging = false;\n this.selectedNode = null;\n }\n\n handleDoubleClick(e) {\n const rect = this.canvas.getBoundingClientRect();\n const x = e.clientX - rect.left;\n const y = e.clientY - rect.top;\n \n for (let node of this.nodes) {\n if (node.isPointInside(x, y)) {\n this.editNode(node);\n break;\n }\n }\n }\n\n handleRightClick(e) {\n e.preventDefault();\n const rect = this.canvas.getBoundingClientRect();\n const x = e.clientX - rect.left;\n const y = e.clientY - rect.top;\n \n for (let i = this.nodes.length - 1; i >= 0; i--) {\n if (this.nodes[i].isPointInside(x, y)) {\n this.nodes.splice(i, 1);\n break;\n }\n }\n }\n\n editNode(node) {\n const dialog = document.getElementById('editDialog');\n const textarea = document.getElementById('nodeContent');\n textarea.value = node.content;\n \n dialog.showModal();\n \n dialog.querySelector('form').onsubmit = (e) => {\n e.preventDefault();\n node.content = textarea.value;\n dialog.close();\n };\n \n document.getElementById('cancelEdit').onclick = () => dialog.close();\n }\n\n addNode() {\n const x = this.canvas.width / 2 - 75;\n const y = this.canvas.height / 2 - 50;\n this.nodes.push(new Node(x, y));\n }\n\n resizeCanvas() {\n this.canvas.width = window.innerWidth;\n this.canvas.height = window.innerHeight;\n }\n\n animate() {\n this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);\n \n for (let node of this.nodes) {\n node.draw(this.ctx);\n }\n \n requestAnimationFrame(this.animate.bind(this));\n }\n}\n\n// Initialize dashboard\nconst canvas = document.getElementById('dashboardCanvas');\nconst dashboard = new Dashboard(canvas);\n\n// Add node button\ndocument.getElementById('addNode').addEventListener('click', () => {\n dashboard.addNode();\n});\n---end---"
+ },
+ "logprobs": null,
+ "finish_reason": "stop"
+ }
+ ],
+ "usage": {
+ "prompt_tokens": 259,
+ "completion_tokens": 1885,
+ "total_tokens": 2144,
+ "prompt_cache_hit_tokens": 0,
+ "prompt_cache_miss_tokens": 259
+ },
+ "system_fingerprint": "fp_f1afce2943"
+}
\ No newline at end of file
diff --git a/readme.scroll b/readme.scroll
new file mode 100644
index 0000000..3da0341
--- /dev/null
+++ b/readme.scroll
@@ -0,0 +1,2 @@
+# nodedash.scroll.pub
+Website generated by DeepSeek from prompt: an animated interactive 3d dashboard with draggable nodes that the user can double click - edit. right click - delete
\ No newline at end of file
diff --git a/script.js b/script.js
new file mode 100644
index 0000000..3bbdb65
--- /dev/null
+++ b/script.js
@@ -0,0 +1,165 @@
+class Node {
+ constructor(x, y, content = 'New Node') {
+ this.x = x;
+ this.y = y;
+ this.width = 150;
+ this.height = 100;
+ this.content = content;
+ this.isDragging = false;
+ }
+
+ draw(ctx) {
+ ctx.save();
+ ctx.translate(this.x, this.y);
+
+ // Node background
+ ctx.fillStyle = '#3b82f6';
+ ctx.beginPath();
+ ctx.roundRect(0, 0, this.width, this.height, 12);
+ ctx.fill();
+
+ // Node content
+ ctx.fillStyle = '#ffffff';
+ ctx.font = '14px sans-serif';
+ ctx.textAlign = 'center';
+ ctx.textBaseline = 'middle';
+ ctx.fillText(this.content, this.width/2, this.height/2);
+
+ ctx.restore();
+ }
+
+ isPointInside(x, y) {
+ return x > this.x && x < this.x + this.width &&
+ y > this.y && y < this.y + this.height;
+ }
+}
+
+class Dashboard {
+ constructor(canvas) {
+ this.canvas = canvas;
+ this.ctx = canvas.getContext('2d');
+ this.nodes = [];
+ this.selectedNode = null;
+ this.isDragging = false;
+ this.offsetX = 0;
+ this.offsetY = 0;
+
+ this.setupEventListeners();
+ this.resizeCanvas();
+ this.animate();
+ }
+
+ setupEventListeners() {
+ this.canvas.addEventListener('mousedown', this.handleMouseDown.bind(this));
+ this.canvas.addEventListener('mousemove', this.handleMouseMove.bind(this));
+ this.canvas.addEventListener('mouseup', this.handleMouseUp.bind(this));
+ this.canvas.addEventListener('dblclick', this.handleDoubleClick.bind(this));
+ this.canvas.addEventListener('contextmenu', this.handleRightClick.bind(this));
+ window.addEventListener('resize', this.resizeCanvas.bind(this));
+ }
+
+ handleMouseDown(e) {
+ const rect = this.canvas.getBoundingClientRect();
+ const x = e.clientX - rect.left;
+ const y = e.clientY - rect.top;
+
+ for (let node of this.nodes) {
+ if (node.isPointInside(x, y)) {
+ this.selectedNode = node;
+ this.isDragging = true;
+ this.offsetX = x - node.x;
+ this.offsetY = y - node.y;
+ break;
+ }
+ }
+ }
+
+ handleMouseMove(e) {
+ if (this.isDragging && this.selectedNode) {
+ const rect = this.canvas.getBoundingClientRect();
+ const x = e.clientX - rect.left;
+ const y = e.clientY - rect.top;
+
+ this.selectedNode.x = x - this.offsetX;
+ this.selectedNode.y = y - this.offsetY;
+ }
+ }
+
+ handleMouseUp() {
+ this.isDragging = false;
+ this.selectedNode = null;
+ }
+
+ handleDoubleClick(e) {
+ const rect = this.canvas.getBoundingClientRect();
+ const x = e.clientX - rect.left;
+ const y = e.clientY - rect.top;
+
+ for (let node of this.nodes) {
+ if (node.isPointInside(x, y)) {
+ this.editNode(node);
+ break;
+ }
+ }
+ }
+
+ handleRightClick(e) {
+ e.preventDefault();
+ const rect = this.canvas.getBoundingClientRect();
+ const x = e.clientX - rect.left;
+ const y = e.clientY - rect.top;
+
+ for (let i = this.nodes.length - 1; i >= 0; i--) {
+ if (this.nodes[i].isPointInside(x, y)) {
+ this.nodes.splice(i, 1);
+ break;
+ }
+ }
+ }
+
+ editNode(node) {
+ const dialog = document.getElementById('editDialog');
+ const textarea = document.getElementById('nodeContent');
+ textarea.value = node.content;
+
+ dialog.showModal();
+
+ dialog.querySelector('form').onsubmit = (e) => {
+ e.preventDefault();
+ node.content = textarea.value;
+ dialog.close();
+ };
+
+ document.getElementById('cancelEdit').onclick = () => dialog.close();
+ }
+
+ addNode() {
+ const x = this.canvas.width / 2 - 75;
+ const y = this.canvas.height / 2 - 50;
+ this.nodes.push(new Node(x, y));
+ }
+
+ resizeCanvas() {
+ this.canvas.width = window.innerWidth;
+ this.canvas.height = window.innerHeight;
+ }
+
+ animate() {
+ this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
+
+ for (let node of this.nodes) {
+ node.draw(this.ctx);
+ }
+
+ requestAnimationFrame(this.animate.bind(this));
+ }
+}
+
+// Initialize dashboard
+const canvas = document.getElementById('dashboardCanvas');
+const dashboard = new Dashboard(canvas);
+
+// Add node button
+document.getElementById('addNode').addEventListener('click', () => {
+ dashboard.addNode();
+});
\ No newline at end of file
diff --git a/style.css b/style.css
new file mode 100644
index 0000000..f288a2e
--- /dev/null
+++ b/style.css
@@ -0,0 +1,102 @@
+:root {
+ --primary-color: #6366f1;
+ --secondary-color: #4f46e5;
+ --background: #1e1e2f;
+ --text-color: #f8fafc;
+ --node-color: #3b82f6;
+}
+
+* {
+ margin: 0;
+ padding: 0;
+ box-sizing: border-box;
+}
+
+body {
+ background-color: var(--background);
+ color: var(--text-color);
+ font-family: system-ui, -apple-system, sans-serif;
+ min-height: 100vh;
+ display: flex;
+ flex-direction: column;
+}
+
+.dashboard {
+ flex: 1;
+ position: relative;
+}
+
+.canvas-container {
+ width: 100%;
+ height: 100vh;
+ overflow: hidden;
+}
+
+canvas {
+ width: 100%;
+ height: 100%;
+ background: radial-gradient(circle at center, #2c2c44, #1e1e2f);
+}
+
+.controls {
+ position: absolute;
+ bottom: 2rem;
+ right: 2rem;
+ z-index: 10;
+}
+
+button {
+ background-color: var(--primary-color);
+ color: white;
+ border: none;
+ padding: 0.75rem 1.5rem;
+ border-radius: 0.5rem;
+ cursor: pointer;
+ font-size: 1rem;
+ transition: background-color 0.2s;
+}
+
+button:hover {
+ background-color: var(--secondary-color);
+}
+
+#editDialog {
+ background-color: var(--background);
+ color: var(--text-color);
+ border: 1px solid #333;
+ border-radius: 0.5rem;
+ padding: 1.5rem;
+ max-width: 400px;
+}
+
+#editDialog::backdrop {
+ background: rgba(0, 0, 0, 0.5);
+}
+
+.dialog-buttons {
+ display: flex;
+ gap: 1rem;
+ margin-top: 1rem;
+}
+
+textarea {
+ width: 100%;
+ padding: 0.5rem;
+ border-radius: 0.25rem;
+ border: 1px solid #333;
+ background-color: #2c2c44;
+ color: var(--text-color);
+ resize: vertical;
+}
+
+@media (max-width: 768px) {
+ .controls {
+ bottom: 1rem;
+ right: 1rem;
+ }
+
+ button {
+ padding: 0.5rem 1rem;
+ font-size: 0.9rem;
+ }
+}
\ No newline at end of file