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]: Browse Patterns in a Modal #35773

Merged
merged 19 commits into from
Nov 5, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
47794da
[Patterns]: Paterns explorer in modal
ntsekouras Oct 19, 2021
df94a0a
add search results header info
ntsekouras Oct 20, 2021
8f15805
Update packages/block-editor/src/components/inserter/block-patterns-e…
ntsekouras Oct 20, 2021
675a8eb
fix lint error
ntsekouras Oct 22, 2021
484a7a9
small design changes
ntsekouras Oct 22, 2021
73ec327
Refactor patterns tab/explorer for performance
ntsekouras Oct 25, 2021
50fb786
Moving hover and focus styles to the preview container.
shaunandrews Nov 1, 2021
4341955
Specifying a gap for the Grid component.
shaunandrews Nov 1, 2021
b6bf5a7
Updating the button label to Explore and using the outlined style of …
shaunandrews Nov 1, 2021
195085a
Visual tweaks to the inserter modal
shaunandrews Nov 1, 2021
d5cf852
adjust min-height in quick inserter
ntsekouras Nov 2, 2021
701ca5e
remove commented line
ntsekouras Nov 2, 2021
7328481
Adjusting min/max height for previews in the modal and changing colum…
shaunandrews Nov 4, 2021
3a1aebc
More visual tweaks to the patterns list.
shaunandrews Nov 4, 2021
9f9839f
Increasing the space between the dropdown and the button to match the…
shaunandrews Nov 4, 2021
3d6c430
Using the Heading component and adding a className to the list contai…
shaunandrews Nov 4, 2021
f340730
Absolute positioning the explorer sidebar to allow for independent sc…
shaunandrews Nov 4, 2021
e0210ce
hide explore button when inserter goes full width + small css fix for…
ntsekouras Nov 5, 2021
d83b678
address feedback
ntsekouras Nov 5, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -9,22 +9,15 @@ import {
} from '@wordpress/components';
import { useInstanceId } from '@wordpress/compose';
import { __ } from '@wordpress/i18n';
import { useSelect } from '@wordpress/data';

/**
* Internal dependencies
*/
import BlockPreview from '../block-preview';
import InserterDraggableBlocks from '../inserter-draggable-blocks';
import { store as blockEditorStore } from '../../store';

function BlockPattern( { isDraggable, pattern, onClick, composite } ) {
const { name, viewportWidth } = pattern;
const { blocks } = useSelect(
( select ) =>
select( blockEditorStore ).__experimentalGetParsedPattern( name ),
[ name ]
);
const { blocks, viewportWidth } = pattern;
const instanceId = useInstanceId( BlockPattern );
const descriptionId = `block-editor-block-patterns-list__item-description-${ instanceId }`;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
.block-editor-block-patterns-list__list-item {
cursor: pointer;
margin-top: $grid-unit-20;
margin-bottom: $grid-unit-30;

&.is-placeholder {
min-height: 100px;
Expand All @@ -13,25 +13,35 @@

.block-editor-block-patterns-list__item {
height: 100%;
border-radius: $radius-block-ui;
transition: all 0.05s ease-in-out;
position: relative;
border: $border-width solid transparent;

&:hover {
.block-editor-block-preview__container {
display: flex;
align-items: center;
overflow: hidden;
border-radius: $radius-block-ui;
border: $border-width solid $gray-100;
}

.block-editor-block-patterns-list__item-title {
padding-top: $grid-unit-10;
font-size: 12px;
text-align: center;
}

&:hover .block-editor-block-preview__container {
border: $border-width solid var(--wp-admin-theme-color);
}

&:focus {
&:focus .block-editor-block-preview__container {
box-shadow: inset 0 0 0 1px $white, 0 0 0 var(--wp-admin-border-width-focus) var(--wp-admin-theme-color);

// Windows High Contrast mode will show this outline, but not the box-shadow.
outline: 2px solid transparent;
}
}

.block-editor-block-patterns-list__item-title {
padding: $grid-unit-05;
font-size: 12px;
text-align: center;

&:hover .block-editor-block-patterns-list__item-title,
&:focus .block-editor-block-patterns-list__item-title {
color: var(--wp-admin-theme-color);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
/**
* WordPress dependencies
*/
import { Modal } from '@wordpress/components';
import { useState } from '@wordpress/element';
import { __ } from '@wordpress/i18n';

/**
* Internal dependencies
*/
import PatternExplorerSidebar from './sidebar';
import PatternList from './patterns-list';

function PatternsExplorer( { initialCategory, patternCategories } ) {
const [ filterValue, setFilterValue ] = useState( '' );
const [ selectedCategory, setSelectedCategory ] = useState(
initialCategory?.name
);
return (
<div className="block-editor-block-patterns-explorer">
<PatternExplorerSidebar
selectedCategory={ selectedCategory }
patternCategories={ patternCategories }
onClickCategory={ setSelectedCategory }
filterValue={ filterValue }
setFilterValue={ setFilterValue }
/>
<PatternList
filterValue={ filterValue }
selectedCategory={ selectedCategory }
patternCategories={ patternCategories }
/>
</div>
);
}

function PatternsExplorerModal( { onModalClose, ...restProps } ) {
return (
<Modal
title={ __( 'Patterns' ) }
closeLabel={ __( 'Close' ) }
onRequestClose={ onModalClose }
isFullScreen
>
<PatternsExplorer { ...restProps } />
</Modal>
);
}

export default PatternsExplorerModal;
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
/**
* WordPress dependencies
*/
import { useMemo, useEffect } from '@wordpress/element';
import { _n, sprintf } from '@wordpress/i18n';
import { useDebounce, useAsyncList } from '@wordpress/compose';
import { __experimentalHeading as Heading } from '@wordpress/components';
import { speak } from '@wordpress/a11y';

/**
* Internal dependencies
*/
import BlockPatternsList from '../../block-patterns-list';
import InserterNoResults from '../no-results';
import useInsertionPoint from '../hooks/use-insertion-point';
import usePatternsState from '../hooks/use-patterns-state';
import InserterListbox from '../../inserter-listbox';
import { searchItems } from '../search-items';

const INITIAL_INSERTER_RESULTS = 2;

function PatternsListHeader( { filterValue, filteredBlockPatternsLength } ) {
if ( ! filterValue ) {
return null;
}
return (
<Heading
level={ 2 }
lineHeight={ '48px' }
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Minor note, but what could we do instead of keeping this magic constant?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I expect this would go away as we iterate more; Right now it helps resolve a visual imbalance when searching, but I expect the headings to change (like adding descriptions or actions) as we add them to the other parts of the browsing experience.

className="block-editor-block-patterns-explorer__search-results-count"
>
{ sprintf(
/* translators: %d: number of patterns. %s: block pattern search query */
_n(
'%1$d pattern found for "%2$s"',
'%1$d patterns found for "%2$s"',
filteredBlockPatternsLength
),
filteredBlockPatternsLength,
filterValue
) }
</Heading>
);
}

function PatternList( { filterValue, selectedCategory, patternCategories } ) {
const debouncedSpeak = useDebounce( speak, 500 );
const [ destinationRootClientId, onInsertBlocks ] = useInsertionPoint( {
shouldFocusBlock: true,
} );
const [ allPatterns, , onSelectBlockPattern ] = usePatternsState(
onInsertBlocks,
destinationRootClientId
);
const registeredPatternCategories = useMemo(
() =>
patternCategories.map(
( patternCategory ) => patternCategory.name
),
[ patternCategories ]
);

const filteredBlockPatterns = useMemo( () => {
if ( ! filterValue ) {
return allPatterns.filter( ( pattern ) =>
selectedCategory === 'uncategorized'
? ! pattern.categories?.length ||
pattern.categories.every(
( category ) =>
! registeredPatternCategories.includes(
category
)
)
: pattern.categories?.includes( selectedCategory )
);
}
return searchItems( allPatterns, filterValue );
}, [ filterValue, selectedCategory, allPatterns ] );

// Announce search results on change.
useEffect( () => {
if ( ! filterValue ) {
return;
}
const count = filteredBlockPatterns.length;
const resultsFoundMessage = sprintf(
/* translators: %d: number of results. */
_n( '%d result found.', '%d results found.', count ),
count
);
debouncedSpeak( resultsFoundMessage );
}, [ filterValue, debouncedSpeak ] );

const currentShownPatterns = useAsyncList( filteredBlockPatterns, {
step: INITIAL_INSERTER_RESULTS,
} );

const hasItems = !! filteredBlockPatterns?.length;
return (
<div className="block-editor-block-patterns-explorer__list">
{ hasItems && (
<PatternsListHeader
filterValue={ filterValue }
filteredBlockPatternsLength={ filteredBlockPatterns.length }
/>
) }
<InserterListbox>
{ ! hasItems && <InserterNoResults /> }
{ hasItems && (
<BlockPatternsList
shownPatterns={ currentShownPatterns }
blockPatterns={ filteredBlockPatterns }
onClickPattern={ onSelectBlockPattern }
isDraggable={ false }
/>
) }
</InserterListbox>
</div>
);
}

export default PatternList;
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
/**
* WordPress dependencies
*/
import { Button, SearchControl } from '@wordpress/components';
import { __ } from '@wordpress/i18n';

function PatternCategoriesList( {
selectedCategory,
patternCategories,
onClickCategory,
} ) {
const baseClassName = 'block-editor-block-patterns-explorer__sidebar';
return (
<div className={ `${ baseClassName }__categories-list` }>
{ patternCategories.map( ( { name, label } ) => {
return (
<Button
key={ name }
label={ label }
className={ `${ baseClassName }__categories-list__item` }
isPressed={ selectedCategory === name }
onClick={ () => {
onClickCategory( name );
} }
>
{ label }
</Button>
);
} ) }
</div>
);
}

function PatternsExplorerSearch( { filterValue, setFilterValue } ) {
const baseClassName = 'block-editor-block-patterns-explorer__search';
return (
<div className={ baseClassName }>
<SearchControl
onChange={ setFilterValue }
value={ filterValue }
label={ __( 'Search for patterns' ) }
placeholder={ __( 'Search' ) }
/>
</div>
);
}

function PatternExplorerSidebar( {
selectedCategory,
patternCategories,
onClickCategory,
filterValue,
setFilterValue,
} ) {
const baseClassName = 'block-editor-block-patterns-explorer__sidebar';
return (
<div className={ baseClassName }>
<PatternsExplorerSearch
filterValue={ filterValue }
setFilterValue={ setFilterValue }
/>
{ ! filterValue && (
<PatternCategoriesList
selectedCategory={ selectedCategory }
patternCategories={ patternCategories }
onClickCategory={ onClickCategory }
/>
) }
</div>
);
}

export default PatternExplorerSidebar;
Loading