From 5b5af8414d150412cb8157bd88ff467edb4af3ad Mon Sep 17 00:00:00 2001 From: Cristian Edwards Date: Sun, 22 Mar 2026 12:21:54 +0100 Subject: [PATCH] feat: mobile slide-in drawers for sidebar and inspector panels On screens <=1100px, sidebar and inspector panels now appear as slide-in overlay drawers instead of being hidden. Floating toggle buttons (bottom-left for sidebar, bottom-right for inspector) open each panel. A backdrop overlay allows dismissing with a tap. --- src/app/layout/AppShell.tsx | 43 +++++++++++++++++++++-- src/styles/globals.css | 69 ++++++++++++++++++++++++++++++++++++- 2 files changed, 108 insertions(+), 4 deletions(-) diff --git a/src/app/layout/AppShell.tsx b/src/app/layout/AppShell.tsx index 34a8c2b..7618980 100644 --- a/src/app/layout/AppShell.tsx +++ b/src/app/layout/AppShell.tsx @@ -1,4 +1,4 @@ -import type { PropsWithChildren, ReactNode } from 'react'; +import { useState, type PropsWithChildren, type ReactNode } from 'react'; interface AppShellProps extends PropsWithChildren { toolbar: ReactNode; @@ -8,13 +8,50 @@ interface AppShellProps extends PropsWithChildren { } export default function AppShell({ toolbar, sidebar, inspector, statusbar, children }: AppShellProps) { + const [mobilePanel, setMobilePanel] = useState<'sidebar' | 'inspector' | null>(null); + + function togglePanel(panel: 'sidebar' | 'inspector') { + setMobilePanel((prev) => (prev === panel ? null : panel)); + } + return (
{toolbar}
- +
{children}
- +
{statusbar}
+ + {/* Mobile toggle buttons — visible only on narrow screens via CSS */} + + + + {/* Backdrop to close panel when tapping canvas area */} + {mobilePanel && ( +
setMobilePanel(null)} /> + )}
); } \ No newline at end of file diff --git a/src/styles/globals.css b/src/styles/globals.css index 224ae8a..561181d 100644 --- a/src/styles/globals.css +++ b/src/styles/globals.css @@ -1137,13 +1137,80 @@ select:focus-visible { gap: 8px; padding: 8px; } + + /* Panels become fixed overlays, hidden by default */ .app-shell__sidebar, .app-shell__inspector { - display: none; + position: fixed; + top: 0; + bottom: 0; + width: min(300px, 80vw); + z-index: 200; + overflow-y: auto; + transition: transform 0.25s ease; + padding: 12px; + box-shadow: 0 0 40px rgba(0, 0, 0, 0.6); + background: + linear-gradient(168deg, rgba(255, 255, 255, 0.04) 0%, transparent 40%), + rgba(15, 23, 42, 0.95); + } + .app-shell__sidebar { + left: 0; + transform: translateX(-100%); + } + .app-shell__sidebar.is-open { + transform: translateX(0); + } + .app-shell__inspector { + right: 0; + transform: translateX(100%); + } + .app-shell__inspector.is-open { + transform: translateX(0); } + .app-shell__main { min-height: 50vh; } + + /* Backdrop */ + .mobile-panel-backdrop { + position: fixed; + inset: 0; + z-index: 199; + background: rgba(0, 0, 0, 0.4); + } + + /* Toggle buttons */ + .mobile-panel-toggle { + display: flex; + position: fixed; + bottom: 56px; + z-index: 201; + align-items: center; + justify-content: center; + width: 40px; + height: 40px; + border: 1px solid rgba(51, 65, 85, 0.6); + border-radius: 12px; + background: rgba(15, 23, 42, 0.85); + -webkit-backdrop-filter: blur(16px); + backdrop-filter: blur(16px); + color: rgba(226, 232, 240, 0.9); + cursor: pointer; + box-shadow: 0 4px 12px rgba(0, 0, 0, 0.4); + } + .mobile-panel-toggle--left { left: 12px; } + .mobile-panel-toggle--right { right: 12px; } + .mobile-panel-toggle:active { + background: rgba(15, 23, 42, 1); + } +} + +/* Hide toggle buttons on desktop */ +@media (min-width: 1101px) { + .mobile-panel-toggle { display: none; } + .mobile-panel-backdrop { display: none; } } @media (max-width: 640px) {