eleven / ocho Public

web: the sidebar heading is the space's name (#1014)

* web: show the space's name above Chats in the sidebar header

The sidebar header now says WHERE you are: the space's name renders as a
small muted line above the bold Chats heading, next to the profile avatar.
The line mirrors document.title โ€” served substituted via __GROUP_NAME__ and
corrected at runtime when sealed branding decrypts or the name is edited โ€”
via a paintSpaceName() helper called after every title update. Web-only by
nature: the native apps hide the web sidebar and draw their own.

Co-Authored-By: Claude <noreply@anthropic.com>

* web: the sidebar heading IS the space's name (drop the Chats label)

Change of plan from the two-line stack: the space's name replaces the
Chats heading outright, reusing the title's existing ellipsis so the
sidebar width never depends on the name. style.css returns to exactly
its pre-branch rule.

Co-Authored-By: Claude <noreply@anthropic.com>

---------
Co-authored-by: Claude <noreply@anthropic.com>
James Adam 835a661aed1b9d7ee9c27d826527350437481c54 parent 19b8e74
3 files changed, +26 −3
  • changelog/2026-07-15-space-name-in-sidebar.md +3 −0
  • web/pages/index.html +3 −1
  • web/static/shell.js +20 −2
diff --git a/changelog/2026-07-15-space-name-in-sidebar.md b/changelog/2026-07-15-space-name-in-sidebar.md
new file mode 100644
index 0000000..f330cab
--- /dev/null
+++ b/changelog/2026-07-15-space-name-in-sidebar.md
@@ -0,0 +1,3 @@
+๐Ÿค– The heading at the top of the sidebar is now your space's name instead of
+"Chats", so you can always see at a glance which space you're in โ€” handy if
+you're a member of more than one.
diff --git a/web/pages/index.html b/web/pages/index.html
index 48f4aa1..ed7ef8f 100644
--- a/web/pages/index.html
+++ b/web/pages/index.html
@@ -127,7 +127,9 @@
<button class="avatar-btn" id="me-btn" aria-label="Edit profile" title="Edit profile">
<span class="avatar" id="me-avatar"></span>
</button>
- <div class="title">Chats</div>
+ <!-- The heading is the space's name, so the top of the sidebar says WHERE
+ you are โ€” kept in step with document.title (sealed branding updates both). -->
+ <div class="title" id="side-space-name">__GROUP_NAME__</div>
<div class="head-actions">
<div class="menu-wrap">
<button class="icon-btn" id="menu-btn" aria-label="Menu" aria-haspopup="true">โ‹ฎ</button>
diff --git a/web/static/shell.js b/web/static/shell.js
index cf5df70..1773bdc 100644
--- a/web/static/shell.js
+++ b/web/static/shell.js
@@ -624,6 +624,17 @@ async function bootstrapBranding() {
}
}
if (sealedBranding && sealedBranding.name) document.title = sealedBranding.name;
+ paintSpaceName();
+}
+
+// paintSpaceName: the sidebar heading IS the space's name (it ellipsizes, so
+// the sidebar width never depends on it). document.title is the one source of
+// the name on this page (served substituted, corrected at runtime when sealed
+// branding decrypts), so the heading just mirrors it โ€” call after every
+// document.title update.
+function paintSpaceName() {
+ const el = document.getElementById("side-space-name");
+ if (el) el.textContent = document.title;
}
// resealBranding: the sealed counterpart of saveGroupSettings โ€” merge the
@@ -649,7 +660,10 @@ async function resealBranding(patch) {
});
if (r.ok) {
setSealedBranding(next);
- if (next.name) document.title = next.name;
+ if (next.name) {
+ document.title = next.name;
+ paintSpaceName();
+ }
}
return r.ok ? "ok" : r.status === 400 ? "invalid" : "error";
} catch {
@@ -2557,6 +2571,7 @@ async function onInstanceKeyReady() {
function renderApp() {
app.innerHTML = "";
app.appendChild(tpl("app-tpl"));
+ paintSpaceName(); // the template carries the served name; sealed branding may already have corrected the title
document.getElementById("new-chat").onclick = showNewChat;
document.getElementById("back-btn").onclick = showList;
@@ -4988,7 +5003,10 @@ async function saveGroupSettings(patch) {
...patch,
};
const r = await fetch("/api/admin/group", { method: "POST", headers: adminAuth(), body: JSON.stringify(body) });
- if (r.ok && patch.name) document.title = patch.name; // header text updates on next load
+ if (r.ok && patch.name) {
+ document.title = patch.name;
+ paintSpaceName();
+ }
return r.ok ? "ok" : r.status === 400 ? "invalid" : "error";
} catch {
return "error";