11import { atom , computed } from "nanostores" ;
22import { useStore } from "@nanostores/react" ;
3+ import { useState } from "react" ;
4+ import { matchSorter } from "match-sorter" ;
35import {
46 collectionComponent ,
57 componentCategories ,
@@ -15,15 +17,19 @@ import {
1517 CommandGroupHeading ,
1618 CommandItem ,
1719 CommandIcon ,
20+ useSelectedAction ,
1821 ScrollArea ,
1922 Flex ,
2023 Kbd ,
2124 Text ,
25+ CommandFooter ,
26+ Separator ,
2227} from "@webstudio-is/design-system" ;
2328import { compareMedia } from "@webstudio-is/css-engine" ;
2429import type { Breakpoint , Page } from "@webstudio-is/sdk" ;
2530import {
2631 $breakpoints ,
32+ $editingPageId ,
2733 $pages ,
2834 $registeredComponentMetas ,
2935 $selectedBreakpoint ,
@@ -34,9 +40,8 @@ import { humanizeString } from "~/shared/string-utils";
3440import { setCanvasWidth } from "~/builder/features/breakpoints" ;
3541import { insert as insertComponent } from "~/builder/features/components/insert" ;
3642import { $selectedPage , selectPage } from "~/shared/awareness" ;
37- import { useState } from "react" ;
38- import { matchSorter } from "match-sorter" ;
3943import { mapGroupBy } from "~/shared/shim" ;
44+ import { setActiveSidebarPanel } from "~/builder/shared/nano-states" ;
4045
4146const $commandPanel = atom <
4247 | undefined
@@ -124,30 +129,35 @@ const $componentOptions = computed(
124129 }
125130) ;
126131
127- const ComponentsGroup = ( { options } : { options : ComponentOption [ ] } ) => {
132+ const ComponentGroup = ( { options } : { options : ComponentOption [ ] } ) => {
128133 return (
129134 < CommandGroup
135+ name = "component"
130136 heading = { < CommandGroupHeading > Components</ CommandGroupHeading > }
137+ actions = { [ "add" ] }
131138 >
132139 { options . map ( ( { component, label, meta } ) => {
133140 return (
134141 < CommandItem
135142 key = { component }
136- keywords = { [ "Components" ] }
143+ // preserve selected state when rerender
144+ value = { component }
137145 onSelect = { ( ) => {
138146 closeCommandPanel ( ) ;
139147 insertComponent ( component ) ;
140148 } }
141149 >
142- < CommandIcon
143- dangerouslySetInnerHTML = { { __html : meta . icon } }
144- > </ CommandIcon >
145- < Text variant = "labelsTitleCase" >
146- { label } { " " }
147- < Text as = "span" color = "moreSubtle" >
148- { humanizeString ( meta . category ?? "" ) }
150+ < Flex gap = { 2 } >
151+ < CommandIcon
152+ dangerouslySetInnerHTML = { { __html : meta . icon } }
153+ > </ CommandIcon >
154+ < Text variant = "labelsTitleCase" >
155+ { label } { " " }
156+ < Text as = "span" color = "moreSubtle" >
157+ { humanizeString ( meta . category ?? "" ) }
158+ </ Text >
149159 </ Text >
150- </ Text >
160+ </ Flex >
151161 </ CommandItem >
152162 ) ;
153163 } ) }
@@ -198,21 +208,24 @@ const getBreakpointLabel = (breakpoint: Breakpoint) => {
198208 return `${ breakpoint . label } : ${ label } ` ;
199209} ;
200210
201- const BreakpointsGroup = ( { options } : { options : BreakpointOption [ ] } ) => {
211+ const BreakpointGroup = ( { options } : { options : BreakpointOption [ ] } ) => {
202212 return (
203213 < CommandGroup
214+ name = "breakpoint"
204215 heading = { < CommandGroupHeading > Breakpoints</ CommandGroupHeading > }
216+ actions = { [ "select" ] }
205217 >
206218 { options . map ( ( { breakpoint, shortcut } ) => (
207219 < CommandItem
208220 key = { breakpoint . id }
221+ // preserve selected state when rerender
222+ value = { breakpoint . id }
209223 onSelect = { ( ) => {
210224 closeCommandPanel ( { restoreFocus : true } ) ;
211225 $selectedBreakpointId . set ( breakpoint . id ) ;
212226 setCanvasWidth ( breakpoint . id ) ;
213227 } }
214228 >
215- < CommandIcon > </ CommandIcon >
216229 < Text variant = "labelsTitleCase" >
217230 { getBreakpointLabel ( breakpoint ) }
218231 </ Text >
@@ -249,18 +262,33 @@ const $pageOptions = computed(
249262 }
250263) ;
251264
252- const PagesGroup = ( { options } : { options : PageOption [ ] } ) => {
265+ const PageGroup = ( { options } : { options : PageOption [ ] } ) => {
266+ const action = useSelectedAction ( ) ;
253267 return (
254- < CommandGroup heading = { < CommandGroupHeading > Pages</ CommandGroupHeading > } >
268+ < CommandGroup
269+ name = "page"
270+ heading = { < CommandGroupHeading > Pages</ CommandGroupHeading > }
271+ actions = { [ "select" , "settings" ] }
272+ >
255273 { options . map ( ( { page } ) => (
256274 < CommandItem
257275 key = { page . id }
276+ // preserve selected state when rerender
277+ value = { page . id }
258278 onSelect = { ( ) => {
259279 closeCommandPanel ( ) ;
260- selectPage ( page . id ) ;
280+ if ( action === "select" ) {
281+ selectPage ( page . id ) ;
282+ setActiveSidebarPanel ( "auto" ) ;
283+ $editingPageId . set ( undefined ) ;
284+ }
285+ if ( action === "settings" ) {
286+ selectPage ( page . id ) ;
287+ setActiveSidebarPanel ( "pages" ) ;
288+ $editingPageId . set ( page . id ) ;
289+ }
261290 } }
262291 >
263- < CommandIcon > </ CommandIcon >
264292 < Text variant = "labelsTitleCase" > { page . name } </ Text >
265293 </ CommandItem >
266294 ) ) }
@@ -288,38 +316,41 @@ const CommandDialogContent = () => {
288316 }
289317 const groups = mapGroupBy ( matches , ( match ) => match . type ) ;
290318 return (
291- < Command shouldFilter = { false } >
319+ < >
292320 < CommandInput value = { search } onValueChange = { setSearch } />
293321 < Flex direction = "column" css = { { maxHeight : 300 } } >
294322 < ScrollArea >
295323 < CommandList >
296324 { Array . from ( groups ) . map ( ( [ group , matches ] ) => {
297325 if ( group === "component" ) {
298326 return (
299- < ComponentsGroup
327+ < ComponentGroup
300328 key = { group }
301329 options = { matches as ComponentOption [ ] }
302330 />
303331 ) ;
304332 }
305333 if ( group === "breakpoint" ) {
306334 return (
307- < BreakpointsGroup
335+ < BreakpointGroup
308336 key = { group }
309337 options = { matches as BreakpointOption [ ] }
310338 />
311339 ) ;
312340 }
313341 if ( group === "page" ) {
314342 return (
315- < PagesGroup key = { group } options = { matches as PageOption [ ] } />
343+ < PageGroup key = { group } options = { matches as PageOption [ ] } />
316344 ) ;
317345 }
346+ group satisfies never ;
318347 } ) }
319348 </ CommandList >
320349 </ ScrollArea >
321350 </ Flex >
322- </ Command >
351+ < Separator />
352+ < CommandFooter />
353+ </ >
323354 ) ;
324355} ;
325356
@@ -330,7 +361,9 @@ export const CommandPanel = () => {
330361 open = { isOpen }
331362 onOpenChange = { ( ) => closeCommandPanel ( { restoreFocus : true } ) }
332363 >
333- < CommandDialogContent />
364+ < Command shouldFilter = { false } >
365+ < CommandDialogContent />
366+ </ Command >
334367 </ CommandDialog >
335368 ) ;
336369} ;
0 commit comments