diff --git a/apps/x/apps/renderer/src/App.tsx b/apps/x/apps/renderer/src/App.tsx
index 9bf73d36..2b879495 100644
--- a/apps/x/apps/renderer/src/App.tsx
+++ b/apps/x/apps/renderer/src/App.tsx
@@ -6,7 +6,7 @@ import type { LanguageModelUsage, ToolUIPart } from 'ai';
import './App.css'
import z from 'zod';
import { Button } from './components/ui/button';
-import { CheckIcon, LoaderIcon, ArrowUp, PanelLeftIcon, PanelRightIcon, Square, X, ChevronLeftIcon, ChevronRightIcon, SquarePen } from 'lucide-react';
+import { CheckIcon, LoaderIcon, ArrowUp, PanelLeftIcon, PanelRightIcon, Search, Square, X, ChevronLeftIcon, ChevronRightIcon, SquarePen } from 'lucide-react';
import { cn } from '@/lib/utils';
import { MarkdownEditor } from './components/markdown-editor';
import { ChatInputBar } from './components/chat-button';
@@ -14,7 +14,7 @@ import { ChatSidebar } from './components/chat-sidebar';
import { GraphView, type GraphEdge, type GraphNode } from '@/components/graph-view';
import { useDebounce } from './hooks/use-debounce';
import { SidebarContentPanel } from '@/components/sidebar-content';
-import { SidebarSectionProvider, type ActiveSection } from '@/contexts/sidebar-context';
+import { SidebarSectionProvider, useSidebarSection, type ActiveSection } from '@/contexts/sidebar-context';
import {
Conversation,
ConversationContent,
@@ -131,8 +131,8 @@ const TITLEBAR_BUTTON_PX = 32
const TITLEBAR_BUTTON_GAP_PX = 4
const TITLEBAR_HEADER_GAP_PX = 8
const TITLEBAR_TOGGLE_MARGIN_LEFT_PX = 12
-const TITLEBAR_BUTTONS_COLLAPSED = 4
-const TITLEBAR_BUTTON_GAPS_COLLAPSED = 3
+const TITLEBAR_BUTTONS_COLLAPSED = 5
+const TITLEBAR_BUTTON_GAPS_COLLAPSED = 4
const clampNumber = (value: number, min: number, max: number) =>
Math.min(max, Math.max(min, value))
@@ -487,6 +487,7 @@ function FixedSidebarToggle({
leftInsetPx: number
}) {
const { toggleSidebar, state } = useSidebar()
+ const { searchOpen, setSearchOpen } = useSidebarSection()
const isCollapsed = state === "collapsed"
return (
@@ -510,6 +511,20 @@ function FixedSidebarToggle({
>
+
{/* Back / Forward navigation */}
{isCollapsed && (
<>
diff --git a/apps/x/apps/renderer/src/components/sidebar-content.tsx b/apps/x/apps/renderer/src/components/sidebar-content.tsx
index 7e99049b..a2e485e3 100644
--- a/apps/x/apps/renderer/src/components/sidebar-content.tsx
+++ b/apps/x/apps/renderer/src/components/sidebar-content.tsx
@@ -401,8 +401,7 @@ export function SidebarContentPanel({
selectedBackgroundTask,
...props
}: SidebarContentPanelProps) {
- const { activeSection, setActiveSection } = useSidebarSection()
- const [searchOpen, setSearchOpen] = useState(false)
+ const { activeSection, setActiveSection, searchOpen, setSearchOpen } = useSidebarSection()
const [searchQuery, setSearchQuery] = useState("")
const searchInputRef = useRef
(null)
@@ -437,7 +436,7 @@ export function SidebarContentPanel({
{/* Top spacer to clear the traffic lights + fixed toggle row */}
- {/* Tab switcher - centered below the traffic lights row */}
+ {/* Tab switcher */}
{sectionTabs.map((tab) => (
@@ -456,6 +455,29 @@ export function SidebarContentPanel({
))}
+ {searchOpen && (
+
+
+ setSearchQuery(e.target.value)}
+ onKeyDown={(e) => {
+ if (e.key === "Escape") setSearchOpen(false)
+ }}
+ placeholder={activeSection === "tasks" ? "Search chats..." : "Search files..."}
+ className="flex-1 bg-transparent text-sm outline-none placeholder:text-muted-foreground/60"
+ />
+ {searchQuery && (
+
+ )}
+
+ )}
{activeSection === "knowledge" && (
@@ -466,11 +488,6 @@ export function SidebarContentPanel({
onSelectFile={onSelectFile}
actions={knowledgeActions}
onVoiceNoteCreated={onVoiceNoteCreated}
- searchOpen={searchOpen}
- setSearchOpen={setSearchOpen}
- searchQuery={searchQuery}
- setSearchQuery={setSearchQuery}
- searchInputRef={searchInputRef}
/>
)}
{activeSection === "tasks" && (
@@ -481,11 +498,6 @@ export function SidebarContentPanel({
actions={tasksActions}
backgroundTasks={filteredBackgroundTasks}
selectedBackgroundTask={selectedBackgroundTask}
- searchOpen={searchOpen}
- setSearchOpen={setSearchOpen}
- searchQuery={searchQuery}
- setSearchQuery={setSearchQuery}
- searchInputRef={searchInputRef}
/>
)}
@@ -762,11 +774,6 @@ function KnowledgeSection({
onSelectFile,
actions,
onVoiceNoteCreated,
- searchOpen,
- setSearchOpen,
- searchQuery,
- setSearchQuery,
- searchInputRef,
}: {
tree: TreeNode[]
selectedPath: string | null
@@ -774,11 +781,6 @@ function KnowledgeSection({
onSelectFile: (path: string, kind: "file" | "dir") => void
actions: KnowledgeActions
onVoiceNoteCreated?: (path: string) => void
- searchOpen: boolean
- setSearchOpen: (open: boolean) => void
- searchQuery: string
- setSearchQuery: (query: string) => void
- searchInputRef: React.RefObject
}) {
const isExpanded = expandedPaths.size > 0
@@ -792,79 +794,38 @@ function KnowledgeSection({
-
-
- {quickActions.map((action) => (
-
-
-
-
- {action.label}
-
- ))}
-
-
+
+ {quickActions.map((action) => (
+
-
- {isExpanded ? "Collapse All" : "Expand All"}
-
+ {action.label}
-
-
-
-
- Search
-
-
- {searchOpen && (
-
-
- setSearchQuery(e.target.value)}
- onKeyDown={(e) => {
- if (e.key === "Escape") setSearchOpen(false)
- }}
- placeholder="Search files..."
- className="flex-1 bg-transparent text-sm outline-none placeholder:text-muted-foreground/60"
- />
- {searchQuery && (
-
- )}
-
- )}
+ ))}
+
+
+
+
+
+
+ {isExpanded ? "Collapse All" : "Expand All"}
+
+
@@ -1118,11 +1079,6 @@ function TasksSection({
actions,
backgroundTasks = [],
selectedBackgroundTask,
- searchOpen,
- setSearchOpen,
- searchQuery,
- setSearchQuery,
- searchInputRef,
}: {
runs: RunListItem[]
currentRunId?: string | null
@@ -1130,65 +1086,19 @@ function TasksSection({
actions?: TasksActions
backgroundTasks?: BackgroundTaskItem[]
selectedBackgroundTask?: string | null
- searchOpen: boolean
- setSearchOpen: (open: boolean) => void
- searchQuery: string
- setSearchQuery: (query: string) => void
- searchInputRef: React.RefObject
}) {
return (
- {/* Sticky New Chat button + search */}
+ {/* Sticky New Chat button - matches Knowledge section height */}
-
-
-
-
-
- New chat
-
-
-
-
-
-
-
- Search
-
-
- {searchOpen && (
-
-
- setSearchQuery(e.target.value)}
- onKeyDown={(e) => {
- if (e.key === "Escape") setSearchOpen(false)
- }}
- placeholder="Search chats..."
- className="flex-1 bg-transparent text-sm outline-none placeholder:text-muted-foreground/60"
- />
- {searchQuery && (
-
- )}
-
- )}
+
+
+
+
+ New chat
+
+
+
{/* Background Tasks Section */}
diff --git a/apps/x/apps/renderer/src/contexts/sidebar-context.tsx b/apps/x/apps/renderer/src/contexts/sidebar-context.tsx
index 61e4bb65..dc3f8984 100644
--- a/apps/x/apps/renderer/src/contexts/sidebar-context.tsx
+++ b/apps/x/apps/renderer/src/contexts/sidebar-context.tsx
@@ -7,6 +7,8 @@ export type ActiveSection = "knowledge" | "tasks"
type SidebarSectionContextProps = {
activeSection: ActiveSection
setActiveSection: (section: ActiveSection) => void
+ searchOpen: boolean
+ setSearchOpen: (open: boolean) => void
}
const SidebarSectionContext = React.createContext(null)
@@ -29,6 +31,7 @@ export function SidebarSectionProvider({
children: React.ReactNode
}) {
const [activeSection, setActiveSectionState] = React.useState(defaultSection)
+ const [searchOpen, setSearchOpen] = React.useState(false)
const setActiveSection = React.useCallback((section: ActiveSection) => {
setActiveSectionState(section)
@@ -39,8 +42,10 @@ export function SidebarSectionProvider({
() => ({
activeSection,
setActiveSection,
+ searchOpen,
+ setSearchOpen,
}),
- [activeSection, setActiveSection]
+ [activeSection, setActiveSection, searchOpen]
)
return (