55 FolderClosedIcon ,
66 FolderIcon ,
77 SearchIcon ,
8+ SlidersHorizontalIcon ,
89 TriangleAlertIcon ,
910} from "lucide-react" ;
1011import { memo , useCallback , useDeferredValue , useState } from "react" ;
@@ -18,6 +19,7 @@ import { cn } from "~/lib/utils";
1819import { readNativeApi } from "~/nativeApi" ;
1920import { resolvePathLinkTarget } from "~/terminal-links" ;
2021import { VscodeEntryIcon } from "./chat/VscodeEntryIcon" ;
22+ import { Collapsible , CollapsibleContent } from "./ui/collapsible" ;
2123import { Input } from "./ui/input" ;
2224import { InputGroup , InputGroupAddon , InputGroupInput } from "./ui/input-group" ;
2325import { toastManager } from "./ui/toast" ;
@@ -34,6 +36,7 @@ export const WorkspaceFileTree = memo(function WorkspaceFileTree(props: {
3436 const [ searchQuery , setSearchQuery ] = useState ( "" ) ;
3537 const [ includePattern , setIncludePattern ] = useState ( "" ) ;
3638 const [ excludePattern , setExcludePattern ] = useState ( "" ) ;
39+ const [ filtersOpen , setFiltersOpen ] = useState ( false ) ;
3740 const deferredSearchQuery = useDeferredValue ( searchQuery ) ;
3841 const deferredIncludePattern = useDeferredValue ( includePattern ) ;
3942 const deferredExcludePattern = useDeferredValue ( excludePattern ) ;
@@ -46,6 +49,9 @@ export const WorkspaceFileTree = memo(function WorkspaceFileTree(props: {
4649 } , [ ] ) ;
4750
4851 const openFileInViewer = useCodeViewerStore ( ( state ) => state . openFile ) ;
52+ const filtersHaveContent = includePattern . trim ( ) . length > 0 || excludePattern . trim ( ) . length > 0 ;
53+ const filtersVisible = filtersOpen || filtersHaveContent ;
54+
4955 const searchActive =
5056 deferredSearchQuery . trim ( ) . length > 0 ||
5157 deferredIncludePattern . trim ( ) . length > 0 ||
@@ -104,6 +110,7 @@ export const WorkspaceFileTree = memo(function WorkspaceFileTree(props: {
104110 setSearchQuery ( "" ) ;
105111 setIncludePattern ( "" ) ;
106112 setExcludePattern ( "" ) ;
113+ setFiltersOpen ( false ) ;
107114 } , [ ] ) ;
108115
109116 return (
@@ -121,28 +128,50 @@ export const WorkspaceFileTree = memo(function WorkspaceFileTree(props: {
121128 spellCheck = { false }
122129 aria-label = "Search files"
123130 />
131+ < InputGroupAddon align = "inline-end" >
132+ < button
133+ type = "button"
134+ onClick = { ( ) => setFiltersOpen ( ( prev ) => ! prev ) }
135+ aria-label = "Toggle file filters"
136+ aria-expanded = { filtersVisible }
137+ className = { cn (
138+ "flex size-6 items-center justify-center rounded-md transition-colors hover:bg-accent/60" ,
139+ filtersHaveContent && "text-foreground" ,
140+ ) }
141+ >
142+ < SlidersHorizontalIcon
143+ className = { cn (
144+ "size-3.5" ,
145+ filtersHaveContent
146+ ? "text-foreground"
147+ : "text-muted-foreground/65" ,
148+ ) }
149+ />
150+ </ button >
151+ </ InputGroupAddon >
124152 </ InputGroup >
125- < div className = "grid gap-1.5" >
126- < Input
127- size = "sm"
128- value = { includePattern }
129- onChange = { ( event ) => setIncludePattern ( event . target . value ) }
130- placeholder = "Include: src/**, *.{ts,tsx}"
131- spellCheck = { false }
132- aria-label = "Files to include"
133- />
134- < Input
135- size = "sm"
136- value = { excludePattern }
137- onChange = { ( event ) => setExcludePattern ( event . target . value ) }
138- placeholder = "Exclude: dist/**, *.snap"
139- spellCheck = { false }
140- aria-label = "Files to exclude"
141- />
142- </ div >
143- < p className = "text-[10px] text-muted-foreground/55" >
144- CamelCase, path-ordered, and glob-restricted search.
145- </ p >
153+ < Collapsible open = { filtersVisible } >
154+ < CollapsibleContent >
155+ < div className = "grid gap-1.5 pt-1.5" >
156+ < Input
157+ size = "sm"
158+ value = { includePattern }
159+ onChange = { ( event ) => setIncludePattern ( event . target . value ) }
160+ placeholder = "Include: src/**, *.{ts,tsx}"
161+ spellCheck = { false }
162+ aria-label = "Files to include"
163+ />
164+ < Input
165+ size = "sm"
166+ value = { excludePattern }
167+ onChange = { ( event ) => setExcludePattern ( event . target . value ) }
168+ placeholder = "Exclude: dist/**, *.snap"
169+ spellCheck = { false }
170+ aria-label = "Files to exclude"
171+ />
172+ </ div >
173+ </ CollapsibleContent >
174+ </ Collapsible >
146175 </ div >
147176
148177 { searchActive ? (
0 commit comments