fix(collab): embed online badge in tab row instead of fixed overlay

The "N online" collab badge was position:fixed at top:8px, overlapping
the header login area. Move it into the tab bar slot (main shell) or
header-right section (standalone shells) so it flows inline with other
chrome elements.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Jeff Emmett 2026-03-23 18:19:29 -07:00
parent 51be476694
commit 0c46e33148
2 changed files with 10 additions and 16 deletions

View File

@ -251,6 +251,7 @@ export function renderShell(opts: ShellOptions): string {
</header>
<div class="rstack-tab-row">
<rstack-tab-bar space="${escapeAttr(spaceSlug)}" active="" view-mode="flat">
<rstack-collab-overlay module-id="${escapeAttr(moduleId)}" space="${escapeAttr(spaceSlug)}"></rstack-collab-overlay>
<button class="rapp-info-btn" id="rapp-info-btn" title="About this rApp"><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><line x1="12" y1="16" x2="12" y2="12"/><line x1="12" y1="8" x2="12.01" y2="8"/></svg></button>
</rstack-tab-bar>
</div>
@ -271,7 +272,6 @@ export function renderShell(opts: ShellOptions): string {
${opts.tabs ? renderTabBar(opts.tabs, opts.activeTab, opts.tabBasePath || ((opts.isSubdomain ?? IS_PRODUCTION) ? `/${escapeAttr(moduleId)}` : `/${escapeAttr(spaceSlug)}/${escapeAttr(moduleId)}`)) : ''}
${body}
</main>
<rstack-collab-overlay module-id="${escapeAttr(moduleId)}" space="${escapeAttr(spaceSlug)}"></rstack-collab-overlay>
${renderWelcomeOverlay()}
@ -1409,7 +1409,9 @@ export function renderExternalAppShell(opts: ExternalAppShellOptions): string {
</div>
</header>
<div class="rstack-tab-row">
<rstack-tab-bar space="${escapeAttr(spaceSlug)}" active="" view-mode="flat"></rstack-tab-bar>
<rstack-tab-bar space="${escapeAttr(spaceSlug)}" active="" view-mode="flat">
<rstack-collab-overlay module-id="${escapeAttr(moduleId)}" space="${escapeAttr(spaceSlug)}" mode="badge-only"></rstack-collab-overlay>
</rstack-tab-bar>
</div>
<div class="rspace-iframe-wrap">
<div class="rspace-iframe-loading" id="iframe-loading">
@ -1426,7 +1428,6 @@ export function renderExternalAppShell(opts: ExternalAppShellOptions): string {
></iframe>
<a class="rspace-iframe-newtab" href="${escapeAttr(appUrl)}" target="_blank" rel="noopener">Open in new tab </a>
</div>
<rstack-collab-overlay module-id="${escapeAttr(moduleId)}" space="${escapeAttr(spaceSlug)}" mode="badge-only"></rstack-collab-overlay>
<script type="module">
import '/shell.js';
@ -2012,11 +2013,11 @@ export function renderModuleLanding(opts: ModuleLandingOptions): string {
<rstack-mi></rstack-mi>
</div>
<div class="rstack-header__right">
<rstack-collab-overlay module-id="${escapeAttr(mod.id)}" mode="badge-only"></rstack-collab-overlay>
<rstack-identity></rstack-identity>
</div>
</header>
${bodyContent}
<rstack-collab-overlay module-id="${escapeAttr(mod.id)}" mode="badge-only"></rstack-collab-overlay>
<script type="module">
import '/shell.js';
if ("serviceWorker" in navigator && location.hostname !== "localhost") {
@ -2359,11 +2360,11 @@ export function renderSubPageInfo(opts: SubPageInfoOptions): string {
<rstack-mi></rstack-mi>
</div>
<div class="rstack-header__right">
<rstack-collab-overlay module-id="${escapeAttr(mod.id)}" mode="badge-only"></rstack-collab-overlay>
<rstack-identity></rstack-identity>
</div>
</header>
${bodyContent}
<rstack-collab-overlay module-id="${escapeAttr(mod.id)}" mode="badge-only"></rstack-collab-overlay>
<script type="module">
import '/shell.js';
if ("serviceWorker" in navigator && location.hostname !== "localhost") {

View File

@ -441,20 +441,13 @@ export class RStackCollabOverlay extends HTMLElement {
const OVERLAY_CSS = `
:host {
display: block;
position: fixed;
top: 0;
left: 0;
width: 0;
height: 0;
z-index: 9999;
display: inline-flex;
align-items: center;
pointer-events: none;
position: relative;
}
.collab-badge {
position: fixed;
top: 8px;
right: 80px;
display: none;
align-items: center;
gap: 4px;
@ -468,9 +461,9 @@ const OVERLAY_CSS = `
pointer-events: auto;
cursor: pointer;
user-select: none;
z-index: 10000;
border: 1px solid var(--rs-border, rgba(255,255,255,0.08));
transition: opacity 0.2s, border-color 0.2s;
white-space: nowrap;
}
.collab-badge:hover {