Skip to content

Commit f5b1a51

Browse files
committed
chore: fit dojo sidebar and chat width for mobile view
1 parent 487e3d0 commit f5b1a51

File tree

5 files changed

+112
-15
lines changed

5 files changed

+112
-15
lines changed

typescript-sdk/apps/dojo/src/app/[integrationId]/feature/agentic_chat/page.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ const Chat = () => {
5151

5252
return (
5353
<div className="flex justify-center items-center h-full w-full" style={{ background }}>
54-
<div className="w-8/10 h-8/10 rounded-lg">
54+
<div className="h-full w-full md:w-8/10 md:h-8/10 rounded-lg">
5555
<CopilotChat
5656
className="h-full rounded-2xl"
5757
labels={{ initial: "Hi, I'm an agent. Want to chat?" }}

typescript-sdk/apps/dojo/src/app/[integrationId]/feature/agentic_generative_ui/page.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -182,7 +182,7 @@ const Chat = () => {
182182

183183
return (
184184
<div className="flex justify-center items-center h-full w-full">
185-
<div className="w-8/10 h-8/10 rounded-lg">
185+
<div className="h-full w-full md:w-8/10 md:h-8/10 rounded-lg">
186186
<CopilotChat
187187
className="h-full rounded-2xl"
188188
labels={{

typescript-sdk/apps/dojo/src/app/[integrationId]/feature/human_in_the_loop/page.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -326,7 +326,7 @@ const Chat = ({ integrationId }: { integrationId: string }) => {
326326

327327
return (
328328
<div className="flex justify-center items-center h-full w-full">
329-
<div className="w-8/10 h-8/10 rounded-lg">
329+
<div className="h-full w-full md:w-8/10 md:h-8/10 rounded-lg">
330330
<CopilotChat
331331
className="h-full rounded-2xl"
332332
labels={{
Lines changed: 90 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,114 @@
11
"use client";
22

3-
import React, { Suspense } from "react";
3+
import React, { Suspense, useState, useEffect } from "react";
44
import { ViewerLayout } from "@/components/layout/viewer-layout";
55
import { Sidebar } from "@/components/sidebar/sidebar";
6+
import { Menu, X } from "lucide-react";
7+
import { Button } from "@/components/ui/button";
8+
69
import { useURLParams } from "@/contexts/url-params-context";
710

811
export function MainLayout({ children }: { children: React.ReactNode }) {
12+
const [isMobileSidebarOpen, setIsMobileSidebarOpen] = useState(false);
13+
const [isMobile, setIsMobile] = useState(false);
14+
15+
// Check if we're on mobile
16+
useEffect(() => {
17+
const checkMobile = () => {
18+
const mobile = window.innerWidth < 768; // md breakpoint
19+
setIsMobile(mobile);
20+
// Auto-close sidebar when switching to desktop
21+
if (!mobile) {
22+
setIsMobileSidebarOpen(false);
23+
}
24+
};
25+
26+
// Initial check
27+
if (typeof window !== 'undefined') {
28+
checkMobile();
29+
}
30+
31+
// Listen for resize events
32+
window.addEventListener('resize', checkMobile);
33+
return () => window.removeEventListener('resize', checkMobile);
34+
}, []);
35+
36+
const toggleMobileSidebar = () => {
37+
setIsMobileSidebarOpen(!isMobileSidebarOpen);
38+
};
39+
940
return (
1041
<ViewerLayout>
11-
<div className="flex h-full w-full overflow-hidden">
42+
<div className="flex h-full w-full overflow-hidden relative">
43+
{/* Mobile Header with Hamburger Menu */}
44+
{isMobile && (
45+
<div className="absolute top-0 left-0 right-0 z-50 bg-background border-b p-2 md:hidden">
46+
<div className="flex items-center justify-between">
47+
<Button
48+
variant="ghost"
49+
size="sm"
50+
onClick={toggleMobileSidebar}
51+
className="p-2"
52+
>
53+
{isMobileSidebarOpen ? <X className="h-5 w-5" /> : <Menu className="h-5 w-5" />}
54+
</Button>
55+
<h1 className="text-sm font-medium text-center flex-1">AG-UI Dojo</h1>
56+
<div className="w-9" /> {/* Spacer for centering */}
57+
</div>
58+
</div>
59+
)}
60+
61+
{/* Mobile Overlay */}
62+
{isMobile && isMobileSidebarOpen && (
63+
<div
64+
className="absolute inset-0 bg-black/50 z-40 md:hidden"
65+
onClick={toggleMobileSidebar}
66+
/>
67+
)}
1268
{/* Sidebar */}
1369
<Suspense>
14-
<MaybeSidebar/>
70+
<MaybeSidebar
71+
isMobile={isMobile}
72+
isMobileSidebarOpen={isMobileSidebarOpen}
73+
onMobileClose={() => setIsMobileSidebarOpen(false)}
74+
/>
1575
</Suspense>
1676

17-
1877
{/* Content */}
19-
<div className="flex-1 overflow-auto">
78+
<div className={`flex-1 overflow-auto ${isMobile ? 'pt-12' : ''}`}>
2079
<div className="h-full">{children}</div>
2180
</div>
2281
</div>
2382
</ViewerLayout>
2483
);
2584
}
2685

27-
function MaybeSidebar() {
86+
interface MaybeSidebarProps {
87+
isMobile: boolean;
88+
isMobileSidebarOpen: boolean;
89+
onMobileClose: () => void;
90+
}
91+
92+
function MaybeSidebar({ isMobile, isMobileSidebarOpen, onMobileClose }: MaybeSidebarProps) {
2893
const { sidebarHidden } = useURLParams();
2994

30-
return !sidebarHidden && <Sidebar />;
95+
// Don't render sidebar if disabled by query param
96+
if (sidebarHidden) return null;
97+
98+
// On mobile, only show if open
99+
if (isMobile && !isMobileSidebarOpen) return null;
100+
101+
return (
102+
<div className={`
103+
${isMobile
104+
? 'absolute left-0 top-0 z-50 h-full w-80 transform transition-transform duration-300 ease-in-out'
105+
: 'relative'
106+
}
107+
`}>
108+
<Sidebar
109+
isMobile={isMobile}
110+
onMobileClose={onMobileClose}
111+
/>
112+
</div>
113+
);
31114
}

typescript-sdk/apps/dojo/src/components/sidebar/sidebar.tsx

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,12 @@ import { Feature } from "@/types/integration";
2020
import { useURLParams } from "@/contexts/url-params-context";
2121
import { View } from "@/types/interface";
2222

23-
export function Sidebar() {
23+
interface SidebarProps {
24+
isMobile?: boolean;
25+
onMobileClose?: () => void;
26+
}
27+
28+
export function Sidebar({ isMobile, onMobileClose }: SidebarProps) {
2429
const router = useRouter();
2530
const pathname = usePathname();
2631
const { view, pickerDisabled, setView } = useURLParams();
@@ -48,9 +53,18 @@ export function Sidebar() {
4853
const handleDemoSelect = (demoId: string) => {
4954
if (currentIntegration) {
5055
router.push(`/${currentIntegration.id}/feature/${demoId}`);
56+
// Close mobile sidebar when demo is selected
57+
if (isMobile && onMobileClose) {
58+
onMobileClose();
59+
}
5160
}
5261
};
5362

63+
// Handle integration selection
64+
const handleIntegrationSelect = (integrationId: string) => {
65+
router.push(`/${integrationId}`);
66+
};
67+
5468
// Check for dark mode using media query
5569
useEffect(() => {
5670
// Check if we're in the browser
@@ -84,7 +98,9 @@ export function Sidebar() {
8498
}, []);
8599

86100
return (
87-
<div className="flex flex-col h-full w-74 min-w-[296px] flex-shrink-0 border-r">
101+
<div className={`flex flex-col h-full bg-background border-r
102+
${isMobile ? 'w-80 shadow-xl' : 'w-74 min-w-[296px] flex-shrink-0'}
103+
`}>
88104
{/* Sidebar Header */}
89105
<div className="p-4 border-b bg-background">
90106
<div className="flex items-center justify-between ml-1">
@@ -115,9 +131,7 @@ export function Sidebar() {
115131
{menuIntegrations.map((integration) => (
116132
<DropdownMenuItem
117133
key={integration.id}
118-
onClick={() => {
119-
router.push(`/${integration.id}`);
120-
}}
134+
onClick={() => handleIntegrationSelect(integration.id)}
121135
className="cursor-pointer"
122136
>
123137
<span>{integration.name}</span>

0 commit comments

Comments
 (0)