pinokiod 3.41.0 → 3.42.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 (82) hide show
  1. package/kernel/api/browser/index.js +3 -1
  2. package/kernel/api/cloudflare/index.js +3 -3
  3. package/kernel/api/index.js +187 -51
  4. package/kernel/api/loading/index.js +15 -0
  5. package/kernel/api/process/index.js +7 -0
  6. package/kernel/api/shell/index.js +0 -2
  7. package/kernel/bin/browserless.js +22 -0
  8. package/kernel/bin/caddy.js +36 -4
  9. package/kernel/bin/index.js +4 -1
  10. package/kernel/bin/setup.js +38 -5
  11. package/kernel/connect/backend.js +110 -0
  12. package/kernel/connect/config.js +171 -0
  13. package/kernel/connect/index.js +18 -7
  14. package/kernel/connect/providers/huggingface/index.js +98 -0
  15. package/kernel/connect/providers/x/index.js +0 -1
  16. package/kernel/environment.js +91 -19
  17. package/kernel/git.js +46 -3
  18. package/kernel/index.js +119 -39
  19. package/kernel/peer.js +40 -5
  20. package/kernel/plugin.js +3 -2
  21. package/kernel/procs.js +27 -20
  22. package/kernel/prototype.js +30 -16
  23. package/kernel/router/common.js +1 -1
  24. package/kernel/router/connector.js +1 -3
  25. package/kernel/router/index.js +38 -4
  26. package/kernel/router/localhost_home_router.js +5 -1
  27. package/kernel/router/localhost_port_router.js +27 -1
  28. package/kernel/router/localhost_static_router.js +93 -0
  29. package/kernel/router/localhost_variable_router.js +14 -9
  30. package/kernel/router/peer_peer_router.js +3 -0
  31. package/kernel/router/peer_static_router.js +43 -0
  32. package/kernel/router/peer_variable_router.js +15 -14
  33. package/kernel/router/processor.js +26 -1
  34. package/kernel/router/rewriter.js +59 -0
  35. package/kernel/scripts/git/commit +11 -1
  36. package/kernel/shell.js +8 -3
  37. package/kernel/util.js +65 -6
  38. package/package.json +2 -1
  39. package/server/index.js +1037 -964
  40. package/server/public/common.js +382 -1
  41. package/server/public/fscreator.js +0 -1
  42. package/server/public/loading.js +17 -0
  43. package/server/public/notifyinput.js +0 -1
  44. package/server/public/opener.js +4 -2
  45. package/server/public/style.css +310 -11
  46. package/server/socket.js +7 -1
  47. package/server/views/app.ejs +1747 -351
  48. package/server/views/columns.ejs +338 -0
  49. package/server/views/connect/huggingface.ejs +353 -0
  50. package/server/views/connect/index.ejs +410 -0
  51. package/server/views/connect/x.ejs +43 -9
  52. package/server/views/connect.ejs +709 -49
  53. package/server/views/container.ejs +357 -0
  54. package/server/views/d.ejs +251 -62
  55. package/server/views/download.ejs +54 -10
  56. package/server/views/editor.ejs +11 -0
  57. package/server/views/explore.ejs +40 -15
  58. package/server/views/file_explorer.ejs +25 -246
  59. package/server/views/form.ejs +44 -1
  60. package/server/views/frame.ejs +39 -1
  61. package/server/views/github.ejs +48 -11
  62. package/server/views/help.ejs +48 -7
  63. package/server/views/index.ejs +119 -58
  64. package/server/views/index2.ejs +3 -4
  65. package/server/views/init/index.ejs +651 -197
  66. package/server/views/install.ejs +1 -1
  67. package/server/views/mini.ejs +47 -18
  68. package/server/views/net.ejs +199 -67
  69. package/server/views/network.ejs +220 -94
  70. package/server/views/network2.ejs +3 -4
  71. package/server/views/old_network.ejs +3 -3
  72. package/server/views/prototype/index.ejs +48 -11
  73. package/server/views/review.ejs +1005 -0
  74. package/server/views/rows.ejs +341 -0
  75. package/server/views/screenshots.ejs +1020 -0
  76. package/server/views/settings.ejs +160 -23
  77. package/server/views/setup.ejs +49 -7
  78. package/server/views/setup_home.ejs +43 -10
  79. package/server/views/shell.ejs +7 -1
  80. package/server/views/start.ejs +14 -9
  81. package/server/views/terminal.ejs +13 -2
  82. package/server/views/tools.ejs +1015 -0
@@ -16,14 +16,12 @@
16
16
  <% } %>
17
17
  <style>
18
18
  main {
19
- max-width: 1000px;
20
- width: 100%;
21
19
  box-sizing: border-box;
22
- display: flex;
23
20
  /*
24
21
  flex-wrap: wrap;
25
22
  */
26
- padding: 20px;
23
+ max-width: 800px;
24
+ padding: 30px 45px;
27
25
  /*
28
26
  justify-content: center;
29
27
  */
@@ -31,17 +29,16 @@ main {
31
29
  .tab-content {
32
30
  display: flex;
33
31
  flex-wrap: wrap;
34
- gap: 15px;
35
- padding: 10px 0px 0;
32
+ gap: 5px;
33
+ flex-grow: 1;
34
+ width: 100%;
36
35
  }
37
36
  .submenu.tab {
38
37
  margin: 10px 0;
39
38
  }
40
- /*
41
39
  .tab:hover {
42
- border: 2px solid royalblue;
40
+ color: royalblue;
43
41
  }
44
- */
45
42
  .tab {
46
43
  /*
47
44
  min-width: 250px;
@@ -57,9 +54,9 @@ main {
57
54
  color: black;
58
55
  overflow: hidden;
59
56
  box-sizing: border-box;
60
- border-radius: 10px;
61
- align-items: flex-start;
62
- padding: 10px 15px;
57
+ border-radius: 4px;
58
+ align-items: center;
59
+ gap: 10px;
63
60
  /*
64
61
  width: 120px;
65
62
  */
@@ -74,14 +71,8 @@ body.dark .tab {
74
71
  background: rgba(255,255,255,0.03);
75
72
  }
76
73
  .tab h2 {
77
- /*
78
- padding: 5px 2px 10px;
79
- */
80
- /*
81
- text-align: center;
82
- */
83
74
  margin: 0;
84
- font-size: 14px;
75
+ font-size: 18px;
85
76
  }
86
77
  .tab .col {
87
78
  flex-grow: 1;
@@ -94,7 +85,7 @@ body.dark .tab {
94
85
  color: black;
95
86
  display: flex;
96
87
  justify-content: center;
97
- font-size: 30px;
88
+ font-size: 20px;
98
89
  align-items: center;
99
90
  border-radius: 3px;
100
91
  }
@@ -128,6 +119,8 @@ body.dark .tab i {
128
119
  background: white;
129
120
  border-radius: 20px;
130
121
  */
122
+ margin-bottom: 30px;
123
+ align-items: flex-start;
131
124
  }
132
125
  /*
133
126
  body.dark .menu-container {
@@ -135,30 +128,13 @@ body.dark .menu-container {
135
128
  }
136
129
  */
137
130
  .menu-container {
138
- width: 100%;
131
+ display: flex;
132
+ flex-direction: column;
139
133
  box-sizing: border-box;
140
- margin: 20px;
141
- }
142
- body.dark .tab-header {
143
- /*
144
- background: rgba(0,0,0,0.3);
145
- */
146
- /*
147
- border-left: 10px solid white;
148
- */
149
134
  }
150
135
  .tab-header {
151
- padding: 0 5px;
152
- /*
153
- background: rgba(0,0,0,0.04);
154
- */
155
- /*
156
- padding: 8px 10px;
157
- */
136
+ margin-bottom: 10px;
158
137
  font-weight: bold;
159
- /*
160
- border-left: 10px solid black;
161
- */
162
138
  }
163
139
  .container {
164
140
  margin: 0;
@@ -167,35 +143,90 @@ body.dark .tab-header {
167
143
  .subtitle {
168
144
  font-size: 12px;
169
145
  opacity: 0.6;
170
- padding: 2px;
146
+ padding: 2px 0;
147
+ font-weight: normal;
171
148
  }
172
149
  .btns {
173
150
  display: flex;
174
- padding-top: 10px;
175
151
  gap: 5px;
152
+ align-items: center;
153
+ flex-shrink: 0;
154
+ /*
155
+ padding: 0 10px;
156
+ */
176
157
  }
177
158
  body.dark .btn {
159
+ /*
178
160
  background: rgba(255,255,255,0.08);
161
+ */
162
+ background: none;
179
163
  color: white;
180
164
  border: none;
181
165
  }
166
+ .btn:hover {
167
+ color: royalblue;
168
+ }
182
169
  .btn {
183
- padding: 7px 10px;
170
+ padding: 2px 10px;
184
171
  background: none;
172
+ /*
185
173
  background: rgba(0,0,0,0.08);
174
+ */
186
175
  color: rgba(0,0,0,0.7);
187
176
  /*
188
177
  border: 1px solid rgba(0,0,0,0.4);
189
178
  */
179
+ /*
190
180
  border-radius: 30px;
181
+ */
191
182
  /*
192
183
  background: rgba(0,0,0,0.8);
193
184
  */
194
185
  }
186
+ .spec {
187
+ display: none;
188
+ width: 100%;
189
+ padding-bottom: 30px;
190
+ }
191
+ .spec .explain {
192
+ display: flex;
193
+ flex-direction: column;
194
+ }
195
+ .spec .explain h3 {
196
+ margin: 0 0 10px;
197
+ }
198
+ body.dark .spec .explain {
199
+ border-left: 5px solid rgba(255,255,255,0.04);
200
+ }
201
+ .spec .explain {
202
+ padding: 15px;
203
+ border-left: 5px solid rgba(0,0,0,0.04);
204
+ background: rgba(0,0,0,0.02);
205
+ margin: 20px 0;
206
+ }
207
+ .spec .explain ol {
208
+ margin: 0;
209
+ padding-inline-start: 20px;
210
+ }
211
+ .spec .explain li {
212
+ padding: 5px 0;
213
+ }
214
+ .spec textarea {
215
+ border: none;
216
+ padding: 10px;
217
+ margin: 5px 0 0 20px;
218
+ box-sizing: border-box;
219
+ }
220
+ body.dark .btn.run-btn {
221
+ background: black;
222
+ }
195
223
  .btn.run-btn {
196
224
  flex-grow: 1;
197
225
  text-align: center;
198
- margin-right: 2px;
226
+ background: black;
227
+ width: 50px;
228
+ padding: 10px;
229
+ border-radius: 0;
199
230
  /*
200
231
  background: royalblue !important;
201
232
  */
@@ -203,17 +234,20 @@ body.dark .btn {
203
234
  .tab-header h3 {
204
235
  margin: 0;
205
236
  font-size: 16px;
237
+ text-transform: capitalize;
206
238
  }
207
239
  .tab-header h3 i {
208
- font-size: 18px;
209
240
  }
210
241
  header {
211
- padding: 50px 40px 0;
242
+ padding: 20px 0;
212
243
  display: flex;
213
244
  gap: 10px;
245
+ position: relative;
246
+ align-items: center;
214
247
  }
215
248
  header h1 {
216
249
  font-size: 40px;
250
+ line-height: 40px;
217
251
  }
218
252
  .pulling {
219
253
  display: flex;
@@ -231,6 +265,27 @@ header h1 {
231
265
  align-items: center;
232
266
  gap: 5px;
233
267
  }
268
+ h4 {
269
+ margin: 0 0 5px;
270
+ }
271
+ body.dark .btn.file-open {
272
+ background: rgba(255,255,255,0.1) !important;
273
+ }
274
+ .btn.file-open {
275
+ background: black;
276
+ color: white;
277
+ }
278
+ body.dark #update-spec {
279
+ background: rgba(255,255,255,0.1) !important;
280
+ color: white;
281
+ }
282
+ #update-spec {
283
+ border: none;
284
+ padding: 10px;
285
+ margin: 10px 0 0 20px;
286
+ background: rgba(0,0,0,0.8);
287
+ color: white;
288
+ }
234
289
  </style>
235
290
  <script src="/hotkeys.min.js"></script>
236
291
  <script src="/sweetalert2.js"></script>
@@ -239,8 +294,13 @@ header h1 {
239
294
  <script src="/nav.js"></script>
240
295
  </head>
241
296
  <body class='<%=theme%>' data-agent="<%=agent%>">
297
+ <main>
298
+ <form class='search'>
299
+ <input type='search' class="flexible" placeholder='Filter tools'>
300
+ </form>
242
301
  <header>
243
302
  <h1>Build</h1>
303
+ <div class='flexible'></div>
244
304
  <a class='btn' href="https://github.com/pinokiocomputer/code/issues" target="_blank"><i class="fa-solid fa-up-right-from-square"></i> Request a tool</a>
245
305
  <a class='btn' id='git-pull'><i class="fa-solid fa-rotate"></i> Check for new tools</a>
246
306
  <div class='pulling hidden'>
@@ -249,8 +309,25 @@ header h1 {
249
309
  </div>
250
310
  </div>
251
311
  </header>
252
- <main>
253
- <% dynamic.forEach((item, index) => { %>
312
+ <div class='spec'>
313
+ <div class='explain'>
314
+ <h3><i class="fa-regular fa-circle-check"></i> TODO</h3>
315
+ <ol>
316
+ <li><strong>Build manually:</strong> Open the project files and start building. <a class='btn file-open' data-filepath="<%=filepath%>"><i class="fa-solid fa-folder-open"></i> open project folder</a></li>
317
+ <li><strong>Build with AI:</strong> Click any of the below AI tools to instantly start building with AI.</li>
318
+ <!--
319
+ <li><strong>Build with AI:</strong> Click any of the AI tools below to start building with AI. The AI will automatically build based on the spec:</li>
320
+ -->
321
+ </ol>
322
+ <!--
323
+ <textarea><%=spec%></textarea>
324
+ <button id='update-spec'>Update</button>
325
+ -->
326
+ </div>
327
+ </div>
328
+
329
+ <% index = 0 %>
330
+ <% dynamic.forEach((item) => { %>
254
331
  <% if (item.menu) { %>
255
332
  <div class='menu-container'>
256
333
  <div class='tab-header'>
@@ -261,37 +338,44 @@ header h1 {
261
338
  </div>
262
339
  <div class='tab-content'>
263
340
  <% item.menu.forEach((i) => { %>
264
- <div class='tab'>
341
+ <a href="<%=i.href%>" class='tab' data-index="<%=index++%>" data-target="@<%=i.href.split("?")[0].replace("/run", "")%>">
265
342
  <% if (i.image) { %>
266
343
  <img src="<%=i.image%>">
267
344
  <% } else if (i.icon) { %>
268
345
  <i class="img <%=i.icon%>"></i>
269
346
  <% } %>
270
- <div class='col'>
271
- <h2><%=i.title%></h1>
272
- <% if (i.subtitle) { %>
273
- <div class='subtitle'><%=i.subtitle%></div>
274
- <% } %>
275
- <div class='btns'>
276
- <a class='run-btn btn' href="<%=i.href%>"><i class="fa-solid <%=i.type === "Start" ? 'fa-play' : 'fa-rocket'%>"></i> <%=i.type%></a>
277
- <a class='btn' target="_blank" href="<%=i.link%>"><i class="fa-solid fa-question"></i></a>
278
- </div>
347
+ <h2><%=i.title%></h1>
348
+ <% if (i.subtitle) { %>
349
+ <div class='subtitle'><%=i.subtitle%></div>
350
+ <% } %>
351
+ <% if (i.link) { %>
352
+ <div target="_blank" data-href="<%=i.link%>"><i class="fa-solid fa-circle-info"></i></div>
353
+ <% } %>
354
+ <div class='flexible'></div>
355
+ <div class='btn'>
356
+ <i class="fa-solid fa-angle-right"></i>
279
357
  </div>
280
- </div>
358
+ </a>
281
359
  <% }) %>
282
360
  </div>
283
361
  </div>
284
362
  <% } else { %>
285
- <div class='tab'>
286
- <img src="<%=item.image%>">
363
+ <div class='tab' data-index="<%=index++%>">
364
+ <% if (item.image) { %>
365
+ <img src="<%=item.image%>">
366
+ <% } else if (item.icon) { %>
367
+ <i class="img <%=item.icon%>"></i>
368
+ <% } %>
287
369
  <div class='col'>
288
370
  <h2><%=item.title%></h1>
289
371
  <% if (item.subtitle) { %>
290
372
  <div class='subtitle'><%=item.subtitle%></div>
291
373
  <% } %>
292
374
  <div class='btns'>
375
+ <% if (item.link) { %>
376
+ <a class='btn' target="_blank" href="<%=item.link%>"><i class="fa-solid fa-circle-info"></i></a>
377
+ <% } %>
293
378
  <a class='run-btn btn' href="<%=item.href%>"><i class="fa-solid <%=item.type === "Start" ? 'fa-play' : 'fa-rocket'%>"></i> <%=item.type%></a>
294
- <a class='btn' target="_blank" href="<%=item.link%>"><i class="fa-solid fa-question"></i></a>
295
379
  </div>
296
380
  </div>
297
381
  </div>
@@ -331,6 +415,111 @@ document.querySelector("#git-pull").addEventListener("click", (e) => {
331
415
  }
332
416
  })
333
417
  })
418
+ /*
419
+ const resize = (textarea) => {
420
+ textarea.style.height = "";
421
+ textarea.style.height = textarea.scrollHeight + "px";
422
+ }
423
+ document.querySelector(".spec textarea").addEventListener("input", (e) => {
424
+ resize(e.target)
425
+ })
426
+ resize(document.querySelector(".spec textarea"))
427
+ document.querySelector("#update-spec").addEventListener("click", (e) => {
428
+ e.preventDefault()
429
+ e.stopPropagation()
430
+ let filepath = document.querySelector(".file-open").getAttribute('data-filepath')
431
+ fetch("/plugin/update_spec", {
432
+ method: "POST",
433
+ headers: {
434
+ "Content-Type": "application/json"
435
+ },
436
+ body: JSON.stringify({
437
+ spec: document.querySelector(".spec textarea").value || "",
438
+ filepath: filepath
439
+ })
440
+ }).then((res) => {
441
+ return res.json()
442
+ }).then((res) => {
443
+ if (res.success) {
444
+ location.href = location.href
445
+ } else if(res.error) {
446
+ alert(res.error)
447
+ }
448
+ })
449
+ })
450
+ */
451
+ let list = []
452
+ document.querySelectorAll(".tab").forEach((el, index) => {
453
+ list.push({
454
+ index: parseInt(el.getAttribute("data-index")),
455
+ text: el.textContent,
456
+ })
457
+ })
458
+ const search = (items, value) => {
459
+ let filtered = []
460
+ for(let i=0; i<items.length; i++) {
461
+ let item = items[i]
462
+ let re = new RegExp(value, "i")
463
+ if (re.test(item.text)) {
464
+ filtered.push({ item })
465
+ }
466
+ }
467
+ return filtered
468
+ }
469
+
470
+ let selectedIndex = -1
471
+ let selectedBtnIndex = 0
472
+ let filteredCount = list.length
473
+ let filteredBtnsCount = 0
474
+
475
+ const renderSearch = () => {
476
+ let target = document.querySelector("form input[type=search]")
477
+ let result
478
+ if (target.value.trim().length === 0) {
479
+ result = list.map((i, index) => {
480
+ return { item: i }
481
+ })
482
+ } else {
483
+ result = search(list, target.value)
484
+ }
485
+ let all = document.querySelectorAll(".tab")
486
+ for(let el of all) {
487
+ el.classList.add("hidden")
488
+ el.classList.remove("selected")
489
+ }
490
+
491
+ filteredCount = result.length
492
+ for(let i=0; i<result.length; i++) {
493
+ let selector = result[i]
494
+ let el = document.querySelector(".tab[data-index='" + selector.item.index + "']")
495
+ el.classList.remove("hidden")
496
+ if (i === selectedIndex) {
497
+ el.classList.add("selected")
498
+ } else {
499
+ el.classList.remove("selected")
500
+ }
501
+ }
502
+ }
503
+ renderSearch()
504
+ document.querySelector("form input[type=search]").addEventListener("input", (e) => {
505
+ selectedIndex = 0
506
+ selectedBtnIndex = 0
507
+ renderSearch()
508
+ })
509
+ document.querySelector("form input[type=search]").focus()
510
+ document.addEventListener("click", (e) => {
511
+ if (e.target.classList.contains("tab")) {
512
+ e.preventDefault()
513
+ e.stopPropagation()
514
+ let href = e.target.href
515
+ window.parent.postMessage({
516
+ launch: {
517
+ name: e.target.getAttribute("data-target"),
518
+ href
519
+ }
520
+ }, "*")
521
+ }
522
+ })
334
523
  </script>
335
524
  </body>
336
525
  </html>
@@ -88,7 +88,15 @@ body.frozen {
88
88
  .timestamp {
89
89
  color: rgba(0,0,0,0.5);
90
90
  }
91
+ @media only screen and (max-width: 800px) {
92
+ body {
93
+ display: flex !important;
94
+ flex-direction: row !important;
95
+ }
96
+ }
91
97
  </style>
98
+ <script src="/popper.min.js"></script>
99
+ <script src="/tippy-bundle.umd.min.js"></script>
92
100
  <script src="/hotkeys.min.js"></script>
93
101
  <script src="/sweetalert2.js"></script>
94
102
  <script src="/noty.js"></script>
@@ -112,18 +120,54 @@ body.frozen {
112
120
  <header class='grabbable'>
113
121
  <h1>
114
122
  <a class='home' href="/"><img class='icon' src="/pinokio-black.png"></a>
115
- <button class='btn2' id='back'><div><i class="fa-solid fa-chevron-left"></i></div><div>Prev</div></button>
116
- <button class='btn2' id='forward'><div><i class="fa-solid fa-chevron-right"></i></div><div>Next</div></button>
117
- <button class='btn2' id='refresh-page'><div><i class="fa-solid fa-rotate-right"></i></div><div>Refresh</div></button>
118
- <a href="/connect" class='btn2'><div><i class="fa-solid fa-circle-user"></i></div><div>Connect</div></a>
123
+ <button class='btn2' id='back' data-tippy-content="back"><div><i class="fa-solid fa-chevron-left"></i></div></button>
124
+ <button class='btn2' id='forward' data-tippy-content="forward"><div><i class="fa-solid fa-chevron-right"></i></div></button>
125
+ <button class='btn2' id='refresh-page' data-tippy-content="refresh"><div><i class="fa-solid fa-rotate-right"></i></div></button>
126
+ <button class='btn2' id='screenshot' data-tippy-content="take a screenshot"><i class="fa-solid fa-camera"></i></button>
119
127
  <div class='flexible'></div>
120
- <div class='nav-btns'>
121
- <a class='btn2' href="<%=portal%>" target="_blank"><div><i class="fa-solid fa-question"></i></div><div>Help</div></a>
122
- <button class='btn2' id='genlog'><div><i class="fa-solid fa-laptop-code"></i></div><div>Logs</div></button>
123
- <a id='downloadlogs' download class='hidden btn2' href="/pinokio/logs.zip"><div><i class="fa-solid fa-download"></i></div><div>Download logs</div></a>
124
- <a class='btn2' href="/?mode=settings"><div><i class="fa-solid fa-gear"></i></div><div>Settings</div></a>
125
- <button id='new-window' title='open a new window' class='btn2' data-agent="<%=agent%>"><div><i class="fa-solid fa-plus"></i></div><div>Window</div></button>
128
+ <a class='btn2' href="/columns" data-tippy-content="split into 2 columns">
129
+ <div><i class="fa-solid fa-table-columns"></i></div>
130
+ </a>
131
+ <a class='btn2' href="/rows" data-tippy-content="split into 2 rows">
132
+ <div><i class="fa-solid fa-table-columns fa-rotate-270"></i></div>
133
+ </a>
134
+ <div class="dropdown btn2">
135
+ <button class='btn2' id='window-management'>
136
+ <div><i class="fa-solid fa-plus"></i></div>
137
+ </button>
138
+ <div class="dropdown-content" id="dropdown-content">
139
+ <button class='btn2' id='clone-win' data-tippy-content="clone this window">
140
+ <div><i class="fa-solid fa-clone"></i><div>clone this window</div></div>
141
+ </button>
142
+ <button id='new-window' data-tippy-content="open a new window" title='open a new window' class='btn2' data-agent="<%=agent%>">
143
+ <div><i class="fa-solid fa-plus"></i><div>new window</div></div>
144
+ </button>
145
+ </div>
146
+ </div>
147
+ <!--
148
+ <div class="dropdown btn2">
149
+ <button class='btn2' id='window-management'>
150
+ <div><i class="fa-regular fa-window-restore"></i></div>
151
+ </button>
152
+ <div class="dropdown-content" id="dropdown-content">
153
+ <button class='btn2' id='clone-win' data-tippy-content="clone this window">
154
+ <div><i class="fa-solid fa-clone"></i><div>clone this window</div></div>
155
+ </button>
156
+ <a class='btn2' href="/columns" data-tippy-content="split into 2 columns">
157
+ <div><i class="fa-solid fa-table-columns"></i><div>split columns</div></div>
158
+ </a>
159
+ <a class='btn2' href="/rows" data-tippy-content="split into 2 rows">
160
+ <div><i class="fa-solid fa-table-columns fa-rotate-270"></i><div>split rows</div></div>
161
+ </a>
162
+ <button id='new-window' data-tippy-content="open a new window" title='open a new window' class='btn2' data-agent="<%=agent%>">
163
+ <div><i class="fa-solid fa-plus"></i><div>new window</div></div>
164
+ </button>
165
+ </div>
126
166
  </div>
167
+ -->
168
+ <button class='btn2 hidden' id='close-window' data-tippy-content='close this section'>
169
+ <div><i class="fa-solid fa-xmark"></i></div>
170
+ </button>
127
171
  </h1>
128
172
  </header>
129
173
  <% if (requirements_pending) { %>
@@ -109,6 +109,9 @@ td.key {
109
109
  background: var(--dark-bg);
110
110
  }
111
111
  */
112
+ header {
113
+ padding: 10px;
114
+ }
112
115
  header .runner {
113
116
  padding: 10px 0 0;
114
117
  }
@@ -122,6 +125,14 @@ header .runner {
122
125
  body.frozen {
123
126
  overflow: auto !important;
124
127
  }
128
+ @media only screen and (max-width: 800px) {
129
+ header h1 {
130
+ height: unset;
131
+ }
132
+ .appcanvas, main {
133
+ padding-top: unset;
134
+ }
135
+ }
125
136
  </style>
126
137
  <script>
127
138
  let shell_id
@@ -113,6 +113,8 @@ body main iframe {
113
113
  width: 100%;
114
114
  }
115
115
  </style>
116
+ <script src="/popper.min.js"></script>
117
+ <script src="/tippy-bundle.umd.min.js"></script>
116
118
  <script src="/hotkeys.min.js"></script>
117
119
  <script src="/sweetalert2.js"></script>
118
120
  <script src="/nav.js"></script>
@@ -121,26 +123,49 @@ body main iframe {
121
123
  <header class='navheader grabbable'>
122
124
  <h1>
123
125
  <a class='home' href="/"><img class='icon' src="/pinokio-black.png"></a>
124
- <button class='btn2' id='back'><div><i class="fa-solid fa-chevron-left"></i></div><div>Prev</div></button>
125
- <button class='btn2' id='forward'><div><i class="fa-solid fa-chevron-right"></i></div><div>Next</div></button>
126
- <button class='btn2' id='refresh-page'><div><i class="fa-solid fa-rotate-right"></i></div><div>Refresh</div></button>
126
+ <button class='btn2' id='back' data-tippy-content="back"><div><i class="fa-solid fa-chevron-left"></i></div></button>
127
+ <button class='btn2' id='forward' data-tippy-content="forward"><div><i class="fa-solid fa-chevron-right"></i></div></button>
128
+ <button class='btn2' id='refresh-page' data-tippy-content="refresh"><div><i class="fa-solid fa-rotate-right"></i></div></button>
129
+ <button class='btn2' id='screenshot' data-tippy-content="take a screenshot"><i class="fa-solid fa-camera"></i></button>
127
130
  <div class='flexible'></div>
128
- <a href="/connect" class='btn2'><div><i class="fa-solid fa-circle-user"></i></div><div>Connect</div></a>
129
- <div class='nav-btns'>
130
- <a class='btn2' href="<%=portal%>" target="_blank"><div><i class="fa-solid fa-question"></i></div><div>Help</div></a>
131
- <button class='btn2' id='genlog'><div><i class="fa-solid fa-laptop-code"></i></div><div>Logs</div></button>
132
- <a id='downloadlogs' download class='hidden btn2' href="/pinokio/logs.zip"><div><i class="fa-solid fa-download"></i></div><div>Download logs</div></a>
133
- <a class='btn2' href="/?mode=settings"><div><i class="fa-solid fa-gear"></i></div><div>Settings</div></a>
134
- <button id='new-window' title='open a new window' class='btn2' data-agent="<%=agent%>"><div><i class="fa-solid fa-plus"></i></div><div>Window</div></button>
131
+ <a class='btn2' href="/columns" data-tippy-content="split into 2 columns">
132
+ <div><i class="fa-solid fa-table-columns"></i></div>
133
+ </a>
134
+ <a class='btn2' href="/rows" data-tippy-content="split into 2 rows">
135
+ <div><i class="fa-solid fa-table-columns fa-rotate-270"></i></div>
136
+ </a>
137
+ <div class="dropdown-content" id="dropdown-content">
138
+ <button class='btn2' id='clone-win' data-tippy-content="clone this window">
139
+ <div><i class="fa-solid fa-clone"></i><div>clone this window</div></div>
140
+ </button>
141
+ <button id='new-window' data-tippy-content="open a new window" title='open a new window' class='btn2' data-agent="<%=agent%>">
142
+ <div><i class="fa-solid fa-plus"></i><div>new window</div></div>
143
+ </button>
135
144
  </div>
136
145
  <!--
137
- <div class='nav-btns'>
138
- <a class='btn2' href='https://discord.gg/TQdNwadtE4' target="_blank"><div><i class="fa-brands fa-discord"></i></div><div>Discord</div></a>
139
- <a class='btn2' href='https://twitter.com/cocktailpeanut' target="_blank"><div><i class="fa-brands fa-twitter"></i></div><div>Twitter</div></a>
140
- <a class='btn2' href="/?mode=settings"><div><i class="fa-solid fa-gear"></i></div><div>Settings</div></a>
146
+ <div class="dropdown btn2">
147
+ <button class='btn2' id='window-management'>
148
+ <div><i class="fa-regular fa-window-restore"></i></div>
149
+ </button>
150
+ <div class="dropdown-content" id="dropdown-content">
151
+ <button class='btn2' id='clone-win' data-tippy-content="clone this window">
152
+ <div><i class="fa-solid fa-clone"></i><div>clone this window</div></div>
153
+ </button>
154
+ <a class='btn2' href="/columns" data-tippy-content="split into 2 columns">
155
+ <div><i class="fa-solid fa-table-columns"></i><div>split columns</div></div>
156
+ </a>
157
+ <a class='btn2' href="/rows" data-tippy-content="split into 2 rows">
158
+ <div><i class="fa-solid fa-table-columns fa-rotate-270"></i><div>split rows</div></div>
159
+ </a>
160
+ <button id='new-window' data-tippy-content="open a new window" title='open a new window' class='btn2' data-agent="<%=agent%>">
161
+ <div><i class="fa-solid fa-plus"></i><div>new window</div></div>
162
+ </button>
163
+ </div>
141
164
  </div>
142
- <button id='new-window' title='open a new window' class='btn2'><i class="fa-solid fa-plus"></i></button>
143
165
  -->
166
+ <button class='btn2 hidden' id='close-window' data-tippy-content='close this section'>
167
+ <div><i class="fa-solid fa-xmark"></i></div>
168
+ </button>
144
169
  </h1>
145
170
  </header>
146
171
  <main>