pinokiod 8.2.34 → 8.2.35
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/package.json +1 -1
- package/server/views/anywhere.ejs +30 -52
- package/test/anywhere-onboarding.test.js +15 -13
package/package.json
CHANGED
|
@@ -38,31 +38,15 @@ body.dark .anywhere-card { border-color: rgba(255,255,255,0.1); background: rgba
|
|
|
38
38
|
.anywhere-card h3 { margin: 18px 0 6px; font-size: 13px; text-transform: uppercase; letter-spacing: 0.04em; opacity: 0.7; }
|
|
39
39
|
.anywhere-card p { margin: 6px 0; line-height: 1.5; }
|
|
40
40
|
.anywhere-muted { opacity: 0.7; font-size: 13px; }
|
|
41
|
-
.anywhere-
|
|
42
|
-
@media (max-width: 900px) { .anywhere-
|
|
43
|
-
.anywhere-
|
|
44
|
-
|
|
45
|
-
.anywhere-
|
|
46
|
-
|
|
47
|
-
.anywhere-
|
|
48
|
-
.anywhere-
|
|
49
|
-
.anywhere-
|
|
50
|
-
.anywhere-segments span:hover { opacity: 1; }
|
|
51
|
-
.anywhere-segments input:checked + span { background: white; font-weight: bold; opacity: 1; box-shadow: 0 1px 3px rgba(0,0,0,0.12); }
|
|
52
|
-
body.dark .anywhere-segments input:checked + span { background: rgba(255,255,255,0.16); box-shadow: none; }
|
|
53
|
-
.anywhere-segments input:focus-visible + span { outline: 2px solid currentColor; outline-offset: 1px; }
|
|
54
|
-
#anywhere-connect[data-device=phone] [data-panel=computer], #anywhere-connect[data-device=computer] [data-panel=phone] { display: none; }
|
|
55
|
-
#anywhere-connect [data-panel] { display: flex; flex-direction: column; align-items: center; gap: 14px; width: 100%; }
|
|
56
|
-
#anywhere-connect [data-panel] p { margin: 0; max-width: 360px; font-size: 15px; line-height: 1.5; }
|
|
57
|
-
#anywhere-connect [data-panel=computer] { padding-top: 10px; }
|
|
58
|
-
.anywhere-warning { padding: 10px 14px; border-radius: 8px; background: rgba(255,140,0,0.14); font-size: 13px; line-height: 1.5; margin: 16px 0 0; }
|
|
59
|
-
.anywhere-warning a { color: inherit; }
|
|
60
|
-
.anywhere-connect-card { max-width: 440px; padding: 22px 24px 24px; }
|
|
61
|
-
.anywhere-connect-title { text-align: center; font-size: 17px; margin: 0 0 14px; }
|
|
62
|
-
.anywhere-qr { display: flex; flex-direction: column; align-items: center; gap: 14px; text-align: center; }
|
|
63
|
-
.anywhere-qr img { width: 212px; height: 212px; border-radius: 14px; background: white; padding: 12px; border: 1px solid rgba(0,0,0,0.08); margin-top: 4px; }
|
|
64
|
-
body.dark .anywhere-qr img { border-color: transparent; }
|
|
65
|
-
.anywhere-qr > .anywhere-muted { font-size: 12px; margin-top: 2px; }
|
|
41
|
+
.anywhere-connect { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; align-items: stretch; }
|
|
42
|
+
@media (max-width: 900px) { .anywhere-connect { grid-template-columns: 1fr; } }
|
|
43
|
+
.anywhere-device-card { display: flex; flex-direction: column; align-items: center; justify-content: flex-start; gap: 12px; text-align: center; padding: 22px 24px 24px; }
|
|
44
|
+
.anywhere-device-icon { font-size: 32px; line-height: 1; opacity: 0.7; margin-bottom: -2px; }
|
|
45
|
+
.anywhere-device-card h2 { font-size: 17px; margin: 0; }
|
|
46
|
+
.anywhere-device-card p { margin: 0; max-width: 360px; font-size: 15px; line-height: 1.5; }
|
|
47
|
+
.anywhere-device-card img { width: 212px; height: 212px; border-radius: 14px; background: white; padding: 12px; border: 1px solid rgba(0,0,0,0.08); }
|
|
48
|
+
body.dark .anywhere-device-card img { border-color: transparent; }
|
|
49
|
+
.anywhere-account-line { display: flex; justify-content: space-between; align-items: center; gap: 12px; flex-wrap: wrap; margin: 14px 0 18px; }
|
|
66
50
|
.anywhere-address {
|
|
67
51
|
font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
|
|
68
52
|
font-size: 15px; word-break: break-all;
|
|
@@ -225,31 +209,29 @@ document.addEventListener('DOMContentLoaded', function() {
|
|
|
225
209
|
|
|
226
210
|
<div class='anywhere-state' data-state='ready'>
|
|
227
211
|
<div class='anywhere-warning' id='anywhere-expiry-warning' hidden></div>
|
|
228
|
-
<div class='anywhere-
|
|
229
|
-
<div class='anywhere-card anywhere-
|
|
230
|
-
<
|
|
231
|
-
<
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
<div id='anywhere-copy-status' class='anywhere-muted' role='status' aria-live='polite'></div>
|
|
245
|
-
<div id='anywhere-copy-manual' class='anywhere-copy-manual' hidden>
|
|
246
|
-
<input id='anywhere-copy-value' type='text' readonly aria-label='Remote link' aria-describedby='anywhere-copy-status'>
|
|
247
|
-
</div>
|
|
248
|
-
</div>
|
|
249
|
-
<div class='anywhere-muted'>signed in as <b id='anywhere-account'></b> · <button type='button' class='anywhere-signout' data-action='logout'>Sign out</button></div>
|
|
250
|
-
<div class='anywhere-waiting' id='anywhere-waiting'><i class="fa-solid fa-circle-notch fa-spin"></i> Waiting for another device to join…</div>
|
|
212
|
+
<div class='anywhere-connect' id='anywhere-connect'>
|
|
213
|
+
<div class='anywhere-card anywhere-device-card'>
|
|
214
|
+
<i class='fa-solid fa-mobile-screen anywhere-device-icon' aria-hidden='true'></i>
|
|
215
|
+
<h2>Connect a phone or tablet</h2>
|
|
216
|
+
<p>Scan with your phone. It walks you through the rest.</p>
|
|
217
|
+
<img id='anywhere-qr' alt='QR code to connect' src=''>
|
|
218
|
+
</div>
|
|
219
|
+
<div class='anywhere-card anywhere-device-card'>
|
|
220
|
+
<i class='fa-solid fa-laptop anywhere-device-icon' aria-hidden='true'></i>
|
|
221
|
+
<h2>Connect another computer</h2>
|
|
222
|
+
<p>Open this link on the other computer. It walks you through installing Tailscale and signing in as <b class='anywhere-account-inline'></b>, then opens this Pinokio.</p>
|
|
223
|
+
<div class='anywhere-address'><a id='anywhere-address' href='#' target='_blank' rel='noopener'></a></div>
|
|
224
|
+
<p><button type='button' class='anywhere-btn secondary anywhere-copy' id='anywhere-copy' disabled><i class='fa-regular fa-copy' aria-hidden='true'></i> Copy link</button></p>
|
|
225
|
+
<div id='anywhere-copy-status' class='anywhere-muted' role='status' aria-live='polite'></div>
|
|
226
|
+
<div id='anywhere-copy-manual' class='anywhere-copy-manual' hidden>
|
|
227
|
+
<input id='anywhere-copy-value' type='text' readonly aria-label='Remote link' aria-describedby='anywhere-copy-status'>
|
|
251
228
|
</div>
|
|
252
229
|
</div>
|
|
230
|
+
</div>
|
|
231
|
+
<div class='anywhere-account-line'>
|
|
232
|
+
<span class='anywhere-muted'>signed in as <b id='anywhere-account'></b> · <button type='button' class='anywhere-signout' data-action='logout'>Sign out</button></span>
|
|
233
|
+
<div class='anywhere-waiting' id='anywhere-waiting'><i class="fa-solid fa-circle-notch fa-spin"></i> Waiting for another device to join…</div>
|
|
234
|
+
</div>
|
|
253
235
|
<div id='anywhere-details' hidden>
|
|
254
236
|
<div class='anywhere-card'>
|
|
255
237
|
<h2>Running apps</h2>
|
|
@@ -275,7 +257,6 @@ document.addEventListener('DOMContentLoaded', function() {
|
|
|
275
257
|
</p>
|
|
276
258
|
</div>
|
|
277
259
|
</div>
|
|
278
|
-
</div>
|
|
279
260
|
</div>
|
|
280
261
|
|
|
281
262
|
</div>
|
|
@@ -525,9 +506,6 @@ document.addEventListener('DOMContentLoaded', function() {
|
|
|
525
506
|
openExternal(link.href)
|
|
526
507
|
}
|
|
527
508
|
})
|
|
528
|
-
for (const input of document.querySelectorAll('input[name=anywhere-device]')) {
|
|
529
|
-
input.addEventListener('change', () => { document.getElementById('anywhere-connect').dataset.device = input.value })
|
|
530
|
-
}
|
|
531
509
|
switchEl.addEventListener('click', () => {
|
|
532
510
|
if (switchEl.dataset.on === 'true') {
|
|
533
511
|
act('stop')
|
|
@@ -36,22 +36,24 @@ test('before any device joins, the ready state is the connect card alone, with s
|
|
|
36
36
|
const h = render(t, { phase: 'ready', peers: [] })
|
|
37
37
|
const card = h.document.querySelector('[data-state=ready] .anywhere-card')
|
|
38
38
|
assert.equal(h.document.getElementById('anywhere-details').hidden, true, 'apps, devices and details wait for a device')
|
|
39
|
-
assert.ok(
|
|
39
|
+
assert.ok(h.document.querySelector('.anywhere-account-line .anywhere-signout[data-action=logout]'), 'a wrong-account sign-in is fixable during onboarding')
|
|
40
40
|
assert.ok(!h.document.querySelector('#anywhere-details [data-action=logout]'), 'sign out lives with the account, not in details')
|
|
41
41
|
assert.equal(card.querySelectorAll('ol, h3').length, 0, 'no step lists on the desk: the phone page explains Tailscale after the scan')
|
|
42
42
|
const connect = h.document.getElementById('anywhere-connect')
|
|
43
|
-
|
|
44
|
-
assert.
|
|
45
|
-
const
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
assert.
|
|
51
|
-
|
|
52
|
-
assert.
|
|
53
|
-
|
|
54
|
-
assert.equal(
|
|
43
|
+
const cards = connect.querySelectorAll('.anywhere-device-card')
|
|
44
|
+
assert.equal(cards.length, 2, 'both ways in, side by side, nothing behind a toggle')
|
|
45
|
+
for (const card of cards) {
|
|
46
|
+
const icon = card.querySelector('.anywhere-device-icon')
|
|
47
|
+
assert.ok(icon, 'each card leads with its own icon row')
|
|
48
|
+
assert.strictEqual(icon.nextElementSibling.tagName, 'H2')
|
|
49
|
+
}
|
|
50
|
+
assert.match(cards[0].textContent, /Connect a phone or tablet.*Scan with your phone\./s)
|
|
51
|
+
assert.ok(cards[0].querySelector('#anywhere-qr'))
|
|
52
|
+
assert.match(cards[1].textContent, /Connect another computer.*installing Tailscale and signing in as me@example\.com/s)
|
|
53
|
+
const link = cards[1].querySelector('#anywhere-address')
|
|
54
|
+
assert.equal(link.getAttribute('href'), connectUrl, 'the same link the QR carries')
|
|
55
|
+
assert.equal(link.textContent, 'pinokio.co/anywhere/connect#…')
|
|
56
|
+
assert.equal(h.document.querySelector('.anywhere-segments'), null)
|
|
55
57
|
assert.match(h.text('anywhere-waiting'), /Waiting for another device/)
|
|
56
58
|
assert.equal(h.document.getElementById('anywhere-expiry-warning').hidden, true)
|
|
57
59
|
})
|