1- import {
2- ChevronUp ,
3- ClipboardPaste ,
4- FolderPlus ,
5- FolderUp ,
6- Loader2 ,
7- RefreshCw ,
8- Upload
9- } from "lucide-react" ;
10- import { useEffect , useState } from "react" ;
1+ import { ChevronUp , ClipboardPaste , RefreshCw , Search , X } from "lucide-react" ;
112
123interface Props {
134 currentPath : string ;
145 parentPath : string ;
156 deviceRootPath : string ;
167 loading : boolean ;
17- uploading : boolean ;
188 disabled : boolean ;
199 onNavigate : ( path : string ) => void ;
20- onUploadFiles : ( ) => void ;
21- onUploadFolder : ( ) => void ;
22- onCreateFolderClick : ( ) => void ;
2310 onShareClipboard : ( ) => void ;
11+ searchQuery : string ;
12+ setSearchQuery : ( query : string ) => void ;
13+ isSearchActive : boolean ;
14+ setIsSearchActive : ( active : boolean ) => void ;
2415}
2516
2617export function BrowserToolbar ( {
2718 currentPath,
2819 parentPath,
2920 deviceRootPath,
3021 loading,
31- uploading,
3222 disabled,
3323 onNavigate,
34- onUploadFiles,
35- onUploadFolder,
36- onCreateFolderClick,
37- onShareClipboard
24+ onShareClipboard,
25+ searchQuery,
26+ setSearchQuery,
27+ isSearchActive,
28+ setIsSearchActive,
3829} : Props ) {
39- const [ showFolderMenu , setShowFolderMenu ] = useState ( false ) ;
40-
41- // Close dropdown on outside click
42- useEffect ( ( ) => {
43- const handleClickOutside = ( ) => setShowFolderMenu ( false ) ;
44- if ( showFolderMenu ) document . addEventListener ( "click" , handleClickOutside ) ;
45- return ( ) => document . removeEventListener ( "click" , handleClickOutside ) ;
46- } , [ showFolderMenu ] ) ;
47-
4830 // ── Path Calculations ──
4931 const normPath = currentPath ? currentPath . replace ( / \\ / g, "/" ) : "" ;
5032 const normRoot = deviceRootPath ? deviceRootPath . replace ( / \\ / g, "/" ) : "" ;
@@ -72,7 +54,7 @@ export function BrowserToolbar({
7254 } ;
7355
7456 return (
75- < div className = "flex items-center gap-2 px-4 py-2.5 border-b border-[#1e2535] bg-surface/60 shrink-0" >
57+ < div className = "flex items-center gap-2 px-4 py-2.5 border-b border-[#1e2535] bg-surface/60 shrink-0 h-12 " >
7658 < button
7759 onClick = { ( ) => onNavigate ( parentPath || "/" ) }
7860 disabled = { ! canGoUp || disabled }
@@ -81,52 +63,75 @@ export function BrowserToolbar({
8163 < ChevronUp size = { 16 } />
8264 </ button >
8365
84- { /* ── Breadcrumbs ── */ }
85- < div className = "flex-1 flex items-center gap-1 overflow-x-auto hide-scrollbar min-w-0" >
86- < button
87- onClick = { ( ) => onNavigate ( "/" ) }
88- className = "text-[11px] font-mono text-[#3d4d63] hover:text-accent transition-colors shrink-0 px-1 py-0.5 rounded hover:bg-accent/8"
89- >
90- /
91- </ button >
66+ { /* ── DYNAMIC AREA: Search Input OR Breadcrumbs ── */ }
67+ { isSearchActive ? (
68+ < div className = "flex-1 flex items-center gap-2 px-2 bg-bg-base/50 border border-accent/30 rounded-lg h-full" >
69+ < Search size = { 14 } className = "text-accent shrink-0" />
70+ < input
71+ autoFocus
72+ type = "text"
73+ value = { searchQuery }
74+ onChange = { ( e ) => setSearchQuery ( e . target . value ) }
75+ placeholder = "Search locally..."
76+ className = "flex-1 bg-transparent border-none outline-none text-[13px] text-[#dde4f0] placeholder-[#3d4d63] min-w-0"
77+ />
78+ < button
79+ onClick = { ( ) => {
80+ setSearchQuery ( "" ) ;
81+ setIsSearchActive ( false ) ;
82+ } }
83+ className = "p-1 text-[#8090a8] hover:text-[#dde4f0] rounded"
84+ >
85+ < X size = { 14 } />
86+ </ button >
87+ </ div >
88+ ) : (
89+ < div className = "flex-1 flex items-center gap-1 overflow-x-auto hide-scrollbar min-w-0" >
90+ < button
91+ onClick = { ( ) => onNavigate ( "/" ) }
92+ className = "text-[11px] font-mono text-[#3d4d63] hover:text-accent transition-colors shrink-0 px-1 py-0.5 rounded hover:bg-accent/8"
93+ >
94+ /
95+ </ button >
9296
93- { showEllipsis && (
94- < span className = "flex items-center gap-1 shrink-0" >
95- < span className = "text-[#1e2535] text-[11px]" > /</ span >
96- < span className = "text-[11px] font-mono px-1 py-0.5 text-[#8090a8] select-none" >
97- ...
97+ { showEllipsis && (
98+ < span className = "flex items-center gap-1 shrink-0" >
99+ < span className = "text-[#1e2535] text-[11px]" > /</ span >
100+ < span className = "text-[11px] font-mono px-1 py-0.5 text-[#8090a8] select-none" >
101+ ...
102+ </ span >
98103 </ span >
99- </ span >
100- ) }
101-
102- { visibleSegments . map ( ( seg , i ) => {
103- const originalIndex =
104- pathSegments . length - visibleSegments . length + i ;
105- const relativeSegPath =
106- "/" + pathSegments . slice ( 0 , originalIndex + 1 ) . join ( "/" ) ;
107- const absoluteSegPath = buildAbsolutePath ( relativeSegPath ) ;
108- const isLast = originalIndex === pathSegments . length - 1 ;
104+ ) }
109105
110- return (
111- < span
112- key = { originalIndex }
113- className = "flex items-center gap-1 shrink-0 min-w-0"
114- >
115- < span className = "text-[#1e2535] text-[11px]" > /</ span >
116- < button
117- onClick = { ( ) => ! isLast && onNavigate ( absoluteSegPath ) }
118- title = { seg }
119- className = { `
120- text-[11px] font-mono px-1 py-0.5 rounded transition-colors truncate max-w-30
121- ${ isLast ? "text-[#dde4f0] cursor-default" : "text-[#3d4d63] hover:text-accent hover:bg-accent/8 cursor-pointer" }
122- ` }
106+ { visibleSegments . map ( ( seg , i ) => {
107+ const originalIndex =
108+ pathSegments . length - visibleSegments . length + i ;
109+ const relativeSegPath =
110+ "/" + pathSegments . slice ( 0 , originalIndex + 1 ) . join ( "/" ) ;
111+ const absoluteSegPath = buildAbsolutePath ( relativeSegPath ) ;
112+ const isLast = originalIndex === pathSegments . length - 1 ;
113+
114+ return (
115+ < span
116+ key = { originalIndex }
117+ className = "flex items-center gap-1 shrink-0 min-w-0"
123118 >
124- { seg }
125- </ button >
126- </ span >
127- ) ;
128- } ) }
129- </ div >
119+ < span className = "text-[#1e2535] text-[11px]" > /</ span >
120+ < button
121+ onClick = { ( ) => ! isLast && onNavigate ( absoluteSegPath ) }
122+ title = { seg }
123+ className = { `
124+ text-[11px] font-mono px-1 py-0.5 rounded transition-colors truncate max-w-30
125+ ${ isLast ? "text-[#dde4f0] cursor-default" : "text-[#3d4d63] hover:text-accent hover:bg-accent/8 cursor-pointer" }
126+ ` }
127+ >
128+ { seg }
129+ </ button >
130+ </ span >
131+ ) ;
132+ } ) }
133+ </ div >
134+ ) }
130135
131136 { /* ── Actions ── */ }
132137 < div className = "flex items-center gap-1.5 shrink-0" >
@@ -144,55 +149,19 @@ export function BrowserToolbar({
144149 disabled = { disabled }
145150 className = "flex items-center gap-1.5 px-3 py-1.5 rounded-lg text-[12px] font-semibold text-[#a78bfa] bg-[#a78bfa]/8 border border-[#a78bfa]/25 hover:bg-[#a78bfa]/15 hover:border-[#a78bfa]/40 disabled:opacity-40 transition-all"
146151 >
147- < ClipboardPaste size = { 12 } /> Share Clipboard
152+ < ClipboardPaste size = { 12 } /> Share
148153 </ button >
149154
150- < button
151- onClick = { onUploadFiles }
152- disabled = { disabled }
153- className = "flex items-center gap-1.5 px-3 py-1.5 rounded-lg text-[12px] font-semibold text-accent bg-accent/8 border border-accent/25 hover:bg-accent/15 hover:border-accent/40 disabled:opacity-40 transition-all"
154- >
155- { uploading ? (
156- < Loader2 size = { 12 } className = "animate-spin" />
157- ) : (
158- < Upload size = { 12 } />
159- ) } { " " }
160- Files
161- </ button >
162-
163- < div className = "relative" onClick = { ( e ) => e . stopPropagation ( ) } >
155+ { /* ── Search Trigger Button ── */ }
156+ { ! isSearchActive && (
164157 < button
165- onClick = { ( ) => setShowFolderMenu ( ! showFolderMenu ) }
158+ onClick = { ( ) => setIsSearchActive ( true ) }
166159 disabled = { disabled }
167160 className = "flex items-center gap-1.5 px-3 py-1.5 rounded-lg text-[12px] font-semibold text-[#00c9a7] bg-[#00c9a7]/8 border border-[#00c9a7]/25 hover:bg-[#00c9a7]/15 hover:border-[#00c9a7]/40 disabled:opacity-40 transition-all"
168161 >
169- < FolderUp size = { 12 } /> Folder
162+ < Search size = { 12 } /> Search
170163 </ button >
171-
172- { showFolderMenu && (
173- < div className = "absolute top-full right-0 mt-1.5 w-44 bg-panel border border-[#1e2535] rounded-xl shadow-2xl py-1.5 px-1.5 z-50 animate-in fade-in zoom-in-95 duration-100" >
174- < button
175- onClick = { ( ) => {
176- setShowFolderMenu ( false ) ;
177- onUploadFolder ( ) ;
178- } }
179- className = "w-full rounded-lg flex items-center gap-2.5 px-3 py-2 text-[12px] font-medium text-[#dde4f0] hover:bg-[#00c9a7]/10 hover:text-[#00c9a7] transition-colors"
180- >
181- < FolderUp size = { 13 } /> Upload Folder
182- </ button >
183- < div className = "h-px w-full bg-[#1e2535] my-1" />
184- < button
185- onClick = { ( ) => {
186- setShowFolderMenu ( false ) ;
187- onCreateFolderClick ( ) ;
188- } }
189- className = "w-full rounded-lg flex items-center gap-2.5 px-3 py-2 text-[12px] font-medium text-[#dde4f0] hover:bg-accent/10 hover:text-accent transition-colors"
190- >
191- < FolderPlus size = { 13 } /> Create Folder
192- </ button >
193- </ div >
194- ) }
195- </ div >
164+ ) }
196165 </ div >
197166 </ div >
198167 ) ;
0 commit comments