From 6c225590d9cbb5af4ff052a0bac7466885104aa0 Mon Sep 17 00:00:00 2001 From: Jeff Emmett Date: Fri, 27 Feb 2026 17:09:28 -0800 Subject: [PATCH] feat: standardize canvas header to match renderShell (MI bar, welcome, Try Demo) Canvas.html now has full parity with the shell header used by all other rApps: - Register RStackMi so the MI bar actually works on canvas - Add "Try Demo" button, welcome overlay for first-time demo visitors - Add iframe detection (rspace-embedded), auth-change listener, auto-space resolution Co-Authored-By: Claude Opus 4.6 --- website/canvas.html | 165 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 165 insertions(+) diff --git a/website/canvas.html b/website/canvas.html index 039c452..3e587ab 100644 --- a/website/canvas.html +++ b/website/canvas.html @@ -5,6 +5,14 @@ rSpace Canvas + + +
@@ -683,6 +761,7 @@
@@ -694,6 +773,33 @@

+ + +
@@ -894,13 +1000,24 @@ import { RStackAppSwitcher } from "@shared/components/rstack-app-switcher"; import { RStackSpaceSwitcher } from "@shared/components/rstack-space-switcher"; import { RStackTabBar } from "@shared/components/rstack-tab-bar"; + import { RStackMi } from "@shared/components/rstack-mi"; import { rspaceNavUrl } from "@shared/url-helpers"; + // Expose URL helper globally (matches shell.js) + window.__rspaceNavUrl = rspaceNavUrl; + // Register shell header components RStackIdentity.define(); RStackAppSwitcher.define(); RStackSpaceSwitcher.define(); RStackTabBar.define(); + RStackMi.define(); + + // Reload space list when user signs in/out + document.addEventListener("auth-change", () => { + const sw = document.querySelector("rstack-space-switcher"); + sw?.reload?.(); + }); // Load module list for app switcher fetch("/api/modules").then(r => r.json()).then(data => { @@ -1038,6 +1155,54 @@ tabBar.setAttribute("space", communitySlug); } + // ── "Try Demo" button visibility ── + // Hide on demo space, show on bare domain + (function() { + var btn = document.querySelector('.rstack-header__demo-btn'); + if (!btn) return; + if (communitySlug === 'demo') btn.setAttribute('data-hide', ''); + var host = window.location.host.split(':')[0]; + if (host === 'rspace.online' || host === 'www.rspace.online') { + btn.removeAttribute('data-hide'); + } + })(); + + // ── Auto-space resolution (logged-in users on demo → personal space) ── + (function() { + try { + var raw = localStorage.getItem('encryptid_session'); + if (!raw) return; + var session = JSON.parse(raw); + if (!session || !session.claims || !session.claims.username) return; + if (communitySlug !== 'demo') return; + fetch('/api/spaces/auto-provision', { + method: 'POST', + headers: { + 'Authorization': 'Bearer ' + session.accessToken, + 'Content-Type': 'application/json' + } + }).then(function(r) { return r.json(); }) + .then(function(data) { + if (data.slug) { + window.location.replace(rspaceNavUrl(data.slug, 'rspace')); + } + }).catch(function() {}); + } catch(e) {} + })(); + + // ── Welcome overlay (first visit to demo) ── + (function() { + if (communitySlug !== 'demo') return; + if (localStorage.getItem('rspace_welcomed')) return; + var el = document.getElementById('rspace-welcome'); + if (el) el.style.display = 'flex'; + })(); + window.__rspaceDismissWelcome = function() { + localStorage.setItem('rspace_welcomed', '1'); + var el = document.getElementById('rspace-welcome'); + if (el) el.style.display = 'none'; + }; + const canvas = document.getElementById("canvas"); const canvasContent = document.getElementById("canvas-content"); const status = document.getElementById("status");