diff --git a/components/studio/layout/studio-layout.test.tsx b/components/studio/layout/studio-layout.test.tsx index b76a95c..7e2aa34 100644 --- a/components/studio/layout/studio-layout.test.tsx +++ b/components/studio/layout/studio-layout.test.tsx @@ -43,9 +43,16 @@ vi.mock("@/components/ui/sidebar", () => ({ {children} ), - SidebarRail: () => ( - ), + useSidebar: () => ({ + toggleSidebar: vi.fn(), + open: true, + isMobile: false + }) })) describe("StudioLayout", () => { @@ -64,7 +71,7 @@ describe("StudioLayout", () => { expect(screen.getByTestId("sidebar-content")).toBeInTheDocument() expect(screen.getByTestId("canvas-content")).toBeInTheDocument() - + // Check if SidebarProvider for left sidebar receives correct open prop const providers = screen.getAllByTestId("sidebar-provider") expect(providers[0]).toHaveAttribute("data-open", "true") @@ -81,12 +88,12 @@ describe("StudioLayout", () => { ) expect(screen.getByTestId("gallery-content")).toBeInTheDocument() - + // Check if nested SidebarProvider for gallery receives correct open prop const providers = screen.getAllByTestId("sidebar-provider") // Provider 0 is usually left, Provider 1 is inner/right expect(providers[1]).toHaveAttribute("data-open", "true") - + // Check if right sidebar is rendered const sidebars = screen.getAllByTestId("studio-gallery-panel") expect(sidebars.length).toBeGreaterThan(0) @@ -124,7 +131,7 @@ describe("StudioLayout", () => { ) @@ -144,4 +151,38 @@ describe("StudioLayout", () => { const layout = screen.getByTestId("studio-layout") expect(layout).toHaveClass("custom-class") }) + + it("renders mobile toggle buttons", () => { + render( + + ) + + // There should be two mobile triggers (left and right) + // We can find them by the Button (which renders as button) or the icon? + // Note: MobileMenuButton has sr-only text "Toggle Sidebar" + // But checking for 'md:hidden' class on the container or button is a good proxy for "mobile only" validity + + // Use getAllByRole to find buttons with "Toggle Sidebar" name + // We expect at least 2 (Left, Right) + Rails might have aria-label "Toggle Sidebar" too? + // The mock SidebarRail has aria-label="Toggle Sidebar". + // The real SidebarRail does too. + + // Let's look at the implementation. MobileMenuButton has Toggle Sidebar + // So they will be found. + + // Filter for the ones that are NOT the rails. + // The rails in our mock have data-testid="sidebar-rail". + // The mobile buttons do not have that test id, but they have class 'md:hidden' + + const buttons = screen.getAllByRole("button", { name: "Toggle Sidebar" }) + const mobileButtons = buttons.filter(b => b.classList.contains("md:hidden")) + + expect(mobileButtons.length).toBeGreaterThanOrEqual(2) + }) }) diff --git a/components/studio/layout/studio-layout.tsx b/components/studio/layout/studio-layout.tsx index d42713a..0b34fb4 100644 --- a/components/studio/layout/studio-layout.tsx +++ b/components/studio/layout/studio-layout.tsx @@ -11,8 +11,10 @@ import { SidebarInset, SidebarProvider, SidebarRail, + useSidebar, } from "@/components/ui/sidebar" -import { ChevronLeft, ChevronRight } from "lucide-react" +import { ChevronLeft, ChevronRight, PanelLeft, PanelRight } from "lucide-react" +import { Button } from "@/components/ui/button" import { cn } from "@/lib/utils" import * as React from "react" @@ -33,7 +35,7 @@ export interface StudioLayoutProps { onGalleryOpenChange?: (open: boolean) => void /** Additional class names */ className?: string - + // Legacy props - kept for compatibility but unused defaultSidebarSize?: number | string defaultGallerySize?: number | string @@ -42,6 +44,22 @@ export interface StudioLayoutProps { defaultLayout?: Record } +function MobileMenuButton({ side, className }: { side: "left" | "right", className?: string }) { + const { toggleSidebar } = useSidebar() + + return ( + + ) +} + export function StudioLayout({ sidebar, canvas, @@ -77,9 +95,9 @@ export function StudioLayout({ {sidebar} - +
-
+
@@ -87,6 +105,11 @@ export function StudioLayout({ + {/* Left Mobile Trigger - Top Left */} +
+ +
+ {/* Right Sidebar Provider (Nested) */} - -
- {canvas} -
-
+ + {/* Right Mobile Trigger - Top Right (only if gallery enabled) */} + {gallery && ( +
+ +
+ )} + +
+ {canvas} +
+
- {gallery && ( + {gallery && ( {gallery} - +
-
+
diff --git a/components/studio/layout/studio-shell.tsx b/components/studio/layout/studio-shell.tsx index ca16e71..aa1d0dd 100644 --- a/components/studio/layout/studio-shell.tsx +++ b/components/studio/layout/studio-shell.tsx @@ -478,7 +478,7 @@ export function StudioShell({ defaultLayout, initialGalleryPage }: StudioShellPr
{/* Generate / Pause / Resume Batch Button */} -
+
{batchMode.isBatchActive ? (