From c67ec8195dc662fe2ddd5386c29d722965030f51 Mon Sep 17 00:00:00 2001 From: Rishabh Date: Thu, 21 May 2026 12:32:25 +0530 Subject: [PATCH 1/2] feat: add mobile responsive layout for default theme Sidebar becomes slide-out drawer on <768px with backdrop overlay. Desktop sub-nav replaced with mobile header (hamburger + logo + search + theme switcher). Sidebar closes on navigation. Content padding and spacing reduced for mobile. Co-Authored-By: Claude Opus 4.6 (1M context) --- .../src/themes/default/Layout.module.css | 86 +++++++++++++++++++ .../chronicle/src/themes/default/Layout.tsx | 29 ++++++- .../src/themes/default/Page.module.css | 14 +++ 3 files changed, 127 insertions(+), 2 deletions(-) diff --git a/packages/chronicle/src/themes/default/Layout.module.css b/packages/chronicle/src/themes/default/Layout.module.css index f5fcef2..bcbf194 100644 --- a/packages/chronicle/src/themes/default/Layout.module.css +++ b/packages/chronicle/src/themes/default/Layout.module.css @@ -279,3 +279,89 @@ line-height: var(--rs-line-height-mini); flex-shrink: 0; } + +.mobileMenuBtn { + display: none; +} + +.backdrop { + display: none; +} + +.mobileHeader { + display: none; +} + +.desktopOnly { + display: flex; +} + +@media (max-width: 768px) { + .sidebar { + position: fixed; + top: 0; + left: 0; + z-index: 100; + height: 100vh; + transform: translateX(-100%); + transition: transform 0.25s ease; + } + + .sidebar[data-mobile-open='true'] { + transform: translateX(0); + } + + .backdrop { + display: none; + position: fixed; + inset: 0; + z-index: 99; + background: rgba(0, 0, 0, 0.4); + } + + .backdrop[data-visible='true'] { + display: block; + } + + .mobileHeader { + display: flex; + align-items: center; + justify-content: space-between; + height: var(--navbar-height); + padding: 0 var(--rs-space-5); + background: var(--rs-color-background-base-primary); + border-bottom: 0.5px solid var(--rs-color-border-base-primary); + } + + .mobileMenuBtn { + display: flex; + align-items: center; + justify-content: center; + background: none; + border: none; + cursor: pointer; + padding: var(--rs-space-2); + color: var(--rs-color-foreground-base-primary); + } + + .desktopOnly { + display: none; + } + + .subNav { + display: none; + } + + .content { + padding: var(--rs-space-5) var(--rs-space-5); + } + + .card { + border-left: none; + box-shadow: none; + } + + .cardWrapper { + padding: 0; + } +} diff --git a/packages/chronicle/src/themes/default/Layout.tsx b/packages/chronicle/src/themes/default/Layout.tsx index faa9a51..5b9472d 100644 --- a/packages/chronicle/src/themes/default/Layout.tsx +++ b/packages/chronicle/src/themes/default/Layout.tsx @@ -4,7 +4,8 @@ import { CodeBracketSquareIcon, RectangleStackIcon, DocumentTextIcon, - Squares2X2Icon + Squares2X2Icon, + Bars3Icon } from '@heroicons/react/24/outline'; import { Flex, IconButton, Button, Sidebar } from '@raystack/apsara'; import { PlayIcon } from '@radix-ui/react-icons'; @@ -70,6 +71,7 @@ export function Layout({ const navigate = useNavigate(); const { page, version } = usePageContext(); const scrollRef = useRef(null); + const [mobileSidebarOpen, setMobileSidebarOpen] = useState(false); const isApiRoute = pathname === '/apis' || pathname.startsWith('/apis/'); const isApiBase = (basePath: string) => pathname === basePath || pathname.startsWith(`${basePath}/`); @@ -106,16 +108,39 @@ export function Layout({ requestAnimationFrame(() => { el.scrollTop = savedScrollTop; }); + setMobileSidebarOpen(false); }, [pathname]); return ( +
setMobileSidebarOpen(false)} + /> +
+ + + + + + {config.search?.enabled && } + + +
{hideSidebar ? null : ( @@ -187,7 +212,7 @@ export function Layout({
-