build-container / build (push) Canceled after 4m16s
- Mobile-first PWA (phone tab bar with More menu, iPad/desktop rail) - Passkey (WebAuthn) sign-in gates the whole app; first passkey via setup code - Files: Seafile browse/upload/new doc/rename/move/share link/preview/delete - In-app OnlyOffice editing with JWT-signed configs and save-back to Seafile - Plex music player via plex.tv sign-in and a server-side proxy - Calendar agenda from private ICS links (recurrence + time zones) - Search, Home dashboard, webmail deep links, audiobooks frame - Dockerfile, compose, and a Gitea Actions workflow that builds the image Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
31 lines
1.6 KiB
JavaScript
31 lines
1.6 KiB
JavaScript
const $ = s => document.querySelector(s);
|
|
const fail = e => { $('#err').textContent = e && e.name === 'NotAllowedError' ? 'Cancelled. Try again.' : (e.message || String(e)); };
|
|
|
|
async function signIn() {
|
|
$('#err').textContent = '';
|
|
try { await passkeyLogin(); location.replace('/'); } catch (e) { fail(e); }
|
|
}
|
|
|
|
async function init() {
|
|
if (!window.PublicKeyCredential) { $('#sub').textContent = ''; return fail(new Error('This browser does not support passkeys.')); }
|
|
const st = await (await fetch('/api/auth/state')).json();
|
|
if (st.authed) return location.replace('/');
|
|
if (st.registered) {
|
|
$('#sub').textContent = 'Sign in with your passkey';
|
|
$('#ui').innerHTML = '<button class="btn" id="go">Sign in with passkey</button>';
|
|
$('#go').onclick = signIn;
|
|
signIn(); // prompt straight away; the button is there if it's dismissed
|
|
} else {
|
|
$('#sub').textContent = 'First-time setup: create a passkey for this device';
|
|
$('#ui').innerHTML = `<form id="f"><label for="sc">Setup code (from the server log or HUB_SETUP_CODE)</label>
|
|
<input type="text" id="sc" autocomplete="off" autocapitalize="off" required>
|
|
<label for="nm">Name this passkey</label><input type="text" id="nm" value="${/iPad|iPhone/.test(navigator.userAgent) ? 'iPhone/iPad' : 'This device'}" autocomplete="off">
|
|
<div class="bar"><button class="btn">Create passkey</button></div></form>`;
|
|
$('#f').onsubmit = async e => {
|
|
e.preventDefault(); $('#err').textContent = '';
|
|
try { await passkeyRegister($('#sc').value.trim(), $('#nm').value.trim() || 'Passkey'); location.replace('/'); } catch (err) { fail(err); }
|
|
};
|
|
}
|
|
}
|
|
init().catch(fail);
|