7
7
ThemeProvider ,
8
8
} from '@codesandbox/components' ;
9
9
import { useActions , useAppState } from 'app/overmind' ;
10
- import React , { ReactNode , useState } from 'react' ;
10
+ import React , { ReactNode , useState , useEffect } from 'react' ;
11
11
import { TabStateReturn , useTabState } from 'reakit/Tab' ;
12
12
import slugify from '@codesandbox/common/lib/utils/slugify' ;
13
13
import { getTemplateIcon } from '@codesandbox/common/lib/utils/getTemplateIcon' ;
@@ -31,6 +31,8 @@ import { useOfficialTemplates } from './useOfficialTemplates';
31
31
import { useTeamTemplates } from './useTeamTemplates' ;
32
32
import { CloudBetaBadge } from '../../CloudBetaBadge' ;
33
33
import { CreateSandboxParams } from './types' ;
34
+ import { SearchBox } from './SearchBox' ;
35
+ import { SearchResults } from './SearchResults' ;
34
36
35
37
export const COLUMN_MEDIA_THRESHOLD = 1600 ;
36
38
@@ -80,6 +82,8 @@ export const CreateSandbox: React.FC<CreateSandboxProps> = ({
80
82
const { hasLogIn, activeTeamInfo, user } = useAppState ( ) ;
81
83
const actions = useActions ( ) ;
82
84
const isSyncedSandboxesPage = location . pathname . includes ( '/synced-sandboxes' ) ;
85
+ const defaultSelectedTab =
86
+ initialTab || isSyncedSandboxesPage ? 'import' : 'quickstart' ;
83
87
const isUser = user ?. username === activeTeamInfo ?. name ;
84
88
85
89
/**
@@ -131,14 +135,21 @@ export const CreateSandbox: React.FC<CreateSandboxProps> = ({
131
135
132
136
const tabState = useTabState ( {
133
137
orientation : 'vertical' ,
134
- selectedId : initialTab || isSyncedSandboxesPage ? 'import' : 'quickstart' ,
138
+ selectedId : defaultSelectedTab ,
135
139
} ) ;
136
140
137
141
const [ viewState , setViewState ] = useState <
138
- 'initial' | 'fromTemplate' | 'fork' /* | 'search' */
142
+ 'initial' | 'fromTemplate' | 'fork'
139
143
> ( 'initial' ) ;
140
144
// ❗️ We could combine viewState with selectedtemplate to limit the amout of states.
141
145
const [ selectedTemplate , setSelectedTemplate ] = useState < TemplateFragment > ( ) ;
146
+ const [ searchQuery , setSearchQuery ] = useState < string > ( '' ) ;
147
+
148
+ useEffect ( ( ) => {
149
+ if ( searchQuery && tabState . selectedId ) {
150
+ setSearchQuery ( '' ) ;
151
+ }
152
+ } , [ tabState . selectedId ] ) ;
142
153
143
154
const createFromTemplate = (
144
155
template : TemplateFragment ,
@@ -189,10 +200,21 @@ export const CreateSandbox: React.FC<CreateSandboxProps> = ({
189
200
</ HeaderInformation >
190
201
191
202
{ viewState === 'initial' ? (
192
- < div >
193
- { /* ❗️ TODO: Search */ }
194
- search
195
- </ div >
203
+ < SearchBox
204
+ value = { searchQuery }
205
+ onChange = { e => {
206
+ const query = e . target . value ;
207
+ if ( query ) {
208
+ // Reset tab panel when typing in the search query box
209
+ tabState . select ( null ) ;
210
+ } else {
211
+ // Restore the default tab when search query is removed
212
+ tabState . select ( defaultSelectedTab ) ;
213
+ }
214
+
215
+ setSearchQuery ( query ) ;
216
+ } }
217
+ />
196
218
) : null }
197
219
198
220
{ /* isModal is undefined on /s/ page */ }
@@ -280,66 +302,74 @@ export const CreateSandbox: React.FC<CreateSandboxProps> = ({
280
302
</ ModalSidebar >
281
303
282
304
< ModalContent >
283
- { viewState === 'initial' ? (
284
- < >
285
- < Panel tab = { tabState } id = "quickstart" >
286
- < TemplateCategoryList
287
- title = "Start from a template"
288
- templates = { quickStartTemplates }
289
- onSelectTemplate = { selectTemplate }
290
- />
291
- </ Panel >
292
-
293
- < Panel tab = { tabState } id = "import" >
294
- < Import />
295
- </ Panel >
296
-
297
- { showTeamTemplates ? (
298
- < Panel tab = { tabState } id = "team-templates" >
305
+ { viewState === 'initial' &&
306
+ ( searchQuery ? (
307
+ < SearchResults
308
+ search = { searchQuery }
309
+ onSelectTemplate = { selectTemplate }
310
+ />
311
+ ) : (
312
+ < >
313
+ < Panel tab = { tabState } id = "quickstart" >
299
314
< TemplateCategoryList
300
- title = { ` ${ isUser ? 'My' : activeTeamInfo . name } templates` }
301
- templates = { teamTemplates }
315
+ title = "Start from a template"
316
+ templates = { quickStartTemplates }
302
317
onSelectTemplate = { selectTemplate }
303
318
/>
304
319
</ Panel >
305
- ) : null }
306
-
307
- < Panel tab = { tabState } id = "cloud-templates" >
308
- < TemplateCategoryList
309
- title = "Cloud templates"
310
- showBetaTag
311
- templates = { officialTemplates . filter (
312
- template => template . sandbox . isV2
313
- ) }
314
- onSelectTemplate = { selectTemplate }
315
- />
316
- </ Panel >
317
-
318
- < Panel tab = { tabState } id = "official-templates" >
319
- < TemplateCategoryList
320
- title = "Official templates"
321
- templates = { officialTemplates }
322
- onSelectTemplate = { selectTemplate }
323
- />
324
- </ Panel >
325
-
326
- { essentialState . state === 'success'
327
- ? essentialState . essentials . map ( essential => (
328
- < Panel
329
- key = { essential . key }
330
- tab = { tabState }
331
- id = { slugify ( essential . title ) }
332
- >
333
- < TemplateCategoryList
334
- title = { essential . title }
335
- templates = { essential . templates }
336
- onSelectTemplate = { selectTemplate }
337
- />
338
- </ Panel >
339
- ) )
340
- : null }
341
- </ >
342
- ) : null }
320
+
321
+ < Panel tab = { tabState } id = "import" >
322
+ < Import />
323
+ </ Panel >
324
+
325
+ { showTeamTemplates ? (
326
+ < Panel tab = { tabState } id = "team-templates" >
327
+ < TemplateCategoryList
328
+ title = { `${
329
+ isUser ? 'My' : activeTeamInfo . name
330
+ } templates`}
331
+ templates = { teamTemplates }
332
+ onSelectTemplate = { selectTemplate }
333
+ />
334
+ </ Panel >
335
+ ) : null }
336
+
337
+ < Panel tab = { tabState } id = "cloud-templates" >
338
+ < TemplateCategoryList
339
+ title = "Cloud templates"
340
+ showBetaTag
341
+ templates = { officialTemplates . filter (
342
+ template => template . sandbox . isV2
343
+ ) }
344
+ onSelectTemplate = { selectTemplate }
345
+ />
346
+ </ Panel >
347
+
348
+ < Panel tab = { tabState } id = "official-templates" >
349
+ < TemplateCategoryList
350
+ title = "Official templates"
351
+ templates = { officialTemplates }
352
+ onSelectTemplate = { selectTemplate }
353
+ />
354
+ </ Panel >
355
+
356
+ { essentialState . state === 'success'
357
+ ? essentialState . essentials . map ( essential => (
358
+ < Panel
359
+ key = { essential . key }
360
+ tab = { tabState }
361
+ id = { slugify ( essential . title ) }
362
+ >
363
+ < TemplateCategoryList
364
+ title = { essential . title }
365
+ templates = { essential . templates }
366
+ onSelectTemplate = { selectTemplate }
367
+ />
368
+ </ Panel >
369
+ ) )
370
+ : null }
371
+ </ >
372
+ ) ) }
343
373
344
374
{ viewState === 'fromTemplate' ? (
345
375
< FromTemplate
0 commit comments