diff --git a/frontend/src/components/assistant/ChatSidebar.tsx b/frontend/src/components/assistant/ChatSidebar.tsx index d474e5e9..133f0a60 100644 --- a/frontend/src/components/assistant/ChatSidebar.tsx +++ b/frontend/src/components/assistant/ChatSidebar.tsx @@ -1,4 +1,4 @@ -import { Plus, Pin, Trash2, MessageSquare } from 'lucide-react' +import { Plus, Pin, Trash2, MessageSquare, History, X } from 'lucide-react' import { cn } from '@/lib/utils' import type { ChatListItem } from '@/types/assistant-chat' @@ -11,6 +11,8 @@ interface ChatSidebarProps { onTogglePin: (id: string, pinned: boolean) => void mobileOpen?: boolean onMobileClose?: () => void + collapsed?: boolean + onToggleCollapse?: () => void } export function ChatSidebar({ @@ -22,6 +24,8 @@ export function ChatSidebar({ onTogglePin, mobileOpen = false, onMobileClose, + collapsed = false, + onToggleCollapse, }: ChatSidebarProps) { const pinnedChats = chats.filter(c => c.pinned) const unpinnedChats = chats.filter(c => !c.pinned) @@ -36,6 +40,11 @@ export function ChatSidebar({ onMobileClose?.() } + // When collapsed on desktop, render nothing — parent renders the top bar + if (collapsed && !mobileOpen) { + return null + } + return ( <> {/* Mobile overlay */} @@ -52,14 +61,23 @@ export function ChatSidebar({ style={{ background: 'var(--color-bg-sidebar)' }} > {/* Header */} -
+
+ {onToggleCollapse && ( + + )}
{/* Chat list */} @@ -108,6 +126,51 @@ export function ChatSidebar({ ) } +/** Collapsed top bar — rendered by the parent page above the chat area */ +export function ChatSidebarCollapsedBar({ + chats, + activeChatId, + onNewChat, + onExpand, +}: { + chats: ChatListItem[] + activeChatId: string | null + onNewChat: () => void + onExpand: () => void +}) { + return ( +
+ + +
+ {activeChatId && ( + + {chats.find(c => c.id === activeChatId)?.title} + + )} +
+ ) +} + function ChatItem({ chat, isActive, diff --git a/frontend/src/pages/AssistantChatPage.tsx b/frontend/src/pages/AssistantChatPage.tsx index 05747412..c8de1740 100644 --- a/frontend/src/pages/AssistantChatPage.tsx +++ b/frontend/src/pages/AssistantChatPage.tsx @@ -10,7 +10,7 @@ import { aiSessionsApi } from '@/api/aiSessions' import { useBranching } from '@/hooks/useBranching' import { analytics } from '@/lib/analytics' import { toast } from '@/lib/toast' -import { ChatSidebar } from '@/components/assistant/ChatSidebar' +import { ChatSidebar, ChatSidebarCollapsedBar } from '@/components/assistant/ChatSidebar' import { ChatMessage } from '@/components/assistant/ChatMessage' import { TaskLane } from '@/components/assistant/TaskLane' import { ConcludeSessionModal } from '@/components/assistant/ConcludeSessionModal' @@ -45,6 +45,14 @@ export default function AssistantChatPage() { const [activeQuestions, setActiveQuestions] = useState([]) const [activeActions, setActiveActions] = useState([]) const [showTaskLane, setShowTaskLane] = useState(false) + const [sidebarCollapsed, setSidebarCollapsed] = useState(() => + localStorage.getItem('rf-chat-sidebar-collapsed') === 'true' + ) + const toggleSidebarCollapse = () => { + const next = !sidebarCollapsed + setSidebarCollapsed(next) + localStorage.setItem('rf-chat-sidebar-collapsed', String(next)) + } const messagesEndRef = useRef(null) const inputRef = useRef(null) const fileInputRef = useRef(null) @@ -470,17 +478,20 @@ export default function AssistantChatPage() { <>
- {/* Sidebar — hidden on mobile, slide-out via toggle */} -
- -
+ {/* Sidebar — hidden on mobile, collapsed to top bar or full sidebar on desktop */} + {!sidebarCollapsed && ( +
+ +
+ )}
{/* Main chat area + optional branch sidebar */} -
+
+ + {/* Collapsed sidebar top bar — desktop only */} + {sidebarCollapsed && ( +
+ +
+ )} + + {/* Chat content row: chat column + TaskLane side by side */} +
{/* Mobile header with chat history toggle */}
@@ -555,7 +581,7 @@ export default function AssistantChatPage() {
{/* Rich Input */} -
+
{/* close chat content row */} +
{/* close outer flex-col */} {/* Conclude Session Modal */}