1
1
/**
2
2
* WordPress dependencies
3
3
*/
4
- import { useContext , useEffect , useState , useMemo } from '@wordpress/element' ;
4
+ import {
5
+ useContext ,
6
+ useEffect ,
7
+ useState ,
8
+ useMemo ,
9
+ createInterpolateElement ,
10
+ } from '@wordpress/element' ;
5
11
import {
6
12
__experimentalSpacer as Spacer ,
7
13
__experimentalInputControl as InputControl ,
8
14
__experimentalText as Text ,
15
+ __experimentalHStack as HStack ,
9
16
SelectControl ,
10
17
Spinner ,
11
18
Icon ,
@@ -14,15 +21,14 @@ import {
14
21
Button ,
15
22
} from '@wordpress/components' ;
16
23
import { debounce } from '@wordpress/compose' ;
17
- import { __ , _x } from '@wordpress/i18n' ;
24
+ import { sprintf , __ , _x } from '@wordpress/i18n' ;
18
25
import { search , closeSmall } from '@wordpress/icons' ;
19
26
20
27
/**
21
28
* Internal dependencies
22
29
*/
23
30
import TabPanelLayout from './tab-panel-layout' ;
24
31
import { FontLibraryContext } from './context' ;
25
- import FontsGrid from './fonts-grid' ;
26
32
import FontCard from './font-card' ;
27
33
import filterFonts from './utils/filter-fonts' ;
28
34
import CollectionFontDetails from './collection-font-details' ;
@@ -48,6 +54,7 @@ function FontCollection( { slug } ) {
48
54
49
55
const [ selectedFont , setSelectedFont ] = useState ( null ) ;
50
56
const [ fontsToInstall , setFontsToInstall ] = useState ( [ ] ) ;
57
+ const [ page , setPage ] = useState ( 1 ) ;
51
58
const [ filters , setFilters ] = useState ( { } ) ;
52
59
const [ renderConfirmDialog , setRenderConfirmDialog ] = useState (
53
60
requiresPermission && ! getGoogleFontsPermissionFromStorage ( )
@@ -109,22 +116,34 @@ function FontCollection( { slug } ) {
109
116
[ collectionFonts , filters ]
110
117
) ;
111
118
119
+ // NOTE: The height of the font library modal unavailable to use for rendering font family items is roughly 417px
120
+ // The height of each font family item is 61px.
121
+ const pageSize = Math . floor ( ( window . innerHeight - 417 ) / 61 ) ;
122
+ const totalPages = Math . ceil ( fonts . length / pageSize ) ;
123
+ const itemsStart = ( page - 1 ) * pageSize ;
124
+ const itemsLimit = page * pageSize ;
125
+ const items = fonts . slice ( itemsStart , itemsLimit ) ;
126
+
112
127
const handleCategoryFilter = ( category ) => {
113
128
setFilters ( { ...filters , category } ) ;
129
+ setPage ( 1 ) ;
114
130
} ;
115
131
116
132
const handleUpdateSearchInput = ( value ) => {
117
133
setFilters ( { ...filters , search : value } ) ;
134
+ setPage ( 1 ) ;
118
135
} ;
119
136
120
137
const debouncedUpdateSearchInput = debounce ( handleUpdateSearchInput , 300 ) ;
121
138
122
139
const resetFilters = ( ) => {
123
140
setFilters ( { } ) ;
141
+ setPage ( 1 ) ;
124
142
} ;
125
143
126
144
const resetSearch = ( ) => {
127
145
setFilters ( { ...filters , search : '' } ) ;
146
+ setPage ( 1 ) ;
128
147
} ;
129
148
130
149
const handleUnselectFont = ( ) => {
@@ -186,6 +205,24 @@ function FontCollection( { slug } ) {
186
205
resetFontsToInstall ( ) ;
187
206
} ;
188
207
208
+ let footerComponent = null ;
209
+ if ( selectedFont ) {
210
+ footerComponent = (
211
+ < InstallFooter
212
+ handleInstall = { handleInstall }
213
+ isDisabled = { fontsToInstall . length === 0 }
214
+ />
215
+ ) ;
216
+ } else if ( ! renderConfirmDialog && totalPages > 1 ) {
217
+ footerComponent = (
218
+ < PaginationFooter
219
+ page = { page }
220
+ totalPages = { totalPages }
221
+ setPage = { setPage }
222
+ />
223
+ ) ;
224
+ }
225
+
189
226
return (
190
227
< TabPanelLayout
191
228
title = {
@@ -198,12 +235,7 @@ function FontCollection( { slug } ) {
198
235
}
199
236
notice = { notice }
200
237
handleBack = { ! ! selectedFont && handleUnselectFont }
201
- footer = {
202
- < Footer
203
- handleInstall = { handleInstall }
204
- isDisabled = { fontsToInstall . length === 0 }
205
- />
206
- }
238
+ footer = { footerComponent }
207
239
>
208
240
{ renderConfirmDialog && (
209
241
< >
@@ -275,8 +307,8 @@ function FontCollection( { slug } ) {
275
307
) }
276
308
277
309
{ ! renderConfirmDialog && ! selectedFont && (
278
- < FontsGrid >
279
- { fonts . map ( ( font ) => (
310
+ < div className = "font-library-modal__fonts-grid__main" >
311
+ { items . map ( ( font ) => (
280
312
< FontCard
281
313
key = { font . font_family_settings . slug }
282
314
font = { font . font_family_settings }
@@ -285,13 +317,86 @@ function FontCollection( { slug } ) {
285
317
} }
286
318
/>
287
319
) ) }
288
- </ FontsGrid >
320
+ </ div >
289
321
) }
290
322
</ TabPanelLayout >
291
323
) ;
292
324
}
293
325
294
- function Footer ( { handleInstall, isDisabled } ) {
326
+ function PaginationFooter ( { page, totalPages, setPage } ) {
327
+ return (
328
+ < Flex justify = "center" >
329
+ < Button
330
+ label = { __ ( 'First page' ) }
331
+ size = "compact"
332
+ onClick = { ( ) => setPage ( 1 ) }
333
+ disabled = { page === 1 }
334
+ __experimentalIsFocusable
335
+ >
336
+ < span > «</ span >
337
+ </ Button >
338
+ < Button
339
+ label = { __ ( 'Previous page' ) }
340
+ size = "compact"
341
+ onClick = { ( ) => setPage ( page - 1 ) }
342
+ disabled = { page === 1 }
343
+ __experimentalIsFocusable
344
+ >
345
+ < span > ‹</ span >
346
+ </ Button >
347
+ < HStack justify = "flex-start" expanded = { false } spacing = { 2 } >
348
+ { createInterpolateElement (
349
+ sprintf (
350
+ // translators: %s: Total number of pages.
351
+ _x ( 'Page <CurrenPageControl /> of %s' , 'paging' ) ,
352
+ totalPages
353
+ ) ,
354
+ {
355
+ CurrenPageControl : (
356
+ < SelectControl
357
+ aria-label = { __ ( 'Current page' ) }
358
+ value = { page }
359
+ options = { [ ...Array ( totalPages ) ] . map (
360
+ ( e , i ) => {
361
+ return {
362
+ label : i + 1 ,
363
+ value : i + 1 ,
364
+ } ;
365
+ }
366
+ ) }
367
+ onChange = { ( newPage ) =>
368
+ setPage ( parseInt ( newPage ) )
369
+ }
370
+ size = { 'compact' }
371
+ __nextHasNoMarginBottom
372
+ />
373
+ ) ,
374
+ }
375
+ ) }
376
+ </ HStack >
377
+ < Button
378
+ label = { __ ( 'Next page' ) }
379
+ size = "compact"
380
+ onClick = { ( ) => setPage ( page + 1 ) }
381
+ disabled = { page === totalPages }
382
+ __experimentalIsFocusable
383
+ >
384
+ < span > ›</ span >
385
+ </ Button >
386
+ < Button
387
+ label = { __ ( 'Last page' ) }
388
+ size = "compact"
389
+ onClick = { ( ) => setPage ( totalPages ) }
390
+ disabled = { page === totalPages }
391
+ __experimentalIsFocusable
392
+ >
393
+ < span > »</ span >
394
+ </ Button >
395
+ </ Flex >
396
+ ) ;
397
+ }
398
+
399
+ function InstallFooter ( { handleInstall, isDisabled } ) {
295
400
const { isInstalling } = useContext ( FontLibraryContext ) ;
296
401
297
402
return (
0 commit comments