@@ -8,16 +8,19 @@ import { useEffect, useMemo, useRef, useState } from "react";
88import { useStore } from "../state.store" ;
99import { FrameMessage } from "../types" ;
1010import { useWhisker } from "../hooks.useWhisker" ;
11+ import cls from "classnames" ;
1112
1213export function FrameInspector ( ) {
1314 const [ selectedTypes , setSelectedTypes ] = useState < Set < string > > ( new Set ( ) ) ;
1415 const [ isFilterOpen , setIsFilterOpen ] = useState ( false ) ;
1516 const [ typeSearch , setTypeSearch ] = useState ( "" ) ;
16- const [ showPush , setShowPush ] = useState ( true ) ;
17- const [ showProcess , setShowProcess ] = useState ( true ) ;
1817 const [ showUpstream , setShowUpstream ] = useState ( true ) ;
1918 const [ showDownstream , setShowDownstream ] = useState ( true ) ;
2019 const frames = useStore ( ( s ) => s . frames ) ;
20+ const showPush = useStore ( ( s ) => s . showPush ) ;
21+ const showProcess = useStore ( ( s ) => s . showProcess ) ;
22+ const setShowPush = useStore ( ( s ) => s . setShowPush ) ;
23+ const setShowProcess = useStore ( ( s ) => s . setShowProcess ) ;
2124 const selected = useStore ( ( s ) => s . selectedProcessor ) ;
2225 const selectedFrame = useStore ( ( s ) => s . selectedFrame ) ;
2326 const setSelectedFrame = useStore ( ( s ) => s . setSelectedFrame ) ;
@@ -93,25 +96,11 @@ export function FrameInspector() {
9396
9497 return (
9598 < div className = "split" >
96- < div style = { { display : "flex" , alignItems : "center" , gap : "8px" } } >
97- < div style = { { position : "relative" , flex : 1 } } >
99+ < div className = "filter-row" >
100+ < div className = "filter-dropdown" >
98101 < button
102+ className = "filter-button"
99103 onClick = { ( ) => setIsFilterOpen ( ! isFilterOpen ) }
100- style = { {
101- width : "100%" ,
102- padding : "8px 10px" ,
103- fontSize : "14px" ,
104- borderRadius : "8px" ,
105- border : "1px solid var(--border)" ,
106- margin : "4px 0 4px 0" ,
107- background : "var(--bg)" ,
108- color : "var(--text)" ,
109- cursor : "pointer" ,
110- textAlign : "left" ,
111- display : "flex" ,
112- justifyContent : "space-between" ,
113- alignItems : "center" ,
114- } }
115104 >
116105 < span >
117106 { selectedTypes . size === 0
@@ -121,223 +110,79 @@ export function FrameInspector() {
121110 < span > { isFilterOpen ? "▲" : "▼" } </ span >
122111 </ button >
123112 { isFilterOpen && (
124- < div
125- style = { {
126- position : "absolute" ,
127- top : "100%" ,
128- left : 0 ,
129- right : 0 ,
130- background : "var(--bg)" ,
131- border : "1px solid var(--border)" ,
132- borderRadius : "8px" ,
133- zIndex : 100 ,
134- maxHeight : "300px" ,
135- overflowY : "auto" ,
136- boxShadow : "0 4px 12px rgba(0,0,0,0.15)" ,
137- } }
138- >
139- < div
140- style = { {
141- display : "flex" ,
142- gap : "8px" ,
143- padding : "8px" ,
144- borderBottom : "1px solid var(--border)" ,
145- } }
146- >
147- < button
148- onClick = { selectAll }
149- style = { {
150- flex : 1 ,
151- padding : "6px 8px" ,
152- fontSize : "14px" ,
153- borderRadius : "4px" ,
154- border : "none" ,
155- background : "var(--border)" ,
156- color : "var(--text)" ,
157- cursor : "pointer" ,
158- fontWeight : 500 ,
159- } }
160- >
113+ < div className = "filter-menu" >
114+ < div className = "filter-menu-header" >
115+ < button className = "btn-sm" onClick = { selectAll } >
161116 Select All
162117 </ button >
163- < button
164- onClick = { clearAll }
165- style = { {
166- flex : 1 ,
167- padding : "6px 8px" ,
168- fontSize : "14px" ,
169- borderRadius : "4px" ,
170- border : "none" ,
171- background : "var(--border)" ,
172- color : "var(--text)" ,
173- cursor : "pointer" ,
174- fontWeight : 500 ,
175- } }
176- >
118+ < button className = "btn-sm" onClick = { clearAll } >
177119 Clear All
178120 </ button >
179121 </ div >
180- < div
181- style = { {
182- padding : "8px" ,
183- borderBottom : "1px solid var(--border)" ,
184- } }
185- >
122+ < div className = "filter-menu-search" >
186123 < input
187124 type = "text"
125+ className = "filter-input"
188126 placeholder = "Search frames..."
189127 value = { typeSearch }
190128 onChange = { ( e ) => setTypeSearch ( e . target . value ) }
191- style = { {
192- width : "100%" ,
193- padding : "6px 8px" ,
194- fontSize : "14px" ,
195- borderRadius : "4px" ,
196- border : "1px solid var(--border)" ,
197- background : "var(--bg)" ,
198- color : "var(--text)" ,
199- boxSizing : "border-box" ,
200- } }
201129 />
202130 </ div >
203131 { filteredTypes . length === 0 ? (
204- < div
205- style = { {
206- padding : "12px" ,
207- color : "var(--text)" ,
208- opacity : 0.6 ,
209- } }
210- >
211- No frames available
212- </ div >
132+ < div className = "filter-menu-empty" > No frames available</ div >
213133 ) : (
214134 filteredTypes . map ( ( type ) => (
215- < label
216- key = { type }
217- style = { {
218- display : "flex" ,
219- alignItems : "center" ,
220- gap : "8px" ,
221- padding : "8px 12px" ,
222- cursor : "pointer" ,
223- borderBottom : "1px solid var(--border)" ,
224- fontSize : "14px" ,
225- } }
226- >
135+ < label key = { type } className = "filter-menu-item" >
227136 < input
228137 type = "checkbox"
229138 checked = { selectedTypes . has ( type ) }
230139 onChange = { ( ) => toggleType ( type ) }
231- style = { { cursor : "pointer" } }
232140 />
233- < span style = { { color : "var(--text)" } } > { type } </ span >
141+ < span > { type } </ span >
234142 </ label >
235143 ) )
236144 ) }
237145 </ div >
238146 ) }
239147 </ div >
240- < div
241- style = { {
242- display : "flex" ,
243- gap : "8px" ,
244- padding : "6px 10px" ,
245- border : "1px solid var(--border)" ,
246- borderRadius : "8px" ,
247- } }
248- >
249- < label
250- style = { {
251- display : "flex" ,
252- alignItems : "center" ,
253- gap : "4px" ,
254- cursor : "pointer" ,
255- fontSize : "14px" ,
256- color : "var(--text)" ,
257- } }
258- >
148+ < div className = "checkbox-group" >
149+ < label className = "checkbox-label" >
259150 < input
260151 type = "checkbox"
261152 checked = { showPush }
262153 onChange = { ( e ) => setShowPush ( e . target . checked ) }
263- style = { { cursor : "pointer" } }
264154 />
265155 PUSH
266156 </ label >
267- < label
268- style = { {
269- display : "flex" ,
270- alignItems : "center" ,
271- gap : "4px" ,
272- cursor : "pointer" ,
273- fontSize : "14px" ,
274- color : "var(--text)" ,
275- } }
276- >
157+ < label className = "checkbox-label" >
277158 < input
278159 type = "checkbox"
279160 checked = { showProcess }
280161 onChange = { ( e ) => setShowProcess ( e . target . checked ) }
281- style = { { cursor : "pointer" } }
282162 />
283163 PROCESS
284164 </ label >
285165 </ div >
286- < div
287- style = { {
288- display : "flex" ,
289- gap : "8px" ,
290- padding : "6px 10px" ,
291- border : "1px solid var(--border)" ,
292- borderRadius : "8px" ,
293- } }
294- >
295- < label
296- style = { {
297- display : "flex" ,
298- alignItems : "center" ,
299- gap : "4px" ,
300- cursor : "pointer" ,
301- fontSize : "14px" ,
302- color : "var(--text)" ,
303- } }
304- >
166+ < div className = "checkbox-group" >
167+ < label className = "checkbox-label" >
305168 < input
306169 type = "checkbox"
307170 checked = { showUpstream }
308171 onChange = { ( e ) => setShowUpstream ( e . target . checked ) }
309- style = { { cursor : "pointer" } }
310172 />
311173 UPSTREAM
312174 </ label >
313- < label
314- style = { {
315- display : "flex" ,
316- alignItems : "center" ,
317- gap : "4px" ,
318- cursor : "pointer" ,
319- fontSize : "14px" ,
320- color : "var(--text)" ,
321- } }
322- >
175+ < label className = "checkbox-label" >
323176 < input
324177 type = "checkbox"
325178 checked = { showDownstream }
326179 onChange = { ( e ) => setShowDownstream ( e . target . checked ) }
327- style = { { cursor : "pointer" } }
328180 />
329181 DOWNSTREAM
330182 </ label >
331183 </ div >
332184 </ div >
333- < span
334- style = { {
335- fontSize : "14px" ,
336- color : "var(--text)" ,
337- opacity : 0.7 ,
338- margin : "4px 0" ,
339- } }
340- >
185+ < span className = "frame-count" >
341186 Showing { sortedFrames . length } frames out of { allFrames . length }
342187 </ span >
343188 < div className = "pane" >
@@ -390,23 +235,10 @@ function FrameItem({
390235 < div
391236 key = { `frame-${ frame . id } -${ idx } ` }
392237 ref = { ref }
393- className = "list-item"
394- style = { {
395- background : frameBackground ( frame ) ,
396- display : "flex" ,
397- flexDirection : "column" ,
398- border : isSelected ? "2px solid black" : "1px solid transparent" ,
399- } }
238+ className = { cls ( "list-item" , "frame-item" , { selected : isSelected } ) }
239+ style = { { background : frameBackground ( frame ) } }
400240 >
401- < div
402- style = { {
403- display : "flex" ,
404- alignItems : "center" ,
405- gap : 6 ,
406- cursor : "pointer" ,
407- } }
408- onClick = { onClick }
409- >
241+ < div className = "frame-header" onClick = { onClick } >
410242 < span > { frame . direction === "upstream" ? "⬆️️" : "⬇️️" } </ span >
411243 < span >
412244 < b > { frame . event === "process" ? "PROCESS ⚙️️" : "PUSH 🚀" } </ b >
@@ -415,13 +247,10 @@ function FrameItem({
415247 < span className = "footer-note" >
416248 • { new Date ( frame . timestamp ) . toISOString ( ) }
417249 </ span >
418- < span style = { { marginLeft : " auto" } } > { isSelected ? "▼" : "▶" } </ span >
250+ < span className = "ml- auto"> { isSelected ? "▼" : "▶" } </ span >
419251 </ div >
420252 { isSelected && (
421- < div
422- className = "footer-note"
423- style = { { whiteSpace : "pre-wrap" , marginTop : 4 , userSelect : "text" } }
424- >
253+ < div className = "footer-note frame-details" >
425254 { JSON . stringify ( frame . payload , null , 2 ) }
426255 </ div >
427256 ) }
0 commit comments