refactor(layout): floating sidebar + floating top header #113

Merged
varutasu merged 1 commit from redesign-v2-floating-chrome into main 2026-06-04 13:07:17 -04:00
2 changed files with 44 additions and 13 deletions

View file

@ -664,7 +664,18 @@ export default function Layout({ children, user = null, showSearch = false }) {
}, []); }, []);
return ( return (
<div className="flex h-screen"> // Outer shell — `md:p-4 md:gap-4` pulls both the sidebar and the
// main column in from the viewport edges so the sidebar and the
// top header read as floating chrome chips (operator feedback
// 2026-06-04: "pull out the left nav to make it look like it is
// its own floating section versus attached to the top-left"). The
// `md:gap-4` on this row also creates the visible page-body
// background between the sidebar's right edge and the main
// column, which replaces the previous hard divider — "all feels
// like one large page" is achieved by the hearth gradient
// showing through the gap. Mobile (< 768px) keeps the current
// flush layout because the sidebar is `hidden md:flex` anyway.
<div className="flex h-screen md:p-4 md:gap-4">
{/* Mobile Navigation - Bottom bar for mobile */} {/* Mobile Navigation - Bottom bar for mobile */}
<MobileNavigation <MobileNavigation
onMenuOpen={() => setIsMobileMenuOpen(true)} onMenuOpen={() => setIsMobileMenuOpen(true)}
@ -815,14 +826,21 @@ export default function Layout({ children, user = null, showSearch = false }) {
{/* Desktop Sidebar - Hidden on mobile. Liquid Glass mid-tint, ambient {/* Desktop Sidebar - Hidden on mobile. Liquid Glass mid-tint, ambient
elevation + rim-light edges; the page background visibly cools elevation + rim-light edges; the page background visibly cools
through the rail. */} through the rail. 2026-06-04 floating-chrome pass: rounded-3xl
+ overflow-hidden so the rail reads as its own floating chip;
`var(--rim-light-outer)` dropped from the box-shadow stack
because that 1px outer ring was the "vertical divider between
the sidebar and the right side" the operator wanted gone. The
chip's edge is now defined solely by `var(--elevation-ambient)`
(drop shadow) + the glass-surface-mid tint against the body
gradient that shows through `md:gap-4` on the outer flex. */}
<div <div
className="hidden md:flex md:static inset-y-0 left-0 w-64" className="hidden md:flex md:static inset-y-0 left-0 w-64 md:rounded-3xl md:overflow-hidden"
style={{ style={{
background: 'var(--glass-surface-mid)', background: 'var(--glass-surface-mid)',
backdropFilter: 'blur(var(--glass-blur-mid)) saturate(var(--glass-saturate))', backdropFilter: 'blur(var(--glass-blur-mid)) saturate(var(--glass-saturate))',
WebkitBackdropFilter: 'blur(var(--glass-blur-mid)) saturate(var(--glass-saturate))', WebkitBackdropFilter: 'blur(var(--glass-blur-mid)) saturate(var(--glass-saturate))',
boxShadow: 'var(--rim-light-inner), var(--rim-light-outer), var(--elevation-ambient)', boxShadow: 'var(--rim-light-inner), var(--elevation-ambient)',
}} }}
> >
<div className="p-4 h-full flex flex-col w-full"> <div className="p-4 h-full flex flex-col w-full">
@ -933,8 +951,14 @@ export default function Layout({ children, user = null, showSearch = false }) {
</div> </div>
</div> </div>
{/* Main Content */} {/* Main Content. `md:gap-4` adds vertical breathing room between
<div className="flex-1 flex flex-col pb-16 md:pb-0"> the floating TopSearchBar header and the page content so they
read as two distinct floating chrome elements over the body
gradient (rather than the header sitting flush against the
content). `min-w-0` prevents flex children from blowing past
the column width when long card titles or table cells refuse
to wrap. */}
<div className="flex-1 flex flex-col pb-16 md:pb-0 md:gap-4 min-w-0">
{/* Global top bar redesign-v2 sub-convoy #3 (2026-06-04). {/* Global top bar redesign-v2 sub-convoy #3 (2026-06-04).
Rendered for ALL authenticated pages so the search + Rendered for ALL authenticated pages so the search +
notifications + user-menu chrome is consistent everywhere notifications + user-menu chrome is consistent everywhere

View file

@ -62,17 +62,24 @@ export default function TopSearchBar({
return ( return (
<header <header
className="px-4 sm:px-6 py-3 flex items-center gap-3 sm:gap-4" // Floating-chrome pass 2026-06-04: `md:rounded-2xl` so the bar
// reads as its own floating chip on desktop (Layout's
// `md:p-4 md:gap-4` puts visible body gradient on all four sides
// of it). Mobile keeps square corners since the header runs
// edge-to-edge there. The shadow stack pairs `rim-light-inner`
// (subtle top inset highlight kept from the prior pass) with
// `elevation-ambient` (drop shadow) so it floats over the body
// gradient. We deliberately did NOT add `rim-light-outer` here:
// the operator's "remove the divider" feedback from the prior
// pass applies to any visible 1px edge, and a hairline outer
// ring would re-introduce one on mobile where the bar abuts
// content directly.
className="px-4 sm:px-6 py-3 flex items-center gap-3 sm:gap-4 md:rounded-2xl"
style={{ style={{
background: 'var(--glass-surface-mid)', background: 'var(--glass-surface-mid)',
backdropFilter: 'blur(12px) saturate(180%)', backdropFilter: 'blur(12px) saturate(180%)',
WebkitBackdropFilter: 'blur(12px) saturate(180%)', WebkitBackdropFilter: 'blur(12px) saturate(180%)',
// The hairline border-bottom (`0 1px 0 var(--border)`) was boxShadow: 'var(--rim-light-inner), var(--elevation-ambient)',
// removed 2026-06-04 per operator feedback ("almost looks
// seamless between that header and the rest of that page
// content"). The rim-light-inner highlight stays so the bar
// still reads as elevated chrome against the gradient body.
boxShadow: 'var(--rim-light-inner)',
}} }}
> >
{/* Search affordance read-only-ish input that opens the {/* Search affordance read-only-ish input that opens the