1+ import React from 'react' ;
2+ import { Button } from "@/components/ui/button" ;
3+ import { Input } from "@/components/ui/input" ;
4+ import { Label } from "@/components/ui/label" ;
5+ import { Info , ChevronDown , ChevronUp } from "lucide-react" ;
6+
7+ interface SearchParams {
8+ startingUrl : string ;
9+ goal : string ;
10+ maxDepth : number ;
11+ num_simulations : number ;
12+ }
13+
14+ interface ControlPanelProps {
15+ searchParams : SearchParams ;
16+ handleParamChange : ( param : keyof SearchParams , value : string | boolean | number ) => void ;
17+ handleStart : ( ) => void ;
18+ disconnect : ( ) => void ;
19+ isSearching : boolean ;
20+ connected : boolean ;
21+ }
22+
23+ const ControlPanelLATS : React . FC < ControlPanelProps > = ( {
24+ searchParams,
25+ handleParamChange,
26+ handleStart,
27+ disconnect,
28+ isSearching,
29+ connected,
30+ } ) => {
31+ const [ showParameters , setShowParameters ] = React . useState ( true ) ;
32+
33+ return (
34+ < div className = "bg-white dark:bg-slate-800 shadow-sm border-b sticky top-0 z-10" >
35+ < div className = "py-3 px-4 max-w-full" >
36+ < div className = "flex justify-between items-center" >
37+ < h1 className = "text-2xl font-bold text-sky-950 dark:text-sky-100" > Visual Tree Search</ h1 >
38+
39+ < div className = "flex gap-2" >
40+ < Button
41+ onClick = { handleStart }
42+ disabled = { isSearching }
43+ className = "bg-cyan-600 hover:bg-cyan-700 text-white disabled:bg-cyan-300 dark:disabled:bg-cyan-900"
44+ >
45+ Start
46+ </ Button >
47+ < Button
48+ onClick = { disconnect }
49+ disabled = { ! connected }
50+ variant = "destructive"
51+ className = "bg-rose-600 hover:bg-rose-700 text-white"
52+ >
53+ End
54+ </ Button >
55+ </ div >
56+ </ div >
57+
58+ < div className = "mt-3 bg-sky-50 dark:bg-sky-900/20 border border-sky-200 dark:border-sky-800 rounded-lg overflow-hidden" >
59+ < div
60+ className = "p-3 flex justify-between items-center cursor-pointer hover:bg-sky-100 dark:hover:bg-sky-900/30 transition-colors"
61+ onClick = { ( ) => setShowParameters ( ! showParameters ) }
62+ >
63+ < div className = "flex items-start gap-2" >
64+ < Info className = "h-5 w-5 text-cyan-600 dark:text-cyan-400 flex-shrink-0 mt-0.5" />
65+ < div >
66+ < h3 className = "font-medium text-sky-800 dark:text-sky-300" > How to use this playground</ h3 >
67+ < p className = "text-sm text-sky-700 dark:text-sky-400" >
68+ Configure your search parameters and visualize web browsing automation with tree search algorithms.
69+ </ p >
70+ </ div >
71+ </ div >
72+ { showParameters ? < ChevronUp className = "text-cyan-600" /> : < ChevronDown className = "text-cyan-600" /> }
73+ </ div >
74+
75+ { showParameters && (
76+ < div className = "p-4 border-t border-sky-200 dark:border-sky-800 bg-white/90 dark:bg-slate-800/90" >
77+ { /* Instructions */ }
78+ < div className = "mb-4 ml-1 text-sm text-slate-700 dark:text-slate-300" >
79+ < ol className = "list-decimal list-inside space-y-1" >
80+ < li > Click the "Start" button above to connect and begin the search.</ li >
81+ < li > Configure your search parameters below.</ li >
82+ < li > The tree of possible actions will appear on the right, while the resulting web page will display on the left.</ li >
83+ < li > You can drag the divider to resize the panels as needed.</ li >
84+ </ ol >
85+ </ div >
86+
87+ { /* Parameters Grid */ }
88+ < div className = "grid grid-cols-1 md:grid-cols-4 gap-4 mt-4" >
89+ < div className = "space-y-2" >
90+ < Label htmlFor = "startingUrl" className = "text-slate-700 dark:text-slate-300 font-medium" > Starting URL</ Label >
91+ < Input
92+ id = "startingUrl"
93+ value = { searchParams . startingUrl }
94+ onChange = { ( e ) => handleParamChange ( 'startingUrl' , e . target . value ) }
95+ className = "border-slate-300 dark:border-slate-600 focus:ring-cyan-500 focus:border-cyan-500"
96+ />
97+ </ div >
98+
99+ < div className = "space-y-2" >
100+ < Label htmlFor = "goal" className = "text-slate-700 dark:text-slate-300 font-medium" > Goal</ Label >
101+ < Input
102+ id = "goal"
103+ value = { searchParams . goal }
104+ onChange = { ( e ) => handleParamChange ( 'goal' , e . target . value ) }
105+ className = "border-slate-300 dark:border-slate-600 focus:ring-cyan-500 focus:border-cyan-500"
106+ />
107+ </ div >
108+
109+ < div className = "space-y-2" >
110+ < Label htmlFor = "maxDepth" className = "text-slate-700 dark:text-slate-300 font-medium" > Max Depth</ Label >
111+ < Input
112+ id = "maxDepth"
113+ type = "number"
114+ min = { 1 }
115+ max = { 10 }
116+ value = { searchParams . maxDepth }
117+ onChange = { ( e ) => handleParamChange ( 'maxDepth' , parseInt ( e . target . value ) ) }
118+ className = "border-slate-300 dark:border-slate-600 focus:ring-cyan-500 focus:border-cyan-500"
119+ />
120+ </ div >
121+
122+ < div className = "space-y-2" >
123+ < Label htmlFor = "num_simulations" className = "text-slate-700 dark:text-slate-300 font-medium" > Number of Simulations</ Label >
124+ < Input
125+ id = "num_simulations"
126+ type = "number"
127+ min = { 1 }
128+ max = { 100 }
129+ value = { searchParams . num_simulations }
130+ onChange = { ( e ) => handleParamChange ( 'num_simulations' , parseInt ( e . target . value ) ) }
131+ className = "border-slate-300 dark:border-slate-600 focus:ring-cyan-500 focus:border-cyan-500"
132+ />
133+ </ div >
134+ </ div >
135+ </ div >
136+ ) }
137+ </ div >
138+ </ div >
139+ </ div >
140+ ) ;
141+ } ;
142+
143+ export default ControlPanelLATS ;
0 commit comments