peter649 commited on
Commit
5cdf7f6
Β·
verified Β·
1 Parent(s): 8e3c36a

create a graph app with nodes and edges. all commands are clickable nodes. connected commands have a edge. background of node is light blue

Browse files
Files changed (2) hide show
  1. README.md +8 -5
  2. index.html +239 -18
README.md CHANGED
@@ -1,10 +1,13 @@
1
  ---
2
- title: Nodeflow Navigator
3
- emoji: πŸ‘€
4
- colorFrom: gray
5
- colorTo: yellow
6
  sdk: static
7
  pinned: false
 
 
8
  ---
9
 
10
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
 
1
  ---
2
+ title: NodeFlow Navigator πŸŒ€
3
+ colorFrom: purple
4
+ colorTo: blue
5
+ emoji: 🐳
6
  sdk: static
7
  pinned: false
8
+ tags:
9
+ - deepsite-v3
10
  ---
11
 
12
+ # Welcome to your new DeepSite project!
13
+ This project was created with [DeepSite](https://deepsite.hf.co).
index.html CHANGED
@@ -1,19 +1,240 @@
1
- <!doctype html>
2
- <html>
3
- <head>
4
- <meta charset="utf-8" />
5
- <meta name="viewport" content="width=device-width" />
6
- <title>My static Space</title>
7
- <link rel="stylesheet" href="style.css" />
8
- </head>
9
- <body>
10
- <div class="card">
11
- <h1>Welcome to your static Space!</h1>
12
- <p>You can modify this app directly by editing <i>index.html</i> in the Files and versions tab.</p>
13
- <p>
14
- Also don't forget to check the
15
- <a href="https://huggingface.co/docs/hub/spaces" target="_blank">Spaces documentation</a>.
16
- </p>
17
- </div>
18
- </body>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
19
  </html>
 
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>NodeFlow Navigator</title>
7
+ <script src="https://cdn.tailwindcss.com"></script>
8
+ <script src="https://unpkg.com/feather-icons"></script>
9
+ <script src="https://cdn.jsdelivr.net/npm/vue@3.2.47/dist/vue.global.min.js"></script>
10
+ <script src="https://cdn.jsdelivr.net/npm/cytoscape@3.23.0/dist/cytoscape.min.js"></script>
11
+ <style>
12
+ #cy {
13
+ width: 100%;
14
+ height: 80vh;
15
+ background-color: #f8fafc;
16
+ border-radius: 1rem;
17
+ box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1);
18
+ }
19
+ .node-label {
20
+ font-size: 12px;
21
+ text-align: center;
22
+ color: #1e293b;
23
+ font-weight: 600;
24
+ overflow: hidden;
25
+ text-overflow: ellipsis;
26
+ }
27
+ </style>
28
+ </head>
29
+ <body class="bg-gray-50 min-h-screen">
30
+ <div id="app" class="container mx-auto px-4 py-8">
31
+ <header class="mb-8 text-center">
32
+ <h1 class="text-4xl font-bold text-blue-600 mb-2">NodeFlow Navigator πŸŒ€</h1>
33
+ <p class="text-gray-600">Visualize command relationships with interactive nodes</p>
34
+ </header>
35
+
36
+ <div class="grid grid-cols-1 lg:grid-cols-4 gap-6">
37
+ <div class="lg:col-span-3">
38
+ <div id="cy"></div>
39
+ </div>
40
+
41
+ <div class="bg-white p-6 rounded-lg shadow-md">
42
+ <h2 class="text-xl font-semibold mb-4 text-blue-700">Controls</h2>
43
+
44
+ <div class="space-y-4">
45
+ <div>
46
+ <label class="block text-sm font-medium text-gray-700 mb-1">Node Label</label>
47
+ <input v-model="newNodeLabel" type="text" class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500">
48
+ </div>
49
+
50
+ <div>
51
+ <label class="block text-sm font-medium text-gray-700 mb-1">Connections</label>
52
+ <div class="flex space-x-2">
53
+ <select v-model="sourceNode" class="flex-1 px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500">
54
+ <option value="">Select source</option>
55
+ <option v-for="node in nodes" :value="node.data.id">{{ node.data.label }}</option>
56
+ </select>
57
+ <select v-model="targetNode" class="flex-1 px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500">
58
+ <option value="">Select target</option>
59
+ <option v-for="node in nodes" :value="node.data.id">{{ node.data.label }}</option>
60
+ </select>
61
+ </div>
62
+ </div>
63
+
64
+ <div class="flex space-x-2">
65
+ <button @click="addNode" class="flex-1 bg-blue-500 hover:bg-blue-600 text-white px-4 py-2 rounded-md transition">
66
+ <i data-feather="plus-circle" class="inline mr-2"></i> Add Node
67
+ </button>
68
+ <button @click="addEdge" class="flex-1 bg-green-500 hover:bg-green-600 text-white px-4 py-2 rounded-md transition">
69
+ <i data-feather="link" class="inline mr-2"></i> Connect
70
+ </button>
71
+ </div>
72
+
73
+ <div class="pt-4 border-t border-gray-200">
74
+ <button @click="resetGraph" class="w-full bg-red-500 hover:bg-red-600 text-white px-4 py-2 rounded-md transition">
75
+ <i data-feather="trash-2" class="inline mr-2"></i> Reset
76
+ </button>
77
+ </div>
78
+ </div>
79
+ </div>
80
+ </div>
81
+ </div>
82
+
83
+ <script>
84
+ const { createApp, ref, onMounted } = Vue;
85
+
86
+ createApp({
87
+ setup() {
88
+ const newNodeLabel = ref('');
89
+ const sourceNode = ref('');
90
+ const targetNode = ref('');
91
+ const nodes = ref([
92
+ { data: { id: 'cmd1', label: 'git init' } },
93
+ { data: { id: 'cmd2', label: 'git add' } },
94
+ { data: { id: 'cmd3', label: 'git commit' } },
95
+ { data: { id: 'cmd4', label: 'git push' } }
96
+ ]);
97
+ const edges = ref([
98
+ { data: { id: 'e1', source: 'cmd1', target: 'cmd2' } },
99
+ { data: { id: 'e2', source: 'cmd2', target: 'cmd3' } },
100
+ { data: { id: 'e3', source: 'cmd3', target: 'cmd4' } }
101
+ ]);
102
+ let cy = null;
103
+
104
+ onMounted(() => {
105
+ cy = cytoscape({
106
+ container: document.getElementById('cy'),
107
+ elements: {
108
+ nodes: nodes.value,
109
+ edges: edges.value
110
+ },
111
+ style: [
112
+ {
113
+ selector: 'node',
114
+ style: {
115
+ 'label': 'data(label)',
116
+ 'text-valign': 'center',
117
+ 'text-halign': 'center',
118
+ 'background-color': '#bfdbfe',
119
+ 'border-width': 2,
120
+ 'border-color': '#3b82f6',
121
+ 'width': '100px',
122
+ 'height': '60px',
123
+ 'shape': 'round-rectangle',
124
+ 'font-size': '12px'
125
+ }
126
+ },
127
+ {
128
+ selector: 'edge',
129
+ style: {
130
+ 'width': 2,
131
+ 'line-color': '#64748b',
132
+ 'curve-style': 'bezier',
133
+ 'target-arrow-color': '#64748b',
134
+ 'target-arrow-shape': 'triangle'
135
+ }
136
+ }
137
+ ],
138
+ layout: {
139
+ name: 'cose',
140
+ animate: true,
141
+ animationDuration: 1000,
142
+ fit: true,
143
+ padding: 50
144
+ }
145
+ });
146
+
147
+ // Make nodes draggable
148
+ cy.on('drag', 'node', function(event) {
149
+ event.target.style('background-color', '#93c5fd');
150
+ });
151
+
152
+ cy.on('free', 'node', function(event) {
153
+ event.target.style('background-color', '#bfdbfe');
154
+ });
155
+
156
+ // Click handler for nodes
157
+ cy.on('click', 'node', function(event) {
158
+ const node = event.target;
159
+ node.animate({
160
+ style: { 'background-color': '#60a5fa' }
161
+ }, {
162
+ duration: 300,
163
+ complete: function() {
164
+ node.animate({
165
+ style: { 'background-color': '#bfdbfe' }
166
+ }, {
167
+ duration: 300
168
+ });
169
+ }
170
+ });
171
+ alert(`Command executed: ${node.data('label')}`);
172
+ });
173
+ });
174
+
175
+ function addNode() {
176
+ if (!newNodeLabel.value) return;
177
+
178
+ const id = 'cmd' + (nodes.value.length + 1);
179
+ const newNode = {
180
+ data: { id, label: newNodeLabel.value }
181
+ };
182
+
183
+ nodes.value.push(newNode);
184
+ cy.add(newNode);
185
+ cy.layout({ name: 'cose', animate: true }).run();
186
+ newNodeLabel.value = '';
187
+ }
188
+
189
+ function addEdge() {
190
+ if (!sourceNode.value || !targetNode.value) return;
191
+
192
+ const id = 'e' + (edges.value.length + 1);
193
+ const newEdge = {
194
+ data: { id, source: sourceNode.value, target: targetNode.value }
195
+ };
196
+
197
+ edges.value.push(newEdge);
198
+ cy.add(newEdge);
199
+ cy.layout({ name: 'cose', animate: true }).run();
200
+
201
+ // Reset select inputs
202
+ sourceNode.value = '';
203
+ targetNode.value = '';
204
+ }
205
+
206
+ function resetGraph() {
207
+ nodes.value = [
208
+ { data: { id: 'cmd1', label: 'git init' } },
209
+ { data: { id: 'cmd2', label: 'git add' } },
210
+ { data: { id: 'cmd3', label: 'git commit' } },
211
+ { data: { id: 'cmd4', label: 'git push' } }
212
+ ];
213
+ edges.value = [
214
+ { data: { id: 'e1', source: 'cmd1', target: 'cmd2' } },
215
+ { data: { id: 'e2', source: 'cmd2', target: 'cmd3' } },
216
+ { data: { id: 'e3', source: 'cmd3', target: 'cmd4' } }
217
+ ];
218
+
219
+ cy.elements().remove();
220
+ cy.add(nodes.value);
221
+ cy.add(edges.value);
222
+ cy.layout({ name: 'cose', animate: true }).run();
223
+ }
224
+
225
+ return {
226
+ newNodeLabel,
227
+ sourceNode,
228
+ targetNode,
229
+ nodes,
230
+ addNode,
231
+ addEdge,
232
+ resetGraph
233
+ };
234
+ }
235
+ }).mount('#app');
236
+
237
+ feather.replace();
238
+ </script>
239
+ </body>
240
  </html>