feat: restructure settings into identity, server, backup and advanced tabs
Drops the per-server pin list down to the one server your account is bound to, adds an enforced network timeout, and replaces the global status toast inside settings with inline feedback and a reusable confirm dialog for rotate/log out. Mail-fetching preferences move into the server tab; the now-superseded claim/recall forms are gone since onboarding covers both.
This commit is contained in:
parent
fb0ca5c8cc
commit
84397a3fdd
6 changed files with 270 additions and 334 deletions
118
web/index.html
118
web/index.html
|
|
@ -152,9 +152,9 @@
|
|||
</form>
|
||||
</dialog>
|
||||
|
||||
<!-- Tabs, not one scroll: the account, the server, a mailbox preference, the
|
||||
backup file and the irreversible operations have nothing to say to each
|
||||
other, and reading all five at once was the overwhelming part. -->
|
||||
<!-- Tabs, not one scroll: identity, server, the backup file and the
|
||||
irreversible operations have nothing to say to each other, and reading
|
||||
all four at once was the overwhelming part. -->
|
||||
<dialog id="settings">
|
||||
<header class="dialog-head">
|
||||
<h2>settings</h2>
|
||||
|
|
@ -164,97 +164,85 @@
|
|||
|
||||
<div class="settings-body">
|
||||
<nav id="settings-tabs" class="settings-tabs" aria-label="settings sections">
|
||||
<button type="button" data-tab="account" class="active" aria-current="true">account</button>
|
||||
<button type="button" data-tab="identity" class="active" aria-current="true">identity</button>
|
||||
<button type="button" data-tab="server">server</button>
|
||||
<button type="button" data-tab="mail">mail</button>
|
||||
<button type="button" data-tab="data">backup</button>
|
||||
<button type="button" data-tab="backup">backup</button>
|
||||
<button type="button" data-tab="advanced">advanced</button>
|
||||
</nav>
|
||||
|
||||
<div id="settings-panels" class="settings-panels">
|
||||
<section class="panel" data-panel="account">
|
||||
<div id="account-card"></div>
|
||||
|
||||
<details id="account-claim">
|
||||
<summary id="account-claim-summary">claim your address</summary>
|
||||
<p class="hint">Pick a username on a server you have pinned. This is what people write to.</p>
|
||||
<form id="register-form">
|
||||
<label>address<input name="address" placeholder="alice@example.org" spellcheck="false" required></label>
|
||||
<label>invite token<input name="token" placeholder="only if your server asks"></label>
|
||||
<button class="filled">register</button>
|
||||
</form>
|
||||
<p class="hint">Already registered this identity in another browser? Look the address up
|
||||
instead — this checks it resolves to this identity and claims nothing.</p>
|
||||
<form id="recall-form">
|
||||
<label>address<input name="address" placeholder="alice@example.org" spellcheck="false" required></label>
|
||||
<button>look it up</button>
|
||||
</form>
|
||||
</details>
|
||||
<section class="panel" data-panel="identity">
|
||||
<div id="identity-fields"></div>
|
||||
|
||||
<h3>recovery secret</h3>
|
||||
<div id="identity-card"></div>
|
||||
<div id="identity-secret"></div>
|
||||
</section>
|
||||
|
||||
<section class="panel" data-panel="server" hidden>
|
||||
<h3>your server</h3>
|
||||
<p class="hint">Pinning a server's public key is what lets this client tell your real server
|
||||
from anything pretending to be it. Ask its operator for the key over a channel you already
|
||||
trust.</p>
|
||||
<details>
|
||||
<summary>why does this matter?</summary>
|
||||
<p class="hint">Nothing else authenticates the server, so an unpinned host could be anyone —
|
||||
registering, looking up an address and fetching all refuse to run against one.</p>
|
||||
</details>
|
||||
<ul id="pins" class="kv"></ul>
|
||||
<form id="pin-form">
|
||||
<label>host<input name="host" placeholder="example.org" spellcheck="false" required></label>
|
||||
<label>public key<input name="key" placeholder="base32" spellcheck="false" required></label>
|
||||
<button class="filled">pin</button>
|
||||
</form>
|
||||
</section>
|
||||
<h3>connection</h3>
|
||||
<div id="server-connection"></div>
|
||||
|
||||
<section class="panel" data-panel="mail" hidden>
|
||||
<h3>fetching</h3>
|
||||
<label class="check-row">
|
||||
<input type="checkbox" id="leave-on-server">
|
||||
<span>
|
||||
<span class="check-title">leave mail on server</span>
|
||||
<span class="hint">Keep a copy on the server after fetching, so another browser can
|
||||
fetch it too. Deleting a message here removes it from both.</span>
|
||||
<span class="check-title">Leave mail on server</span>
|
||||
<span class="hint">Keep a copy on the server after fetching, so another client can fetch
|
||||
it too. When this is enabled, deleting a message removes it from this client and the
|
||||
server.</span>
|
||||
</span>
|
||||
</label>
|
||||
<details>
|
||||
<summary>what happens by default?</summary>
|
||||
<p class="hint">Fetching acknowledges each message once it has been verified, and the server
|
||||
drops its copy — so mail you have read lives only in this browser. Back it up under
|
||||
"backup", or turn the option above on.</p>
|
||||
</details>
|
||||
</section>
|
||||
|
||||
<section class="panel" data-panel="data" hidden>
|
||||
<h3>backup & transfer</h3>
|
||||
<p class="hint">One file holding your mail, contacts and pinned servers — for moving to
|
||||
another browser, or for keeping what the server no longer has.</p>
|
||||
<div class="backup-row">
|
||||
<button type="button" id="export-data" class="filled">export</button>
|
||||
<button type="button" id="import-data-trigger" class="outline">import</button>
|
||||
<section class="panel" data-panel="backup" hidden>
|
||||
<p class="hint">One file holding your mail, contacts and server info for moving to another
|
||||
client, or for keeping what the server no longer has. It is sealed to this identity and
|
||||
deliberately leaves the secret itself out.</p>
|
||||
<div class="action-row">
|
||||
<button type="button" id="export-data" class="filled">Export</button>
|
||||
<span class="hint">Write a backup file</span>
|
||||
</div>
|
||||
<div class="action-row">
|
||||
<button type="button" id="import-data-trigger" class="outline">Import</button>
|
||||
<span class="hint">Restore from a backup file</span>
|
||||
<input id="import-data" type="file" accept="application/json" hidden>
|
||||
</div>
|
||||
<details>
|
||||
<summary>what is in the file, and is it safe?</summary>
|
||||
<p class="hint">It is sealed to this identity: only a browser with this secret restored can
|
||||
open it. It deliberately leaves the secret itself out — that belongs in a password
|
||||
manager, not in a file in your downloads folder.</p>
|
||||
</details>
|
||||
<span id="backup-error" class="error"></span>
|
||||
</section>
|
||||
|
||||
<section class="panel" data-panel="advanced" hidden>
|
||||
<div id="advanced-card"></div>
|
||||
<h3>rotations</h3>
|
||||
<p id="rotations-description" class="hint">Issues a fresh key from your secret with a signed
|
||||
certificate proving it replaces this one. Contacts accept the change from that chain, and
|
||||
the old key stays readable. Rotation is not revocation.</p>
|
||||
<div id="rotations-count"></div>
|
||||
<button type="button" id="rotate-identity" class="outline">Rotate identity</button>
|
||||
<span id="rotate-error" class="error"></span>
|
||||
|
||||
<h3 class="danger-head">log out</h3>
|
||||
<p id="logout-description" class="hint">Removes this identity from this client entirely: the
|
||||
secret, pins, contacts and every cached message. Without a backup of the secret there is no
|
||||
way back in. Mail already fetched here may have no other copy anywhere, unless "leave mail on
|
||||
server" was on. Whatever is still on the server comes back on the first fetch after logging
|
||||
back in.</p>
|
||||
<button type="button" id="logout" class="danger">Log out and delete all data</button>
|
||||
<span id="logout-error" class="error"></span>
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
</dialog>
|
||||
|
||||
<dialog id="confirm">
|
||||
<div class="confirm-body">
|
||||
<h2 id="confirm-title"></h2>
|
||||
<p id="confirm-text"></p>
|
||||
</div>
|
||||
<footer>
|
||||
<button type="button" id="confirm-cancel" autofocus>Cancel</button>
|
||||
<button type="button" id="confirm-ok"></button>
|
||||
</footer>
|
||||
</dialog>
|
||||
|
||||
<div id="status" class="toast" role="status" aria-live="polite" hidden></div>
|
||||
<script type="module" src="js/app.js"></script>
|
||||
</body>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue