feat(shell): add header minimize toggle for more viewport space
Adds a [^] chevron button at the right end of the tab row that collapses all header bars into a thin 24px restore strip. State persists via localStorage across page reloads. Works on both desktop (fixed) and mobile (sticky) layouts. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
7fec0cb699
commit
36ae954da4
|
|
@ -318,6 +318,7 @@ 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>
|
||||
|
|
@ -352,6 +353,14 @@ export function renderShell(opts: ShellOptions): string {
|
|||
window.__rspaceInstallPrompt = () => { e.prompt(); return e.userChoice; };
|
||||
window.dispatchEvent(new CustomEvent("rspace-install-available"));
|
||||
});
|
||||
// ── 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');
|
||||
});
|
||||
// ── Settings panel toggle (close history first) ──
|
||||
document.getElementById('settings-btn')?.addEventListener('click', () => {
|
||||
document.querySelector('rstack-history-panel')?.close();
|
||||
|
|
@ -1533,6 +1542,7 @@ 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">
|
||||
|
|
@ -1555,6 +1565,15 @@ 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)}';
|
||||
|
|
|
|||
|
|
@ -326,8 +326,6 @@ body {
|
|||
|
||||
/* ── Sidebar push offsets ── */
|
||||
|
||||
.rstack-tab-row,
|
||||
#app,
|
||||
rstack-user-dashboard,
|
||||
.rspace-iframe-wrap,
|
||||
#toolbar {
|
||||
|
|
@ -489,3 +487,79 @@ body.rstack-sidebar-open #toolbar {
|
|||
.hover-reveal { opacity: 0.5 !important; }
|
||||
.hover-reveal:active { opacity: 1 !important; }
|
||||
}
|
||||
|
||||
/* ── Header minimize toggle ── */
|
||||
|
||||
.rapp-minimize-btn {
|
||||
display: flex; align-items: center; justify-content: center;
|
||||
width: 28px; height: 28px; padding: 0; margin-right: 2px;
|
||||
background: none; border: 1px solid transparent; border-radius: 6px;
|
||||
color: var(--rs-text-muted); cursor: pointer; flex-shrink: 0;
|
||||
transition: color 0.15s, background 0.15s, border-color 0.15s;
|
||||
}
|
||||
.rapp-minimize-btn:hover {
|
||||
color: var(--rs-text-primary); background: var(--rs-bg-hover); border-color: var(--rs-border);
|
||||
}
|
||||
.rapp-minimize-btn svg {
|
||||
transition: transform 0.25s ease;
|
||||
}
|
||||
body.rspace-headers-minimized .rapp-minimize-btn svg {
|
||||
transform: rotate(180deg);
|
||||
}
|
||||
|
||||
/* Minimized state: slide header up, shrink tab row to 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;
|
||||
}
|
||||
body.rspace-headers-minimized #app {
|
||||
padding-top: 24px;
|
||||
}
|
||||
body.rspace-headers-minimized #app.canvas-layout {
|
||||
padding-top: 24px;
|
||||
}
|
||||
body.rspace-headers-minimized .rapp-subnav {
|
||||
top: 25px;
|
||||
}
|
||||
|
||||
/* Smooth transitions for header minimize/restore */
|
||||
.rstack-header {
|
||||
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;
|
||||
}
|
||||
#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;
|
||||
}
|
||||
body.rspace-headers-minimized .rapp-subnav {
|
||||
top: auto;
|
||||
}
|
||||
.rapp-minimize-btn { display: flex; } /* keep visible on mobile unlike info btn */
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue