pinokiod 1.0.30 → 1.0.32
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/kernel/shell.js +12 -2
- package/package.json +1 -1
- package/server/index.js +26 -1
- package/server/public/install.js +2 -1
- package/server/public/style.css +19 -4
- package/server/views/bootstrap.ejs +2 -1
- package/server/views/browser.ejs +376 -81
- package/server/views/editor.ejs +2 -1
- package/server/views/fullscreen_editor.ejs +4 -1
- package/server/views/install.ejs +2 -1
- package/server/views/partials/menu.ejs +3 -0
- package/server/views/settings.ejs +17 -6
package/kernel/shell.js
CHANGED
|
@@ -31,6 +31,11 @@ class Shell {
|
|
|
31
31
|
this.platform = os.platform()
|
|
32
32
|
this.logs = {}
|
|
33
33
|
this.shell = this.platform === 'win32' ? 'cmd.exe' : 'bash';
|
|
34
|
+
|
|
35
|
+
// Windows: /D => ignore AutoRun Registry Key
|
|
36
|
+
// Others: --noprofile => ignore .bash_profile, --norc => ignore .bashrc
|
|
37
|
+
this.args = this.platform === 'win32' ? ["/D"] : ["--noprofile", "--norc"]
|
|
38
|
+
|
|
34
39
|
//this.vt = new Terminal({ allowProposedApi: true, scrollback: 5, })
|
|
35
40
|
// this.vt = new Terminal({
|
|
36
41
|
// allowProposedApi: true,
|
|
@@ -113,6 +118,9 @@ class Shell {
|
|
|
113
118
|
this.env.GRADIO_TEMP_DIR = path.resolve(this.kernel.homedir, "cache", "GRADIO_TEMP_DIR")
|
|
114
119
|
this.env.PIP_CONFIG_FILE = path.resolve(this.kernel.homedir, "pipconfig")
|
|
115
120
|
|
|
121
|
+
this.env.PS1 = "<<PINOKIO SHELL>> "
|
|
122
|
+
// this.env.PROMPT_COMMAND = "export PS1=\"<<PINOKIO SHELL>> \""
|
|
123
|
+
|
|
116
124
|
let PATH_KEY;
|
|
117
125
|
if (this.env.Path) {
|
|
118
126
|
PATH_KEY = "Path"
|
|
@@ -182,6 +190,8 @@ class Shell {
|
|
|
182
190
|
// automatically add self to the shells registry
|
|
183
191
|
this.kernel.shell.add(this)
|
|
184
192
|
|
|
193
|
+
console.log("** this.env", this.env)
|
|
194
|
+
|
|
185
195
|
if (params.sudo) {
|
|
186
196
|
let options = {
|
|
187
197
|
name: "Pinokio",
|
|
@@ -352,7 +362,7 @@ class Shell {
|
|
|
352
362
|
//let re = /([\r\n]+[^\r\n]+)(\1)/gs
|
|
353
363
|
let re = /(.+)(\1)/gs
|
|
354
364
|
console.log("get prompt - pty.spawn", config)
|
|
355
|
-
let term = pty.spawn(this.shell,
|
|
365
|
+
let term = pty.spawn(this.shell, this.args, config)
|
|
356
366
|
console.log("terminal spawned", term)
|
|
357
367
|
let ready
|
|
358
368
|
console.log("create terminal for prompt")
|
|
@@ -544,7 +554,7 @@ class Shell {
|
|
|
544
554
|
if (!this.ptyProcess) {
|
|
545
555
|
// ptyProcess doesn't exist => create
|
|
546
556
|
this.done = false
|
|
547
|
-
this.ptyProcess = pty.spawn(this.shell,
|
|
557
|
+
this.ptyProcess = pty.spawn(this.shell, this.args, config)
|
|
548
558
|
this.ptyProcess.onData((data) => {
|
|
549
559
|
if (!this.done) {
|
|
550
560
|
this.queue.push(data)
|
package/package.json
CHANGED
package/server/index.js
CHANGED
|
@@ -343,6 +343,7 @@ class Server {
|
|
|
343
343
|
} else if (pathComponents.length === 0 && req.query.mode === "settings") {
|
|
344
344
|
let configArray = [{
|
|
345
345
|
key: "home",
|
|
346
|
+
description: "* Do NOT use exFAT drives",
|
|
346
347
|
val: this.kernel.homedir,
|
|
347
348
|
placeholder: "Enter the absolute path to use as your Pinokio home folder (D:\\pinokio, /Users/alice/pinokiofs, etc.)"
|
|
348
349
|
}, {
|
|
@@ -351,6 +352,7 @@ class Server {
|
|
|
351
352
|
options: ["light", "dark"]
|
|
352
353
|
}]
|
|
353
354
|
console.log("agent", this.agent)
|
|
355
|
+
console.log({ configArray })
|
|
354
356
|
res.render("settings", {
|
|
355
357
|
version: this.version,
|
|
356
358
|
logo: this.logo,
|
|
@@ -1168,10 +1170,16 @@ class Server {
|
|
|
1168
1170
|
}
|
|
1169
1171
|
}
|
|
1170
1172
|
}
|
|
1173
|
+
config.menu[i].target = "@" + (config.menu[i].id || config.menu[i].src)
|
|
1171
1174
|
}
|
|
1175
|
+
|
|
1176
|
+
|
|
1172
1177
|
config.menu = config.menu.filter((item) => {
|
|
1173
1178
|
return item.btn
|
|
1174
1179
|
})
|
|
1180
|
+
|
|
1181
|
+
|
|
1182
|
+
|
|
1175
1183
|
console.log("config", JSON.stringify(config,null,2))
|
|
1176
1184
|
return config
|
|
1177
1185
|
} else {
|
|
@@ -1602,6 +1610,7 @@ class Server {
|
|
|
1602
1610
|
if (req.query.mode === 'settings') {
|
|
1603
1611
|
let configArray = [{
|
|
1604
1612
|
key: "home",
|
|
1613
|
+
description: "* Do NOT use exFAT drives",
|
|
1605
1614
|
val: this.kernel.homedir ? this.kernel.homedir : path.resolve(os.homedir(), "pinokio"),
|
|
1606
1615
|
placeholder: "Enter the absolute path to use as your Pinokio home folder (D:\\pinokio, /Users/alice/pinokiofs, etc.)"
|
|
1607
1616
|
}, {
|
|
@@ -1849,9 +1858,25 @@ class Server {
|
|
|
1849
1858
|
theme: this.theme,
|
|
1850
1859
|
agent: this.agent,
|
|
1851
1860
|
src: "/_api/" + name,
|
|
1852
|
-
rawpath
|
|
1861
|
+
rawpath,
|
|
1853
1862
|
})
|
|
1854
1863
|
})
|
|
1864
|
+
this.app.post("/pinokio/delete", async (req, res) => {
|
|
1865
|
+
if (req.body.name) {
|
|
1866
|
+
let folderPath = this.kernel.path("api", req.body.name)
|
|
1867
|
+
console.log("delete", folderPath)
|
|
1868
|
+
await rimraf(folderPath)
|
|
1869
|
+
await new Promise((resolve, reject) => {
|
|
1870
|
+
setTimeout(() => {
|
|
1871
|
+
resolve()
|
|
1872
|
+
}, 5000)
|
|
1873
|
+
})
|
|
1874
|
+
console.log("deleted")
|
|
1875
|
+
res.json({ success: true })
|
|
1876
|
+
} else {
|
|
1877
|
+
res.json({ error: e.stack })
|
|
1878
|
+
}
|
|
1879
|
+
})
|
|
1855
1880
|
// this.app.get("/pinokio/shell_state", (req, res) => {
|
|
1856
1881
|
// let states = this.kernel.shell.shells.map((s) => {
|
|
1857
1882
|
// return {
|
package/server/public/install.js
CHANGED
|
@@ -135,7 +135,8 @@ const createTerm = () => {
|
|
|
135
135
|
//theme: xtermTheme.Piatto_Light,
|
|
136
136
|
//theme: xtermTheme.Github,
|
|
137
137
|
//theme: xtermTheme.Cobalt_Neon, // top legibility
|
|
138
|
-
theme: xtermTheme.Duotone_Dark,
|
|
138
|
+
//theme: xtermTheme.Duotone_Dark,
|
|
139
|
+
theme: xtermTheme.FrontEndDelight,
|
|
139
140
|
//theme: xtermTheme.Seafoam_Pastel,
|
|
140
141
|
//theme: xtermTheme.IC_Green_PPL,
|
|
141
142
|
//theme: xtermTheme.FunForrest,
|
package/server/public/style.css
CHANGED
|
@@ -7,19 +7,21 @@
|
|
|
7
7
|
*/
|
|
8
8
|
/*
|
|
9
9
|
--dark-nav-bg: #161616;
|
|
10
|
-
*/
|
|
11
10
|
--dark-nav-bg: rgb(31, 29, 39);
|
|
11
|
+
*/
|
|
12
|
+
--dark-nav-bg: rgb(27, 28, 29);
|
|
12
13
|
|
|
14
|
+
--dark-bg: rgb(27, 28, 29);
|
|
13
15
|
/*
|
|
14
16
|
--dark-bg: #202020;
|
|
15
|
-
*/
|
|
16
17
|
--dark-bg: rgb(31, 29, 39);
|
|
18
|
+
*/
|
|
17
19
|
--light-bg: rgba(0,0,150,0.05);
|
|
18
20
|
|
|
19
21
|
--light-thin: rgba(0,0,0,0.1);
|
|
20
22
|
--dark-thin: rgba(255,255,255,0.03);
|
|
21
23
|
|
|
22
|
-
--dark-color: rgba(255,255,255,0.
|
|
24
|
+
--dark-color: rgba(255,255,255,0.8);
|
|
23
25
|
--light-color: rgba(0,0,0,0.9);
|
|
24
26
|
|
|
25
27
|
--dark-fade: rgba(255,255,255,0.6);
|
|
@@ -43,7 +45,10 @@
|
|
|
43
45
|
--light-btn-color: white;
|
|
44
46
|
|
|
45
47
|
--dark-btn-bg: rgba(0,0,0,0.8);
|
|
48
|
+
/*
|
|
46
49
|
--dark-btn-color: #b7a1ff;
|
|
50
|
+
*/
|
|
51
|
+
--dark-btn-color: whitesmoke;
|
|
47
52
|
}
|
|
48
53
|
body.columns footer {
|
|
49
54
|
}
|
|
@@ -77,14 +82,19 @@ footer pre {
|
|
|
77
82
|
background: none !important;
|
|
78
83
|
}
|
|
79
84
|
footer {
|
|
85
|
+
font-family: verdana;
|
|
80
86
|
overflow: hidden;
|
|
87
|
+
font-size: 11px;
|
|
88
|
+
font-weight: normal;
|
|
81
89
|
/*
|
|
82
90
|
overflow: auto;
|
|
83
91
|
*/
|
|
84
92
|
box-sizing: border-box;
|
|
85
93
|
color: var(--dark-color);
|
|
86
94
|
background: var(--dark-bg);
|
|
95
|
+
/*
|
|
87
96
|
border-top: 1px solid rgba(255,255,255,0.05);
|
|
97
|
+
*/
|
|
88
98
|
display: flex;
|
|
89
99
|
align-items: center;
|
|
90
100
|
padding: 10px;
|
|
@@ -99,6 +109,8 @@ footer b {
|
|
|
99
109
|
flex-shrink: 0;
|
|
100
110
|
color: var(--dark-btn-color);
|
|
101
111
|
margin-right: 10px;
|
|
112
|
+
font-weight: normal;
|
|
113
|
+
font-size: 11px;
|
|
102
114
|
/*
|
|
103
115
|
background: var(--dark-btn-color);
|
|
104
116
|
color: var(--dark-bg);
|
|
@@ -837,9 +849,12 @@ body.dark .line:hover {
|
|
|
837
849
|
vertical-align: middle;
|
|
838
850
|
font-weight: normal;
|
|
839
851
|
}
|
|
852
|
+
body.dark .line .avatar i {
|
|
853
|
+
color: var(--dark-btn-color);
|
|
854
|
+
}
|
|
840
855
|
.line .avatar i {
|
|
841
856
|
font-size: 60px;
|
|
842
|
-
color: var(--dark-
|
|
857
|
+
color: var(--dark-bg);
|
|
843
858
|
}
|
|
844
859
|
.line .description {
|
|
845
860
|
font-size: 13px;
|
|
@@ -132,7 +132,8 @@ document.addEventListener("DOMContentLoaded", () => {
|
|
|
132
132
|
//theme: xtermTheme.Seafoam_Pastel,
|
|
133
133
|
//theme: xtermTheme.IC_Green_PPL,
|
|
134
134
|
//theme: xtermTheme.FunForrest,
|
|
135
|
-
theme: xtermTheme.Jackie_Brown,
|
|
135
|
+
//theme: xtermTheme.Jackie_Brown,
|
|
136
|
+
theme: xtermTheme.FrontEndDelight,
|
|
136
137
|
//theme: xtermTheme.Ocean,
|
|
137
138
|
|
|
138
139
|
//theme: xtermTheme.Blazer,
|
package/server/views/browser.ejs
CHANGED
|
@@ -30,6 +30,12 @@ body {
|
|
|
30
30
|
.menu {
|
|
31
31
|
overflow: auto;
|
|
32
32
|
}
|
|
33
|
+
body.dark .m {
|
|
34
|
+
border-top: 1px solid rgba(255,255,255,0.04);
|
|
35
|
+
}
|
|
36
|
+
.m {
|
|
37
|
+
border-top: 1px solid rgba(0,0,0,0.04);
|
|
38
|
+
}
|
|
33
39
|
.container {
|
|
34
40
|
display: flex;
|
|
35
41
|
flex-direction: column;
|
|
@@ -196,6 +202,9 @@ body.dark .header-item.cursor {
|
|
|
196
202
|
border-left: 5px solid gold;
|
|
197
203
|
*/
|
|
198
204
|
}
|
|
205
|
+
.frame-link {
|
|
206
|
+
cursor: pointer;
|
|
207
|
+
}
|
|
199
208
|
body .frame-link.selected {
|
|
200
209
|
/*
|
|
201
210
|
border-right: 10px solid gold;
|
|
@@ -210,7 +219,10 @@ body .frame-link.selected {
|
|
|
210
219
|
color: white;
|
|
211
220
|
}
|
|
212
221
|
body.dark .frame-link.selected {
|
|
213
|
-
background: rgba(0,0,0,0.
|
|
222
|
+
background: rgba(0,0,0,0.7) !important;
|
|
223
|
+
}
|
|
224
|
+
.frame-link .loader {
|
|
225
|
+
padding: 5px;
|
|
214
226
|
}
|
|
215
227
|
.frame-link .tab {
|
|
216
228
|
flex-grow: 1;
|
|
@@ -218,7 +230,9 @@ body.dark .frame-link.selected {
|
|
|
218
230
|
width: 100%;
|
|
219
231
|
*/
|
|
220
232
|
word-break: break-word;
|
|
233
|
+
/*
|
|
221
234
|
margin-right: 10px;
|
|
235
|
+
*/
|
|
222
236
|
}
|
|
223
237
|
.frame-link .tab .flexible {
|
|
224
238
|
min-width: 5px;
|
|
@@ -265,22 +279,31 @@ body.dark .grid-btns .btn2 {
|
|
|
265
279
|
margin-right: 10px;
|
|
266
280
|
}
|
|
267
281
|
.temp-menu {
|
|
282
|
+
/*
|
|
268
283
|
border-top: 1px solid rgba(0,0,0,0.1);
|
|
284
|
+
*/
|
|
269
285
|
}
|
|
270
286
|
.temp-menu .del i {
|
|
271
287
|
margin: 0;
|
|
272
288
|
}
|
|
289
|
+
#delete {
|
|
290
|
+
color: brown;
|
|
291
|
+
}
|
|
273
292
|
body .footer {
|
|
274
293
|
}
|
|
275
294
|
body.dark nav {
|
|
295
|
+
/*
|
|
276
296
|
border-bottom: 1px solid rgba(255,255,255,0.04);
|
|
297
|
+
*/
|
|
277
298
|
}
|
|
278
299
|
nav {
|
|
279
300
|
background: white;
|
|
280
301
|
padding: 5px;
|
|
281
302
|
cursor: grab !important;
|
|
282
303
|
-webkit-app-region: drag !important;
|
|
304
|
+
/*
|
|
283
305
|
border-bottom: 1px solid rgba(0,0,0,0.04);
|
|
306
|
+
*/
|
|
284
307
|
box-sizing: border-box;
|
|
285
308
|
}
|
|
286
309
|
nav .btn2 {
|
|
@@ -293,7 +316,8 @@ nav .logo {
|
|
|
293
316
|
}
|
|
294
317
|
#location {
|
|
295
318
|
padding: 5px;
|
|
296
|
-
font-size:
|
|
319
|
+
font-size: 12px;
|
|
320
|
+
font-family: verdana;
|
|
297
321
|
}
|
|
298
322
|
.bar {
|
|
299
323
|
-webkit-app-region: no-drag !important;
|
|
@@ -333,6 +357,21 @@ body.dark #new-tab {
|
|
|
333
357
|
padding-left: 15px;
|
|
334
358
|
box-sizing: border-box;
|
|
335
359
|
}
|
|
360
|
+
body.dark .loader-popup {
|
|
361
|
+
background: rgba(0,0,0,0.2);
|
|
362
|
+
color: whitesmoke;
|
|
363
|
+
}
|
|
364
|
+
.loader-popup {
|
|
365
|
+
text-transform: uppercase;
|
|
366
|
+
font-size: 12px;
|
|
367
|
+
letter-spacing: 1px;
|
|
368
|
+
padding: 20px;
|
|
369
|
+
background: rgba(0,0,0,0.2);
|
|
370
|
+
color: white;
|
|
371
|
+
}
|
|
372
|
+
body.dark .loader-container {
|
|
373
|
+
background: rgba(255,255,255,0.3);
|
|
374
|
+
}
|
|
336
375
|
</style>
|
|
337
376
|
</head>
|
|
338
377
|
<body class='<%=theme%>'>
|
|
@@ -343,9 +382,12 @@ body.dark #new-tab {
|
|
|
343
382
|
<div><%=config.title%></div>
|
|
344
383
|
</div>
|
|
345
384
|
</div>
|
|
346
|
-
<div class='m system'>
|
|
385
|
+
<div class='m n system' data-type="n">
|
|
347
386
|
<!--<a data-index="0" target="<%=src%>" href="<%=src%>" class='btn header-item frame-link'>-->
|
|
348
|
-
<
|
|
387
|
+
<div id='delete' data-name="<%=name%>" class='btn header-item frame-link'>
|
|
388
|
+
<div class='tab'><i class="fa-solid fa-trash-can"></i> Delete</div>
|
|
389
|
+
</div>
|
|
390
|
+
<a target="<%=src%>" href="<%=src%>" class='btn header-item frame-link' data-index="0">
|
|
349
391
|
<div class='tab'><i class="fa-regular fa-folder-open"></i> Files</div>
|
|
350
392
|
</a>
|
|
351
393
|
</div>
|
|
@@ -399,12 +441,14 @@ body.dark #new-tab {
|
|
|
399
441
|
-->
|
|
400
442
|
</nav>
|
|
401
443
|
<main class='browserview'>
|
|
402
|
-
<% if (false
|
|
403
|
-
<% config.menu
|
|
404
|
-
<%
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
444
|
+
<% if (false) { %>
|
|
445
|
+
<% if (config.menu) { %>
|
|
446
|
+
<% config.menu.forEach((item) => { %>
|
|
447
|
+
<% if (item.btn && item.src) { %>
|
|
448
|
+
<iframe name='<%=item.src%>' class='hidden'></iframe>
|
|
449
|
+
<% } %>
|
|
450
|
+
<% }) %>
|
|
451
|
+
<% } %>
|
|
408
452
|
<% } %>
|
|
409
453
|
</main>
|
|
410
454
|
</div>
|
|
@@ -425,6 +469,35 @@ const getTarget = (href) => {
|
|
|
425
469
|
return u.pathname
|
|
426
470
|
}
|
|
427
471
|
}
|
|
472
|
+
const subUrlOf = (s, f) => {
|
|
473
|
+
debugger
|
|
474
|
+
|
|
475
|
+
let subsetUrl = (s.startsWith("http") ? s : "http://localhost" + s)
|
|
476
|
+
let fullUrl = (f.startsWith("http") ? f: "http://localhost" + f)
|
|
477
|
+
|
|
478
|
+
const subsetParsed = new URL(subsetUrl)
|
|
479
|
+
const fullParsed = new URL(fullUrl)
|
|
480
|
+
|
|
481
|
+
if (subsetParsed.pathname !== fullParsed.pathname) {
|
|
482
|
+
return false;
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
// Check if all search parameters in the subset URL are present in the full URL
|
|
486
|
+
for (const [key, val] of subsetParsed.searchParams) {
|
|
487
|
+
|
|
488
|
+
if (!fullParsed.searchParams.has(key)) {
|
|
489
|
+
return false
|
|
490
|
+
}
|
|
491
|
+
console.log("key", key)
|
|
492
|
+
console.log("f", fullParsed.searchParams.get(key))
|
|
493
|
+
console.log("s", val)
|
|
494
|
+
if (fullParsed.searchParams.get(key) !== val) {
|
|
495
|
+
return false
|
|
496
|
+
}
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
return true;
|
|
500
|
+
}
|
|
428
501
|
const renderCursor = () => {
|
|
429
502
|
document.querySelectorAll(".selectable").forEach((el) => {
|
|
430
503
|
el.classList.remove("cursor")
|
|
@@ -462,10 +535,18 @@ const renderSelection = (e, force) => {
|
|
|
462
535
|
document.querySelector(".bar").classList.remove("hidden")
|
|
463
536
|
//let id = getTarget(location.hash.slice(1))
|
|
464
537
|
let id = location.hash.slice(1)
|
|
465
|
-
let type = id[0]
|
|
466
|
-
let index = id.slice(1)
|
|
467
538
|
|
|
468
|
-
|
|
539
|
+
|
|
540
|
+
let selector
|
|
541
|
+
if (id.startsWith("@")) {
|
|
542
|
+
selector = `aside [target='${id.slice(1)}']`
|
|
543
|
+
} else {
|
|
544
|
+
let type = id[0]
|
|
545
|
+
let index = id.slice(1)
|
|
546
|
+
console.log({ type, index })
|
|
547
|
+
selector = `aside .${type} [data-index='${index}']`
|
|
548
|
+
}
|
|
549
|
+
|
|
469
550
|
|
|
470
551
|
// select the selected link
|
|
471
552
|
// document.querySelectorAll(".frame-link").forEach((el) => {
|
|
@@ -475,107 +556,162 @@ console.log({ type, index })
|
|
|
475
556
|
|
|
476
557
|
|
|
477
558
|
// const target = document.querySelector(`[target='${id}']`)
|
|
559
|
+
|
|
560
|
+
|
|
478
561
|
let target
|
|
479
562
|
if (e) {
|
|
563
|
+
// If the renderSelection is triggered by an event, look for the frame-link that's triggering the event
|
|
480
564
|
if (e.target.classList.contains("frame-link")) {
|
|
481
565
|
target = e.target
|
|
482
566
|
} else {
|
|
483
567
|
target = e.target.closest(".frame-link")
|
|
484
568
|
}
|
|
569
|
+
} else {
|
|
570
|
+
// if not triggered by an event, look for the target from the location hash
|
|
571
|
+
target = document.querySelector(selector)
|
|
485
572
|
}
|
|
486
573
|
|
|
487
574
|
|
|
488
|
-
if
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
575
|
+
// if the target was found either through:
|
|
576
|
+
// 1. looking for the frame-link that triggered the event
|
|
577
|
+
// 2. or by looking at the location hash
|
|
578
|
+
//
|
|
579
|
+
// => select that tab and frame
|
|
493
580
|
|
|
494
581
|
if (target) {
|
|
495
582
|
console.log("# 3")
|
|
496
583
|
|
|
497
584
|
|
|
585
|
+
// Instantiate a frame with the selected target's href
|
|
498
586
|
let url = target.href
|
|
587
|
+
console.log("> url", url)
|
|
499
588
|
document.querySelector("#open-browser").href = url
|
|
500
589
|
document.querySelector("#clone-tab").setAttribute("data-href", url)
|
|
501
590
|
document.querySelector("#location").innerHTML = url
|
|
502
591
|
|
|
503
|
-
// document.querySelector("#location").innerHTML = location.hash.slice(1)
|
|
504
|
-
//
|
|
505
|
-
// if (location.hash.slice(1).startsWith("/")) {
|
|
506
|
-
// //document.querySelector("#open-browser").classList.add("hidden")
|
|
507
|
-
// document.querySelector("#open-browser").classList.remove("hidden")
|
|
508
|
-
// document.querySelector("#open-browser").href = location.hash.slice(1)
|
|
509
|
-
// } else {
|
|
510
|
-
// document.querySelector("#open-browser").classList.remove("hidden")
|
|
511
|
-
// //document.querySelector("#open-browser").href = id
|
|
512
|
-
// document.querySelector("#open-browser").href = location.hash.slice(1)
|
|
513
|
-
// }
|
|
514
|
-
// document.querySelector("#clone-tab").setAttribute("data-href", location.hash.slice(1))
|
|
515
|
-
|
|
516
|
-
|
|
517
592
|
|
|
593
|
+
// select the selected target element (tab)
|
|
518
594
|
target.classList.add("selected")
|
|
519
595
|
|
|
520
|
-
//
|
|
596
|
+
// hide all frames
|
|
521
597
|
document.querySelectorAll("iframe").forEach((el) => {
|
|
522
598
|
el.classList.add("hidden")
|
|
523
599
|
})
|
|
524
|
-
let targetFrame = document.querySelector(`iframe[name='${target.target}']`)
|
|
525
|
-
if (targetFrame) {
|
|
526
|
-
targetFrame.classList.remove("hidden")
|
|
527
600
|
|
|
528
|
-
// if the iframe already exists, do not
|
|
529
|
-
if (loaded[target.target]){
|
|
530
601
|
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
602
|
+
debugger
|
|
603
|
+
|
|
604
|
+
// Look for the frame
|
|
605
|
+
// 1. if it's hard (".h")
|
|
606
|
+
// look for the url that matches
|
|
607
|
+
// 2. if it's soft (".s")
|
|
608
|
+
// find using the name attribute
|
|
609
|
+
let targetFrame;
|
|
610
|
+
if (target.closest(".h")) {
|
|
611
|
+
let hardFrames = document.querySelectorAll(".browserview iframe[name^='@']")
|
|
612
|
+
let port = new URL(target.href).port
|
|
613
|
+
for(let frame of hardFrames) {
|
|
614
|
+
console.log({ src: frame.src, href: target.href, target: target.target })
|
|
615
|
+
// Types of links in the tab
|
|
616
|
+
if (String(port) === "42000") {
|
|
617
|
+
// 1. running from 42000 => find a frame whose base URL matches the tab's base URL
|
|
618
|
+
// Pinokio links
|
|
619
|
+
let targetPath = new URL(target.href).pathname
|
|
620
|
+
let framePath = new URL(frame.src).pathname
|
|
621
|
+
if (targetPath === framePath) {
|
|
622
|
+
let beforeName = frame.name
|
|
623
|
+
frame.name = target.target
|
|
624
|
+
console.log("SET FRAME", { before: beforeName, after: frame.name, target: target.target })
|
|
625
|
+
targetFrame = frame
|
|
626
|
+
break
|
|
627
|
+
}
|
|
628
|
+
} else {
|
|
629
|
+
// 2. rest => find the frame whose src exactly matches the tab's url
|
|
630
|
+
if (target.href === frame.src) {
|
|
631
|
+
frame.name = target.target
|
|
632
|
+
targetFrame = frame
|
|
633
|
+
break
|
|
634
|
+
}
|
|
535
635
|
}
|
|
636
|
+
// find the frame whose path matches
|
|
637
|
+
}
|
|
638
|
+
} else if (target.closest(".s")) {
|
|
639
|
+
targetFrame = document.querySelector(`iframe[name='${target.target}']`)
|
|
640
|
+
} else if (target.closest(".n")) {
|
|
641
|
+
targetFrame = document.querySelector(`iframe[name='${target.target}']`)
|
|
642
|
+
}
|
|
643
|
+
|
|
644
|
+
|
|
645
|
+
/*
|
|
646
|
+
// Load the link in the frame
|
|
647
|
+
|
|
648
|
+
1. if the frame was found:
|
|
649
|
+
- if "refresh": true => refresh
|
|
650
|
+
- otherwise,
|
|
651
|
+
- if the target frame has been already loaded, don't do anything
|
|
652
|
+
- frame: start.json?mode=abc, link: start.json?mode=abc => don't touch
|
|
653
|
+
- link === frame
|
|
654
|
+
- frame: start.json?mode=abc, link: start.json?mode=def => should load
|
|
655
|
+
- link !== frame && !frame.includes(link)
|
|
656
|
+
- frame: start.json?mode=abc, link: start.json => don't touch
|
|
657
|
+
- link !== frame && frame.includes(link)
|
|
536
658
|
|
|
537
|
-
console.log("# 4")
|
|
538
659
|
|
|
660
|
+
|
|
661
|
+
if the link is different
|
|
662
|
+
|
|
663
|
+
- if the target frame has not been loaded, refresh
|
|
664
|
+
2. if the frame was NOT found => create one
|
|
665
|
+
|
|
666
|
+
*/
|
|
667
|
+
|
|
668
|
+
if (targetFrame) {
|
|
669
|
+
targetFrame.classList.remove("hidden")
|
|
670
|
+
let mode = target.getAttribute("data-mode")
|
|
671
|
+
if (mode === "refresh") {
|
|
672
|
+
targetFrame.src = target.href
|
|
673
|
+
} else {
|
|
539
674
|
if (e) {
|
|
540
|
-
console.log("# 5", { src: targetFrame.src, href: target.href, target: target.target })
|
|
541
|
-
// triggered with a click
|
|
542
|
-
// do not reload iframe if the href and the src is the same
|
|
543
675
|
if (target.closest(".h")) {
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
676
|
+
debugger
|
|
677
|
+
e.preventDefault()
|
|
678
|
+
e.stopPropagation()
|
|
679
|
+
let sub = subUrlOf(target.href, targetFrame.src)
|
|
680
|
+
console.log("issub", sub)
|
|
681
|
+
if (!sub) {
|
|
682
|
+
targetFrame.src = target.href
|
|
549
683
|
}
|
|
684
|
+
//if (target.href === targetFrame.src) {
|
|
685
|
+
// // same url. don't do anything
|
|
686
|
+
// e.preventDefault()
|
|
687
|
+
// e.stopPropagation()
|
|
688
|
+
//} else {
|
|
689
|
+
// if (targetFrame.src.includes(target.href)) {
|
|
690
|
+
// // different url, but the frame's url contains the tab url => don't touch
|
|
691
|
+
// e.preventDefault()
|
|
692
|
+
// e.stopPropagation()
|
|
693
|
+
// } else {
|
|
694
|
+
// // different url, and the frame's url does not contain the tab url => change the src of the frame and load
|
|
695
|
+
// targetFrame.src = target.href
|
|
696
|
+
// e.preventDefault()
|
|
697
|
+
// e.stopPropagation()
|
|
698
|
+
// }
|
|
699
|
+
//}
|
|
550
700
|
} else if (target.closest(".s")) {
|
|
701
|
+
// load unconditionally => .s doesn't change
|
|
702
|
+
e.preventDefault()
|
|
703
|
+
e.stopPropagation()
|
|
704
|
+
} else if (target.closest(".n")) {
|
|
705
|
+
// load unconditionally => .n doesn't change
|
|
551
706
|
e.preventDefault()
|
|
552
707
|
e.stopPropagation()
|
|
553
708
|
}
|
|
554
709
|
} else {
|
|
555
|
-
console.log("# 6")
|
|
556
710
|
if (force) {
|
|
557
711
|
console.log("# 7")
|
|
558
|
-
|
|
559
|
-
targetFrame.src = target.href
|
|
560
|
-
// }
|
|
712
|
+
targetFrame.src = target.href
|
|
561
713
|
}
|
|
562
714
|
}
|
|
563
|
-
} else {
|
|
564
|
-
console.log("# 8")
|
|
565
|
-
//targetFrame.contentWindow.addEventListener("load", () => {
|
|
566
|
-
if (e) {
|
|
567
|
-
console.log("# 9")
|
|
568
|
-
// coming from a click => don't need to set the src
|
|
569
|
-
} else {
|
|
570
|
-
console.log("# 10")
|
|
571
|
-
// load without click
|
|
572
|
-
if (targetFrame.src !== target.href) {
|
|
573
|
-
console.log("# 11")
|
|
574
|
-
targetFrame.src = target.href
|
|
575
|
-
}
|
|
576
|
-
}
|
|
577
|
-
loaded[target.target] = true
|
|
578
|
-
//});
|
|
579
715
|
}
|
|
580
716
|
} else {
|
|
581
717
|
console.log("# 12")
|
|
@@ -589,6 +725,84 @@ console.log({ type, index })
|
|
|
589
725
|
document.querySelector("main").appendChild(frame)
|
|
590
726
|
loaded[target.target] = true
|
|
591
727
|
}
|
|
728
|
+
|
|
729
|
+
// if (targetFrame) {
|
|
730
|
+
// targetFrame.classList.remove("hidden")
|
|
731
|
+
//
|
|
732
|
+
// // if the iframe already exists, do not
|
|
733
|
+
// if (loaded[target.target]){
|
|
734
|
+
//
|
|
735
|
+
// // Force refresh option
|
|
736
|
+
// //
|
|
737
|
+
// // menu := [{
|
|
738
|
+
// // text,
|
|
739
|
+
// // icon,
|
|
740
|
+
// // mode: "refresh" => refresh regardless of any condition
|
|
741
|
+
// // }]
|
|
742
|
+
// let mode = target.getAttribute("data-mode")
|
|
743
|
+
// if (mode === "refresh") {
|
|
744
|
+
// targetFrame.src = target.href
|
|
745
|
+
// } else {
|
|
746
|
+
// console.log("# 4")
|
|
747
|
+
// if (e) {
|
|
748
|
+
// // if triggered by a click event,
|
|
749
|
+
// // 1. if it's a hard link (".h")
|
|
750
|
+
// // - ignore if the pathname is the same
|
|
751
|
+
// // - reload if
|
|
752
|
+
// console.log("# 5", { src: targetFrame.src, href: target.href, target: target.target })
|
|
753
|
+
// // triggered with a click
|
|
754
|
+
// // do not reload iframe if the href and the src is the same
|
|
755
|
+
// if (target.closest(".h")) {
|
|
756
|
+
// // if (targetFrame.src.includes(target.target)) {
|
|
757
|
+
// if (targetFrame.src.includes(target.href)) {
|
|
758
|
+
// // if (targetFrame.src === target.href) {
|
|
759
|
+
// e.preventDefault()
|
|
760
|
+
// e.stopPropagation()
|
|
761
|
+
// }
|
|
762
|
+
// } else if (target.closest(".s")) {
|
|
763
|
+
// e.preventDefault()
|
|
764
|
+
// e.stopPropagation()
|
|
765
|
+
// }
|
|
766
|
+
// } else {
|
|
767
|
+
// // if not triggered by event
|
|
768
|
+
// // refresh ONLY if programmatically forced refresh
|
|
769
|
+
// console.log("# 6")
|
|
770
|
+
// if (force) {
|
|
771
|
+
// console.log("# 7")
|
|
772
|
+
// targetFrame.src = target.href
|
|
773
|
+
// }
|
|
774
|
+
// }
|
|
775
|
+
// }
|
|
776
|
+
//
|
|
777
|
+
// } else {
|
|
778
|
+
// console.log("# 8")
|
|
779
|
+
// //targetFrame.contentWindow.addEventListener("load", () => {
|
|
780
|
+
// if (e) {
|
|
781
|
+
// console.log("# 9")
|
|
782
|
+
// // coming from a click => don't need to set the src
|
|
783
|
+
// } else {
|
|
784
|
+
// console.log("# 10")
|
|
785
|
+
// // load without click
|
|
786
|
+
// if (targetFrame.src !== target.href) {
|
|
787
|
+
// console.log("# 11")
|
|
788
|
+
// targetFrame.src = target.href
|
|
789
|
+
// }
|
|
790
|
+
// }
|
|
791
|
+
// loaded[target.target] = true
|
|
792
|
+
// //});
|
|
793
|
+
// }
|
|
794
|
+
// } else {
|
|
795
|
+
// console.log("# 12")
|
|
796
|
+
// let frame = document.createElement("iframe")
|
|
797
|
+
// frame.name = target.target
|
|
798
|
+
// frame.src = target.href
|
|
799
|
+
// frame.setAttribute(
|
|
800
|
+
// "allow",
|
|
801
|
+
// "clipboard-read *; clipboard-write *; accelerometer *; ambient-light-sensor *; autoplay *; battery *; camera *; display-capture *; gamepad *; geolocation *; gyroscope *; hid *; identity-credentials-get *; microphone *; midi *; otp-credentials *; serial *;"
|
|
802
|
+
// )
|
|
803
|
+
// document.querySelector("main").appendChild(frame)
|
|
804
|
+
// loaded[target.target] = true
|
|
805
|
+
// }
|
|
592
806
|
} else {
|
|
593
807
|
console.log("# 13")
|
|
594
808
|
// couldn't find item,
|
|
@@ -598,7 +812,7 @@ console.log({ type, index })
|
|
|
598
812
|
}
|
|
599
813
|
} else {
|
|
600
814
|
console.log("# 14")
|
|
601
|
-
document.querySelector(".bar").classList.add("hidden")
|
|
815
|
+
// document.querySelector(".bar").classList.add("hidden")
|
|
602
816
|
}
|
|
603
817
|
}
|
|
604
818
|
console.log("loaded before", loaded)
|
|
@@ -673,7 +887,6 @@ const syncTabs = async () => {
|
|
|
673
887
|
})
|
|
674
888
|
}
|
|
675
889
|
const addTab = async (url) => {
|
|
676
|
-
debugger
|
|
677
890
|
let item = document.createElement("a")
|
|
678
891
|
//let id = "ts" + Date.now()
|
|
679
892
|
let index = document.querySelectorAll("aside .s .frame-link").length
|
|
@@ -717,6 +930,47 @@ document.querySelector(".app-info").addEventListener("click", async (e) => {
|
|
|
717
930
|
renderSelection()
|
|
718
931
|
|
|
719
932
|
})
|
|
933
|
+
document.querySelector("#delete").addEventListener("click", async (e) => {
|
|
934
|
+
e.preventDefault()
|
|
935
|
+
e.stopPropagation()
|
|
936
|
+
const confirmed = confirm("Are you sure you wish to delete the app?")
|
|
937
|
+
if (confirmed) {
|
|
938
|
+
|
|
939
|
+
|
|
940
|
+
|
|
941
|
+
let name = document.querySelector("#delete").getAttribute("data-name")
|
|
942
|
+
console.log("delete", name)
|
|
943
|
+
Swal.fire({
|
|
944
|
+
html: '<i class="fa-solid fa-circle-notch fa-spin"></i> Deleting',
|
|
945
|
+
customClass: {
|
|
946
|
+
container: "loader-container",
|
|
947
|
+
popup: "loader-popup",
|
|
948
|
+
htmlContainer: "loader-dialog",
|
|
949
|
+
footer: "hidden",
|
|
950
|
+
actions: "hidden"
|
|
951
|
+
}
|
|
952
|
+
});
|
|
953
|
+
let res = await fetch("/pinokio/delete", {
|
|
954
|
+
method: "post",
|
|
955
|
+
headers: {
|
|
956
|
+
"Content-Type": "application/json"
|
|
957
|
+
},
|
|
958
|
+
body: JSON.stringify({ name })
|
|
959
|
+
}).then((res) => {
|
|
960
|
+
return res.json()
|
|
961
|
+
})
|
|
962
|
+
console.log("res", res)
|
|
963
|
+
Swal.close()
|
|
964
|
+
if (res) {
|
|
965
|
+
if (res.success) {
|
|
966
|
+
location.href = "/"
|
|
967
|
+
} else if (res.error) {
|
|
968
|
+
alert(res.error)
|
|
969
|
+
}
|
|
970
|
+
}
|
|
971
|
+
} else {
|
|
972
|
+
}
|
|
973
|
+
})
|
|
720
974
|
document.querySelector("aside").addEventListener("click", async (e) => {
|
|
721
975
|
let target
|
|
722
976
|
|
|
@@ -771,9 +1025,19 @@ document.querySelector("aside").addEventListener("click", async (e) => {
|
|
|
771
1025
|
// location.hash = id
|
|
772
1026
|
|
|
773
1027
|
//location.hash = target.getAttribute("href")
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
1028
|
+
|
|
1029
|
+
if (target.closest(".h")) {
|
|
1030
|
+
location.hash = target.target
|
|
1031
|
+
} else {
|
|
1032
|
+
let index = target.getAttribute("data-index")
|
|
1033
|
+
let type = target.closest(".m").getAttribute("data-type")
|
|
1034
|
+
|
|
1035
|
+
console.log({ type, index })
|
|
1036
|
+
|
|
1037
|
+
debugger
|
|
1038
|
+
|
|
1039
|
+
location.hash = type + index
|
|
1040
|
+
}
|
|
777
1041
|
|
|
778
1042
|
document.querySelectorAll(".frame-link").forEach((el) => {
|
|
779
1043
|
el.classList.remove("selected")
|
|
@@ -812,6 +1076,29 @@ const refresh = async () => {
|
|
|
812
1076
|
console.log("refresh", html)
|
|
813
1077
|
*/
|
|
814
1078
|
document.querySelector(".menu").innerHTML = html
|
|
1079
|
+
|
|
1080
|
+
|
|
1081
|
+
// update the frames so the name matches the tab links
|
|
1082
|
+
|
|
1083
|
+
// 1. iterate through all the "h" menu items
|
|
1084
|
+
// 2. for each tab that starts with "h" (hard), iterate through all iframes
|
|
1085
|
+
// 3. to find a frame whose src.includes(item.href)
|
|
1086
|
+
// 4. update the frame's name to the target attribute
|
|
1087
|
+
|
|
1088
|
+
// let hardFrames = document.querySelectorAll(".browserview iframe[name^=h]")
|
|
1089
|
+
// for(let frame of hardFrames) {
|
|
1090
|
+
// frame.removeAttribute("name")
|
|
1091
|
+
// location.hash = ""
|
|
1092
|
+
// }
|
|
1093
|
+
|
|
1094
|
+
|
|
1095
|
+
location.hash = ""
|
|
1096
|
+
|
|
1097
|
+
|
|
1098
|
+
|
|
1099
|
+
|
|
1100
|
+
//
|
|
1101
|
+
|
|
815
1102
|
renderSelection()
|
|
816
1103
|
// cursorIndex = 0
|
|
817
1104
|
//renderCursor()
|
|
@@ -819,13 +1106,21 @@ const refresh = async () => {
|
|
|
819
1106
|
}
|
|
820
1107
|
window.addEventListener('message', (event) => {
|
|
821
1108
|
console.log("Message received from the child: ", event.data); // Message received from child
|
|
822
|
-
if (event.data
|
|
823
|
-
if (event.data.action
|
|
824
|
-
|
|
825
|
-
|
|
1109
|
+
if (event.data) {
|
|
1110
|
+
if (event.data.action) {
|
|
1111
|
+
if (event.data.action.type === "newtab") {
|
|
1112
|
+
console.log("create tab", event.data.action.url)
|
|
1113
|
+
addTab(event.data.action.url)
|
|
1114
|
+
}
|
|
1115
|
+
} else if (event.data.type) {
|
|
1116
|
+
if (event.data.type === 'disconnect') {
|
|
1117
|
+
// location.hash = ""
|
|
1118
|
+
refresh()
|
|
1119
|
+
} else {
|
|
1120
|
+
refresh()
|
|
1121
|
+
}
|
|
826
1122
|
}
|
|
827
1123
|
} else {
|
|
828
|
-
console.log("data", event.data)
|
|
829
1124
|
refresh()
|
|
830
1125
|
}
|
|
831
1126
|
});
|
package/server/views/editor.ejs
CHANGED
|
@@ -517,7 +517,8 @@ document.addEventListener("DOMContentLoaded", async () => {
|
|
|
517
517
|
//theme: xtermTheme.Github,
|
|
518
518
|
|
|
519
519
|
//theme: xtermTheme.Cobalt_Neon, // top legibility
|
|
520
|
-
theme: xtermTheme.Duotone_Dark,
|
|
520
|
+
//theme: xtermTheme.Duotone_Dark,
|
|
521
|
+
theme: xtermTheme.FrontEndDelight,
|
|
521
522
|
//theme: xtermTheme.Seafoam_Pastel,
|
|
522
523
|
//theme: xtermTheme.IC_Green_PPL,
|
|
523
524
|
//theme: xtermTheme.FunForrest,
|
|
@@ -508,7 +508,10 @@ document.addEventListener("DOMContentLoaded", async () => {
|
|
|
508
508
|
//theme: xtermTheme.Github,
|
|
509
509
|
|
|
510
510
|
//theme: xtermTheme.Cobalt_Neon, // top legibility
|
|
511
|
-
theme: xtermTheme.Duotone_Dark,
|
|
511
|
+
//theme: xtermTheme.Duotone_Dark,
|
|
512
|
+
//theme: xtermTheme.Batman,
|
|
513
|
+
//theme: xtermTheme.Brogrammer,
|
|
514
|
+
theme: xtermTheme.FrontEndDelight,
|
|
512
515
|
//theme: xtermTheme.Seafoam_Pastel,
|
|
513
516
|
//theme: xtermTheme.IC_Green_PPL,
|
|
514
517
|
//theme: xtermTheme.FunForrest,
|
package/server/views/install.ejs
CHANGED
|
@@ -128,7 +128,8 @@ const createTerm = () => {
|
|
|
128
128
|
//theme: xtermTheme.Github,
|
|
129
129
|
|
|
130
130
|
//theme: xtermTheme.Cobalt_Neon, // top legibility
|
|
131
|
-
theme: xtermTheme.Duotone_Dark,
|
|
131
|
+
//theme: xtermTheme.Duotone_Dark,
|
|
132
|
+
theme: xtermTheme.FrontEndDelight,
|
|
132
133
|
//theme: xtermTheme.Seafoam_Pastel,
|
|
133
134
|
//theme: xtermTheme.IC_Green_PPL,
|
|
134
135
|
//theme: xtermTheme.FunForrest,
|
|
@@ -10,7 +10,10 @@
|
|
|
10
10
|
</div>
|
|
11
11
|
<% } else { %>
|
|
12
12
|
<% if (item.btn) { %>
|
|
13
|
+
<!--
|
|
13
14
|
<a data-index="<%=index%>" target="h<%=index%>" data-mode="<%=item.mode%>" href="<%=item.href%>" class='btn header-item frame-link'>
|
|
15
|
+
-->
|
|
16
|
+
<a data-index="<%=index%>" target="<%=item.target%>" data-mode="<%=item.mode%>" href="<%=item.href%>" class='btn header-item frame-link'>
|
|
14
17
|
<div class='tab'><%-item.btn%></div>
|
|
15
18
|
<% if (item.running) { %>
|
|
16
19
|
<div class='loader'>
|
|
@@ -63,18 +63,28 @@
|
|
|
63
63
|
border-top: 1px solid rgba(255,255,255,0.1);
|
|
64
64
|
border-bottom: 1px solid rgba(255,255,255,0.1);
|
|
65
65
|
*/
|
|
66
|
-
padding:
|
|
66
|
+
padding: 20px 0;
|
|
67
|
+
}
|
|
68
|
+
.titleview h1 {
|
|
69
|
+
font-size: 40px;
|
|
70
|
+
text-transform: uppercase;
|
|
71
|
+
letter-spacing: 0;
|
|
67
72
|
}
|
|
68
73
|
.item button {
|
|
69
74
|
padding: 10px 20px;
|
|
70
75
|
}
|
|
71
76
|
.item label {
|
|
72
77
|
display: block;
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
font-size: 14px;
|
|
78
|
+
text-transform: uppercase;
|
|
79
|
+
font-size: 30px;
|
|
76
80
|
padding-bottom: 5px;
|
|
77
81
|
}
|
|
82
|
+
.item .explanation {
|
|
83
|
+
padding-top: 5px;
|
|
84
|
+
color: brown;
|
|
85
|
+
font-size: 14px;
|
|
86
|
+
font-weight: bold;
|
|
87
|
+
}
|
|
78
88
|
body.dark .item input[type=text] {
|
|
79
89
|
background: rgba(255,255,255,0.1);
|
|
80
90
|
color: white;
|
|
@@ -87,9 +97,7 @@ body.dark .item select {
|
|
|
87
97
|
padding: 10px;
|
|
88
98
|
flex-grow: 1;
|
|
89
99
|
border: none;
|
|
90
|
-
/*
|
|
91
100
|
background: rgba(0,0,0,0.05);
|
|
92
|
-
*/
|
|
93
101
|
width: 100%;
|
|
94
102
|
}
|
|
95
103
|
.item select {
|
|
@@ -230,6 +238,9 @@ header .home {
|
|
|
230
238
|
<input class='homepath' name="<%=c.key%>" type='text' placeholder="<%=c.placeholder ? c.placeholder : ''%>">
|
|
231
239
|
<% } %>
|
|
232
240
|
<% } %>
|
|
241
|
+
<% if (c.description) { %>
|
|
242
|
+
<div class='explanation'><%=c.description%></div>
|
|
243
|
+
<% } %>
|
|
233
244
|
</div>
|
|
234
245
|
<% }) %>
|
|
235
246
|
<br>
|