-
Notifications
You must be signed in to change notification settings - Fork 4.3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
2d43054
commit 98d9da0
Showing
3 changed files
with
374 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
341 changes: 341 additions & 0 deletions
341
packages/edit-site/src/components/page-patterns/dataviews-patterns.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,341 @@ | ||
/** | ||
* WordPress dependencies | ||
*/ | ||
import { | ||
__experimentalHStack as HStack, | ||
Button, | ||
__experimentalHeading as Heading, | ||
Tooltip, | ||
Flex, | ||
} from '@wordpress/components'; | ||
import { getQueryArgs } from '@wordpress/url'; | ||
import { __ } from '@wordpress/i18n'; | ||
import { useState, useMemo, useCallback, useId } from '@wordpress/element'; | ||
import { | ||
BlockPreview, | ||
privateApis as blockEditorPrivateApis, | ||
} from '@wordpress/block-editor'; | ||
import { DataViews } from '@wordpress/dataviews'; | ||
import { | ||
Icon, | ||
header, | ||
footer, | ||
symbolFilled as uncategorized, | ||
symbol, | ||
lockSmall, | ||
} from '@wordpress/icons'; | ||
|
||
/** | ||
* Internal dependencies | ||
*/ | ||
import Page from '../page'; | ||
import { | ||
LAYOUT_GRID, | ||
PATTERN_TYPES, | ||
TEMPLATE_PART_POST_TYPE, | ||
PATTERN_SYNC_TYPES, | ||
PATTERN_DEFAULT_CATEGORY, | ||
} from '../../utils/constants'; | ||
// import { duplicatePatternAction } from './dataviews-pattern-actions'; | ||
import usePatternSettings from './use-pattern-settings'; | ||
import { unlock } from '../../lock-unlock'; | ||
import usePatterns from './use-patterns'; | ||
import PatternsHeader from './header'; | ||
|
||
const { ExperimentalBlockEditorProvider, useGlobalStyle } = unlock( | ||
blockEditorPrivateApis | ||
); | ||
|
||
const templatePartIcons = { header, footer, uncategorized }; | ||
const EMPTY_ARRAY = []; | ||
const defaultConfigPerViewType = { | ||
[ LAYOUT_GRID ]: { | ||
mediaField: 'preview', | ||
primaryField: 'title', | ||
}, | ||
}; | ||
const DEFAULT_VIEW = { | ||
type: LAYOUT_GRID, | ||
search: '', | ||
page: 1, | ||
perPage: 20, | ||
hiddenFields: [], | ||
layout: { | ||
...defaultConfigPerViewType[ LAYOUT_GRID ], | ||
}, | ||
filters: [], | ||
}; | ||
|
||
function Preview( { item, viewType } ) { | ||
const descriptionId = useId(); | ||
const isUserPattern = item.type === PATTERN_TYPES.user; | ||
const isNonUserPattern = item.type === PATTERN_TYPES.theme; | ||
const isTemplatePart = item.type === TEMPLATE_PART_POST_TYPE; | ||
const isEmpty = ! item.blocks?.length; | ||
// Only custom patterns or custom template parts can be renamed or deleted. | ||
const isCustomPattern = | ||
isUserPattern || ( isTemplatePart && item.isCustom ); | ||
const ariaDescriptions = []; | ||
if ( isCustomPattern ) { | ||
// User patterns don't have descriptions, but can be edited and deleted, so include some help text. | ||
ariaDescriptions.push( | ||
__( 'Press Enter to edit, or Delete to delete the pattern.' ) | ||
); | ||
} else if ( item.description ) { | ||
ariaDescriptions.push( item.description ); | ||
} | ||
|
||
if ( isNonUserPattern ) { | ||
ariaDescriptions.push( | ||
__( 'Theme & plugin patterns cannot be edited.' ) | ||
); | ||
} | ||
const [ backgroundColor ] = useGlobalStyle( 'color.background' ); | ||
return ( | ||
<> | ||
<div | ||
className={ `page-patterns-preview-field is-viewtype-${ viewType }` } | ||
style={ { backgroundColor } } | ||
> | ||
{ isEmpty && isTemplatePart && __( 'Empty template part' ) } | ||
{ isEmpty && ! isTemplatePart && __( 'Empty pattern' ) } | ||
{ ! isEmpty && <BlockPreview blocks={ item.blocks } /> } | ||
</div> | ||
{ ariaDescriptions.map( ( ariaDescription, index ) => ( | ||
<div | ||
key={ index } | ||
hidden | ||
id={ `${ descriptionId }-${ index }` } | ||
> | ||
{ ariaDescription } | ||
</div> | ||
) ) } | ||
</> | ||
); | ||
} | ||
|
||
function Title( { item, onClick, categoryId } ) { | ||
const isUserPattern = item.type === PATTERN_TYPES.user; | ||
const isNonUserPattern = item.type === PATTERN_TYPES.theme; | ||
let itemIcon; | ||
if ( ! isUserPattern && templatePartIcons[ categoryId ] ) { | ||
itemIcon = templatePartIcons[ categoryId ]; | ||
} else { | ||
itemIcon = | ||
item.syncStatus === PATTERN_SYNC_TYPES.full ? symbol : undefined; | ||
} | ||
return ( | ||
<HStack alignment="center" justify="flex-start" spacing={ 3 }> | ||
{ itemIcon && ! isNonUserPattern && ( | ||
<Tooltip | ||
placement="top" | ||
text={ __( | ||
'Editing this pattern will also update anywhere it is used' | ||
) } | ||
> | ||
<Icon | ||
className="edit-site-patterns__pattern-icon" | ||
icon={ itemIcon } | ||
/> | ||
</Tooltip> | ||
) } | ||
<Flex as="span" gap={ 0 } justify="left"> | ||
{ item.type === PATTERN_TYPES.theme ? ( | ||
item.title | ||
) : ( | ||
<Heading level={ 5 }> | ||
<Button | ||
variant="link" | ||
onClick={ onClick } | ||
// Required for the grid's roving tab index system. | ||
// See https://github.com/WordPress/gutenberg/pull/51898#discussion_r1243399243. | ||
tabIndex="-1" | ||
> | ||
{ item.title || item.name } | ||
</Button> | ||
</Heading> | ||
) } | ||
{ item.type === PATTERN_TYPES.theme && ( | ||
<Tooltip | ||
placement="top" | ||
text={ __( 'This pattern cannot be edited.' ) } | ||
> | ||
<Icon | ||
className="edit-site-patterns__pattern-lock-icon" | ||
icon={ lockSmall } | ||
size={ 24 } | ||
/> | ||
</Tooltip> | ||
) } | ||
</Flex> | ||
</HStack> | ||
); | ||
} | ||
|
||
export default function DataviewsPatterns() { | ||
const { categoryType, categoryId = PATTERN_DEFAULT_CATEGORY } = | ||
getQueryArgs( window.location.href ); | ||
const type = categoryType || PATTERN_TYPES.theme; | ||
const [ view, setView ] = useState( DEFAULT_VIEW ); | ||
const isUncategorizedThemePatterns = | ||
type === PATTERN_TYPES.theme && categoryId === 'uncategorized'; | ||
const { patterns, isResolving } = usePatterns( | ||
type, | ||
isUncategorizedThemePatterns ? '' : categoryId, | ||
{ | ||
search: view.search, | ||
// syncStatus: | ||
// deferredSyncedFilter === 'all' | ||
// ? undefined | ||
// : deferredSyncedFilter, | ||
} | ||
); | ||
const fields = useMemo( | ||
() => [ | ||
{ | ||
header: __( 'Preview' ), | ||
id: 'preview', | ||
render: ( { item } ) => ( | ||
<Preview item={ item } viewType={ view.type } /> | ||
), | ||
minWidth: 120, | ||
maxWidth: 120, | ||
enableSorting: false, | ||
enableHiding: false, | ||
}, | ||
{ | ||
header: __( 'Title' ), | ||
id: 'title', | ||
getValue: ( { item } ) => item.title, | ||
render: ( { item } ) => ( | ||
<Title | ||
item={ item } | ||
onClick={ () => {} } | ||
categoryId={ categoryId } | ||
/> | ||
), | ||
maxWidth: 400, | ||
enableHiding: false, | ||
}, | ||
], | ||
[ view.type, categoryId ] | ||
); | ||
|
||
const { data, paginationInfo } = useMemo( () => { | ||
if ( ! patterns ) { | ||
return { | ||
data: EMPTY_ARRAY, | ||
paginationInfo: { totalItems: 0, totalPages: 0 }, | ||
}; | ||
} | ||
let filteredData = [ ...patterns ]; | ||
// Handle filters. | ||
if ( view.filters.length > 0 ) { | ||
// view.filters.forEach( ( filter ) => { | ||
// if ( | ||
// filter.field === 'author' && | ||
// filter.operator === OPERATOR_IN && | ||
// !! filter.value | ||
// ) { | ||
// filteredData = filteredData.filter( ( item ) => { | ||
// return item.author_text === filter.value; | ||
// } ); | ||
// } else if ( | ||
// filter.field === 'author' && | ||
// filter.operator === OPERATOR_NOT_IN && | ||
// !! filter.value | ||
// ) { | ||
// filteredData = filteredData.filter( ( item ) => { | ||
// return item.author_text !== filter.value; | ||
// } ); | ||
// } | ||
// } ); | ||
} | ||
|
||
// Handle sorting. | ||
if ( view.sort ) { | ||
const stringSortingFields = [ 'title' ]; | ||
const fieldId = view.sort.field; | ||
if ( stringSortingFields.includes( fieldId ) ) { | ||
const fieldToSort = fields.find( ( field ) => { | ||
return field.id === fieldId; | ||
} ); | ||
filteredData.sort( ( a, b ) => { | ||
const valueA = fieldToSort.getValue( { item: a } ) ?? ''; | ||
const valueB = fieldToSort.getValue( { item: b } ) ?? ''; | ||
return view.sort.direction === 'asc' | ||
? valueA.localeCompare( valueB ) | ||
: valueB.localeCompare( valueA ); | ||
} ); | ||
} | ||
} | ||
|
||
// Handle pagination. | ||
const start = ( view.page - 1 ) * view.perPage; | ||
const totalItems = filteredData?.length || 0; | ||
filteredData = filteredData?.slice( start, start + view.perPage ); | ||
return { | ||
data: filteredData, | ||
paginationInfo: { | ||
totalItems, | ||
totalPages: Math.ceil( totalItems / view.perPage ), | ||
}, | ||
}; | ||
}, [ patterns, view, fields ] ); | ||
|
||
// const actions = useMemo( () => [ duplicatePatternAction ], [] ); | ||
const onChangeView = useCallback( | ||
( viewUpdater ) => { | ||
let updatedView = | ||
typeof viewUpdater === 'function' | ||
? viewUpdater( view ) | ||
: viewUpdater; | ||
if ( updatedView.type !== view.type ) { | ||
updatedView = { | ||
...updatedView, | ||
layout: { | ||
...defaultConfigPerViewType[ updatedView.type ], | ||
}, | ||
}; | ||
} | ||
setView( updatedView ); | ||
}, | ||
[ view, setView ] | ||
); | ||
const id = useId(); | ||
const titleId = `${ id }-title`; | ||
const descriptionId = `${ id }-description`; | ||
const settings = usePatternSettings(); | ||
// Wrap everything in a block editor provider. | ||
// This ensures 'styles' that are needed for the previews are synced | ||
// from the site editor store to the block editor store. | ||
// TODO: check if I add the provider in every preview like in templates... | ||
return ( | ||
<ExperimentalBlockEditorProvider settings={ settings }> | ||
<Page | ||
title={ __( 'Patterns content' ) } | ||
className="edit-site-page-patterns-dataviews" | ||
hideTitleFromUI | ||
> | ||
<PatternsHeader | ||
categoryId={ categoryId } | ||
type={ type } | ||
titleId={ titleId } | ||
descriptionId={ descriptionId } | ||
/> | ||
<DataViews | ||
paginationInfo={ paginationInfo } | ||
fields={ fields } | ||
// actions={ actions } | ||
data={ data || EMPTY_ARRAY } | ||
getItemId={ ( item ) => item.name } | ||
isLoading={ isResolving } | ||
view={ view } | ||
onChangeView={ onChangeView } | ||
deferredRendering={ true } | ||
supportedLayouts={ [ LAYOUT_GRID ] } | ||
/> | ||
</Page> | ||
</ExperimentalBlockEditorProvider> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters