From 04ca55720c2df4dd6851eba557c69a1351b743e5 Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 23 Nov 2025 07:22:21 +0000 Subject: [PATCH 1/5] feat: add mobile-responsive layout with overlay sidebars Implement comprehensive mobile navigation and responsive design: **Mobile Navigation (< 768px):** - Add hamburger menu buttons in header for toggling sidebars - Sidebars overlay content instead of pushing it - Dark backdrop when sidebars are open - Smooth slide-in/out transitions - Auto-close sidebars when backdrop is clicked **Responsive Components:** - ChatHeader: Compact layout, responsive padding, mobile toggle buttons - ChatSidebar: Full-width overlay on mobile (288px-320px) - RightSidebar: Full-width overlay on mobile, disable resize - MessageInput: Responsive padding, icon-only buttons, smaller controls - Scroll buttons: Adjusted position for mobile **Desktop (>= 768px):** - Maintain existing static sidebar behavior - Keep resizable right sidebar - Show full button labels and larger controls All changes use Tailwind responsive breakpoints (sm:, md:) for seamless mobile-to-desktop experience. --- frontend/components/ChatHeader.tsx | 56 ++++++++++++--- frontend/components/ChatSidebar.tsx | 12 +++- frontend/components/ChatV2.tsx | 101 ++++++++++++++++++--------- frontend/components/MessageInput.tsx | 34 ++++----- frontend/components/RightSidebar.tsx | 13 ++-- 5 files changed, 149 insertions(+), 67 deletions(-) diff --git a/frontend/components/ChatHeader.tsx b/frontend/components/ChatHeader.tsx index 34a89f82..cbb937c0 100644 --- a/frontend/components/ChatHeader.tsx +++ b/frontend/components/ChatHeader.tsx @@ -1,5 +1,5 @@ import React from 'react'; -import { Sun, Moon, Settings, RefreshCw, Loader2 } from 'lucide-react'; +import { Sun, Moon, Settings, RefreshCw, Loader2, Menu, PanelLeft, PanelRight } from 'lucide-react'; import { useTheme } from '../contexts/ThemeContext'; import ModelSelector from './ui/ModelSelector'; import { type Group as TabGroup } from './ui/TabbedSelect'; @@ -20,6 +20,10 @@ interface ChatHeaderProps { fallbackOptions?: { value: string; label: string }[]; modelToProvider?: Record | Map; onFocusMessageInput?: () => void; + onToggleLeftSidebar?: () => void; + onToggleRightSidebar?: () => void; + showLeftSidebarButton?: boolean; + showRightSidebarButton?: boolean; } export function ChatHeader({ @@ -35,6 +39,10 @@ export function ChatHeader({ fallbackOptions, modelToProvider, onFocusMessageInput, + onToggleLeftSidebar, + onToggleRightSidebar, + showLeftSidebarButton = false, + showRightSidebarButton = false, }: ChatHeaderProps) { const { theme, setTheme, resolvedTheme } = useTheme(); @@ -97,15 +105,28 @@ export function ChatHeader({ }; return ( -
-
-
+
+
+
+ {/* Left Sidebar Toggle - Mobile Only */} + {showLeftSidebarButton && onToggleLeftSidebar && ( + + )} + @@ -113,7 +134,7 @@ export function ChatHeader({ - +
+ +
+ + {/* Right Sidebar Toggle - Mobile Only */} + {showRightSidebarButton && onToggleRightSidebar && ( + + )}
diff --git a/frontend/components/ChatSidebar.tsx b/frontend/components/ChatSidebar.tsx index 124e10df..2c46e7f9 100644 --- a/frontend/components/ChatSidebar.tsx +++ b/frontend/components/ChatSidebar.tsx @@ -30,11 +30,17 @@ export function ChatSidebar({ }: ChatSidebarProps) { return (
{/* Removed soft fade to keep a cleaner boundaryless look */} -
+
+ {/* Right Sidebar Resize Handle - Desktop only */} {!chat.rightSidebarCollapsed && (
)} - + + {/* Right Sidebar - Overlay on mobile, static on desktop */} +
+ +
diff --git a/frontend/components/MessageInput.tsx b/frontend/components/MessageInput.tsx index e9483b3c..ca8b61e5 100644 --- a/frontend/components/MessageInput.tsx +++ b/frontend/components/MessageInput.tsx @@ -382,7 +382,7 @@ export const MessageInput = forwardRef(funct )} {/* ===== TEXT INPUT WITH IMAGE/FILE UPLOAD ===== */} -
+
{/* Attach button */} {(onImagesChange || onFilesChange) && (
@@ -483,11 +483,11 @@ export const MessageInput = forwardRef(funct
{/* ===== CONTROLS BAR ===== */} -
+
{/* Left side controls - grouped logically */} -
+
{/* AI Controls Group */} -
+
{/* Quality/Reasoning control - always visible */} (funct
{/* Visual separator */} {(supportsThinking || true) && ( -
+
)} {/* Tools Group */} -
+
{/* Search toggle */} @@ -749,17 +749,17 @@ export const MessageInput = forwardRef(funct } }} disabled={!canSend && !pending.streaming} - className="flex items-center gap-2 px-4 py-2 text-sm rounded-xl bg-slate-800 hover:bg-slate-700 dark:bg-slate-600 dark:hover:bg-slate-500 text-white disabled:opacity-40 disabled:cursor-not-allowed transition-all duration-200 shadow-md hover:shadow-lg disabled:hover:shadow-md transform hover:scale-[1.02] disabled:hover:scale-100" + className="flex items-center gap-1 sm:gap-2 px-3 sm:px-4 py-1.5 sm:py-2 text-xs sm:text-sm rounded-lg sm:rounded-xl bg-slate-800 hover:bg-slate-700 dark:bg-slate-600 dark:hover:bg-slate-500 text-white disabled:opacity-40 disabled:cursor-not-allowed transition-all duration-200 shadow-md hover:shadow-lg disabled:hover:shadow-md transform hover:scale-[1.02] disabled:hover:scale-100 flex-shrink-0" > {pending.streaming ? ( <> - - Stop + + Stop ) : ( <> - - Send + + Send )} diff --git a/frontend/components/RightSidebar.tsx b/frontend/components/RightSidebar.tsx index ae082989..bca9427d 100644 --- a/frontend/components/RightSidebar.tsx +++ b/frontend/components/RightSidebar.tsx @@ -368,17 +368,20 @@ export function RightSidebar({ <>