fix: always show Demo Space at top of space switcher dropdown

Adds a permanent "Demo Space" entry as the first item in the space
switcher dropdown across all rApps. Previously demo only appeared
in the "Public spaces" section (if the API returned it), making it
easy to miss. Now it's always visible at the top with a game
controller icon, followed by the sign-in/personal space CTA.

Also filters demo out of the "Public spaces" section to avoid
showing it twice.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Jeff Emmett 2026-03-04 17:29:04 -08:00
parent e954386489
commit 57fd1f4913
1 changed files with 20 additions and 4 deletions

View File

@ -131,8 +131,20 @@ export class RStackSpaceSwitcher extends HTMLElement {
return s.name;
}
#demoSpaceHTML(current: string, moduleId: string): string {
const isActive = current === "demo";
return `
<a class="item vis-public ${isActive ? "active" : ""}"
href="${rspaceNavUrl("demo", moduleId)}">
<span class="item-icon">🎮</span>
<span class="item-name">Demo Space</span>
<span class="item-vis vis-public">👁</span>
</a>`;
}
#renderMenu(menu: HTMLElement, current: string) {
const auth = isAuthenticated();
const moduleId = this.#getCurrentModule();
if (this.#spaces.length === 0) {
let cta = "";
@ -144,6 +156,8 @@ export class RStackSpaceSwitcher extends HTMLElement {
cta = this.#yourSpaceCTAhtml(label);
}
menu.innerHTML = `
${this.#demoSpaceHTML(current, moduleId)}
<div class="divider"></div>
${cta}
<div class="divider"></div>
<div class="menu-empty">
@ -157,17 +171,19 @@ export class RStackSpaceSwitcher extends HTMLElement {
return;
}
const moduleId = this.#getCurrentModule();
// 3-section split
// 3-section split — exclude demo from public since we show it separately
const mySpaces = this.#spaces.filter((s) => s.role);
const publicSpaces = this.#spaces.filter((s) => s.accessible !== false && !s.role);
const publicSpaces = this.#spaces.filter((s) => s.accessible !== false && !s.role && s.slug !== "demo");
const discoverSpaces = this.#spaces.filter((s) => s.accessible === false);
const hasOwnedSpace = mySpaces.some((s) => s.relationship === "owner");
let html = "";
// ── Demo Space — always first ──
html += this.#demoSpaceHTML(current, moduleId);
html += `<div class="divider"></div>`;
// ── Create personal space CTA — only if user has no owned spaces ──
if (!auth) {
html += this.#yourSpaceCTAhtml("Sign in to create →");