fix(web): wire responsive sidebar — add toggle to AppShell, open prop on Sidebar, CSS !important overrides

This commit is contained in:
saravanakumardb1 2026-03-29 00:03:27 -07:00
parent e362f2aefe
commit 89edf59a4e
3 changed files with 48 additions and 13 deletions

View File

@ -239,22 +239,31 @@ button:active:not(:disabled), [role="button"]:active:not(:disabled) {
/* Responsive sidebar */
@media (max-width: 768px) {
.app-sidebar {
position: fixed;
left: -260px;
top: 0;
position: fixed !important;
left: -280px !important;
top: 0 !important;
z-index: 40;
width: 240px;
height: 100vh;
width: 260px !important;
height: 100vh !important;
transition: left 0.2s ease;
overflow-y: auto;
}
.app-sidebar.open { left: 0; }
.app-sidebar.open { left: 0 !important; }
.sidebar-overlay { display: none; position: fixed; inset: 0; z-index: 39; background: rgba(0,0,0,0.5); }
.sidebar-overlay.open { display: block; }
.sidebar-toggle { display: flex; }
.sidebar-toggle {
display: flex; align-items: center; justify-content: center;
position: fixed; top: 12px; left: 12px; z-index: 38;
width: 40px; height: 40px; border-radius: 8px;
border: 1px solid var(--nl-border-default, #2a2a4a);
background: var(--nl-bg-elevated, #12151c);
color: var(--nl-text-primary, #fff);
cursor: pointer; font-size: 20px; line-height: 1;
}
}
@media (min-width: 769px) {
.sidebar-toggle { display: none; }
.sidebar-overlay { display: none; }
.sidebar-toggle { display: none !important; }
.sidebar-overlay { display: none !important; }
}
/* Respect user motion preference */

View File

@ -1,4 +1,7 @@
import type { ReactNode } from "react";
"use client";
import { type ReactNode, useState, useCallback, useEffect } from "react";
import { usePathname } from "next/navigation";
import { Sidebar } from "@/components/Sidebar";
export function AppShell({
@ -12,12 +15,35 @@ export function AppShell({
actions?: ReactNode;
children: ReactNode;
}) {
const [sidebarOpen, setSidebarOpen] = useState(false);
const pathname = usePathname();
useEffect(() => {
setSidebarOpen(false);
}, [pathname]);
const toggle = useCallback(() => setSidebarOpen((o) => !o), []);
const close = useCallback(() => setSidebarOpen(false), []);
return (
<div className="app-shell">
<a href="#main-content" className="skip-link">
Skip to main content
</a>
<Sidebar />
<button
className="sidebar-toggle"
onClick={toggle}
aria-label={sidebarOpen ? "Close menu" : "Open menu"}
type="button"
>
{sidebarOpen ? "\u2715" : "\u2630"}
</button>
<div
className={`sidebar-overlay${sidebarOpen ? " open" : ""}`}
onClick={close}
aria-hidden="true"
/>
<Sidebar open={sidebarOpen} />
<main id="main-content" className="main-panel" tabIndex={-1} aria-labelledby="page-title">
<div className="page-grid">
<header

View File

@ -14,11 +14,11 @@ const navItems: { href: string; label: string; icon: typeof House; flag?: string
{ href: "/settings", label: "Settings", icon: Settings },
];
export function Sidebar() {
export function Sidebar({ open }: { open?: boolean }) {
const pathname = usePathname() ?? "";
return (
<aside className="sidebar" style={{ padding: "var(--nl-space-6)" }} aria-label="Primary">
<aside className={`sidebar app-sidebar${open ? ' open' : ''}`} style={{ padding: "var(--nl-space-6)" }} aria-label="Primary">
<div style={{ display: "grid", gap: "var(--nl-space-6)" }}>
<div className="surface-card" style={{ padding: "var(--nl-space-5)", display: "grid", gap: "var(--nl-space-3)" }}>
<div className="badge" style={{ width: "fit-content" }}>