Spaces:
Running
Running
import React, { useState, useEffect } from "react"; | |
import URDFViewer from "../URDFViewer"; | |
import { Sidebar, SidebarBody } from "@/components/ui/sidebar"; | |
import { LayoutDashboard, PanelLeft, RotateCcw } from "lucide-react"; | |
import { useUrdf } from "@/hooks/useUrdf"; | |
import { Button } from "../ui/button"; | |
import { useTheme } from "@/hooks/useTheme"; | |
import RobotParameters from "../RobotParameters"; | |
// Calculate header height - should match your Header component height | |
const HEADER_HEIGHT = 0; // in pixels - adjust if your header is different | |
const Layout: React.FC = () => { | |
const [open, setOpen] = useState(true); | |
const { theme } = useTheme(); | |
// Use the centralized UrdfContext for all robot data | |
const { | |
currentRobotData, | |
isDefaultModel, | |
resetToDefaultModel, | |
isSelectionModalOpen, | |
} = useUrdf(); | |
// Log when robot data changes to verify the component is re-rendering | |
useEffect(() => { | |
console.log("Layout: Robot data updated", { | |
isDefaultModel, | |
hasData: !!currentRobotData, | |
name: currentRobotData?.name, | |
}); | |
}, [isDefaultModel, currentRobotData]); | |
// Only set the initial state of the sidebar once | |
useEffect(() => { | |
setOpen(true); | |
}, []); | |
// If there's a selection modal open, render a simplified layout | |
if (isSelectionModalOpen) { | |
return ( | |
<div className="absolute inset-0 overflow-hidden"> | |
{/* Main content that fills the container */} | |
<div className="w-full h-full"> | |
<URDFViewer /> | |
</div> | |
</div> | |
); | |
} | |
return ( | |
<div className="relative w-full h-full overflow-hidden"> | |
{/* Main content that fills the container */} | |
<div className="w-full h-full"> | |
<URDFViewer /> | |
</div> | |
{/* Sidebar positioned above with z-index, with top padding for header */} | |
<div | |
className="absolute inset-y-0 left-0 z-10" | |
style={{ paddingTop: `${HEADER_HEIGHT}px` }} | |
> | |
{open ? ( | |
<Sidebar open={open} setOpen={setOpen} animate={true}> | |
<SidebarBody className="justify-between gap-10"> | |
<div className="flex flex-col flex-1 overflow-y-auto overflow-x-hidden"> | |
<div className="flex items-center justify-between mb-4 mt-2 px-2"> | |
<h2 className="text-xl font-bold tracking-tight font-mono overflow-x-auto whitespace-nowrap scrollbar-none max-w-[200px] pr-2"> | |
{currentRobotData?.name || "Robot Model"} | |
</h2> | |
<div className="flex items-center space-x-2"> | |
{!isDefaultModel && ( | |
<Button | |
variant="ghost" | |
size="icon" | |
onClick={resetToDefaultModel} | |
className={`rounded-full ${ | |
theme === "dark" | |
? "bg-gray-700 hover:bg-gray-600" | |
: "bg-white/80 hover:bg-white" | |
}`} | |
aria-label="Reset to default model" | |
> | |
<RotateCcw className="h-4 w-4" /> | |
<span className="sr-only">Reset to default model</span> | |
</Button> | |
)} | |
<Button | |
variant="ghost" | |
size="icon" | |
onClick={() => setOpen(false)} | |
className={`rounded-full ${ | |
theme === "dark" | |
? "bg-gray-700 hover:bg-gray-600" | |
: "bg-white/80 hover:bg-white" | |
}`} | |
> | |
<PanelLeft className="h-4 w-4" /> | |
<span className="sr-only">Close sidebar</span> | |
</Button> | |
</div> | |
</div> | |
<div className="px-2"> | |
<p className="text-muted-foreground font-mono text-xs"> | |
{currentRobotData?.description || | |
"A detailed 3D model of a robotic system with articulated joints and components."} | |
</p> | |
<div className="sidebar-divider" /> | |
<RobotParameters /> | |
</div> | |
</div> | |
</SidebarBody> | |
</Sidebar> | |
) : ( | |
<div | |
className="flex flex-col items-center justify-center" | |
style={{ paddingTop: `${HEADER_HEIGHT}px` }} | |
> | |
<div | |
className={`flex items-center justify-center hover:bg-muted/80 cursor-pointer rounded-md p-2 m-2 ${"bg-gray-700"} shadow-sm`} | |
onClick={() => setOpen(true)} | |
> | |
<div className="flex items-center space-x-1"> | |
<PanelLeft className="h-4 w-4" /> | |
</div> | |
</div> | |
</div> | |
)} | |
</div> | |
</div> | |
); | |
}; | |
export default Layout; | |