@@ -31,6 +31,28 @@ import {
3131} from '@devtools/kit' ;
3232import { createHighlighter } from 'shiki' ;
3333import { getQwikState , returnQrlData } from './data' ;
34+ import { HiChevronUpMini } from '@qwikest/icons/heroicons' ;
35+
36+ function getValueColorClass ( node : TreeNode , valueText : string ) : string {
37+ switch ( node . elementType ) {
38+ case 'string' :
39+ return 'text-red-400' ;
40+ case 'number' :
41+ return 'text-green-400' ;
42+ case 'boolean' :
43+ return 'text-amber-400' ;
44+ case 'function' :
45+ return 'text-purple-400' ;
46+ case 'array' :
47+ return 'text-muted-foreground' ;
48+ case 'object' :
49+ return / ( A r r a y \[ | O b j e c t \s \{ | C l a s s \s \{ ) / . test ( valueText )
50+ ? 'text-muted-foreground'
51+ : 'text-foreground' ;
52+ default :
53+ return 'text-foreground' ;
54+ }
55+ }
3456
3557export const RenderTree = component$ ( ( ) => {
3658 useStyles$ ( `
@@ -46,6 +68,7 @@ export const RenderTree = component$(() => {
4668
4769 const stateTree = useSignal < TreeNode [ ] > ( [ ] ) ;
4870 const hookFilters = useSignal < { key : QSeqsList ; display : boolean } [ ] > ( [ ] ) ;
71+ const hooksOpen = useSignal ( true ) ;
4972
5073 const qwikContainer = useComputed$ ( ( ) => {
5174 try {
@@ -132,7 +155,7 @@ export const RenderTree = component$(() => {
132155 const currentTab = useSignal < 'state' | 'code' > ( 'state' ) ;
133156
134157 return (
135- < div class = "h-full w-full flex-1 overflow-hidden rounded-md border border-border" >
158+ < div class = "h-full w-full flex-1 overflow-hidden rounded-md border border-border bg-background " >
136159 < div class = "flex h-full w-full" >
137160 < div class = "w-1/2 overflow-hidden p-4" style = { { minWidth : '400px' } } >
138161 < Tree data = { data } onNodeClick = { onNodeClick } > </ Tree >
@@ -148,7 +171,7 @@ export const RenderTree = component$(() => {
148171 ? { borderBottom : '2px solid var(--color-primary-active)' }
149172 : { }
150173 }
151- class = "border-b-2 border-b-transparent px-4 py-3 text-sm font-medium transition-all duration-300 ease-in-out"
174+ class = "border-b-2 border-b-transparent px-4 py-3 text-sm font-medium transition-all duration-300 ease-in-out text-muted-foreground hover:text-foreground "
152175 >
153176 State
154177 </ button >
@@ -159,74 +182,95 @@ export const RenderTree = component$(() => {
159182 ? { borderBottom : '2px solid var(--color-primary-active)' }
160183 : { }
161184 }
162- class = "border-b-2 border-b-transparent px-4 py-3 text-sm font-medium transition-all duration-300 ease-in-out"
185+ class = "border-b-2 border-b-transparent px-4 py-3 text-sm font-medium transition-all duration-300 ease-in-out text-muted-foreground hover:text-foreground "
163186 >
164187 Code
165188 </ button >
166189 </ div >
167190 </ div >
168191
169192 { currentTab . value === 'state' && (
170- < div class = "mt-5 flex min-h-0 flex-1 flex-col rounded-lg border border-border bg-card-item-bg shadow-sm" >
171- < div class = "flex flex-wrap items-center gap-2 border-b border-border px-2 py-2" >
172- < span class = "text-xs text-muted-foreground" > Hooks:</ span >
173- { hookFilters . value . map ( ( item , idx ) => (
174- < label
175- class = "flex items-center space-x-1 rounded border border-border px-2 py-1 text-xs"
176- key = { idx }
193+ < div class = "mt-5 flex min-h-0 flex-1 flex-col" >
194+ < div class = "rounded-lg border border-border bg-card-item-bg shadow-sm" >
195+ < div class = "flex items-center justify-between border-b border-border px-2 py-2" >
196+ < span class = "text-xs font-medium text-muted-foreground" > Hooks</ span >
197+ < div class = "flex items-center space-x-2" >
198+ < button
199+ class = "text-xs text-primary hover:underline px-2 py-1"
200+ onClick$ = { $ ( ( ) => {
201+ hookFilters . value = hookFilters . value . map ( ( item ) => {
202+ item . display = true ;
203+ return item ;
204+ } ) ;
205+ stateTree . value = buildTree ( ) . filter ( ( item ) =>
206+ hookFilters . value . some (
207+ ( hook ) => hook . key === item ?. label && hook . display ,
208+ ) ,
209+ ) as TreeNode [ ] ;
210+ } ) }
211+ >
212+ Select all
213+ </ button >
214+ < button
215+ class = "text-xs text-muted-foreground hover:text-foreground hover:underline px-2 py-1"
216+ onClick$ = { $ ( ( ) => {
217+ hookFilters . value = hookFilters . value . map ( ( item ) => {
218+ item . display = false ;
219+ return item ;
220+ } ) ;
221+ stateTree . value = buildTree ( ) . filter ( ( item ) =>
222+ hookFilters . value . some (
223+ ( hook ) => hook . key === item ?. label && hook . display ,
224+ ) ,
225+ ) as TreeNode [ ] ;
226+ } ) }
177227 >
228+ Clear
229+ </ button >
230+ < button
231+ aria-label = "toggle hooks"
232+ onClick$ = { $ ( ( ) => ( hooksOpen . value = ! hooksOpen . value ) ) }
233+ class = "rounded p-1 text-muted-foreground hover:text-foreground"
234+ >
235+ < HiChevronUpMini
236+ class = { `h-4 w-4 transition-transform duration-200 ${
237+ hooksOpen . value ? 'rotate-180' : '-rotate-90'
238+ } `}
239+ />
240+ </ button >
241+ </ div >
242+ </ div >
243+ < div
244+ class = "grid grid-cols-2 sm:grid-cols-3 lg:grid-cols-4 gap-x-6 gap-y-3 px-3 py-2 text-sm overflow-hidden"
245+ style = { {
246+ maxHeight : hooksOpen . value ? '800px' : '0px' ,
247+ opacity : hooksOpen . value ? '1' : '0' ,
248+ transition : 'max-height 200ms ease, opacity 200ms ease' ,
249+ } }
250+ >
251+ { hookFilters . value . map ( ( item , idx ) => (
252+ < label key = { idx } class = "flex items-center" >
178253 < input
254+ class = "h-4 w-4 rounded-full border-border focus:ring-primary-active focus:ring-offset-0 dark:bg-[#1F2937] dark:border-[#374151]"
255+ style = { { accentColor : 'var(--color-primary-active)' } }
179256 type = "checkbox"
180257 checked = { item . display }
181258 onChange$ = { ( ev ) => {
182259 const target = ev . target as HTMLInputElement ;
183-
184260 hookFilters . value [ idx ] . display = target . checked ;
185-
186261 stateTree . value = buildTree ( ) . filter ( ( item ) =>
187262 hookFilters . value . some (
188263 ( hook ) => hook . key === item ?. label && hook . display ,
189264 ) ,
190265 ) as TreeNode [ ] ;
191266 } }
192267 />
193- < span > { item . key } </ span >
268+ < span class = "ml-2 select-none" > { item . key } </ span >
194269 </ label >
195270 ) ) }
196- < button
197- class = "ml-auto rounded border border-border px-2 py-1 text-xs"
198- onClick$ = { $ ( ( ) => {
199- hookFilters . value = hookFilters . value . map ( ( item ) => {
200- item . display = true ;
201- return item ;
202- } ) ;
203- stateTree . value = buildTree ( ) . filter ( ( item ) =>
204- hookFilters . value . some (
205- ( hook ) => hook . key === item ?. label && hook . display ,
206- ) ,
207- ) as TreeNode [ ] ;
208- } ) }
209- >
210- Select all
211- </ button >
212- < button
213- class = "rounded border border-border px-2 py-1 text-xs"
214- onClick$ = { $ ( ( ) => {
215- hookFilters . value = hookFilters . value . map ( ( item ) => {
216- item . display = false ;
217- return item ;
218- } ) ;
219- stateTree . value = buildTree ( ) . filter ( ( item ) =>
220- hookFilters . value . some (
221- ( hook ) => hook . key === item ?. label && hook . display ,
222- ) ,
223- ) as TreeNode [ ] ;
224- } ) }
225- >
226- Clear
227- </ button >
228271 </ div >
229- < div class = "min-h-0 flex-1 overflow-y-auto p-2" >
272+ </ div >
273+ < div class = "min-h-0 flex-1 overflow-y-auto p-2 mt-4" >
230274 < Tree
231275 data = { stateTree }
232276 gap = { 10 }
@@ -235,32 +279,35 @@ export const RenderTree = component$(() => {
235279 isHover
236280 renderNode = { $ ( ( node ) => {
237281 const label = node . label || node . name || '' ;
238- const isProperty = label . split ( ':' ) ;
239- return isProperty . length > 1 ? (
240- < >
241- < span class = "text-red-300 dark:text-red-500" >
242- { isProperty [ 0 ] }
243- </ span >
244- < span class = "text-gray-700 dark:text-white" >
245- { ' ' }
246- : { isProperty [ 1 ] }
247- </ span >
248- </ >
249- ) : (
250- < span > { label } </ span >
251- ) ;
282+ const parts = label . split ( ':' ) ;
283+ if ( node . children && parts . length === 1 ) {
284+ return < span class = "font-semibold text-pink-400" > { label } </ span > ;
285+ }
286+ if ( parts . length > 1 ) {
287+ const key = parts [ 0 ] ;
288+ const value = parts . slice ( 1 ) . join ( ':' ) . trim ( ) ;
289+ const valueClass = getValueColorClass ( node , value ) ;
290+ return (
291+ < >
292+ < span class = "text-blue-400" > { key } </ span >
293+ < span class = "text-foreground/70" > : </ span >
294+ < span class = { valueClass } > { value } </ span >
295+ </ >
296+ ) ;
297+ }
298+ return < span > { label } </ span > ;
252299 } ) }
253300 > </ Tree >
254301 </ div >
255302 </ div >
256303 ) }
257304
258305 { currentTab . value === 'code' && (
259- < div class = "mt-5 min-h-0 flex-1 overflow-y-auto rounded-lg border border-border p-2 shadow-sm" >
306+ < div class = "mt-5 min-h-0 flex-1 overflow-y-auto rounded-lg border border-border p-2 shadow-sm" >
260307 { codes . value . map ( ( item , idx ) => {
261308 return (
262309 < >
263- < div class = "mb-4 rounded-xl border border-border bg-background p-4 shadow-lg " >
310+ < div class = "mb-4 rounded-xl border border-border bg-card-item-bg p-4 shadow-sm hover:bg-card-item-hover-bg transition-colors " >
264311 < div class = "mb-2 break-all text-base font-semibold text-primary" >
265312 { item . pathId }
266313 </ div >
0 commit comments