pinokiod 3.20.18 → 3.20.20
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/favicon.js +56 -0
- package/kernel/index.js +2 -0
- package/kernel/prototype.js +0 -1
- package/package.json +1 -1
- package/server/index.js +152 -68
- package/server/public/style.css +49 -42
- package/server/views/app.ejs +6 -2
- package/server/views/connect/x.ejs +0 -1
- package/server/views/connect.ejs +0 -1
- package/server/views/download.ejs +0 -1
- package/server/views/explore.ejs +0 -1
- package/server/views/file_explorer.ejs +0 -1
- package/server/views/github.ejs +0 -1
- package/server/views/index.ejs +133 -44
- package/server/views/init/index.ejs +0 -1
- package/server/views/mini.ejs +0 -1
- package/server/views/net.ejs +1035 -0
- package/server/views/network.ejs +181 -119
- package/server/views/network2.ejs +897 -0
- package/server/views/old_network.ejs +0 -1
- package/server/views/prototype/index.ejs +0 -1
- package/server/views/setup_home.ejs +0 -1
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
const axios = require('axios')
|
|
2
|
+
const { URL } = require("url");
|
|
3
|
+
const { JSDOM } = require("jsdom");
|
|
4
|
+
|
|
5
|
+
class Favicon {
|
|
6
|
+
async get(pageUrl) {
|
|
7
|
+
let origin;
|
|
8
|
+
try {
|
|
9
|
+
origin = new URL(pageUrl).origin;
|
|
10
|
+
} catch {
|
|
11
|
+
throw new Error("Invalid URL: " + pageUrl);
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
const candidates = [
|
|
15
|
+
"/favicon.ico",
|
|
16
|
+
"/favicon.png",
|
|
17
|
+
"/assets/favicon.ico",
|
|
18
|
+
"/static/favicon.ico",
|
|
19
|
+
"/favicon.svg",
|
|
20
|
+
];
|
|
21
|
+
|
|
22
|
+
// 1. Try common favicon paths first
|
|
23
|
+
for (const path of candidates) {
|
|
24
|
+
const fullUrl = origin + path;
|
|
25
|
+
if (await this.checkImageUrl(fullUrl)) return fullUrl;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// 2. Fallback to parsing HTML
|
|
29
|
+
try {
|
|
30
|
+
const res = await axios.get(pageUrl, { timeout: 1000 });
|
|
31
|
+
const dom = new JSDOM(res.data);
|
|
32
|
+
const icons = Array.from(dom.window.document.querySelectorAll("link[rel~='icon'], link[rel='apple-touch-icon']"));
|
|
33
|
+
|
|
34
|
+
for (const icon of icons) {
|
|
35
|
+
const href = icon.getAttribute("href");
|
|
36
|
+
if (!href) continue;
|
|
37
|
+
const resolvedUrl = new URL(href, origin).href;
|
|
38
|
+
if (await this.checkImageUrl(resolvedUrl)) return resolvedUrl;
|
|
39
|
+
}
|
|
40
|
+
} catch {
|
|
41
|
+
// Ignore HTML errors
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
return null;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
async checkImageUrl(url) {
|
|
48
|
+
try {
|
|
49
|
+
const res = await axios.head(url, { timeout: 3000 });
|
|
50
|
+
return res.status === 200 && res.headers["content-type"]?.startsWith("image/");
|
|
51
|
+
} catch {
|
|
52
|
+
return false;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
module.exports = Favicon
|
package/kernel/index.js
CHANGED
|
@@ -37,6 +37,7 @@ const Procs = require('./procs')
|
|
|
37
37
|
const Peer = require('./peer')
|
|
38
38
|
const Git = require('./git')
|
|
39
39
|
const Connect = require('./connect')
|
|
40
|
+
const Favicon = require('./favicon')
|
|
40
41
|
const { DownloaderHelper } = require('node-downloader-helper');
|
|
41
42
|
const { ProxyAgent } = require('proxy-agent');
|
|
42
43
|
const fakeUa = require('fake-useragent');
|
|
@@ -83,6 +84,7 @@ class Kernel {
|
|
|
83
84
|
this.exposed = {}
|
|
84
85
|
this.envs = {}
|
|
85
86
|
this.shellpath = shellPath.sync()
|
|
87
|
+
this.favicon = new Favicon()
|
|
86
88
|
|
|
87
89
|
|
|
88
90
|
}
|
package/kernel/prototype.js
CHANGED
package/package.json
CHANGED
package/server/index.js
CHANGED
|
@@ -659,6 +659,12 @@ class Server {
|
|
|
659
659
|
}
|
|
660
660
|
return shell_id
|
|
661
661
|
}
|
|
662
|
+
is_subpath(parent, child) {
|
|
663
|
+
const relative = path.relative(parent, child);
|
|
664
|
+
let check = !!relative && !relative.startsWith('..') && !path.isAbsolute(relative);
|
|
665
|
+
console.log({ relative, parent, child, check })
|
|
666
|
+
return check
|
|
667
|
+
}
|
|
662
668
|
async render(req, res, pathComponents, meta) {
|
|
663
669
|
let base_path = req.base || this.kernel.path("api")
|
|
664
670
|
let full_filepath = path.resolve(base_path, ...pathComponents)
|
|
@@ -1326,35 +1332,6 @@ class Server {
|
|
|
1326
1332
|
let p = path.resolve(uri, item.name, "pinokio.js")
|
|
1327
1333
|
let config = (await this.kernel.loader.load(p)).resolved
|
|
1328
1334
|
if (config) {
|
|
1329
|
-
/*
|
|
1330
|
-
if (config.version) {
|
|
1331
|
-
let coerced = semver.coerce(config.version)
|
|
1332
|
-
console.log("version", { coerced, v: config.version })
|
|
1333
|
-
if (semver.satisfies(coerced, this.kernel.schema)) {
|
|
1334
|
-
console.log("semver satisfied", config.version, this.kernel.schema)
|
|
1335
|
-
} else {
|
|
1336
|
-
console.log("semver NOT satisfied", config.version, this.kernel.schema)
|
|
1337
|
-
error = `Please update Pinokio to the latest version (current script version: ${config.version}, supported: ${this.kernel.schema}`
|
|
1338
|
-
}
|
|
1339
|
-
}
|
|
1340
|
-
*/
|
|
1341
|
-
// if (config.run) {
|
|
1342
|
-
// items[i].run = config.run
|
|
1343
|
-
// }
|
|
1344
|
-
// if (config.menu) {
|
|
1345
|
-
// if (typeof config.menu === "function") {
|
|
1346
|
-
// if (config.menu.constructor.name === "AsyncFunction") {
|
|
1347
|
-
// config.menu = await config.menu(this.kernel, this.kernel.info)
|
|
1348
|
-
// } else {
|
|
1349
|
-
// config.menu = config.menu(this.kernel, this.kernel.info)
|
|
1350
|
-
// }
|
|
1351
|
-
// }
|
|
1352
|
-
//
|
|
1353
|
-
// await this.renderMenu(uri, item.name, config, pathComponents)
|
|
1354
|
-
//
|
|
1355
|
-
// items[i].menu = config.menu
|
|
1356
|
-
// }
|
|
1357
|
-
|
|
1358
1335
|
if (config.shortcuts) {
|
|
1359
1336
|
if (typeof config.shortcuts === "function") {
|
|
1360
1337
|
if (config.shortcuts.constructor.name === "AsyncFunction") {
|
|
@@ -1372,36 +1349,35 @@ class Server {
|
|
|
1372
1349
|
if (config && config.type === "lib") {
|
|
1373
1350
|
continue
|
|
1374
1351
|
}
|
|
1375
|
-
|
|
1376
|
-
// // if there's a run clause, do not display on the home page
|
|
1377
|
-
// if (config && config.run && Array.isArray(config.run)) {
|
|
1378
|
-
// continue
|
|
1379
|
-
// }
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
1352
|
// check if there is a running process with this folder name
|
|
1383
1353
|
let runningApps = new Set()
|
|
1384
1354
|
for(let key in this.kernel.api.running) {
|
|
1385
1355
|
//let p = this.kernel.path("api", items[i].name) + path.sep
|
|
1386
1356
|
let p = this.kernel.path("api", items[i].name)
|
|
1387
1357
|
|
|
1388
|
-
//let re = new RegExp(items[i].name)
|
|
1389
|
-
//if (re.test(key)) {
|
|
1390
|
-
//if (p === key) {
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
1358
|
// not only should include the pattern, but also end with it (otherwise can include similar patterns such as /api/qqqa, /api/qqqaaa, etc.
|
|
1394
1359
|
|
|
1395
1360
|
let is_running
|
|
1396
1361
|
let api_path = this.kernel.path("api")
|
|
1397
|
-
if (
|
|
1398
|
-
|
|
1399
|
-
if (key.startsWith(p)) {
|
|
1362
|
+
if (this.is_subpath(api_path, key)) {
|
|
1363
|
+
if (this.is_subpath(p, key)) {
|
|
1400
1364
|
is_running = true
|
|
1401
1365
|
}
|
|
1402
1366
|
} else {
|
|
1403
1367
|
if (key.endsWith(p)) {
|
|
1404
1368
|
is_running = true
|
|
1369
|
+
} else {
|
|
1370
|
+
if (!path.isAbsolute(key)) {
|
|
1371
|
+
let chunks = key.split("_")
|
|
1372
|
+
if (chunks.length > 1) {
|
|
1373
|
+
let folder = chunks[0]
|
|
1374
|
+
/// if the folder name matches, it's running
|
|
1375
|
+
if (folder === items[i].name) {
|
|
1376
|
+
is_running = true
|
|
1377
|
+
}
|
|
1378
|
+
}
|
|
1379
|
+
|
|
1380
|
+
}
|
|
1405
1381
|
}
|
|
1406
1382
|
}
|
|
1407
1383
|
// 1. if the script path starts with api path => api script
|
|
@@ -1412,34 +1388,46 @@ class Server {
|
|
|
1412
1388
|
|
|
1413
1389
|
//if (key.includes(p) && key.endsWith(p)) {
|
|
1414
1390
|
if (is_running) {
|
|
1415
|
-
|
|
1416
|
-
items[i]
|
|
1391
|
+
// add to running
|
|
1392
|
+
running.push(items[i])
|
|
1417
1393
|
if (!items[i].running_scripts) {
|
|
1418
1394
|
items[i].running_scripts = []
|
|
1419
1395
|
}
|
|
1420
|
-
if (key.startsWith(p)) {
|
|
1421
|
-
items[i].running_scripts.push({ path: path.relative(this.kernel.homedir, key), name: path.relative(p, key) })
|
|
1422
|
-
} else {
|
|
1423
|
-
let chunks = key.split("?")
|
|
1424
|
-
let dev = chunks[0]
|
|
1425
|
-
let name_chunks = dev.split(path.sep)
|
|
1426
|
-
let name = name_chunks[name_chunks.length-1]
|
|
1427
|
-
items[i].running_scripts.push({ id: key, name })
|
|
1428
|
-
}
|
|
1429
|
-
index++;
|
|
1430
|
-
running.push(items[i])
|
|
1431
|
-
// break
|
|
1432
|
-
}
|
|
1433
|
-
let shell = this.kernel.shell.find({
|
|
1434
|
-
filter: (shell) => {
|
|
1435
|
-
return shell.id.startsWith(items[i].name + "_")
|
|
1436
|
-
}
|
|
1437
|
-
})
|
|
1438
|
-
if (shell.length > 0) {
|
|
1439
1396
|
items[i].running = true
|
|
1440
1397
|
items[i].index = index
|
|
1398
|
+
|
|
1399
|
+
// add the running script to running_scripts array
|
|
1400
|
+
// 1. normal api script
|
|
1401
|
+
if (path.isAbsolute(key)) {
|
|
1402
|
+
// script
|
|
1403
|
+
if (this.is_subpath(api_path, key)) {
|
|
1404
|
+
// scripts inside api folder
|
|
1405
|
+
if (this.is_subpath(p, key)) {
|
|
1406
|
+
items[i].running_scripts.push({ path: path.relative(this.kernel.homedir, key), name: path.relative(p, key) })
|
|
1407
|
+
}
|
|
1408
|
+
} else {
|
|
1409
|
+
// other global scripts
|
|
1410
|
+
let chunks = key.split("?")
|
|
1411
|
+
let dev = chunks[0]
|
|
1412
|
+
let name_chunks = dev.split(path.sep)
|
|
1413
|
+
let name = name_chunks[name_chunks.length-1]
|
|
1414
|
+
items[i].running_scripts.push({ id: key, name })
|
|
1415
|
+
}
|
|
1416
|
+
} else {
|
|
1417
|
+
let shell = this.kernel.shell.find({
|
|
1418
|
+
filter: (shell) => {
|
|
1419
|
+
return shell.id.startsWith(items[i].name + "_")
|
|
1420
|
+
}
|
|
1421
|
+
})
|
|
1422
|
+
if (shell.length > 0) {
|
|
1423
|
+
items[i].running = true
|
|
1424
|
+
items[i].index = index
|
|
1425
|
+
for(let sh of shell) {
|
|
1426
|
+
items[i].running_scripts.push({ id: sh.id, name: "Terminal", type: "shell" })
|
|
1427
|
+
}
|
|
1428
|
+
}
|
|
1429
|
+
}
|
|
1441
1430
|
index++;
|
|
1442
|
-
running.push(items[i])
|
|
1443
1431
|
}
|
|
1444
1432
|
}
|
|
1445
1433
|
if (!items[i].running) {
|
|
@@ -1447,8 +1435,6 @@ class Server {
|
|
|
1447
1435
|
index++;
|
|
1448
1436
|
notRunning.push(items[i])
|
|
1449
1437
|
}
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
1438
|
}
|
|
1453
1439
|
}
|
|
1454
1440
|
|
|
@@ -1567,9 +1553,13 @@ class Server {
|
|
|
1567
1553
|
|
|
1568
1554
|
let current_urls = await this.current_urls()
|
|
1569
1555
|
|
|
1556
|
+
let list = this.getPeerInfo()
|
|
1557
|
+
|
|
1570
1558
|
if (meta) {
|
|
1571
1559
|
items = running.concat(notRunning)
|
|
1572
1560
|
res.render("index", {
|
|
1561
|
+
list,
|
|
1562
|
+
current_host: this.kernel.peer.host,
|
|
1573
1563
|
current_urls,
|
|
1574
1564
|
portal: this.portal,
|
|
1575
1565
|
install: this.install,
|
|
@@ -3715,6 +3705,98 @@ class Server {
|
|
|
3715
3705
|
requirements_pending,
|
|
3716
3706
|
})
|
|
3717
3707
|
}))
|
|
3708
|
+
this.app.get("/net/:name", ex(async (req, res) => {
|
|
3709
|
+
let { requirements, install_required, requirements_pending, error } = await this.kernel.bin.check({
|
|
3710
|
+
bin: this.kernel.bin.preset("network"),
|
|
3711
|
+
})
|
|
3712
|
+
|
|
3713
|
+
if (!requirements_pending && install_required) {
|
|
3714
|
+
console.log("redirect to /setup/network")
|
|
3715
|
+
res.redirect("/setup/network?callback=/network")
|
|
3716
|
+
return
|
|
3717
|
+
}
|
|
3718
|
+
|
|
3719
|
+
let list = this.getPeerInfo()
|
|
3720
|
+
let processes
|
|
3721
|
+
let host
|
|
3722
|
+
let peer
|
|
3723
|
+
for(let item of list) {
|
|
3724
|
+
if (item.name === req.params.name) {
|
|
3725
|
+
processes = item.processes
|
|
3726
|
+
host = item.host
|
|
3727
|
+
console.log("matched", processes)
|
|
3728
|
+
peer = item
|
|
3729
|
+
}
|
|
3730
|
+
}
|
|
3731
|
+
let favicons = {}
|
|
3732
|
+
let titles = {}
|
|
3733
|
+
let descriptions = {}
|
|
3734
|
+
console.time("Favicon")
|
|
3735
|
+
//await Promise.all(peer.processes.map((proc) => {
|
|
3736
|
+
// console.log("Proc", proc)
|
|
3737
|
+
// return new Promise(async (resolve, reject) => {
|
|
3738
|
+
// let favicon = await this.kernel.favicon.get("http://" + proc.ip)
|
|
3739
|
+
// console.log("Got favicon", { favicon, ip: proc.ip })
|
|
3740
|
+
// if (favicon) {
|
|
3741
|
+
// favicons[proc.host] = favicon
|
|
3742
|
+
// }
|
|
3743
|
+
// })
|
|
3744
|
+
//}))
|
|
3745
|
+
for(let proc of peer.processes) {
|
|
3746
|
+
if (proc.external_router) {
|
|
3747
|
+
// try to get icons from pinokio
|
|
3748
|
+
for(let router of proc.external_router) {
|
|
3749
|
+
// replace the root domain: facefusion-pinokio.git.x.localhost => facefusion-pinokio.git
|
|
3750
|
+
let pattern = `.${req.params.name}.localhost`
|
|
3751
|
+
if (router.endsWith(pattern)) {
|
|
3752
|
+
let name = router.replace(pattern, "")
|
|
3753
|
+
let api_path = this.kernel.path("api", name)
|
|
3754
|
+
let exists = await this.exists(api_path)
|
|
3755
|
+
if (exists) {
|
|
3756
|
+
let meta = await this.kernel.api.meta(name)
|
|
3757
|
+
if (meta.icon) {
|
|
3758
|
+
favicons[proc.ip] = meta.icon
|
|
3759
|
+
}
|
|
3760
|
+
if (meta.title) {
|
|
3761
|
+
titles[proc.ip] = meta.title
|
|
3762
|
+
}
|
|
3763
|
+
if (meta.description) {
|
|
3764
|
+
descriptions[proc.ip] = meta.description
|
|
3765
|
+
}
|
|
3766
|
+
}
|
|
3767
|
+
}
|
|
3768
|
+
}
|
|
3769
|
+
}
|
|
3770
|
+
// if not running from pinokio, try to fetch and infer the favicon
|
|
3771
|
+
if (!favicons[proc.ip]) {
|
|
3772
|
+
let favicon = await this.kernel.favicon.get("http://" + proc.ip)
|
|
3773
|
+
if (favicon) {
|
|
3774
|
+
favicons[proc.ip] = favicon
|
|
3775
|
+
}
|
|
3776
|
+
}
|
|
3777
|
+
}
|
|
3778
|
+
console.timeEnd("Favicon")
|
|
3779
|
+
|
|
3780
|
+
let current_urls = await this.current_urls(req.originalUrl.slice(1))
|
|
3781
|
+
console.log("LIST", JSON.stringify(list, null, 2))
|
|
3782
|
+
res.render("net", {
|
|
3783
|
+
favicons,
|
|
3784
|
+
titles,
|
|
3785
|
+
descriptions,
|
|
3786
|
+
current_urls,
|
|
3787
|
+
docs: this.docs,
|
|
3788
|
+
portal: this.portal,
|
|
3789
|
+
install: this.install,
|
|
3790
|
+
agent: this.agent,
|
|
3791
|
+
theme: this.theme,
|
|
3792
|
+
processes,
|
|
3793
|
+
error: null,
|
|
3794
|
+
list,
|
|
3795
|
+
host,
|
|
3796
|
+
running: [],
|
|
3797
|
+
current_host: this.kernel.peer.host,
|
|
3798
|
+
})
|
|
3799
|
+
}))
|
|
3718
3800
|
this.app.get("/network", ex(async (req, res) => {
|
|
3719
3801
|
let { requirements, install_required, requirements_pending, error } = await this.kernel.bin.check({
|
|
3720
3802
|
bin: this.kernel.bin.preset("network"),
|
|
@@ -3812,8 +3894,10 @@ class Server {
|
|
|
3812
3894
|
}
|
|
3813
3895
|
|
|
3814
3896
|
|
|
3897
|
+
let current_urls = await this.current_urls(req.originalUrl.slice(1))
|
|
3815
3898
|
|
|
3816
3899
|
res.render("network", {
|
|
3900
|
+
current_urls,
|
|
3817
3901
|
requirements_pending,
|
|
3818
3902
|
install_required,
|
|
3819
3903
|
docs: this.docs,
|
package/server/public/style.css
CHANGED
|
@@ -111,6 +111,9 @@ body.dark *::-webkit-scrollbar-thumb {
|
|
|
111
111
|
border: 2px dotted silver !important;
|
|
112
112
|
}
|
|
113
113
|
.app-btns {
|
|
114
|
+
display: flex;
|
|
115
|
+
gap: 5px;
|
|
116
|
+
align-items: center;
|
|
114
117
|
}
|
|
115
118
|
.drawer {
|
|
116
119
|
max-height: 100000px;
|
|
@@ -151,6 +154,10 @@ body.dark .dynamic.selected {
|
|
|
151
154
|
background: rgba(0,0,0,0.05);
|
|
152
155
|
*/
|
|
153
156
|
}
|
|
157
|
+
.submenu {
|
|
158
|
+
margin-left: 10px;
|
|
159
|
+
box-sizing: border-box;
|
|
160
|
+
}
|
|
154
161
|
|
|
155
162
|
.url-bar {
|
|
156
163
|
font-family: verdana;
|
|
@@ -160,12 +167,12 @@ body.dark .dynamic.selected {
|
|
|
160
167
|
flex-grow: 1;
|
|
161
168
|
}
|
|
162
169
|
.url-bar .http-url:hover {
|
|
163
|
-
color:
|
|
164
|
-
border-color:
|
|
170
|
+
color: royalblue;
|
|
171
|
+
border-color: royalblue;
|
|
165
172
|
}
|
|
166
173
|
.url-bar .https-url:hover {
|
|
167
|
-
color:
|
|
168
|
-
border-color:
|
|
174
|
+
color: royalblue;
|
|
175
|
+
border-color: royalblue;
|
|
169
176
|
}
|
|
170
177
|
.url-bar .https-url {
|
|
171
178
|
cursor: pointer;
|
|
@@ -652,7 +659,13 @@ form.search {
|
|
|
652
659
|
margin: 0;
|
|
653
660
|
display: flex;
|
|
654
661
|
flex-grow: 1;
|
|
662
|
+
/*
|
|
655
663
|
padding: 0 10px 20px;
|
|
664
|
+
*/
|
|
665
|
+
padding: 0 10px 10px;
|
|
666
|
+
/*
|
|
667
|
+
padding: 10px 20px 10px;
|
|
668
|
+
*/
|
|
656
669
|
}
|
|
657
670
|
.input-form {
|
|
658
671
|
padding: 10px;
|
|
@@ -720,7 +733,7 @@ body.dark form.search input[type=search] {
|
|
|
720
733
|
}
|
|
721
734
|
form.search input[type=search] {
|
|
722
735
|
flex-grow: 1;
|
|
723
|
-
padding: 10px;
|
|
736
|
+
padding: 8px 10px;
|
|
724
737
|
/*
|
|
725
738
|
margin: 0 0 0 10px;
|
|
726
739
|
*/
|
|
@@ -733,8 +746,9 @@ form.search input[type=search] {
|
|
|
733
746
|
border: 1px solid rgba(0,0,0,0.1);
|
|
734
747
|
border-right: none;
|
|
735
748
|
background: rgba(0,0,0,0.05);
|
|
736
|
-
*/
|
|
737
749
|
background: white;
|
|
750
|
+
*/
|
|
751
|
+
background: rgba(0,0,0,0.05);
|
|
738
752
|
border: none;
|
|
739
753
|
outline: none;
|
|
740
754
|
}
|
|
@@ -996,7 +1010,7 @@ header {
|
|
|
996
1010
|
background: white;
|
|
997
1011
|
*/
|
|
998
1012
|
position: sticky;
|
|
999
|
-
padding: 10px;
|
|
1013
|
+
padding: 10px 10px 0;
|
|
1000
1014
|
top: 0;
|
|
1001
1015
|
box-sizing: border-box;
|
|
1002
1016
|
z-index: 1000;
|
|
@@ -1121,6 +1135,9 @@ main {
|
|
|
1121
1135
|
main h1 {
|
|
1122
1136
|
margin: 0;
|
|
1123
1137
|
}
|
|
1138
|
+
body.dark .offline .indicator {
|
|
1139
|
+
background: rgba(255,255,255,0.1);
|
|
1140
|
+
}
|
|
1124
1141
|
.hidden {
|
|
1125
1142
|
display: none !important;
|
|
1126
1143
|
}
|
|
@@ -1137,6 +1154,9 @@ main h1 {
|
|
|
1137
1154
|
box-sizing: border-box;
|
|
1138
1155
|
}
|
|
1139
1156
|
.container {
|
|
1157
|
+
flex-grow: 1;
|
|
1158
|
+
box-sizing: border-box;
|
|
1159
|
+
padding: 0 20px;
|
|
1140
1160
|
/*
|
|
1141
1161
|
max-width: var(--content-width);
|
|
1142
1162
|
margin: 20px auto;
|
|
@@ -1227,9 +1247,11 @@ body.dark .readme a {
|
|
|
1227
1247
|
.line:last-child {
|
|
1228
1248
|
border: none;
|
|
1229
1249
|
}
|
|
1250
|
+
/*
|
|
1230
1251
|
body.dark .line {
|
|
1231
1252
|
border-bottom: 1px solid var(--dark-thin);
|
|
1232
1253
|
}
|
|
1254
|
+
*/
|
|
1233
1255
|
body.dark .line.selected, body.dark .line:hover {
|
|
1234
1256
|
/*
|
|
1235
1257
|
border-left: 6px solid white;
|
|
@@ -1257,7 +1279,9 @@ body.dark .line:hover {
|
|
|
1257
1279
|
padding: 15px 15px;
|
|
1258
1280
|
*/
|
|
1259
1281
|
padding: 7px 5px;
|
|
1282
|
+
/*
|
|
1260
1283
|
border-bottom: 1px solid var(--light-thin);
|
|
1284
|
+
*/
|
|
1261
1285
|
}
|
|
1262
1286
|
.thick.line {
|
|
1263
1287
|
padding: 15px;
|
|
@@ -1345,22 +1369,34 @@ body.dark .line.align-top h3 .col .uri {
|
|
|
1345
1369
|
.line.align-top h3 .col .uri {
|
|
1346
1370
|
opacity: 0.9;
|
|
1347
1371
|
padding-bottom: 2px;
|
|
1348
|
-
color:
|
|
1372
|
+
color: rgba(0,0,0,0.4);
|
|
1349
1373
|
font-size: 12px;
|
|
1350
1374
|
font-family: verdana;
|
|
1351
1375
|
}
|
|
1352
1376
|
body.dark .line.align-top h3 .col .title a {
|
|
1353
1377
|
color: var(--dark-link-color);
|
|
1354
1378
|
}
|
|
1355
|
-
.line.align-top h3 .col .title
|
|
1356
|
-
font-size: 15px;
|
|
1379
|
+
.line.align-top h3 .col .title span {
|
|
1357
1380
|
margin-left: 5px;
|
|
1358
1381
|
}
|
|
1382
|
+
|
|
1383
|
+
.running-apps .line.align-top h3 .col .title {
|
|
1384
|
+
/*
|
|
1385
|
+
color: yellowgreen;
|
|
1386
|
+
*/
|
|
1387
|
+
}
|
|
1388
|
+
.running-apps .line.align-top h3 .col .title i {
|
|
1389
|
+
color: yellowgreen;
|
|
1390
|
+
}
|
|
1391
|
+
.line.align-top h3 .col .title i {
|
|
1392
|
+
font-size: 12px;
|
|
1393
|
+
}
|
|
1394
|
+
body.dark .line.align-top h3 .col .title i {
|
|
1395
|
+
}
|
|
1359
1396
|
.line.align-top h3 .col .title a {
|
|
1360
1397
|
text-decoration: none;
|
|
1361
1398
|
display: flex;
|
|
1362
1399
|
align-items: center;
|
|
1363
|
-
color: var(--light-link-color);
|
|
1364
1400
|
}
|
|
1365
1401
|
.line.align-top h3 .col .title .btn {
|
|
1366
1402
|
letter-spacing: 0;
|
|
@@ -1376,10 +1412,7 @@ body.dark .line.align-top h3 .col .title a {
|
|
|
1376
1412
|
*/
|
|
1377
1413
|
display: flex;
|
|
1378
1414
|
align-items: center;
|
|
1379
|
-
|
|
1380
|
-
font-size: 20px;
|
|
1381
|
-
*/
|
|
1382
|
-
font-size: 16px;
|
|
1415
|
+
font-size: 14px;
|
|
1383
1416
|
font-family: arial;
|
|
1384
1417
|
font-weight: bold;
|
|
1385
1418
|
}
|
|
@@ -1942,30 +1975,11 @@ nav.error-message {
|
|
|
1942
1975
|
font-weight: bold;
|
|
1943
1976
|
}
|
|
1944
1977
|
/*
|
|
1945
|
-
.not-running-apps, .running-apps {
|
|
1946
|
-
background: rgba(0,0,100,0.04);
|
|
1947
|
-
}
|
|
1948
|
-
body.dark .not-running-apps, body.dark .running-apps {
|
|
1949
|
-
background: rgba(255,255,255,0.03);
|
|
1950
|
-
}
|
|
1951
|
-
*/
|
|
1952
|
-
/*
|
|
1953
|
-
.running-apps .line .title {
|
|
1954
|
-
color: #82bc09;
|
|
1955
|
-
}
|
|
1956
|
-
*/
|
|
1957
1978
|
.running-apps .line {
|
|
1958
1979
|
border-left: 10px solid #82bc09;
|
|
1959
1980
|
}
|
|
1960
1981
|
.running-apps .line img {
|
|
1961
1982
|
padding-left: 3px;
|
|
1962
|
-
/*
|
|
1963
|
-
padding-left: 10px;
|
|
1964
|
-
border: 3px solid #8fd400;
|
|
1965
|
-
*/
|
|
1966
|
-
/*
|
|
1967
|
-
border-radius: 5px;
|
|
1968
|
-
*/
|
|
1969
1983
|
}
|
|
1970
1984
|
body.dark .not-running-apps .line {
|
|
1971
1985
|
border-left: 10px solid rgba(255,255,255,0.1);
|
|
@@ -1976,21 +1990,14 @@ body.dark .not-running-apps .line {
|
|
|
1976
1990
|
.not-running-apps .line img {
|
|
1977
1991
|
padding-left: 3px;
|
|
1978
1992
|
}
|
|
1979
|
-
/*
|
|
1980
|
-
.running-apps .line.align-top h3 .col .title {
|
|
1981
|
-
color: #8fd400;
|
|
1982
|
-
}
|
|
1983
|
-
*/
|
|
1984
1993
|
.running-apps .spinner, .not-running-apps .spinner {
|
|
1985
1994
|
width: 50px;
|
|
1986
1995
|
text-align: center;
|
|
1987
1996
|
font-size: 20px;
|
|
1988
1997
|
}
|
|
1998
|
+
*/
|
|
1989
1999
|
body.dark header .home {
|
|
1990
2000
|
color: var(--dark-btn-color);
|
|
1991
|
-
/*
|
|
1992
|
-
color: white;
|
|
1993
|
-
*/
|
|
1994
2001
|
}
|
|
1995
2002
|
header .home {
|
|
1996
2003
|
color: var(--light-color);
|
package/server/views/app.ejs
CHANGED
|
@@ -760,7 +760,7 @@ body.dark .top-menu .btn2.selected {
|
|
|
760
760
|
color: white;
|
|
761
761
|
}
|
|
762
762
|
body.minimized #collapse {
|
|
763
|
-
background: none;
|
|
763
|
+
background: none !important;
|
|
764
764
|
}
|
|
765
765
|
body.dark #collapse {
|
|
766
766
|
background: rgba(255,255,255,0.07);
|
|
@@ -776,8 +776,13 @@ body.dark .mode-selector .btn2.selected {
|
|
|
776
776
|
}
|
|
777
777
|
.mode-selector {
|
|
778
778
|
display: flex;
|
|
779
|
+
gap: 3px;
|
|
780
|
+
/*
|
|
781
|
+
gap: 5px;
|
|
782
|
+
*/
|
|
779
783
|
}
|
|
780
784
|
.mode-selector .btn2 {
|
|
785
|
+
border-radius: 0;
|
|
781
786
|
padding: 10px 0;
|
|
782
787
|
min-width: 40px;
|
|
783
788
|
}
|
|
@@ -900,7 +905,6 @@ body.dark .mode-selector .btn2.selected {
|
|
|
900
905
|
<a class='http-url' target="_blank" href="<%=current_urls.http%>"><i class="fa-solid fa-square-arrow-up-right"></i> <%=current_urls.http%></a>
|
|
901
906
|
<% } %>
|
|
902
907
|
</div>
|
|
903
|
-
<a href="/network" class='btn2'><div><i class="fa-solid fa-wifi"></i></div><div>Network</div></a>
|
|
904
908
|
<a href="/connect" class='btn2'><div><i class="fa-solid fa-circle-user"></i></div><div>Connect</div></a>
|
|
905
909
|
<!--
|
|
906
910
|
<input type='url' id='location' readonly value="<%=execUrl%>">
|
|
@@ -196,7 +196,6 @@ pre {
|
|
|
196
196
|
<button class='btn2' id='forward'><div><i class="fa-solid fa-chevron-right"></i></div><div>Next</div></button>
|
|
197
197
|
<button class='btn2' id='refresh-page'><div><i class="fa-solid fa-rotate-right"></i></div><div>Refresh</div></button>
|
|
198
198
|
<div class='flexible'></div>
|
|
199
|
-
<a href="/network" class='btn2'><div><i class="fa-solid fa-wifi"></i></div><div>Network</div></a>
|
|
200
199
|
<a href="/connect" class='btn2'><div><i class="fa-solid fa-circle-user"></i></div><div>Connect</div></a>
|
|
201
200
|
<div class='nav-btns'>
|
|
202
201
|
<a class='btn2' href="<%=portal%>" target="_blank"><div><i class="fa-solid fa-question"></i></div><div>Help</div></a>
|
package/server/views/connect.ejs
CHANGED
|
@@ -232,7 +232,6 @@ body.dark .config {
|
|
|
232
232
|
<button class='btn2' id='forward'><div><i class="fa-solid fa-chevron-right"></i></div><div>Next</div></button>
|
|
233
233
|
<button class='btn2' id='refresh-page'><div><i class="fa-solid fa-rotate-right"></i></div><div>Refresh</div></button>
|
|
234
234
|
<div class='flexible'></div>
|
|
235
|
-
<a href="/network" class='btn2'><div><i class="fa-solid fa-wifi"></i></div><div>Network</div></a>
|
|
236
235
|
<a href="/connect" class='btn2'><div><i class="fa-solid fa-circle-user"></i></div><div>Connect</div></a>
|
|
237
236
|
<div class='nav-btns'>
|
|
238
237
|
<a class='btn2' href="<%=portal%>" target="_blank"><div><i class="fa-solid fa-question"></i></div><div>Help</div></a>
|
|
@@ -115,7 +115,6 @@ body.frozen {
|
|
|
115
115
|
<button class='btn2' id='back'><div><i class="fa-solid fa-chevron-left"></i></div><div>Prev</div></button>
|
|
116
116
|
<button class='btn2' id='forward'><div><i class="fa-solid fa-chevron-right"></i></div><div>Next</div></button>
|
|
117
117
|
<button class='btn2' id='refresh-page'><div><i class="fa-solid fa-rotate-right"></i></div><div>Refresh</div></button>
|
|
118
|
-
<a href="/network" class='btn2'><div><i class="fa-solid fa-wifi"></i></div><div>Network</div></a>
|
|
119
118
|
<a href="/connect" class='btn2'><div><i class="fa-solid fa-circle-user"></i></div><div>Connect</div></a>
|
|
120
119
|
<div class='flexible'></div>
|
|
121
120
|
<div class='nav-btns'>
|
package/server/views/explore.ejs
CHANGED
|
@@ -125,7 +125,6 @@ body main iframe {
|
|
|
125
125
|
<button class='btn2' id='forward'><div><i class="fa-solid fa-chevron-right"></i></div><div>Next</div></button>
|
|
126
126
|
<button class='btn2' id='refresh-page'><div><i class="fa-solid fa-rotate-right"></i></div><div>Refresh</div></button>
|
|
127
127
|
<div class='flexible'></div>
|
|
128
|
-
<a href="/network" class='btn2'><div><i class="fa-solid fa-wifi"></i></div><div>Network</div></a>
|
|
129
128
|
<a href="/connect" class='btn2'><div><i class="fa-solid fa-circle-user"></i></div><div>Connect</div></a>
|
|
130
129
|
<div class='nav-btns'>
|
|
131
130
|
<a class='btn2' href="<%=portal%>" target="_blank"><div><i class="fa-solid fa-question"></i></div><div>Help</div></a>
|
|
@@ -234,7 +234,6 @@ body.dark .browser-options-row {
|
|
|
234
234
|
</div>
|
|
235
235
|
<% } %>
|
|
236
236
|
<div class='browser-options-row'>
|
|
237
|
-
<a href="/network" class='btn'><div><i class="fa-solid fa-gauge"></i> Configure</div></a>
|
|
238
237
|
<div class='flexible'>
|
|
239
238
|
<h3><i class="fa-solid fa-wifi"></i> Local Sharing</h3>
|
|
240
239
|
<div>Serve Pinokio, installed apps, and even external apps (example: Ollama) to any device on the same network.</div>
|