Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Patterns: Add client side pagination to patterns list #52538

Merged
merged 11 commits into from
Jul 13, 2023
119 changes: 103 additions & 16 deletions packages/edit-site/src/components/page-patterns/grid.js
Original file line number Diff line number Diff line change
@@ -1,26 +1,117 @@
/**
* 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 (
<HStack
expanded={ false }
spacing={ 3 }
className="edit-site-patterns__grid-pagination"
>
<Text variant="muted">
{
// translators: %s: Total number of patterns.
sprintf(
// translators: %s: Total number of patterns.
_n( '%s item', '%s items', totalItems ),
totalItems
)
}
</Text>
<HStack expanded={ false } spacing={ 1 }>
<Button
variant="tertiary"
onClick={ () => changePage( 1 ) }
disabled={ currentPage === 1 }
aria-label={ __( 'First page' ) }
>
«
</Button>
<Button
variant="tertiary"
onClick={ () => changePage( currentPage - 1 ) }
disabled={ currentPage === 1 }
aria-label={ __( 'Previous page' ) }
>
</Button>
</HStack>
<Text variant="muted">
{ sprintf(
// translators: %1$s: Current page number, %2$s: Total number of pages.
_x( '%1$s of %2$s', 'paging' ),
currentPage,
numPages
) }
</Text>
<HStack expanded={ false } spacing={ 1 }>
<Button
variant="tertiary"
onClick={ () => changePage( currentPage + 1 ) }
disabled={ currentPage === numPages }
aria-label={ __( 'Next page' ) }
>
</Button>
<Button
variant="tertiary"
onClick={ () => changePage( numPages ) }
disabled={ currentPage === numPages }
aria-label={ __( 'Last page' ) }
>
»
</Button>
</HStack>
</HStack>
);
}

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.getElementsByClassName( 'edit-site-patterns' );
ramonjd marked this conversation as resolved.
Show resolved Hide resolved

scrollContainer[ 0 ]?.scrollTo( 0, 0 );

setCurrentPage( page );
};

return (
<>
Expand All @@ -30,22 +121,18 @@ export default function Grid( { categoryId, items, ...props } ) {
{ ...props }
ref={ gridRef }
>
{ list.map( ( item ) => (
{ asyncList.map( ( item ) => (
<GridItem
key={ item.name }
item={ item }
categoryId={ categoryId }
/>
) ) }
</ul>
{ restLength > 0 && (
<Text variant="muted" as="p" align="center">
{ sprintf(
/* translators: %d: number of patterns */
__( '+ %d more patterns discoverable by searching' ),
restLength
) }
</Text>
{ numPages > 1 && (
<Pagination
{ ...{ currentPage, numPages, changePage, totalItems } }
/>
) }
</>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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 (
<VStack spacing={ 6 }>
Expand Down Expand Up @@ -132,7 +131,7 @@ export default function PatternsList( { categoryId, type } ) {
</Flex>
{ syncFilter !== 'all' && (
<VStack className="edit-site-patterns__section-header">
<Heading as="h3" level={ 4 } id={ titleId }>
<Heading as="h3" level={ 5 } id={ titleId }>
{ title }
</Heading>
{ description ? (
Expand All @@ -145,7 +144,7 @@ export default function PatternsList( { categoryId, type } ) {
{ hasPatterns && (
<Grid
categoryId={ categoryId }
items={ shownPatterns }
items={ patterns }
aria-labelledby={ titleId }
aria-describedby={ descriptionId }
/>
Expand Down
22 changes: 21 additions & 1 deletion packages/edit-site/src/components/page-patterns/style.scss
Original file line number Diff line number Diff line change
@@ -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 {
Expand Down Expand Up @@ -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 {
Expand All @@ -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;
Expand Down