eleven / messenger Public

home: last admin + owner — destroy becomes THE button, not a footnote link (#489)

When the space reports this is its only admin key AND this account
created it, 'Delete your access' was a permanently-disabled button with
a note pointing at a small 'Destroy the space for everyone…' link below
it — three competing elements for one possible action. Now that state
flips the whole step to the destroy framing: title 'Destroy this
space?', one red note naming the space and the consequence, and the
destroy action promoted into the primary button slot (same typed-host
arming + fresh-passkey ceremony). The other states are unchanged:
owner-not-sole-admin keeps the footnote link; sole-admin-not-owner keeps
the make-another-admin-first hold.
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Paul Campbell 4effd1c6f7cf1a3897332134dffd368b3250d663 parent 04a7a84
2 files changed, +36 −11
  • home/web/pages/index.html +9 −4
  • home/web/static/home.js +27 −7
diff --git a/home/web/pages/index.html b/home/web/pages/index.html
index 8bbd5f7..6f0d5e4 100644
--- a/home/web/pages/index.html
+++ b/home/web/pages/index.html
@@ -178,6 +178,9 @@
/* Archive screen. The list is quiet; the permanent delete is deliberately loud. */
#archive { text-align: center; }
#destroy-zone { margin-top: 20px; padding-top: 14px; border-top: 1px solid var(--border); }
+ /* When destroying is the only action (last admin + owner), the zone IS the
+ primary action — no footnote separator; the button sits where Delete did. */
+ #destroy-zone.primary { margin-top: 0; padding-top: 0; border-top: none; }
.danger-link { color: var(--danger); font-size: .9rem; }
.danger-link:disabled { opacity: .4; cursor: default; text-decoration: none; }
.danger-ink { color: var(--danger); }
@@ -465,8 +468,8 @@
<p class="create-sub">Checking with the space…</p>
</div>
<div id="archive-stern" class="hidden">
- <h2 class="create-title danger-ink">Delete your access?</h2>
- <p class="create-sub stern-copy">Deleting <b id="stern-name"></b> removes your only
+ <h2 class="create-title danger-ink" id="stern-title">Delete your access?</h2>
+ <p class="create-sub stern-copy" id="stern-intro">Deleting <b id="stern-name"></b> removes your only
saved way back into <b id="stern-host"></b>. If you're not signed in to it on
another device, you'll lose access <b>forever</b> — there will be no way back
in. <b>This cannot be undone.</b></p>
@@ -477,9 +480,11 @@
spellcheck="false" aria-label="Type the space address to confirm">
<button id="delete-access" type="button" class="btn-danger" disabled>Delete forever</button>
<!-- Owner-only, revealed once ownership is confirmed: also destroy the space
- itself, for everyone. Gated by the same typed confirmation + a passkey. -->
+ itself, for everyone. Gated by the same typed confirmation + a passkey.
+ When the last-admin hold engages too, destroying is the only real action
+ left, so home.js promotes this from a footnote link to THE button. -->
<div id="destroy-zone" class="hidden">
- <p class="create-sub stern-copy">You created this space, so you can also
+ <p class="create-sub stern-copy" id="destroy-note">You created this space, so you can also
<b>destroy it for everyone</b> — every message, photo, and member in it.</p>
<button id="destroy-forever" type="button" class="linkish danger-link" disabled>Destroy the space for everyone…</button>
</div>
diff --git a/home/web/static/home.js b/home/web/static/home.js
index e396d33..0a23fc1 100644
--- a/home/web/static/home.js
+++ b/home/web/static/home.js
@@ -867,19 +867,39 @@ function checkSoleAdmin(s) {
// updateSternHold renders what the checks learned: the destroy zone when this
// account owns the space, and the last-admin hold — "Delete your access" goes
-// (and stays) off, with the note saying why and what to do instead: destroy the
-// space below, or hand admin to someone else first.
+// (and stays) off. When BOTH hold (last admin of a space this account created),
+// destroying is the only real action left, so it isn't offered as a footnote
+// link under a dead button: the whole step flips to the destroy framing —
+// title, copy, and the destroy button promoted to the primary slot. Rendering
+// is declarative from the two flags, so straggling checks re-render cleanly.
function updateSternHold() {
+ const destroyOnly = sternSoleAdmin && sternDestroyable;
+ $("stern-title").textContent = destroyOnly ? "Destroy this space?" : "Delete your access?";
+ $("stern-intro").classList.toggle("hidden", destroyOnly);
+ $("delete-access").classList.toggle("hidden", destroyOnly);
$("destroy-zone").classList.toggle("hidden", !sternDestroyable);
+ $("destroy-zone").classList.toggle("primary", destroyOnly);
+ $("destroy-note").classList.toggle("hidden", destroyOnly);
+ const destroy = $("destroy-forever");
+ destroy.className = destroyOnly ? "btn-danger" : "linkish danger-link";
+ destroy.textContent = destroyOnly ? "Destroy the space for everyone" : "Destroy the space for everyone…";
const note = $("sole-admin-note");
if (!sternSoleAdmin) { note.classList.add("hidden"); return; }
- note.textContent = sternDestroyable
- ? "This is the space's only admin key. Deleting just your access would leave " +
- "the space running with no admin, forever — to actually shut it down, use " +
- "“Destroy the space for everyone” below instead."
- : "This is the space's only admin key. Deleting it would leave the space " +
+ if (destroyOnly) {
+ const host = Object.assign(document.createElement("b"), { textContent: $("stern-host").textContent });
+ const noUndo = Object.assign(document.createElement("b"), { textContent: "This cannot be undone." });
+ note.replaceChildren(
+ "This is the only admin key for ", host, " — deleting just your access would ",
+ "leave the space running with no admin, forever. You created it, so you can ",
+ "destroy the space for everyone instead: every message, photo, and member ",
+ "in it. ", noUndo,
+ );
+ } else {
+ note.textContent =
+ "This is the space's only admin key. Deleting it would leave the space " +
"running with no admin, forever. Make another member an admin first, then " +
"come back to delete your access.";
+ }
note.classList.remove("hidden");
$("delete-access").disabled = true;
}