feat(layout): migrate to full-width topbar with mobile drawer navigation

Move topbar outside the grid container as a standalone sticky header
(Shopify/Stripe pattern). Sidebar and icon bar use position:sticky
relative to topbar height. Mobile uses drawer pattern with backdrop,
focus trap, ESC close, and scroll lock. Tenant branding moved from
sidebar header into the topbar.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-04-06 22:21:39 +02:00
parent fe88e748a3
commit a3f270408b
13 changed files with 543 additions and 340 deletions

View File

@@ -83,63 +83,13 @@
display: none !important;
}
.app-sidebar.is-collapsed .app-sidebar-panels,
.app-sidebar.is-collapsed .app-sidebar-titlebar,
.sidebar-collapsed .app-sidebar .app-sidebar-titlebar,
.sidebar-collapsed .app-sidebar .app-sidebar-panels {
display: none;
}
.app-sidebar-tenant-logo {
display: flex;
align-items: center;
justify-content: space-between;
gap: var(--app-sidebar-gap);
padding: var(--app-spacing);
margin-bottom: var(--app-spacing);
}
.app-sidebar .app-sidebar-tenant-logo a:hover {
background: transparent;
border: 0;
}
.app-sidebar .app-sidebar-tenant-logo > a {
padding: 0;
flex: 1;
border: 0;
text-decoration: none;
}
.app-sidebar .app-sidebar-tenant-logo img {
display: block;
max-width: 100%;
max-height: 48px;
width: auto;
height: auto;
object-fit: contain;
}
.app-sidebar-tenant-toggle {
display: none;
border: 1px solid var(--app-border);
background: transparent;
margin: 0;
}
.app-sidebar-tenant-toggle:hover {
color: var(--app-contrast);
border-color: var(--app-contrast);
}
.app-sidebar-tenant-name {
font-weight: var(--font-semibold);
font-size: var(--text-base);
color: var(--app-contrast);
text-align: left;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
@media (min-width: 768px) {
.app-sidebar.is-collapsed .app-sidebar-panels,
.app-sidebar.is-collapsed .app-sidebar-titlebar,
.sidebar-collapsed .app-sidebar .app-sidebar-titlebar,
.sidebar-collapsed .app-sidebar .app-sidebar-panels {
display: none;
}
}
.app-sidebar-title {
@@ -180,33 +130,64 @@
.app-sidebar {
position: sticky;
top: 0;
top: var(--app-topbar-height);
align-self: start;
z-index: 1;
height: 100vh;
height: calc(100dvh - var(--app-topbar-height));
overflow-y: auto;
}
.app-sidebar-panels {
padding-block-start: var(--app-spacing);
}
}
@media (max-width: 767px) {
.app-sidebar-tenant-toggle {
display: inline-flex;
align-items: center;
justify-content: center;
}
.app-sidebar-tenant-logo img {
max-width: 120px;
max-height: 40px;
flex-shrink: 0;
}
.app-sidebar {
border-bottom: 1px solid var(--app-border);
position: fixed;
top: var(--app-topbar-height);
left: 0;
bottom: 0;
width: min(280px, 85vw);
z-index: var(--z-drawer);
transform: translateX(-100%);
transition: transform 300ms ease;
background: var(--app-sidebar-background-color);
overflow-y: auto;
}
.drawer-open .app-sidebar {
transform: translateX(0);
}
.app-sidebar-panels {
padding-block-end: var(--app-spacing);
padding-block-start: calc(
var(--app-icon-bar-item-padding, 0.6875rem) * 2
+ var(--app-icon-bar-item-size, 22px)
+ var(--app-icon-bar-border-width, 3px)
);
padding-block-end: calc(var(--app-spacing) + env(safe-area-inset-bottom));
}
}
/* ── Drawer backdrop ── */
.app-drawer-backdrop {
display: none;
position: fixed;
inset: 0;
top: var(--app-topbar-height);
z-index: var(--z-drawer-backdrop);
background: rgba(0, 0, 0, 0.5);
}
.drawer-open .app-drawer-backdrop {
display: block;
}
html.drawer-open {
overflow: hidden;
}
.app-sidebar a {
color: inherit;
display: block;
@@ -215,7 +196,6 @@
margin: 0;
border-left: var(--app-sidebar-border-width) solid transparent;
width: 100%;
font-size: var(--text-base);
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;
@@ -226,7 +206,8 @@
.app-sidebar .active > a {
color: var(--app-nav-icon-color, var(--app-primary));
background: var(--app-sidebar-hover-bg);
border-left: var(--app-sidebar-border-width) solid var(--app-nav-icon-color, var(--app-primary));
border-left: var(--app-sidebar-border-width) solid
var(--app-nav-icon-color, var(--app-primary));
}
aside.app-sidebar ul,
@@ -321,7 +302,7 @@
details
> ul
li:last-child {
margin-bottom: 0.35rem;
margin-bottom: 1rem;
}
.app-sidebar .app-sidebar-group details > ul li:first-child {