refactor(shell): move minimize chevron from tab row to subnav bar
The minimize toggle now lives at the right edge of each rApp's subnav bar instead of the tab row. When minimized, both header and tab row slide up and the subnav becomes a thin fixed strip with just the restore chevron. Every rApp already has a subnav (except canvas which has its own chrome). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
f6767ca841
commit
7888596623
|
|
@ -319,7 +319,6 @@ export function renderShell(opts: ShellOptions): string {
|
|||
<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>
|
||||
<button class="rapp-minimize-btn" id="header-minimize-btn" title="Minimize headers"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><polyline points="18 15 12 9 6 15"/></svg></button>
|
||||
</rstack-tab-bar>
|
||||
</div>
|
||||
<div id="rapp-info-overlay" class="rapp-info-overlay" style="display:none"></div>
|
||||
|
|
@ -1543,7 +1542,6 @@ export function renderExternalAppShell(opts: ExternalAppShellOptions): string {
|
|||
<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)}" mode="badge-only"></rstack-collab-overlay>
|
||||
<button class="rapp-minimize-btn" id="header-minimize-btn" title="Minimize headers"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><polyline points="18 15 12 9 6 15"/></svg></button>
|
||||
</rstack-tab-bar>
|
||||
</div>
|
||||
<div class="rspace-iframe-wrap">
|
||||
|
|
@ -1566,15 +1564,6 @@ export function renderExternalAppShell(opts: ExternalAppShellOptions): string {
|
|||
import '/shell.js';
|
||||
document.querySelector('rstack-app-switcher')?.setModules(${moduleListJSON});
|
||||
|
||||
// ── Header minimize toggle ──
|
||||
if (localStorage.getItem('rspace_headers_minimized') === '1') {
|
||||
document.body.classList.add('rspace-headers-minimized');
|
||||
}
|
||||
document.getElementById('header-minimize-btn')?.addEventListener('click', () => {
|
||||
const minimized = document.body.classList.toggle('rspace-headers-minimized');
|
||||
localStorage.setItem('rspace_headers_minimized', minimized ? '1' : '0');
|
||||
});
|
||||
|
||||
const tabBar = document.querySelector('rstack-tab-bar');
|
||||
const spaceSlug = '${escapeAttr(spaceSlug)}';
|
||||
const currentModuleId = '${escapeAttr(moduleId)}';
|
||||
|
|
@ -1982,6 +1971,7 @@ const INFO_PANEL_CSS = `
|
|||
const SUBNAV_CSS = `
|
||||
.rapp-subnav {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.375rem;
|
||||
padding: 0.5rem 1rem;
|
||||
overflow-x: auto;
|
||||
|
|
@ -2056,11 +2046,10 @@ function renderModuleSubNav(moduleId: string, spaceSlug: string, modules: Module
|
|||
}
|
||||
}
|
||||
|
||||
// Don't render if no sub-paths
|
||||
if (items.length === 0) return '';
|
||||
|
||||
const base = (isSubdomain ?? IS_PRODUCTION) ? `/${escapeAttr(moduleId)}` : `/${escapeAttr(spaceSlug)}/${escapeAttr(moduleId)}`;
|
||||
|
||||
const minimizeBtn = `<button class="rapp-minimize-btn" id="header-minimize-btn" title="Minimize headers"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><polyline points="18 15 12 9 6 15"/></svg></button>`;
|
||||
|
||||
const pills = [
|
||||
`<a class="rapp-nav-pill" href="${base}" data-subnav-root>${escapeHtml(mod.name)}</a>`,
|
||||
...items.map(it =>
|
||||
|
|
@ -2069,7 +2058,7 @@ function renderModuleSubNav(moduleId: string, spaceSlug: string, modules: Module
|
|||
...(mod.externalApp ? [`<a class="rapp-nav-pill rapp-nav-pill--external" href="${escapeAttr(mod.externalApp.url)}" target="_blank" rel="noopener">Open ${escapeHtml(mod.externalApp.name)} ↗</a>`] : []),
|
||||
];
|
||||
|
||||
return `<nav class="rapp-subnav" id="rapp-subnav">${pills.join('')}</nav>
|
||||
return `<nav class="rapp-subnav" id="rapp-subnav">${pills.join('')}${minimizeBtn}</nav>
|
||||
<script>(function(){var ps=document.querySelectorAll('#rapp-subnav .rapp-nav-pill'),p=location.pathname.replace(/\\/$/,'');var matched=false;ps.forEach(function(a){var h=a.getAttribute('href');if(h&&h===p){a.classList.add('rapp-nav-pill--active');matched=true}else if(h&&p.startsWith(h+'/')&&!a.hasAttribute('data-subnav-root')){a.classList.add('rapp-nav-pill--active');matched=true}});if(!matched){var root=document.querySelector('[data-subnav-root]');if(root)root.classList.add('rapp-nav-pill--active')}})()</script>`;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -488,13 +488,15 @@ body.rstack-sidebar-open #toolbar {
|
|||
.hover-reveal:active { opacity: 1 !important; }
|
||||
}
|
||||
|
||||
/* ── Header minimize toggle ── */
|
||||
/* ── Header minimize toggle (lives in .rapp-subnav) ── */
|
||||
|
||||
.rapp-minimize-btn {
|
||||
display: flex; align-items: center; justify-content: center;
|
||||
width: 28px; height: 28px; padding: 0; margin-right: 2px;
|
||||
width: 24px; height: 24px; padding: 0;
|
||||
margin-left: auto; /* push to right edge of subnav */
|
||||
flex-shrink: 0;
|
||||
background: none; border: 1px solid transparent; border-radius: 6px;
|
||||
color: var(--rs-text-muted); cursor: pointer; flex-shrink: 0;
|
||||
color: var(--rs-text-muted); cursor: pointer;
|
||||
transition: color 0.15s, background 0.15s, border-color 0.15s;
|
||||
}
|
||||
.rapp-minimize-btn:hover {
|
||||
|
|
@ -507,25 +509,29 @@ body.rspace-headers-minimized .rapp-minimize-btn svg {
|
|||
transform: rotate(180deg);
|
||||
}
|
||||
|
||||
/* Minimized state: slide header up, shrink tab row to thin restore strip */
|
||||
/* Minimized state: hide header + tab row, subnav becomes thin restore strip */
|
||||
body.rspace-headers-minimized .rstack-header {
|
||||
transform: translateY(-100%);
|
||||
pointer-events: none;
|
||||
}
|
||||
body.rspace-headers-minimized .rstack-tab-row {
|
||||
top: 0;
|
||||
height: 24px;
|
||||
overflow: hidden;
|
||||
justify-content: flex-end;
|
||||
transform: translateY(-100%);
|
||||
pointer-events: none;
|
||||
}
|
||||
body.rspace-headers-minimized #app {
|
||||
padding-top: 24px;
|
||||
padding-top: 0;
|
||||
}
|
||||
body.rspace-headers-minimized #app.canvas-layout {
|
||||
padding-top: 24px;
|
||||
padding-top: 0;
|
||||
}
|
||||
body.rspace-headers-minimized .rapp-subnav {
|
||||
top: 25px;
|
||||
position: fixed;
|
||||
top: 0; left: 0; right: 0;
|
||||
z-index: 9997;
|
||||
height: 28px;
|
||||
padding: 2px 8px;
|
||||
overflow: hidden;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
|
||||
/* Smooth transitions for header minimize/restore */
|
||||
|
|
@ -533,33 +539,27 @@ body.rspace-headers-minimized .rapp-subnav {
|
|||
transition: transform 0.25s ease;
|
||||
}
|
||||
.rstack-tab-row {
|
||||
transition: margin-left 0.25s ease, left 0.25s ease, top 0.25s ease, height 0.25s ease;
|
||||
transition: margin-left 0.25s ease, left 0.25s ease, transform 0.25s ease;
|
||||
}
|
||||
#app {
|
||||
transition: margin-left 0.25s ease, left 0.25s ease, padding-top 0.25s ease;
|
||||
}
|
||||
.rapp-subnav {
|
||||
transition: top 0.25s ease;
|
||||
}
|
||||
|
||||
/* Mobile: minimized state adjustments (sticky, not fixed) */
|
||||
@media (max-width: 640px) {
|
||||
body.rspace-headers-minimized .rstack-header {
|
||||
transform: translateY(-100%);
|
||||
max-height: 0;
|
||||
overflow: hidden;
|
||||
padding: 0;
|
||||
border: 0;
|
||||
}
|
||||
body.rspace-headers-minimized .rstack-tab-row {
|
||||
top: auto;
|
||||
height: 24px;
|
||||
}
|
||||
body.rspace-headers-minimized #app {
|
||||
padding-top: 0;
|
||||
max-height: 0;
|
||||
overflow: hidden;
|
||||
transform: none;
|
||||
}
|
||||
body.rspace-headers-minimized .rapp-subnav {
|
||||
top: auto;
|
||||
position: sticky;
|
||||
top: 0;
|
||||
}
|
||||
.rapp-minimize-btn { display: flex; } /* keep visible on mobile unlike info btn */
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue