Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 53 additions & 4 deletions frontend/ChatLayout.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,63 @@
import { SidebarProvider } from '@/frontend/components/ui/sidebar';
import {
SidebarProvider,
SidebarTrigger, // Import SidebarTrigger for the Sidebar opening and closing
Sidebar,
SidebarInset, //Import SidebarInset as the main content wrapper
useSidebar, // Import useSidebar to conditionally render the trigger
} from '@/frontend/components/ui/sidebar';

import ChatSidebar from '@/frontend/components/ChatSidebar';
import { Outlet } from 'react-router';
import { Button } from '@/frontend/components/ui/button';
import { PanelLeftIcon } from 'lucide-react';
import { cn } from '@/lib/utils';

export default function ChatLayout() {
return (
<SidebarProvider>
<ChatSidebar />
<div className="flex-1 relative">
<Outlet />
<div className="flex min-h-svh w-full">
<ChatSidebar />
<SidebarInset className="relative flex-1">
{/*
This is the global toggle button.
It's placed *outside* the ChatSidebar, ensuring it's always visible
even when the main sidebar is off-screen.
*/}
<GlobalSidebarToggleButton />

<Outlet />
</SidebarInset>
</div>
</SidebarProvider>
);
}

/**
* A standalone component for the sidebar toggle button.
* It uses the sidebar context to determine its visibility and action.
* Renders fixed, ensuring it's always accessible.
*/
function GlobalSidebarToggleButton() {
const { toggleSidebar, open, isMobile } = useSidebar();

const isButtonVisible = isMobile || !open;

if (!isButtonVisible) {
return null;
}

return (
<Button
variant="ghost"
size="icon"
onClick={toggleSidebar} // Calls the context function to toggle
className={cn(
'fixed top-4 z-50',
'left-4',
)}
aria-label="Toggle Sidebar"
>
<PanelLeftIcon className="size-4" />
</Button>
);
}