pinokiod 7.3.9 → 7.3.11
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/bin/brew.js +12 -2
- package/kernel/bin/caddy.js +24 -20
- package/kernel/bin/huggingface.js +2 -2
- package/kernel/bin/setup.js +2 -3
- package/kernel/bin/uv.js +13 -6
- package/kernel/connect/index.js +5 -1
- package/kernel/connect/providers/huggingface/index.js +213 -75
- package/kernel/environment.js +16 -1
- package/kernel/router/localhost_home_router.js +7 -0
- package/kernel/shell.js +1 -5
- package/kernel/util.js +1 -0
- package/package.json +1 -1
- package/server/index.js +75 -33
- package/server/public/common.js +52 -88
- package/server/public/install.js +20 -2
- package/server/public/layout.js +1 -1
- package/server/public/nav.js +3 -1
- package/server/public/style.css +1455 -521
- package/server/public/tab-link-popover.css +162 -18
- package/server/public/tab-link-popover.js +230 -21
- package/server/public/task-launcher.css +182 -91
- package/server/public/terminal-settings.js +227 -50
- package/server/public/universal-launcher.css +42 -33
- package/server/public/urldropdown.css +284 -0
- package/server/views/app.ejs +1718 -352
- package/server/views/autolaunch.ejs +4 -5
- package/server/views/checkpoints.ejs +223 -50
- package/server/views/connect/huggingface.ejs +406 -325
- package/server/views/connect.ejs +0 -1
- package/server/views/github.ejs +277 -324
- package/server/views/index.ejs +65 -8
- package/server/views/install.ejs +134 -65
- package/server/views/logs.ejs +9 -8
- package/server/views/net.ejs +341 -64
- package/server/views/network.ejs +85 -63
- package/server/views/partials/main_sidebar.ejs +249 -24
- package/server/views/plugins.ejs +141 -3
- package/server/views/settings.ejs +103 -7
- package/server/views/setup.ejs +0 -5
- package/server/views/skills.ejs +0 -1
- package/server/views/task_list.ejs +0 -1
- package/server/views/terminal.ejs +285 -60
- package/server/views/terminals.ejs +346 -6
- package/server/views/tools.ejs +828 -1691
- package/test/caddy-install.test.js +53 -0
- package/test/connect-setup.test.js +16 -0
- package/test/github-connection.test.js +1 -1
- package/test/huggingface-bin.test.js +4 -4
- package/test/huggingface-connect.test.js +73 -0
- package/test/main-sidebar.test.js +31 -0
- package/test/shell-run-template.test.js +5 -1
- package/test/uv-bin.test.js +29 -0
package/server/views/network.ejs
CHANGED
|
@@ -1052,10 +1052,10 @@ body.dark .troubleshoot {
|
|
|
1052
1052
|
}
|
|
1053
1053
|
}
|
|
1054
1054
|
body.network-page .task-container {
|
|
1055
|
-
padding:
|
|
1055
|
+
padding: 0;
|
|
1056
1056
|
}
|
|
1057
1057
|
body.network-page .task-shell {
|
|
1058
|
-
width:
|
|
1058
|
+
width: 100%;
|
|
1059
1059
|
margin: 0;
|
|
1060
1060
|
background: transparent;
|
|
1061
1061
|
border: 0;
|
|
@@ -1065,19 +1065,29 @@ body.network-page .task-shell {
|
|
|
1065
1065
|
backdrop-filter: none;
|
|
1066
1066
|
}
|
|
1067
1067
|
body.network-page .task-shell-header {
|
|
1068
|
-
padding
|
|
1068
|
+
padding: 12px 18px 14px;
|
|
1069
1069
|
}
|
|
1070
1070
|
body.network-page .task-shell-body {
|
|
1071
|
-
padding:
|
|
1071
|
+
padding: 0 28px 28px;
|
|
1072
1072
|
}
|
|
1073
1073
|
body.network-page .c {
|
|
1074
1074
|
display: grid;
|
|
1075
|
-
gap:
|
|
1075
|
+
gap: 0;
|
|
1076
1076
|
min-width: 0;
|
|
1077
1077
|
}
|
|
1078
1078
|
body.network-page .container {
|
|
1079
1079
|
margin: 0;
|
|
1080
1080
|
}
|
|
1081
|
+
body.network-page .network-config-section {
|
|
1082
|
+
padding-top: 18px;
|
|
1083
|
+
border-top: 0;
|
|
1084
|
+
}
|
|
1085
|
+
body.network-page .network-config-head {
|
|
1086
|
+
align-items: center;
|
|
1087
|
+
margin-bottom: 16px;
|
|
1088
|
+
padding-bottom: 16px;
|
|
1089
|
+
border-bottom: 1px solid var(--task-border);
|
|
1090
|
+
}
|
|
1081
1091
|
body.network-page .config {
|
|
1082
1092
|
margin: 0;
|
|
1083
1093
|
padding: 0;
|
|
@@ -1088,13 +1098,13 @@ body.network-page .config-header {
|
|
|
1088
1098
|
}
|
|
1089
1099
|
body.network-page .config-body {
|
|
1090
1100
|
display: grid;
|
|
1091
|
-
grid-template-columns: minmax(0, 1fr)
|
|
1092
|
-
gap:
|
|
1093
|
-
padding:
|
|
1094
|
-
border:
|
|
1095
|
-
border-radius:
|
|
1096
|
-
background:
|
|
1097
|
-
align-items:
|
|
1101
|
+
grid-template-columns: minmax(0, 1fr);
|
|
1102
|
+
gap: 16px;
|
|
1103
|
+
padding: 0;
|
|
1104
|
+
border: 0;
|
|
1105
|
+
border-radius: 0;
|
|
1106
|
+
background: transparent;
|
|
1107
|
+
align-items: stretch;
|
|
1098
1108
|
}
|
|
1099
1109
|
body.network-page .config-row {
|
|
1100
1110
|
padding: 0;
|
|
@@ -1106,15 +1116,21 @@ body.network-page .config-row .label {
|
|
|
1106
1116
|
font-weight: 700;
|
|
1107
1117
|
color: var(--task-text);
|
|
1108
1118
|
}
|
|
1109
|
-
body.network-page .config-
|
|
1119
|
+
body.network-page .config-access-copy {
|
|
1120
|
+
min-width: 0;
|
|
1121
|
+
}
|
|
1122
|
+
body.network-page .config-access-titleline {
|
|
1110
1123
|
display: flex;
|
|
1111
|
-
align-items:
|
|
1112
|
-
|
|
1113
|
-
|
|
1124
|
+
align-items: baseline;
|
|
1125
|
+
gap: 10px;
|
|
1126
|
+
min-width: 0;
|
|
1114
1127
|
}
|
|
1115
|
-
body.network-page .config-toggle-
|
|
1116
|
-
display:
|
|
1117
|
-
|
|
1128
|
+
body.network-page .config-toggle-actions {
|
|
1129
|
+
display: flex;
|
|
1130
|
+
align-items: center;
|
|
1131
|
+
justify-content: flex-end;
|
|
1132
|
+
gap: 12px;
|
|
1133
|
+
flex: 0 0 auto;
|
|
1118
1134
|
}
|
|
1119
1135
|
body.network-page #active-label {
|
|
1120
1136
|
padding: 0;
|
|
@@ -1129,18 +1145,11 @@ body.network-page .switcher {
|
|
|
1129
1145
|
}
|
|
1130
1146
|
body.network-page .config-save-btn {
|
|
1131
1147
|
min-width: 104px;
|
|
1132
|
-
min-height:
|
|
1133
|
-
padding: 0
|
|
1134
|
-
border-radius:
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
border: 1px solid var(--task-accent-surface) !important;
|
|
1138
|
-
font-size: 14px;
|
|
1139
|
-
font-weight: 700;
|
|
1140
|
-
}
|
|
1141
|
-
body.network-page .config-save-btn:hover {
|
|
1142
|
-
background: var(--task-accent-hover) !important;
|
|
1143
|
-
border-color: var(--task-accent-hover) !important;
|
|
1148
|
+
min-height: 32px;
|
|
1149
|
+
padding: 0 12px;
|
|
1150
|
+
border-radius: 7px;
|
|
1151
|
+
font-size: 12px;
|
|
1152
|
+
font-weight: 600;
|
|
1144
1153
|
}
|
|
1145
1154
|
body.network-page .slider {
|
|
1146
1155
|
border: 1px solid var(--task-border-strong);
|
|
@@ -1158,7 +1167,8 @@ body.network-page .switcher input:checked + .slider {
|
|
|
1158
1167
|
border-color: color-mix(in srgb, var(--task-accent) 72%, var(--task-panel));
|
|
1159
1168
|
}
|
|
1160
1169
|
body.network-page #network_name {
|
|
1161
|
-
|
|
1170
|
+
display: grid;
|
|
1171
|
+
gap: 8px;
|
|
1162
1172
|
}
|
|
1163
1173
|
body.network-page .network-name {
|
|
1164
1174
|
display: block;
|
|
@@ -1166,22 +1176,22 @@ body.network-page .network-name {
|
|
|
1166
1176
|
body.network-page .network-name input[type=text] {
|
|
1167
1177
|
width: 100%;
|
|
1168
1178
|
min-width: 0;
|
|
1179
|
+
min-height: 38px;
|
|
1180
|
+
padding: 7px 12px;
|
|
1169
1181
|
border: 1px solid var(--task-border-strong);
|
|
1170
|
-
border-radius:
|
|
1171
|
-
background: color-mix(in srgb, var(--task-panel)
|
|
1182
|
+
border-radius: 9px;
|
|
1183
|
+
background: color-mix(in srgb, var(--task-panel) 92%, var(--task-soft));
|
|
1172
1184
|
color: var(--task-text);
|
|
1173
|
-
padding: 0 14px;
|
|
1174
|
-
height: 44px;
|
|
1175
1185
|
box-sizing: border-box;
|
|
1176
1186
|
}
|
|
1177
1187
|
body.dark.network-page .network-name input[type=text] {
|
|
1178
|
-
background: color-mix(in srgb, var(--task-panel)
|
|
1188
|
+
background: color-mix(in srgb, var(--task-panel) 92%, var(--task-soft));
|
|
1179
1189
|
}
|
|
1180
1190
|
body.network-page #network_name .label {
|
|
1181
|
-
margin-bottom:
|
|
1191
|
+
margin-bottom: 0;
|
|
1182
1192
|
}
|
|
1183
1193
|
body.network-page .advanced {
|
|
1184
|
-
margin-top:
|
|
1194
|
+
margin-top: 14px;
|
|
1185
1195
|
justify-content: flex-start;
|
|
1186
1196
|
}
|
|
1187
1197
|
body.network-page .troubleshoot,
|
|
@@ -1189,14 +1199,20 @@ body.dark.network-page .troubleshoot {
|
|
|
1189
1199
|
color: var(--task-muted);
|
|
1190
1200
|
padding: 0;
|
|
1191
1201
|
font-size: 13px;
|
|
1202
|
+
line-height: 1.5;
|
|
1203
|
+
}
|
|
1204
|
+
body.network-page .troubleshoot .link-label {
|
|
1205
|
+
margin-right: 0;
|
|
1206
|
+
padding: 0 !important;
|
|
1192
1207
|
}
|
|
1193
1208
|
body.network-page .link-label {
|
|
1194
1209
|
color: var(--task-accent);
|
|
1195
1210
|
}
|
|
1196
1211
|
body.network-page .loading {
|
|
1197
|
-
|
|
1198
|
-
border-
|
|
1199
|
-
|
|
1212
|
+
margin-top: 16px;
|
|
1213
|
+
border-top: 1px solid var(--task-border);
|
|
1214
|
+
border-radius: 0;
|
|
1215
|
+
background: transparent;
|
|
1200
1216
|
color: var(--task-muted);
|
|
1201
1217
|
}
|
|
1202
1218
|
body.network-page .running-apps {
|
|
@@ -1294,12 +1310,8 @@ body.dark.network-page .badge {
|
|
|
1294
1310
|
padding-left: 18px;
|
|
1295
1311
|
padding-right: 18px;
|
|
1296
1312
|
}
|
|
1297
|
-
body.network-page .config-body {
|
|
1298
|
-
grid-template-columns: 1fr;
|
|
1299
|
-
gap: 16px;
|
|
1300
|
-
}
|
|
1301
1313
|
body.network-page .config-save-btn {
|
|
1302
|
-
width:
|
|
1314
|
+
width: auto;
|
|
1303
1315
|
}
|
|
1304
1316
|
}
|
|
1305
1317
|
@media only screen and (max-width: 560px) {
|
|
@@ -1309,6 +1321,12 @@ body.dark.network-page .badge {
|
|
|
1309
1321
|
body.network-page .task-shell-body {
|
|
1310
1322
|
padding-bottom: 22px;
|
|
1311
1323
|
}
|
|
1324
|
+
body.network-page .network-config-head {
|
|
1325
|
+
align-items: flex-start;
|
|
1326
|
+
}
|
|
1327
|
+
body.network-page .config-toggle-actions {
|
|
1328
|
+
gap: 10px;
|
|
1329
|
+
}
|
|
1312
1330
|
body.network-page .line.align-top h3 {
|
|
1313
1331
|
grid-template-columns: 1fr;
|
|
1314
1332
|
}
|
|
@@ -1322,7 +1340,7 @@ body.dark.network-page .badge {
|
|
|
1322
1340
|
display: block;
|
|
1323
1341
|
}
|
|
1324
1342
|
body.network-page .network-name input[type=text] {
|
|
1325
|
-
border-radius:
|
|
1343
|
+
border-radius: 9px;
|
|
1326
1344
|
}
|
|
1327
1345
|
}
|
|
1328
1346
|
</style>
|
|
@@ -1384,31 +1402,35 @@ document.addEventListener('DOMContentLoaded', function() {
|
|
|
1384
1402
|
<section class='task-shell network-shell'>
|
|
1385
1403
|
<header class='task-shell-header'>
|
|
1386
1404
|
<div class='task-shell-header-main'>
|
|
1387
|
-
<p class='task-eyebrow'>Network</p>
|
|
1388
1405
|
<h1 class='task-title'>Network settings</h1>
|
|
1389
1406
|
<p class='task-description'>Instantly add HTTPS, CORS, and peer sharing for apps on your local network.</p>
|
|
1390
1407
|
</div>
|
|
1391
1408
|
</header>
|
|
1392
1409
|
<div class='task-shell-body network-shell-body'>
|
|
1393
1410
|
<div class='c'>
|
|
1394
|
-
<
|
|
1411
|
+
<section class='task-section network-config-section' aria-label='Network access'>
|
|
1412
|
+
<div class='task-section-head network-config-head'>
|
|
1413
|
+
<div class='config-access-copy'>
|
|
1414
|
+
<div class='config-access-titleline'>
|
|
1415
|
+
<h2 class='task-section-title'>Network access</h2>
|
|
1416
|
+
<div id='active-label'><%=peer_active ? "On" : "Off"%></div>
|
|
1417
|
+
</div>
|
|
1418
|
+
<p class='task-section-subcopy'>Enable local sharing and set this machine's network name.</p>
|
|
1419
|
+
</div>
|
|
1420
|
+
<div class='config-toggle-actions'>
|
|
1421
|
+
<label class="switcher">
|
|
1422
|
+
<input id='active' type="checkbox" <%=peer_active ? 'checked' : ''%>>
|
|
1423
|
+
<span class="slider"></span>
|
|
1424
|
+
</label>
|
|
1425
|
+
<button class='task-button primary save config-save-btn'>Save</button>
|
|
1426
|
+
</div>
|
|
1427
|
+
</div>
|
|
1395
1428
|
<div class='config'>
|
|
1396
1429
|
<div class='config-body'>
|
|
1397
|
-
<div class='config-row config-toggle-row'>
|
|
1398
|
-
<div class='config-toggle-copy'>
|
|
1399
|
-
<div class='label'>Network access</div>
|
|
1400
|
-
<div id='active-label'><%=peer_active ? "On" : "Off"%></div>
|
|
1401
|
-
</div>
|
|
1402
|
-
<label class="switcher">
|
|
1403
|
-
<input id='active' type="checkbox" <%=peer_active ? 'checked' : ''%>>
|
|
1404
|
-
<span class="slider"></span>
|
|
1405
|
-
</label>
|
|
1406
|
-
</div>
|
|
1407
|
-
<button class='btn save config-save-btn'>Save</button>
|
|
1408
1430
|
<div class='config-row' id='network_name'>
|
|
1409
1431
|
<div class='label'>Network Name</div>
|
|
1410
1432
|
<div class='network-name'>
|
|
1411
|
-
<input id='name' type='text' value="<%=name%>">
|
|
1433
|
+
<input id='name' class='task-input' type='text' value="<%=name%>">
|
|
1412
1434
|
</div>
|
|
1413
1435
|
</div>
|
|
1414
1436
|
</div>
|
|
@@ -1425,7 +1447,7 @@ document.addEventListener('DOMContentLoaded', function() {
|
|
|
1425
1447
|
<div class='loading hidden'>
|
|
1426
1448
|
<i class="fa-solid fa-circle-notch fa-spin"></i> Stand by. Do not close this window..
|
|
1427
1449
|
</div>
|
|
1428
|
-
</
|
|
1450
|
+
</section>
|
|
1429
1451
|
<div class='container'>
|
|
1430
1452
|
<div class='running-apps'>
|
|
1431
1453
|
<% if (requirements_pending || peer_active && processes.length === 0) { %>
|
|
@@ -4,6 +4,31 @@
|
|
|
4
4
|
const sidebarCurrentHost = (typeof current_host !== "undefined" && current_host) ? current_host : "";
|
|
5
5
|
const sidebarSelectedNetName = (typeof selectedNetName !== "undefined" && selectedNetName) ? String(selectedNetName) : "";
|
|
6
6
|
const sidebarShowPeerAccess = typeof showPeerAccess === "boolean" ? showPeerAccess : true;
|
|
7
|
+
const sidebarPeerSourcePoints = Array.isArray(typeof peer_access_points !== "undefined" ? peer_access_points : null) ? peer_access_points : [];
|
|
8
|
+
const sidebarPeerAccessPoints = sidebarPeerSourcePoints
|
|
9
|
+
.filter((point) => point && point.url)
|
|
10
|
+
.map((point) => {
|
|
11
|
+
const url = String(point.url);
|
|
12
|
+
return {
|
|
13
|
+
url,
|
|
14
|
+
qr: point.qr ? String(point.qr) : `/qr?data=${encodeURIComponent(url)}&s=4&m=0`,
|
|
15
|
+
scope_label: point.scope_label ? String(point.scope_label) : "",
|
|
16
|
+
};
|
|
17
|
+
});
|
|
18
|
+
const sidebarPeerAccessRouterInstalled = typeof peer_access_router_installed === "boolean" ? peer_access_router_installed : true;
|
|
19
|
+
if (
|
|
20
|
+
sidebarPeerAccessPoints.length === 0 &&
|
|
21
|
+
typeof peer_qr !== "undefined" && peer_qr &&
|
|
22
|
+
typeof peer_url !== "undefined" && peer_url
|
|
23
|
+
) {
|
|
24
|
+
sidebarPeerAccessPoints.push({
|
|
25
|
+
url: String(peer_url),
|
|
26
|
+
qr: String(peer_qr),
|
|
27
|
+
scope_label: "",
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
const sidebarShowPhoneAccess = sidebarShowPeerAccess && sidebarPeerAccessPoints.length > 0;
|
|
31
|
+
const sidebarPhoneAccessNeedsSetup = sidebarShowPhoneAccess && !sidebarPeerAccessRouterInstalled;
|
|
7
32
|
const brands = { win32: "windows", darwin: "apple", linux: "Linux" };
|
|
8
33
|
%>
|
|
9
34
|
<button type="button" class="main-sidebar-mobile-toggle" data-main-sidebar-toggle aria-label="Open navigation" aria-expanded="false">
|
|
@@ -29,44 +54,101 @@
|
|
|
29
54
|
|
|
30
55
|
<div class='main-sidebar-section' aria-label="Computer">
|
|
31
56
|
<div class="main-sidebar-section-title">Computer</div>
|
|
32
|
-
<a href="/home" class="tab <%= sidebarSelected === 'home' ? 'selected' : '' %>"
|
|
33
|
-
<a href="/network" class="tab <%= sidebarSelected === 'network' ? 'selected' : '' %>"
|
|
57
|
+
<a href="/home" class="tab <%= sidebarSelected === 'home' ? 'selected' : '' %>"><i class='fas fa-laptop-code'></i><div class='caption'>This machine</div></a>
|
|
58
|
+
<a href="/network" class="tab <%= sidebarSelected === 'network' ? 'selected' : '' %>"><i class="fa-solid fa-wifi"></i><div class='caption'>Local network</div></a>
|
|
34
59
|
<% if (sidebarList.length > 0) { %>
|
|
35
60
|
<% sidebarList.forEach(({ host, name, platform }) => { %>
|
|
36
61
|
<% const selectedNet = sidebarSelectedNetName && String(name || "") === sidebarSelectedNetName; %>
|
|
37
|
-
<a href="/net/<%=name%>" class="submenu tab <%= selectedNet ? 'selected' : '' %>"
|
|
62
|
+
<a href="/net/<%=name%>" class="submenu tab <%= selectedNet ? 'selected' : '' %>"><i class="fa-brands fa-<%=brands[platform]%>"></i><div class='caption'><%=name%> (<%=sidebarCurrentHost === host ? 'this machine' : host%>)</div></a>
|
|
38
63
|
<% }) %>
|
|
39
64
|
<% } %>
|
|
65
|
+
<% if (sidebarShowPhoneAccess) { %>
|
|
66
|
+
<button type="button" class="tab main-sidebar-phone-trigger" data-peer-access-open aria-haspopup="dialog" aria-controls="main-sidebar-peer-dialog" aria-expanded="false">
|
|
67
|
+
<i class="fa-solid fa-mobile-screen-button"></i><div class='caption'>Phone</div>
|
|
68
|
+
</button>
|
|
69
|
+
<% } %>
|
|
40
70
|
</div>
|
|
41
71
|
|
|
42
72
|
<div class='main-sidebar-section' aria-label="Manage">
|
|
43
73
|
<div class="main-sidebar-section-title">Manage</div>
|
|
44
|
-
<a class="tab <%= sidebarSelected === 'checkpoints' ? 'selected' : '' %>" href="/checkpoints"
|
|
45
|
-
<a class="tab <%= sidebarSelected === 'tools' ? 'selected' : '' %>" href="/tools"
|
|
46
|
-
<a class="tab <%= sidebarSelected === 'plugins' ? 'selected' : '' %>" href="/plugins"
|
|
47
|
-
<a class="tab <%= sidebarSelected === 'tasks' ? 'selected' : '' %>" href="/tasks"
|
|
48
|
-
<a class="tab <%= sidebarSelected === 'skills' ? 'selected' : '' %>" href="/skills"
|
|
49
|
-
<a class="tab <%= sidebarSelected === 'logs' ? 'selected' : '' %>" id='genlog' href="/logs"
|
|
74
|
+
<a class="tab <%= sidebarSelected === 'checkpoints' ? 'selected' : '' %>" href="/checkpoints"><i class="fa-solid fa-clock-rotate-left"></i><div class='caption'>Checkpoints</div></a>
|
|
75
|
+
<a class="tab <%= sidebarSelected === 'tools' ? 'selected' : '' %>" href="/tools"><i class="fa-solid fa-toolbox"></i><div class='caption'>Tools</div></a>
|
|
76
|
+
<a class="tab <%= sidebarSelected === 'plugins' ? 'selected' : '' %>" href="/plugins"><i class="fa-solid fa-plug-circle-bolt"></i><div class='caption'>Plugins</div></a>
|
|
77
|
+
<a class="tab <%= sidebarSelected === 'tasks' ? 'selected' : '' %>" href="/tasks"><i class="fa-solid fa-list-check"></i><div class='caption'>Tasks</div></a>
|
|
78
|
+
<a class="tab <%= sidebarSelected === 'skills' ? 'selected' : '' %>" href="/skills"><i class="fa-solid fa-wand-magic-sparkles"></i><div class='caption'>Skills</div></a>
|
|
79
|
+
<a class="tab <%= sidebarSelected === 'logs' ? 'selected' : '' %>" id='genlog' href="/logs"><i class="fa-solid fa-laptop-code"></i><div class='caption'>Logs</div></a>
|
|
50
80
|
</div>
|
|
51
81
|
|
|
52
82
|
<div class='main-sidebar-section' aria-label="Configure">
|
|
53
83
|
<div class="main-sidebar-section-title">Configure</div>
|
|
54
|
-
<a class="tab <%= sidebarSelected === 'autolaunch' ? 'selected' : '' %>" href="/autolaunch"
|
|
55
|
-
<a href="/connect" class="tab <%= sidebarSelected === 'connect' ? 'selected' : '' %>"
|
|
56
|
-
<a class="tab <%= sidebarSelected === 'settings' ? 'selected' : '' %>" href="/home?mode=settings"
|
|
84
|
+
<a class="tab <%= sidebarSelected === 'autolaunch' ? 'selected' : '' %>" href="/autolaunch"><i class="fa-solid fa-power-off"></i><div class='caption'>Autolaunch</div></a>
|
|
85
|
+
<a href="/connect" class="tab <%= sidebarSelected === 'connect' ? 'selected' : '' %>"><i class="fa-solid fa-plug"></i><div class='caption'>Login</div></a>
|
|
86
|
+
<a class="tab <%= sidebarSelected === 'settings' ? 'selected' : '' %>" href="/home?mode=settings"><i class="fa-solid fa-gear"></i><div class='caption'>Settings</div></a>
|
|
57
87
|
</div>
|
|
58
88
|
</nav>
|
|
59
|
-
|
|
60
|
-
<% if (sidebarShowPeerAccess) { %>
|
|
61
|
-
<div class='main-sidebar-peer'>
|
|
62
|
-
<%- include('peer_access_points', {
|
|
63
|
-
peer_access_points: (typeof peer_access_points !== "undefined" ? peer_access_points : null),
|
|
64
|
-
peer_url: (typeof peer_url !== "undefined" ? peer_url : null),
|
|
65
|
-
peer_qr: (typeof peer_qr !== "undefined" ? peer_qr : null),
|
|
66
|
-
}) %>
|
|
67
|
-
</div>
|
|
68
|
-
<% } %>
|
|
69
89
|
</aside>
|
|
90
|
+
<% if (sidebarShowPhoneAccess) { %>
|
|
91
|
+
<div class="main-sidebar-peer-dialog" data-peer-access-modal hidden>
|
|
92
|
+
<button type="button" class="main-sidebar-peer-dialog-backdrop" data-peer-access-close aria-label="Close phone popup" tabindex="-1"></button>
|
|
93
|
+
<section class="main-sidebar-peer-dialog-surface" id="main-sidebar-peer-dialog" role="dialog" aria-modal="true" aria-labelledby="main-sidebar-peer-dialog-title">
|
|
94
|
+
<div class="main-sidebar-peer-dialog-header">
|
|
95
|
+
<div class="main-sidebar-peer-dialog-icon" aria-hidden="true">
|
|
96
|
+
<i class="fa-solid fa-mobile-screen-button"></i>
|
|
97
|
+
</div>
|
|
98
|
+
<div class="main-sidebar-peer-dialog-heading">
|
|
99
|
+
<div class="main-sidebar-peer-dialog-title" id="main-sidebar-peer-dialog-title"><%= sidebarPhoneAccessNeedsSetup ? 'Set up local access' : 'Open from another device' %></div>
|
|
100
|
+
<div class="main-sidebar-peer-dialog-subtitle"><%= sidebarPhoneAccessNeedsSetup ? 'Same network only' : 'Same Wi-Fi/LAN only' %></div>
|
|
101
|
+
</div>
|
|
102
|
+
<button type="button" class="main-sidebar-peer-dialog-close" data-peer-access-close aria-label="Close phone popup">
|
|
103
|
+
<i class="fa-solid fa-xmark" aria-hidden="true"></i>
|
|
104
|
+
</button>
|
|
105
|
+
</div>
|
|
106
|
+
<% if (!sidebarPhoneAccessNeedsSetup && sidebarPeerAccessPoints.length > 1) { %>
|
|
107
|
+
<div class="main-sidebar-peer-dialog-tabs" role="tablist" aria-label="Phone connection options">
|
|
108
|
+
<% sidebarPeerAccessPoints.forEach((point, index) => { %>
|
|
109
|
+
<% const tabLabel = point.scope_label || `Option ${index + 1}`; %>
|
|
110
|
+
<button type="button" class="main-sidebar-peer-dialog-tab <%= index === 0 ? 'is-active' : '' %>" data-peer-access-tab data-peer-access-index="<%= index %>" role="tab" aria-selected="<%= index === 0 ? 'true' : 'false' %>" aria-controls="main-sidebar-peer-panel-<%= index %>" tabindex="<%= index === 0 ? '0' : '-1' %>"><%= tabLabel %></button>
|
|
111
|
+
<% }) %>
|
|
112
|
+
</div>
|
|
113
|
+
<% } %>
|
|
114
|
+
<div class="main-sidebar-peer-dialog-body">
|
|
115
|
+
<% if (sidebarPhoneAccessNeedsSetup) { %>
|
|
116
|
+
<div class="main-sidebar-peer-setup">
|
|
117
|
+
<p class="main-sidebar-peer-setup-copy">To open Pinokio from another device on this network, set up local access first.</p>
|
|
118
|
+
<div class="main-sidebar-peer-setup-actions">
|
|
119
|
+
<a class="main-sidebar-peer-setup-primary" href="/setup/network" data-peer-access-setup>
|
|
120
|
+
Set up local access
|
|
121
|
+
</a>
|
|
122
|
+
<button type="button" class="main-sidebar-peer-setup-secondary" data-peer-access-close>
|
|
123
|
+
Cancel
|
|
124
|
+
</button>
|
|
125
|
+
</div>
|
|
126
|
+
</div>
|
|
127
|
+
<% } else { %>
|
|
128
|
+
<% sidebarPeerAccessPoints.forEach((point, index) => { %>
|
|
129
|
+
<div class="main-sidebar-peer-dialog-panel <%= index === 0 ? 'is-active' : '' %>" id="main-sidebar-peer-panel-<%= index %>" data-peer-access-panel data-peer-access-index="<%= index %>" role="tabpanel" <%= index === 0 ? '' : 'hidden' %>>
|
|
130
|
+
<a class="main-sidebar-peer-qr-link" href="<%= point.url %>" target="_blank" rel="noreferrer">
|
|
131
|
+
<img class="main-sidebar-peer-qr-image" src="<%= point.qr %>" alt="QR code for <%= point.url %>"/>
|
|
132
|
+
</a>
|
|
133
|
+
<div class="main-sidebar-peer-caption">
|
|
134
|
+
Scan with a device on the same local network
|
|
135
|
+
</div>
|
|
136
|
+
<div class="main-sidebar-peer-local-note">
|
|
137
|
+
This link is not public and will not work outside this network.
|
|
138
|
+
</div>
|
|
139
|
+
<div class="main-sidebar-peer-url-row">
|
|
140
|
+
<a class="main-sidebar-peer-url" href="<%= point.url %>" target="_blank" rel="noreferrer"><%= point.url %></a>
|
|
141
|
+
<button type="button" class="main-sidebar-peer-copy" data-peer-access-copy data-peer-access-url="<%= point.url %>" aria-label="Copy phone URL" title="Copy URL">
|
|
142
|
+
<i class="fa-regular fa-copy" aria-hidden="true"></i>
|
|
143
|
+
</button>
|
|
144
|
+
</div>
|
|
145
|
+
</div>
|
|
146
|
+
<% }) %>
|
|
147
|
+
<% } %>
|
|
148
|
+
</div>
|
|
149
|
+
</section>
|
|
150
|
+
</div>
|
|
151
|
+
<% } %>
|
|
70
152
|
<script>
|
|
71
153
|
(() => {
|
|
72
154
|
const body = document.body;
|
|
@@ -123,19 +205,148 @@
|
|
|
123
205
|
};
|
|
124
206
|
}
|
|
125
207
|
|
|
208
|
+
if (window.__pinokioPeerAccessModalInit) return;
|
|
209
|
+
window.__pinokioPeerAccessModalInit = true;
|
|
210
|
+
|
|
211
|
+
const peerAccessTrigger = document.querySelector("[data-peer-access-open]");
|
|
212
|
+
const peerAccessModal = document.querySelector("[data-peer-access-modal]");
|
|
213
|
+
if (body && peerAccessTrigger && peerAccessModal) {
|
|
214
|
+
const peerAccessCloseButtons = peerAccessModal.querySelectorAll("[data-peer-access-close]");
|
|
215
|
+
const peerAccessTabs = peerAccessModal.querySelectorAll("[data-peer-access-tab]");
|
|
216
|
+
const peerAccessPanels = peerAccessModal.querySelectorAll("[data-peer-access-panel]");
|
|
217
|
+
const peerAccessCopyButtons = peerAccessModal.querySelectorAll("[data-peer-access-copy]");
|
|
218
|
+
const peerAccessSetupLinks = peerAccessModal.querySelectorAll("[data-peer-access-setup]");
|
|
219
|
+
const peerAccessFocusTarget = peerAccessModal.querySelector(".main-sidebar-peer-dialog-close");
|
|
220
|
+
|
|
221
|
+
const setPeerAccessOpen = (open) => {
|
|
222
|
+
const nextOpen = !!open;
|
|
223
|
+
peerAccessModal.hidden = !nextOpen;
|
|
224
|
+
body.classList.toggle("main-sidebar-peer-dialog-open", nextOpen);
|
|
225
|
+
peerAccessTrigger.setAttribute("aria-expanded", nextOpen ? "true" : "false");
|
|
226
|
+
if (nextOpen) {
|
|
227
|
+
window.requestAnimationFrame(() => {
|
|
228
|
+
if (peerAccessFocusTarget && typeof peerAccessFocusTarget.focus === "function") {
|
|
229
|
+
peerAccessFocusTarget.focus();
|
|
230
|
+
}
|
|
231
|
+
});
|
|
232
|
+
} else if (typeof peerAccessTrigger.focus === "function") {
|
|
233
|
+
peerAccessTrigger.focus();
|
|
234
|
+
}
|
|
235
|
+
};
|
|
236
|
+
|
|
237
|
+
const setPeerAccessPanel = (index) => {
|
|
238
|
+
const activeIndex = String(index);
|
|
239
|
+
peerAccessTabs.forEach((tab) => {
|
|
240
|
+
const active = tab.dataset.peerAccessIndex === activeIndex;
|
|
241
|
+
tab.classList.toggle("is-active", active);
|
|
242
|
+
tab.setAttribute("aria-selected", active ? "true" : "false");
|
|
243
|
+
tab.setAttribute("tabindex", active ? "0" : "-1");
|
|
244
|
+
});
|
|
245
|
+
peerAccessPanels.forEach((panel) => {
|
|
246
|
+
const active = panel.dataset.peerAccessIndex === activeIndex;
|
|
247
|
+
panel.hidden = !active;
|
|
248
|
+
panel.classList.toggle("is-active", active);
|
|
249
|
+
});
|
|
250
|
+
};
|
|
251
|
+
|
|
252
|
+
const copyText = async (text) => {
|
|
253
|
+
if (navigator.clipboard && typeof navigator.clipboard.writeText === "function") {
|
|
254
|
+
await navigator.clipboard.writeText(text);
|
|
255
|
+
return;
|
|
256
|
+
}
|
|
257
|
+
const textarea = document.createElement("textarea");
|
|
258
|
+
textarea.value = text;
|
|
259
|
+
textarea.setAttribute("readonly", "");
|
|
260
|
+
textarea.style.position = "fixed";
|
|
261
|
+
textarea.style.opacity = "0";
|
|
262
|
+
document.body.appendChild(textarea);
|
|
263
|
+
textarea.select();
|
|
264
|
+
document.execCommand("copy");
|
|
265
|
+
textarea.remove();
|
|
266
|
+
};
|
|
267
|
+
|
|
268
|
+
peerAccessTrigger.addEventListener("click", () => {
|
|
269
|
+
setPeerAccessOpen(peerAccessModal.hidden);
|
|
270
|
+
});
|
|
271
|
+
|
|
272
|
+
peerAccessCloseButtons.forEach((button) => {
|
|
273
|
+
button.addEventListener("click", () => setPeerAccessOpen(false));
|
|
274
|
+
});
|
|
275
|
+
|
|
276
|
+
peerAccessTabs.forEach((tab) => {
|
|
277
|
+
tab.addEventListener("click", () => setPeerAccessPanel(tab.dataset.peerAccessIndex || "0"));
|
|
278
|
+
});
|
|
279
|
+
|
|
280
|
+
peerAccessSetupLinks.forEach((link) => {
|
|
281
|
+
link.addEventListener("click", (event) => {
|
|
282
|
+
event.preventDefault();
|
|
283
|
+
const currentPath = `${window.location.pathname}${window.location.search}`;
|
|
284
|
+
window.location.href = `/setup/network?callback=${encodeURIComponent(currentPath || "/")}`;
|
|
285
|
+
});
|
|
286
|
+
});
|
|
287
|
+
|
|
288
|
+
peerAccessCopyButtons.forEach((button) => {
|
|
289
|
+
button.addEventListener("click", async () => {
|
|
290
|
+
const url = button.dataset.peerAccessUrl || "";
|
|
291
|
+
if (!url) return;
|
|
292
|
+
try {
|
|
293
|
+
await copyText(url);
|
|
294
|
+
const icon = button.querySelector("i");
|
|
295
|
+
button.setAttribute("aria-label", "Copied phone URL");
|
|
296
|
+
button.setAttribute("title", "Copied");
|
|
297
|
+
if (icon) {
|
|
298
|
+
icon.classList.remove("fa-regular", "fa-copy");
|
|
299
|
+
icon.classList.add("fa-solid", "fa-check");
|
|
300
|
+
}
|
|
301
|
+
window.setTimeout(() => {
|
|
302
|
+
button.setAttribute("aria-label", "Copy phone URL");
|
|
303
|
+
button.setAttribute("title", "Copy URL");
|
|
304
|
+
if (icon) {
|
|
305
|
+
icon.classList.remove("fa-solid", "fa-check");
|
|
306
|
+
icon.classList.add("fa-regular", "fa-copy");
|
|
307
|
+
}
|
|
308
|
+
}, 1200);
|
|
309
|
+
} catch (_) {}
|
|
310
|
+
});
|
|
311
|
+
});
|
|
312
|
+
|
|
313
|
+
document.addEventListener("keydown", (event) => {
|
|
314
|
+
if (event.key === "Escape" && !peerAccessModal.hidden) {
|
|
315
|
+
setPeerAccessOpen(false);
|
|
316
|
+
}
|
|
317
|
+
});
|
|
318
|
+
}
|
|
319
|
+
|
|
126
320
|
if (window.__pinokioMainSidebarMobileInit) return;
|
|
127
321
|
window.__pinokioMainSidebarMobileInit = true;
|
|
128
322
|
|
|
129
323
|
const html = document.documentElement;
|
|
130
324
|
const toggle = document.querySelector("[data-main-sidebar-toggle]");
|
|
325
|
+
const mobileHomeToggle = document.querySelector("body.main-sidebar-page > header.navheader .home");
|
|
131
326
|
const backdrop = document.querySelector("[data-main-sidebar-backdrop]");
|
|
132
|
-
const mobileMq = window.matchMedia("(max-width:
|
|
327
|
+
const mobileMq = window.matchMedia("(max-width: 768px)");
|
|
133
328
|
|
|
134
329
|
if (!body || !html || !sidebar || !toggle || !backdrop) return;
|
|
135
330
|
|
|
136
331
|
const sync = () => {
|
|
137
332
|
const open = body.classList.contains("main-sidebar-mobile-open");
|
|
138
333
|
toggle.setAttribute("aria-expanded", open ? "true" : "false");
|
|
334
|
+
if (mobileHomeToggle) {
|
|
335
|
+
if (mobileMq.matches) {
|
|
336
|
+
const label = open ? "Close navigation" : "Open navigation";
|
|
337
|
+
mobileHomeToggle.setAttribute("role", "button");
|
|
338
|
+
mobileHomeToggle.setAttribute("aria-controls", "main-sidebar");
|
|
339
|
+
mobileHomeToggle.setAttribute("aria-expanded", open ? "true" : "false");
|
|
340
|
+
mobileHomeToggle.setAttribute("aria-label", label);
|
|
341
|
+
mobileHomeToggle.setAttribute("title", label);
|
|
342
|
+
} else {
|
|
343
|
+
mobileHomeToggle.removeAttribute("role");
|
|
344
|
+
mobileHomeToggle.removeAttribute("aria-controls");
|
|
345
|
+
mobileHomeToggle.removeAttribute("aria-expanded");
|
|
346
|
+
mobileHomeToggle.removeAttribute("aria-label");
|
|
347
|
+
mobileHomeToggle.removeAttribute("title");
|
|
348
|
+
}
|
|
349
|
+
}
|
|
139
350
|
const icon = toggle.querySelector("i");
|
|
140
351
|
if (icon) {
|
|
141
352
|
icon.classList.toggle("fa-bars", !open);
|
|
@@ -157,14 +368,28 @@
|
|
|
157
368
|
sync();
|
|
158
369
|
};
|
|
159
370
|
|
|
160
|
-
|
|
371
|
+
const toggleMobileSidebar = () => {
|
|
161
372
|
if (body.classList.contains("main-sidebar-mobile-open")) {
|
|
162
373
|
close();
|
|
163
374
|
} else {
|
|
164
375
|
open();
|
|
165
376
|
}
|
|
377
|
+
};
|
|
378
|
+
|
|
379
|
+
toggle.addEventListener("click", () => {
|
|
380
|
+
toggleMobileSidebar();
|
|
166
381
|
});
|
|
167
382
|
|
|
383
|
+
if (mobileHomeToggle) {
|
|
384
|
+
mobileHomeToggle.addEventListener("click", (event) => {
|
|
385
|
+
if (!mobileMq.matches) {
|
|
386
|
+
return;
|
|
387
|
+
}
|
|
388
|
+
event.preventDefault();
|
|
389
|
+
toggleMobileSidebar();
|
|
390
|
+
});
|
|
391
|
+
}
|
|
392
|
+
|
|
168
393
|
backdrop.addEventListener("click", close);
|
|
169
394
|
|
|
170
395
|
sidebar.addEventListener("click", (event) => {
|