diff --git a/packages/edit-site/src/components/page-patterns/grid.js b/packages/edit-site/src/components/page-patterns/grid.js
index 1902b36982c14..47bcdc8a1f768 100644
--- a/packages/edit-site/src/components/page-patterns/grid.js
+++ b/packages/edit-site/src/components/page-patterns/grid.js
@@ -1,26 +1,115 @@
/**
* WordPress dependencies
*/
-import { __experimentalText as Text } from '@wordpress/components';
-import { useRef } from '@wordpress/element';
-import { __, sprintf } from '@wordpress/i18n';
+import {
+ __experimentalHStack as HStack,
+ __experimentalText as Text,
+ Button,
+} from '@wordpress/components';
+import { useRef, useState, useMemo } from '@wordpress/element';
+import { __, _x, _n, sprintf } from '@wordpress/i18n';
+import { useAsyncList } from '@wordpress/compose';
/**
* Internal dependencies
*/
import GridItem from './grid-item';
-const PAGE_SIZE = 100;
+const PAGE_SIZE = 20;
+
+function Pagination( { currentPage, numPages, changePage, totalItems } ) {
+ return (
+
+
+ {
+ // translators: %s: Total number of patterns.
+ sprintf(
+ // translators: %s: Total number of patterns.
+ _n( '%s item', '%s items', totalItems ),
+ totalItems
+ )
+ }
+
+
+
+
+
+
+ { sprintf(
+ // translators: %1$s: Current page number, %2$s: Total number of pages.
+ _x( '%1$s of %2$s', 'paging' ),
+ currentPage,
+ numPages
+ ) }
+
+
+
+
+
+
+ );
+}
export default function Grid( { categoryId, items, ...props } ) {
+ const [ currentPage, setCurrentPage ] = useState( 1 );
const gridRef = useRef();
+ const totalItems = items.length;
+ const pageIndex = currentPage - 1;
- if ( ! items?.length ) {
+ const list = useMemo(
+ () =>
+ items.slice(
+ pageIndex * PAGE_SIZE,
+ pageIndex * PAGE_SIZE + PAGE_SIZE
+ ),
+ [ pageIndex, items ]
+ );
+
+ const asyncList = useAsyncList( list, { step: 10 } );
+
+ if ( ! list?.length ) {
return null;
}
- const list = items.slice( 0, PAGE_SIZE );
- const restLength = items.length - PAGE_SIZE;
+ const numPages = Math.ceil( items.length / PAGE_SIZE );
+ const changePage = ( page ) => {
+ const scrollContainer = document.querySelector( '.edit-site-patterns' );
+ scrollContainer?.scrollTo( 0, 0 );
+
+ setCurrentPage( page );
+ };
return (
<>
@@ -30,7 +119,7 @@ export default function Grid( { categoryId, items, ...props } ) {
{ ...props }
ref={ gridRef }
>
- { list.map( ( item ) => (
+ { asyncList.map( ( item ) => (
) ) }
- { restLength > 0 && (
-
- { sprintf(
- /* translators: %d: number of patterns */
- __( '+ %d more patterns discoverable by searching' ),
- restLength
- ) }
-
+ { numPages > 1 && (
+
) }
>
);
diff --git a/packages/edit-site/src/components/page-patterns/patterns-list.js b/packages/edit-site/src/components/page-patterns/patterns-list.js
index 7bf2a9d506584..f4fefed4a2d3e 100644
--- a/packages/edit-site/src/components/page-patterns/patterns-list.js
+++ b/packages/edit-site/src/components/page-patterns/patterns-list.js
@@ -15,7 +15,7 @@ import {
import { __, isRTL } from '@wordpress/i18n';
import { chevronLeft, chevronRight } from '@wordpress/icons';
import { privateApis as routerPrivateApis } from '@wordpress/router';
-import { useViewportMatch, useAsyncList } from '@wordpress/compose';
+import { useViewportMatch } from '@wordpress/compose';
/**
* Internal dependencies
@@ -70,7 +70,6 @@ export default function PatternsList( { categoryId, type } ) {
const hasPatterns = patterns.length;
const title = SYNC_FILTERS[ syncFilter ];
const description = SYNC_DESCRIPTIONS[ syncFilter ];
- const shownPatterns = useAsyncList( patterns );
return (
@@ -132,7 +131,7 @@ export default function PatternsList( { categoryId, type } ) {
{ syncFilter !== 'all' && (
-
+
{ title }
{ description ? (
@@ -145,7 +144,7 @@ export default function PatternsList( { categoryId, type } ) {
{ hasPatterns && (
diff --git a/packages/edit-site/src/components/page-patterns/style.scss b/packages/edit-site/src/components/page-patterns/style.scss
index 79731999f46ef..d1fbedb141f70 100644
--- a/packages/edit-site/src/components/page-patterns/style.scss
+++ b/packages/edit-site/src/components/page-patterns/style.scss
@@ -1,6 +1,8 @@
.edit-site-patterns {
- background: rgba(0, 0, 0, 0.15);
+ border: 1px solid $gray-800;
+ background: none;
margin: $header-height 0 0;
+ border-radius: 0;
.components-base-control {
width: 100%;
@include break-medium {
@@ -59,6 +61,23 @@
background: $gray-700;
color: $gray-100;
}
+
+ .edit-site-patterns__grid-pagination {
+ width: fit-content;
+ .components-button.is-tertiary {
+ width: $button-size-compact;
+ height: $button-size-compact;
+ color: $gray-100;
+ background-color: $gray-800;
+ &:disabled {
+ color: $gray-600;
+ background: none;
+ }
+ &:hover:not(:disabled) {
+ background-color: $gray-700;
+ }
+ }
+ }
}
.edit-site-patterns__section-header {
@@ -74,6 +93,7 @@
// Small top padding required to avoid cutting off the visible outline
// when hovering items.
padding-top: $border-width-focus-fallback;
+ margin-top: 0;
margin-bottom: $grid-unit-40;
@include break-large {
grid-template-columns: 1fr 1fr;