Skip to content

Commit a502b0a

Browse files
Patterns: merge unsynced into inserter patterns tab and add paging and filtering (#54007)
Co-authored-by: James Koster <james@jameskoster.co.uk>
1 parent d2a48ce commit a502b0a

28 files changed

+791
-375
lines changed

packages/block-editor/src/components/block-patterns-list/index.js

+32-7
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
1+
/**
2+
* External dependencies
3+
*/
4+
import classnames from 'classnames';
5+
16
/**
27
* WordPress dependencies
38
*/
@@ -8,9 +13,11 @@ import {
813
__unstableUseCompositeState as useCompositeState,
914
__unstableCompositeItem as CompositeItem,
1015
Tooltip,
16+
__experimentalHStack as HStack,
1117
} from '@wordpress/components';
1218
import { useInstanceId } from '@wordpress/compose';
1319
import { __ } from '@wordpress/i18n';
20+
import { Icon, symbol } from '@wordpress/icons';
1421

1522
/**
1623
* Internal dependencies
@@ -63,14 +70,20 @@ function BlockPattern( {
6370
} }
6471
>
6572
<WithToolTip
66-
showTooltip={ showTooltip }
73+
showTooltip={ showTooltip && ! pattern.id }
6774
title={ pattern.title }
6875
>
6976
<CompositeItem
7077
role="option"
7178
as="div"
7279
{ ...composite }
73-
className="block-editor-block-patterns-list__item"
80+
className={ classnames(
81+
'block-editor-block-patterns-list__item',
82+
{
83+
'block-editor-block-patterns-list__list-item-synced':
84+
pattern.id && ! pattern.syncStatus,
85+
}
86+
) }
7487
onClick={ () => {
7588
onClick( pattern, blocks );
7689
onHover?.( null );
@@ -91,11 +104,23 @@ function BlockPattern( {
91104
blocks={ blocks }
92105
viewportWidth={ viewportWidth }
93106
/>
94-
{ ! showTooltip && (
95-
<div className="block-editor-block-patterns-list__item-title">
96-
{ pattern.title }
97-
</div>
98-
) }
107+
108+
<HStack className="block-editor-patterns__pattern-details">
109+
{ pattern.id && ! pattern.syncStatus && (
110+
<div className="block-editor-patterns__pattern-icon-wrapper">
111+
<Icon
112+
className="block-editor-patterns__pattern-icon"
113+
icon={ symbol }
114+
/>
115+
</div>
116+
) }
117+
{ ( ! showTooltip || pattern.id ) && (
118+
<div className="block-editor-block-patterns-list__item-title">
119+
{ pattern.title }
120+
</div>
121+
) }
122+
</HStack>
123+
99124
{ !! pattern.description && (
100125
<VisuallyHidden id={ descriptionId }>
101126
{ pattern.description }

packages/block-editor/src/components/block-patterns-list/style.scss

+26-9
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
min-height: 100px;
1212
}
1313

14-
&[draggable="true"] .block-editor-block-preview__container {
14+
&[draggable="true"] {
1515
cursor: grab;
1616
}
1717
}
@@ -27,22 +27,39 @@
2727
}
2828

2929
.block-editor-block-patterns-list__item-title {
30-
padding-top: $grid-unit-10;
31-
font-size: 12px;
32-
text-align: center;
30+
text-align: left;
31+
flex-grow: 1;
3332
}
3433

3534
&:hover .block-editor-block-preview__container {
36-
box-shadow: 0 0 0 2px var(--wp-admin-theme-color);
35+
box-shadow: 0 0 0 2px $gray-900;
3736
}
3837

3938
&:focus .block-editor-block-preview__container {
40-
@include button-style-outset__focus(var(--wp-admin-theme-color));
39+
@include button-style-outset__focus($gray-900);
4140
}
4241

42+
&.block-editor-block-patterns-list__list-item-synced {
43+
&:hover,
44+
&:focus {
45+
.block-editor-block-preview__container {
46+
box-shadow:
47+
0 0 0 2px var(--wp-block-synced-color),
48+
0 15px 25px rgb(0 0 0 / 7%);
49+
}
50+
}
51+
}
52+
53+
.block-editor-patterns__pattern-details {
54+
align-items: center;
55+
margin-top: $grid-unit-10;
56+
}
4357

44-
&:hover .block-editor-block-patterns-list__item-title,
45-
&:focus .block-editor-block-patterns-list__item-title {
46-
color: var(--wp-admin-theme-color);
58+
.block-editor-patterns__pattern-icon-wrapper {
59+
min-width: 24px;
60+
height: 24px;
61+
.block-editor-patterns__pattern-icon {
62+
fill: var(--wp-block-synced-color);
63+
}
4764
}
4865
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
/**
2+
* WordPress dependencies
3+
*/
4+
import {
5+
__experimentalVStack as VStack,
6+
__experimentalHStack as HStack,
7+
__experimentalText as Text,
8+
Button,
9+
} from '@wordpress/components';
10+
import { __, _x, _n, sprintf } from '@wordpress/i18n';
11+
12+
export default function Pagination( {
13+
currentPage,
14+
numPages,
15+
changePage,
16+
totalItems,
17+
} ) {
18+
return (
19+
<VStack>
20+
<Text variant="muted">
21+
{
22+
// translators: %s: Total number of patterns.
23+
sprintf(
24+
// translators: %s: Total number of patterns.
25+
_n( '%s item', '%s items', totalItems ),
26+
totalItems
27+
)
28+
}
29+
</Text>
30+
<HStack
31+
expanded={ false }
32+
spacing={ 3 }
33+
justify="flex-start"
34+
className="block-editor-patterns__grid-pagination"
35+
>
36+
<HStack
37+
expanded={ false }
38+
spacing={ 1 }
39+
className="block-editor-patterns__grid-pagination-previous"
40+
>
41+
<Button
42+
variant="tertiary"
43+
onClick={ () => changePage( 1 ) }
44+
disabled={ currentPage === 1 }
45+
aria-label={ __( 'First page' ) }
46+
>
47+
<span>«</span>
48+
</Button>
49+
<Button
50+
variant="tertiary"
51+
onClick={ () => changePage( currentPage - 1 ) }
52+
disabled={ currentPage === 1 }
53+
aria-label={ __( 'Previous page' ) }
54+
>
55+
<span></span>
56+
</Button>
57+
</HStack>
58+
<Text variant="muted">
59+
{ sprintf(
60+
// translators: %1$s: Current page number, %2$s: Total number of pages.
61+
_x( '%1$s of %2$s', 'paging' ),
62+
currentPage,
63+
numPages
64+
) }
65+
</Text>
66+
<HStack
67+
expanded={ false }
68+
spacing={ 1 }
69+
className="block-editor-patterns__grid-pagination-next"
70+
>
71+
<Button
72+
variant="tertiary"
73+
onClick={ () => changePage( currentPage + 1 ) }
74+
disabled={ currentPage === numPages }
75+
aria-label={ __( 'Next page' ) }
76+
>
77+
<span></span>
78+
</Button>
79+
<Button
80+
variant="tertiary"
81+
onClick={ () => changePage( numPages ) }
82+
disabled={ currentPage === numPages }
83+
aria-label={ __( 'Last page' ) }
84+
size="default"
85+
>
86+
<span>»</span>
87+
</Button>
88+
</HStack>
89+
</HStack>
90+
</VStack>
91+
);
92+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
.block-editor-patterns__grid-pagination {
2+
border-top: 1px solid $gray-800;
3+
padding: $grid-unit-05;
4+
5+
.components-button.is-tertiary {
6+
width: auto;
7+
height: $button-size-compact;
8+
justify-content: center;
9+
10+
&:disabled {
11+
color: $gray-600;
12+
background: none;
13+
}
14+
15+
&:hover:not(:disabled) {
16+
color: $white;
17+
background-color: $gray-700;
18+
}
19+
}
20+
}
21+
22+
.show-icon-labels {
23+
.block-editor-patterns__grid-pagination {
24+
flex-direction: column;
25+
.block-editor-patterns__grid-pagination-previous,
26+
.block-editor-patterns__grid-pagination-next {
27+
flex-direction: column;
28+
}
29+
.components-button {
30+
width: auto;
31+
// Hide the button icons when labels are set to display...
32+
span {
33+
display: none;
34+
}
35+
// ... and display labels.
36+
// Uses ::before as ::after is already used for active tab styling.
37+
&::before {
38+
content: attr(aria-label);
39+
}
40+
}
41+
}
42+
}

packages/block-editor/src/components/inserter/block-patterns-explorer/explorer.js

+42-6
Original file line numberDiff line numberDiff line change
@@ -2,33 +2,69 @@
22
* WordPress dependencies
33
*/
44
import { Modal } from '@wordpress/components';
5-
import { useState } from '@wordpress/element';
5+
import { useState, useEffect } from '@wordpress/element';
66
import { __ } from '@wordpress/i18n';
7+
import { useSelect } from '@wordpress/data';
8+
import { usePrevious } from '@wordpress/compose';
79

810
/**
911
* Internal dependencies
1012
*/
1113
import PatternExplorerSidebar from './sidebar';
1214
import PatternList from './patterns-list';
15+
import { usePatternsCategories } from '../block-patterns-tab';
16+
import { store as blockEditorStore } from '../../../store';
1317

14-
function PatternsExplorer( { initialCategory, patternCategories } ) {
15-
const [ filterValue, setFilterValue ] = useState( '' );
18+
function PatternsExplorer( { initialCategory, rootClientId } ) {
19+
const [ searchValue, setSearchValue ] = useState( '' );
20+
const [ patternSourceFilter, setPatternSourceFilter ] = useState( 'all' );
21+
const patternSyncFilter = useSelect( ( select ) => {
22+
const { getSettings } = select( blockEditorStore );
23+
const settings = getSettings();
24+
return settings.patternsSyncFilter || 'all';
25+
}, [] );
1626
const [ selectedCategory, setSelectedCategory ] = useState(
1727
initialCategory?.name
1828
);
29+
30+
const previousSyncFilter = usePrevious( patternSyncFilter );
31+
32+
// If the sync filter changes, we need to select the "All" category to avoid
33+
// showing a confusing no results screen.
34+
useEffect( () => {
35+
if ( patternSyncFilter && patternSyncFilter !== previousSyncFilter ) {
36+
setSelectedCategory( initialCategory?.name );
37+
}
38+
}, [
39+
patternSyncFilter,
40+
previousSyncFilter,
41+
patternSourceFilter,
42+
initialCategory?.name,
43+
] );
44+
45+
const patternCategories = usePatternsCategories(
46+
rootClientId,
47+
patternSourceFilter,
48+
patternSyncFilter
49+
);
50+
1951
return (
2052
<div className="block-editor-block-patterns-explorer">
2153
<PatternExplorerSidebar
2254
selectedCategory={ selectedCategory }
2355
patternCategories={ patternCategories }
2456
onClickCategory={ setSelectedCategory }
25-
filterValue={ filterValue }
26-
setFilterValue={ setFilterValue }
57+
searchValue={ searchValue }
58+
setSearchValue={ setSearchValue }
59+
patternSourceFilter={ patternSourceFilter }
60+
setPatternSourceFilter={ setPatternSourceFilter }
2761
/>
2862
<PatternList
29-
filterValue={ filterValue }
63+
searchValue={ searchValue }
3064
selectedCategory={ selectedCategory }
3165
patternCategories={ patternCategories }
66+
patternSourceFilter={ patternSourceFilter }
67+
patternSyncFilter={ patternSyncFilter }
3268
/>
3369
</div>
3470
);

0 commit comments

Comments
 (0)