From d3731da85ba5e8fece2e31612e57c10b687cb17e Mon Sep 17 00:00:00 2001 From: Aaron Robertshaw <60436221+aaronrobertshaw@users.noreply.github.com> Date: Thu, 25 May 2023 15:59:18 +1000 Subject: [PATCH 01/73] Add placeholder Library page --- .../edit-site/src/components/library/grid.js | 14 ++++++ .../edit-site/src/components/library/index.js | 47 +++++++++++++++++++ .../src/components/library/use-patterns.js | 5 ++ 3 files changed, 66 insertions(+) create mode 100644 packages/edit-site/src/components/library/grid.js create mode 100644 packages/edit-site/src/components/library/index.js create mode 100644 packages/edit-site/src/components/library/use-patterns.js diff --git a/packages/edit-site/src/components/library/grid.js b/packages/edit-site/src/components/library/grid.js new file mode 100644 index 00000000000000..96e021dabe052a --- /dev/null +++ b/packages/edit-site/src/components/library/grid.js @@ -0,0 +1,14 @@ +/** + * Internal dependencies + */ +import usePatterns from './use-patterns'; + +export default function Grid() { + const patterns = usePatterns(); + + return ( +
+ { patterns.map( () => '' ) } +
+ ); +} diff --git a/packages/edit-site/src/components/library/index.js b/packages/edit-site/src/components/library/index.js new file mode 100644 index 00000000000000..ef1873c2b01121 --- /dev/null +++ b/packages/edit-site/src/components/library/index.js @@ -0,0 +1,47 @@ +/** + * WordPress dependencies + */ +import { useSelect } from '@wordpress/data'; +import { EditorSnackbars } from '@wordpress/editor'; +import { __ } from '@wordpress/i18n'; +import { InterfaceSkeleton } from '@wordpress/interface'; +import { store as keyboardShortcutsStore } from '@wordpress/keyboard-shortcuts'; + +/** + * Internal dependencies + */ +import Grid from './grid'; +import useTitle from '../routes/use-title'; + +export default function Library() { + // Do we need shortcuts if we aren't displaying a header? + const { previousShortcut, nextShortcut } = useSelect( ( select ) => { + return { + previousShortcut: select( + keyboardShortcutsStore + ).getAllShortcutKeyCombinations( 'core/edit-site/previous-region' ), + nextShortcut: select( + keyboardShortcutsStore + ).getAllShortcutKeyCombinations( 'core/edit-site/next-region' ), + }; + }, [] ); + + useTitle( __( 'Library' ) ); + + // If we only have a single region, due to not including a header on this page, + // do we need the aria-label section? + const regionLabels = { body: __( 'Library - Content' ) }; + + return ( + } + content={ } + shortcuts={ { + previous: previousShortcut, + next: nextShortcut, + } } + /> + ); +} diff --git a/packages/edit-site/src/components/library/use-patterns.js b/packages/edit-site/src/components/library/use-patterns.js new file mode 100644 index 00000000000000..b6a65fd32db559 --- /dev/null +++ b/packages/edit-site/src/components/library/use-patterns.js @@ -0,0 +1,5 @@ +export default function usePattern() { + // TODO: Implement retrieval, sorting and merging of user created patterns, + // template parts, reusable blocks etc. + return []; +} From a46d4b58be49e68f9836223e99f0391c7efafc43 Mon Sep 17 00:00:00 2001 From: Aaron Robertshaw <60436221+aaronrobertshaw@users.noreply.github.com> Date: Thu, 25 May 2023 17:27:50 +1000 Subject: [PATCH 02/73] Add placeholder Library nav screen --- .../sidebar-navigation-item/index.js | 2 + .../category-item.js | 23 ++++ .../index.js | 116 ++++++++++++++++++ .../style.scss | 5 + .../use-pattern-categories.js | 34 +++++ .../use-template-part-areas.js | 33 +++++ packages/edit-site/src/style.scss | 1 + 7 files changed, 214 insertions(+) create mode 100644 packages/edit-site/src/components/sidebar-navigation-screen-library/category-item.js create mode 100644 packages/edit-site/src/components/sidebar-navigation-screen-library/index.js create mode 100644 packages/edit-site/src/components/sidebar-navigation-screen-library/style.scss create mode 100644 packages/edit-site/src/components/sidebar-navigation-screen-library/use-pattern-categories.js create mode 100644 packages/edit-site/src/components/sidebar-navigation-screen-library/use-template-part-areas.js diff --git a/packages/edit-site/src/components/sidebar-navigation-item/index.js b/packages/edit-site/src/components/sidebar-navigation-item/index.js index 18b8ea42516cbe..44a41f12d7d691 100644 --- a/packages/edit-site/src/components/sidebar-navigation-item/index.js +++ b/packages/edit-site/src/components/sidebar-navigation-item/index.js @@ -18,6 +18,7 @@ export default function SidebarNavigationItem( { className, icon, withChevron = false, + suffix, children, ...props } ) { @@ -45,6 +46,7 @@ export default function SidebarNavigationItem( { size={ 24 } /> ) } + { ! withChevron && suffix } ); diff --git a/packages/edit-site/src/components/sidebar-navigation-screen-library/category-item.js b/packages/edit-site/src/components/sidebar-navigation-screen-library/category-item.js new file mode 100644 index 00000000000000..1d6685ff41cffc --- /dev/null +++ b/packages/edit-site/src/components/sidebar-navigation-screen-library/category-item.js @@ -0,0 +1,23 @@ +/** + * Internal dependencies + */ +import SidebarNavigationItem from '../sidebar-navigation-item'; +import { useLink } from '../routes/link'; + +export default function CategoryItem( { count, icon, label, name, type } ) { + const linkInfo = useLink( { path: `/library/${ type }/${ name }` } ); + + if ( ! count ) { + return; + } + + return ( + { count } } + > + { label } + + ); +} diff --git a/packages/edit-site/src/components/sidebar-navigation-screen-library/index.js b/packages/edit-site/src/components/sidebar-navigation-screen-library/index.js new file mode 100644 index 00000000000000..5eae3f1d32e8a8 --- /dev/null +++ b/packages/edit-site/src/components/sidebar-navigation-screen-library/index.js @@ -0,0 +1,116 @@ +/** + * WordPress dependencies + */ +import { + __experimentalItemGroup as ItemGroup, + __experimentalItem as Item, +} from '@wordpress/components'; +import { useViewportMatch } from '@wordpress/compose'; +import { useSelect } from '@wordpress/data'; +import { getTemplatePartIcon } from '@wordpress/editor'; +import { __ } from '@wordpress/i18n'; + +/** + * Internal dependencies + */ +import SidebarNavigationItem from '../sidebar-navigation-item'; +import SidebarNavigationScreen from '../sidebar-navigation-screen'; +import CategoryItem from './category-item'; +import usePatternCategories from './use-pattern-categories'; +import useTemplatePartAreas from './use-template-part-areas'; +import { store as editSiteStore } from '../../store'; + +const templatePartAreaLabels = { + header: __( 'Headers' ), + footer: __( 'Footers' ), + sidebar: __( 'Sidebar' ), + rest: __( 'Uncategorized' ), // TODO: Find correct label for this. +}; + +export default function SidebarNavigationScreenLibrary() { + const isMobileViewport = useViewportMatch( 'medium', '<' ); + + const { templatePartAreas, hasTemplateParts, isLoading } = + useTemplatePartAreas(); + const { patternCategories, hasPatterns } = usePatternCategories(); + + const isTemplatePartsMode = useSelect( ( select ) => { + const settings = select( editSiteStore ).getSettings(); + return !! settings.supportsTemplatePartsMode; + }, [] ); + + return ( + + { isLoading && __( 'Loading library' ) } + { ! isLoading && ( + <> + { ! hasTemplateParts && ! hasPatterns && ( + + + { __( + 'No template parts or patterns found' + ) } + + + ) } + { hasTemplateParts && ( + + { Object.entries( templatePartAreas ).map( + ( [ area, parts ] ) => ( + + ) + ) } + + ) } + { hasPatterns && ( + + { patternCategories.map( ( category ) => ( + + ) ) } + + ) } + + { ! isMobileViewport && ( + + { __( 'Manage all reusable blocks' ) } + + ) } + + + ) } + + } + /> + ); +} diff --git a/packages/edit-site/src/components/sidebar-navigation-screen-library/style.scss b/packages/edit-site/src/components/sidebar-navigation-screen-library/style.scss new file mode 100644 index 00000000000000..a054e62b34ad98 --- /dev/null +++ b/packages/edit-site/src/components/sidebar-navigation-screen-library/style.scss @@ -0,0 +1,5 @@ +.edit-site-sidebar-navigation-screen-library__group { + padding-bottom: $grid-unit-20; + border-bottom: 1px solid $gray-800; + margin-bottom: $grid-unit-20; +} diff --git a/packages/edit-site/src/components/sidebar-navigation-screen-library/use-pattern-categories.js b/packages/edit-site/src/components/sidebar-navigation-screen-library/use-pattern-categories.js new file mode 100644 index 00000000000000..a933821afe1ee3 --- /dev/null +++ b/packages/edit-site/src/components/sidebar-navigation-screen-library/use-pattern-categories.js @@ -0,0 +1,34 @@ +/** + * WordPress dependencies + */ +import { store as blockEditorStore } from '@wordpress/block-editor'; +import { useSelect } from '@wordpress/data'; + +export default function usePatternCategories() { + return useSelect( ( select ) => { + const { __experimentalGetAllowedPatterns, getSettings } = + select( blockEditorStore ); + const patterns = __experimentalGetAllowedPatterns(); + const patternCategories = {}; + + getSettings().__experimentalBlockPatternCategories.forEach( + ( category ) => { + category.count = 0; + patternCategories[ category.name ] = category; + } + ); + + patterns.forEach( ( pattern ) => { + pattern.categories.forEach( ( patternCategory ) => { + if ( patternCategories[ patternCategory ] ) { + patternCategories[ patternCategory ].count += 1; + } + } ); + } ); + + return { + hasPatterns: !! patterns.length, + patternCategories: Object.values( patternCategories ), + }; + }, [] ); +} diff --git a/packages/edit-site/src/components/sidebar-navigation-screen-library/use-template-part-areas.js b/packages/edit-site/src/components/sidebar-navigation-screen-library/use-template-part-areas.js new file mode 100644 index 00000000000000..795af3144470a3 --- /dev/null +++ b/packages/edit-site/src/components/sidebar-navigation-screen-library/use-template-part-areas.js @@ -0,0 +1,33 @@ +/** + * WordPress dependencies + */ +import { useEntityRecords } from '@wordpress/core-data'; + +const getTemplatePartAreas = ( items ) => { + const allItems = items || []; + + const groupedByArea = allItems.reduce( + ( accumulator, item ) => { + const key = accumulator[ item.area ] ? item.area : 'rest'; + accumulator[ key ].push( item ); + return accumulator; + }, + { header: [], footer: [], sidebar: [], rest: [] } + ); + + return groupedByArea; +}; + +export default function useTemplatePartAreas() { + const { records: templateParts, isResolving: isLoading } = useEntityRecords( + 'postType', + 'wp_template_part', + { per_page: -1 } + ); + + return { + hasTemplateParts: templateParts ? !! templateParts.length : false, + isLoading, + templatePartAreas: getTemplatePartAreas( templateParts ), + }; +} diff --git a/packages/edit-site/src/style.scss b/packages/edit-site/src/style.scss index 5f434bb84f8f7c..8e4196838c314f 100644 --- a/packages/edit-site/src/style.scss +++ b/packages/edit-site/src/style.scss @@ -31,6 +31,7 @@ @import "./components/sidebar-navigation-screen/style.scss"; @import "./components/sidebar-navigation-screen-details-footer/style.scss"; @import "./components/sidebar-navigation-screen-global-styles/style.scss"; +@import "./components/sidebar-navigation-screen-library/style.scss"; @import "./components/sidebar-navigation-screen-navigation-menu/style.scss"; @import "./components/sidebar-navigation-screen-page/style.scss"; @import "components/sidebar-navigation-screen-details-panel/style.scss"; From 6c2a135ad7e30aef1574bad3bfc014268011ced0 Mon Sep 17 00:00:00 2001 From: Aaron Robertshaw <60436221+aaronrobertshaw@users.noreply.github.com> Date: Thu, 25 May 2023 17:28:52 +1000 Subject: [PATCH 03/73] Use placeholder library page and nav screen --- packages/edit-site/src/components/layout/index.js | 8 +++++--- .../sidebar-navigation-screen-main/index.js | 2 +- packages/edit-site/src/components/sidebar/index.js | 9 ++++++++- packages/edit-site/src/utils/get-is-library-page.js | 11 +++++++++++ 4 files changed, 25 insertions(+), 5 deletions(-) create mode 100644 packages/edit-site/src/utils/get-is-library-page.js diff --git a/packages/edit-site/src/components/layout/index.js b/packages/edit-site/src/components/layout/index.js index 29b4605e67d259..a477ae6957c152 100644 --- a/packages/edit-site/src/components/layout/index.js +++ b/packages/edit-site/src/components/layout/index.js @@ -36,6 +36,7 @@ import Sidebar from '../sidebar'; import Editor from '../editor'; import ErrorBoundary from '../error-boundary'; import { store as editSiteStore } from '../../store'; +import getIsLibraryPage from '../../utils/get-is-library-page'; import getIsListPage from '../../utils/get-is-list-page'; import Header from '../header-edit-mode'; import useInitEditedEntityFromURL from '../sync-state-with-url/use-init-edited-entity-from-url'; @@ -65,8 +66,9 @@ export default function Layout() { const hubRef = useRef(); const { params } = useLocation(); + const isLibraryPage = getIsLibraryPage( params ); const isListPage = getIsListPage( params ); - const isEditorPage = ! isListPage; + const isEditorPage = ! isListPage && ! isLibraryPage; const { hasFixedToolbar, canvasMode, previousShortcut, nextShortcut } = useSelect( ( select ) => { const { getAllShortcutKeyCombinations } = select( @@ -93,14 +95,14 @@ export default function Layout() { const disableMotion = useReducedMotion(); const isMobileViewport = useViewportMatch( 'medium', '<' ); const showSidebar = - ( isMobileViewport && ! isListPage ) || + ( isMobileViewport && isEditorPage ) || ( ! isMobileViewport && ( canvasMode === 'view' || ! isEditorPage ) ); const showCanvas = ( isMobileViewport && isEditorPage && isEditing ) || ! isMobileViewport || ! isEditorPage; const isFullCanvas = - ( isMobileViewport && isListPage ) || ( isEditorPage && isEditing ); + ( isMobileViewport && ! isEditorPage ) || ( isEditorPage && isEditing ); const [ canvasResizer, canvasSize ] = useResizeObserver(); const [ fullResizer ] = useResizeObserver(); const [ isResizing ] = useState( false ); diff --git a/packages/edit-site/src/components/sidebar-navigation-screen-main/index.js b/packages/edit-site/src/components/sidebar-navigation-screen-main/index.js index 5c89c9f72a23b2..6e7810abe81c05 100644 --- a/packages/edit-site/src/components/sidebar-navigation-screen-main/index.js +++ b/packages/edit-site/src/components/sidebar-navigation-screen-main/index.js @@ -75,7 +75,7 @@ export default function SidebarNavigationScreenMain() { diff --git a/packages/edit-site/src/components/sidebar/index.js b/packages/edit-site/src/components/sidebar/index.js index 7e5ede23cc1638..beda8082eeb01e 100644 --- a/packages/edit-site/src/components/sidebar/index.js +++ b/packages/edit-site/src/components/sidebar/index.js @@ -12,6 +12,7 @@ import { privateApis as routerPrivateApis } from '@wordpress/router'; * Internal dependencies */ import SidebarNavigationScreenMain from '../sidebar-navigation-screen-main'; +import SidebarNavigationScreenLibrary from '../sidebar-navigation-screen-library'; import SidebarNavigationScreenTemplates from '../sidebar-navigation-screen-templates'; import SidebarNavigationScreenTemplate from '../sidebar-navigation-screen-template'; import SidebarNavigationScreenTemplatePart from '../sidebar-navigation-screen-template-part'; @@ -55,7 +56,13 @@ function SidebarScreens() { - + + + + + + + diff --git a/packages/edit-site/src/utils/get-is-library-page.js b/packages/edit-site/src/utils/get-is-library-page.js new file mode 100644 index 00000000000000..c978deb26a44f6 --- /dev/null +++ b/packages/edit-site/src/utils/get-is-library-page.js @@ -0,0 +1,11 @@ +/* + * Returns if the params match the library page route. + * + * @param {Object} params The url params. + * @param {string} params.path The current path. + * + * @return {boolean} Is library page or not. + */ +export default function getIsLibraryPage( { path } ) { + return path === '/library'; +} From 01b56aef84d35079bb61344286e1d9ec8179f7f1 Mon Sep 17 00:00:00 2001 From: Aaron Robertshaw <60436221+aaronrobertshaw@users.noreply.github.com> Date: Thu, 25 May 2023 19:47:54 +1000 Subject: [PATCH 04/73] Add dodgy placeholder display for patterns or template parts --- .../edit-site/src/components/library/grid.js | 34 ++++++++++++- .../src/components/library/style.scss | 50 +++++++++++++++++++ .../src/components/library/use-patterns.js | 29 +++++++++-- packages/edit-site/src/style.scss | 1 + 4 files changed, 110 insertions(+), 4 deletions(-) create mode 100644 packages/edit-site/src/components/library/style.scss diff --git a/packages/edit-site/src/components/library/grid.js b/packages/edit-site/src/components/library/grid.js index 96e021dabe052a..6197627f1d4466 100644 --- a/packages/edit-site/src/components/library/grid.js +++ b/packages/edit-site/src/components/library/grid.js @@ -1,3 +1,10 @@ +/** + * WordPress dependencies + */ +import { Button, __experimentalHStack as HStack } from '@wordpress/components'; +import { __ } from '@wordpress/i18n'; +import { moreHorizontal } from '@wordpress/icons'; + /** * Internal dependencies */ @@ -6,9 +13,34 @@ import usePatterns from './use-patterns'; export default function Grid() { const patterns = usePatterns(); + if ( ! patterns ) { + return null; + } + + if ( ! patterns.length ) { + return
{ __( 'No patterns found.' ) }
; + } + return (
- { patterns.map( () => '' ) } + { patterns.map( ( pattern ) => ( +
+
+ { pattern.id } +
+ + { pattern.title.rendered } +
+ ) ) }
); } diff --git a/packages/edit-site/src/components/library/style.scss b/packages/edit-site/src/components/library/style.scss new file mode 100644 index 00000000000000..fa103a5ecfbd18 --- /dev/null +++ b/packages/edit-site/src/components/library/style.scss @@ -0,0 +1,50 @@ +.edit-site-library { + width: 100%; + + .interface-interface-skeleton__content { + border-radius: 0; + } +} + +.edit-site-library__grid { + column-count: 2; + column-gap: $grid-unit-30; + + // Small top padding required to avoid cutting off the visible outline + // when hovering items. + padding-top: $border-width-focus-fallback; + + .edit-site-library__pattern { + break-inside: avoid-column; + display: flex; + flex-direction: column; + margin-bottom: $grid-unit-60; + + // Temp styles for testing - delete asap + min-height: 250px; + + &:nth-child(2) { + min-height: 400px; + } + + &:nth-child(3) { + min-height: 600px; + } + + .edit-site-library__preview { + border-radius: $radius-block-ui * 4; + background: #ededed; + } + + .edit-site-library__footer, + .edit-site-library__button { + color: #e0e0e0; + } + // END: temp styles for testing. + } + + .edit-site-library__preview { + flex: 1; + margin-bottom: $grid-unit-30; + } +} diff --git a/packages/edit-site/src/components/library/use-patterns.js b/packages/edit-site/src/components/library/use-patterns.js index b6a65fd32db559..e9a5ab4279c47a 100644 --- a/packages/edit-site/src/components/library/use-patterns.js +++ b/packages/edit-site/src/components/library/use-patterns.js @@ -1,5 +1,28 @@ +/** + * WordPress dependencies + */ +import { useSelect } from '@wordpress/data'; +import { store as coreStore, useEntityRecords } from '@wordpress/core-data'; + +const TYPE = 'wp_template_part'; + export default function usePattern() { - // TODO: Implement retrieval, sorting and merging of user created patterns, - // template parts, reusable blocks etc. - return []; + const { records: allPatterns } = useEntityRecords( 'postType', TYPE, { + per_page: -1, + } ); + const patterns = useSelect( + ( select ) => + allPatterns?.filter( + ( pattern ) => + ! select( coreStore ).isDeletingEntityRecord( + 'postType', + TYPE, + pattern.id + ) + ), + [ allPatterns ] + ); + + // TODO: Add sorting etc. + return patterns; } diff --git a/packages/edit-site/src/style.scss b/packages/edit-site/src/style.scss index 8e4196838c314f..2d9dd417358412 100644 --- a/packages/edit-site/src/style.scss +++ b/packages/edit-site/src/style.scss @@ -8,6 +8,7 @@ @import "./components/global-styles/screen-revisions/style.scss"; @import "./components/header-edit-mode/style.scss"; @import "./components/header-edit-mode/document-actions/style.scss"; +@import "./components/library/style.scss"; @import "./components/list/style.scss"; @import "./components/page/style.scss"; @import "./components/table/style.scss"; From e59b58711e6d9af26aae50a22b131da612b309e1 Mon Sep 17 00:00:00 2001 From: Aaron Robertshaw <60436221+aaronrobertshaw@users.noreply.github.com> Date: Sun, 28 May 2023 15:07:09 +1000 Subject: [PATCH 05/73] Temporarily add category type and name to query params --- packages/edit-site/src/components/library/grid.js | 4 ++-- packages/edit-site/src/components/library/index.js | 5 ++++- .../sidebar-navigation-screen-library/category-item.js | 6 +++++- packages/edit-site/src/components/sidebar/index.js | 3 --- 4 files changed, 11 insertions(+), 7 deletions(-) diff --git a/packages/edit-site/src/components/library/grid.js b/packages/edit-site/src/components/library/grid.js index 6197627f1d4466..0ce126e4119e29 100644 --- a/packages/edit-site/src/components/library/grid.js +++ b/packages/edit-site/src/components/library/grid.js @@ -10,8 +10,8 @@ import { moreHorizontal } from '@wordpress/icons'; */ import usePatterns from './use-patterns'; -export default function Grid() { - const patterns = usePatterns(); +export default function Grid( { type, name } ) { + const patterns = usePatterns( type, name ); if ( ! patterns ) { return null; diff --git a/packages/edit-site/src/components/library/index.js b/packages/edit-site/src/components/library/index.js index ef1873c2b01121..c496e09a7d151b 100644 --- a/packages/edit-site/src/components/library/index.js +++ b/packages/edit-site/src/components/library/index.js @@ -6,6 +6,7 @@ import { EditorSnackbars } from '@wordpress/editor'; import { __ } from '@wordpress/i18n'; import { InterfaceSkeleton } from '@wordpress/interface'; import { store as keyboardShortcutsStore } from '@wordpress/keyboard-shortcuts'; +import { getQueryArgs } from '@wordpress/url'; /** * Internal dependencies @@ -14,6 +15,8 @@ import Grid from './grid'; import useTitle from '../routes/use-title'; export default function Library() { + const { categoryType, categoryName } = getQueryArgs( window.location.href ); + // Do we need shortcuts if we aren't displaying a header? const { previousShortcut, nextShortcut } = useSelect( ( select ) => { return { @@ -37,7 +40,7 @@ export default function Library() { className="edit-site-library" labels={ regionLabels } notices={ } - content={ } + content={ } shortcuts={ { previous: previousShortcut, next: nextShortcut, diff --git a/packages/edit-site/src/components/sidebar-navigation-screen-library/category-item.js b/packages/edit-site/src/components/sidebar-navigation-screen-library/category-item.js index 1d6685ff41cffc..229299237c8cfd 100644 --- a/packages/edit-site/src/components/sidebar-navigation-screen-library/category-item.js +++ b/packages/edit-site/src/components/sidebar-navigation-screen-library/category-item.js @@ -5,7 +5,11 @@ import SidebarNavigationItem from '../sidebar-navigation-item'; import { useLink } from '../routes/link'; export default function CategoryItem( { count, icon, label, name, type } ) { - const linkInfo = useLink( { path: `/library/${ type }/${ name }` } ); + const linkInfo = useLink( { + path: '/library', + categoryType: type, + categoryName: name, + } ); if ( ! count ) { return; diff --git a/packages/edit-site/src/components/sidebar/index.js b/packages/edit-site/src/components/sidebar/index.js index beda8082eeb01e..5c36eb964fd338 100644 --- a/packages/edit-site/src/components/sidebar/index.js +++ b/packages/edit-site/src/components/sidebar/index.js @@ -59,9 +59,6 @@ function SidebarScreens() { - - - From 322104482f8b73c1c3135ddbcee51c67227da3fd Mon Sep 17 00:00:00 2001 From: Aaron Robertshaw <60436221+aaronrobertshaw@users.noreply.github.com> Date: Mon, 29 May 2023 09:29:32 +1000 Subject: [PATCH 06/73] Try displaying patterns and template parts --- .../edit-site/src/components/library/grid.js | 66 ++++++--- .../src/components/library/style.scss | 14 +- .../src/components/library/use-patterns.js | 128 +++++++++++++++--- .../index.js | 2 +- .../use-pattern-categories.js | 83 +++++++++--- .../use-template-part-areas.js | 4 +- 6 files changed, 227 insertions(+), 70 deletions(-) diff --git a/packages/edit-site/src/components/library/grid.js b/packages/edit-site/src/components/library/grid.js index 0ce126e4119e29..8775ca208f8fec 100644 --- a/packages/edit-site/src/components/library/grid.js +++ b/packages/edit-site/src/components/library/grid.js @@ -1,7 +1,13 @@ /** * WordPress dependencies */ -import { Button, __experimentalHStack as HStack } from '@wordpress/components'; +import { BlockPreview } from '@wordpress/block-editor'; +import { + Button, + VisuallyHidden, + __experimentalHStack as HStack, +} from '@wordpress/components'; +import { useInstanceId } from '@wordpress/compose'; import { __ } from '@wordpress/i18n'; import { moreHorizontal } from '@wordpress/icons'; @@ -10,8 +16,41 @@ import { moreHorizontal } from '@wordpress/icons'; */ import usePatterns from './use-patterns'; +const GridItem = ( { item } ) => { + const instanceId = useInstanceId( GridItem ); + const descriptionId = `edit-site-library__pattern-description-${ instanceId }`; + + return ( +
+
+ + { !! item.description && ( + + { item.description } + + ) } +
+ + { item.title } +
+ ); +}; + export default function Grid( { type, name } ) { - const patterns = usePatterns( type, name ); + const [ patterns, isResolving ] = usePatterns( type, name ); if ( ! patterns ) { return null; @@ -23,24 +62,11 @@ export default function Grid( { type, name } ) { return (
- { patterns.map( ( pattern ) => ( -
-
- { pattern.id } -
- - { pattern.title.rendered } -
- ) ) } + { isResolving && __( 'Loading' ) } + { ! isResolving && + patterns.map( ( pattern ) => ( + + ) ) }
); } diff --git a/packages/edit-site/src/components/library/style.scss b/packages/edit-site/src/components/library/style.scss index fa103a5ecfbd18..45a0c906270820 100644 --- a/packages/edit-site/src/components/library/style.scss +++ b/packages/edit-site/src/components/library/style.scss @@ -13,6 +13,8 @@ // Small top padding required to avoid cutting off the visible outline // when hovering items. padding-top: $border-width-focus-fallback; + padding-left: $grid-unit-15; + padding-right: $grid-unit-15; .edit-site-library__pattern { break-inside: avoid-column; @@ -21,19 +23,9 @@ margin-bottom: $grid-unit-60; // Temp styles for testing - delete asap - min-height: 250px; - - &:nth-child(2) { - min-height: 400px; - } - - &:nth-child(3) { - min-height: 600px; - } - .edit-site-library__preview { border-radius: $radius-block-ui * 4; - background: #ededed; + overflow: hidden; } .edit-site-library__footer, diff --git a/packages/edit-site/src/components/library/use-patterns.js b/packages/edit-site/src/components/library/use-patterns.js index e9a5ab4279c47a..58c80695231bed 100644 --- a/packages/edit-site/src/components/library/use-patterns.js +++ b/packages/edit-site/src/components/library/use-patterns.js @@ -1,28 +1,122 @@ /** * WordPress dependencies */ +import { parse } from '@wordpress/blocks'; import { useSelect } from '@wordpress/data'; -import { store as coreStore, useEntityRecords } from '@wordpress/core-data'; +import { store as coreStore } from '@wordpress/core-data'; +import { useMemo } from '@wordpress/element'; -const TYPE = 'wp_template_part'; +/** + * Internal dependencies + */ +import { unlock } from '../../private-apis'; +import { store as editSiteStore } from '../../store'; + +const TEMPLATE_PARTS = 'wp_template_part'; +const PATTERNS = 'pattern'; + +const createTemplatePartId = ( theme, slug ) => + theme && slug ? theme + '//' + slug : null; + +const toPattern = ( templatePart ) => ( { + name: createTemplatePartId( templatePart.theme, templatePart.slug ), + title: templatePart.title.rendered, + blocks: parse( templatePart.content.raw ), + templatePart, +} ); + +const useTemplatePartsAsPatterns = ( area, postType = TEMPLATE_PARTS ) => { + const { templateParts, isResolving } = useSelect( + ( select ) => { + if ( postType !== TEMPLATE_PARTS ) { + return { templateParts: [], isResolving: false }; + } + + const { getEntityRecords, isResolving: _isResolving } = + select( coreStore ); + const query = { per_page: -1 }; + + return { + templateParts: getEntityRecords( 'postType', postType, query ), + isResolving: _isResolving( 'getEntityRecords', [ + 'postType', + 'wp_template_part', + query, + ] ), + }; + }, + [ postType ] + ); + + const filteredTemplateParts = useMemo( () => { + if ( ! templateParts ) { + return []; + } + + const partsAsPatterns = []; + + templateParts?.forEach( ( templatePart ) => { + if ( ! area || templatePart.area === area ) { + partsAsPatterns.push( toPattern( templatePart ) ); + } + } ); -export default function usePattern() { - const { records: allPatterns } = useEntityRecords( 'postType', TYPE, { - per_page: -1, + return partsAsPatterns; + }, [ templateParts, area ] ); + + return { templateParts: filteredTemplateParts, isResolving }; +}; + +const useBlockPatternsByCategory = ( category, postType = PATTERNS ) => { + const blockPatterns = useSelect( ( select ) => { + const { getSettings } = unlock( select( editSiteStore ) ); + const settings = getSettings(); + return ( + settings.__experimentalAdditionalBlockPatterns ?? + settings.__experimentalBlockPatterns + ); } ); - const patterns = useSelect( - ( select ) => - allPatterns?.filter( - ( pattern ) => - ! select( coreStore ).isDeletingEntityRecord( - 'postType', - TYPE, - pattern.id - ) - ), - [ allPatterns ] + + const restBlockPatterns = useSelect( ( select ) => + select( coreStore ).getBlockPatterns() + ); + + const patterns = useMemo( + () => + [ ...( blockPatterns || [] ), ...( restBlockPatterns || [] ) ] + .filter( + ( x, index, arr ) => + index === arr.findIndex( ( y ) => x.name === y.name ) + ) + .map( ( pattern ) => ( { + ...pattern, + blocks: parse( pattern.content ), + } ) ), + [ blockPatterns, restBlockPatterns ] + ); + + if ( postType !== PATTERNS ) { + return []; + } + + if ( ! category ) { + return patterns || []; + } + + return patterns.filter( ( pattern ) => + pattern.categories?.includes( category ) + ); +}; + +export default function usePatterns( categoryType, categoryName ) { + const patterns = useBlockPatternsByCategory( categoryName, categoryType ); + const { templateParts, isResolving } = useTemplatePartsAsPatterns( + categoryName, + categoryType ); // TODO: Add sorting etc. - return patterns; + + const results = [ ...templateParts, ...patterns ]; + return [ results, isResolving ]; } diff --git a/packages/edit-site/src/components/sidebar-navigation-screen-library/index.js b/packages/edit-site/src/components/sidebar-navigation-screen-library/index.js index 5eae3f1d32e8a8..5567bb18053e89 100644 --- a/packages/edit-site/src/components/sidebar-navigation-screen-library/index.js +++ b/packages/edit-site/src/components/sidebar-navigation-screen-library/index.js @@ -24,7 +24,7 @@ const templatePartAreaLabels = { header: __( 'Headers' ), footer: __( 'Footers' ), sidebar: __( 'Sidebar' ), - rest: __( 'Uncategorized' ), // TODO: Find correct label for this. + uncategorized: __( 'Uncategorized' ), // TODO: Find correct label for this. }; export default function SidebarNavigationScreenLibrary() { diff --git a/packages/edit-site/src/components/sidebar-navigation-screen-library/use-pattern-categories.js b/packages/edit-site/src/components/sidebar-navigation-screen-library/use-pattern-categories.js index a933821afe1ee3..1f1b2341e8202b 100644 --- a/packages/edit-site/src/components/sidebar-navigation-screen-library/use-pattern-categories.js +++ b/packages/edit-site/src/components/sidebar-navigation-screen-library/use-pattern-categories.js @@ -1,34 +1,79 @@ /** * WordPress dependencies */ -import { store as blockEditorStore } from '@wordpress/block-editor'; +import { store as coreStore } from '@wordpress/core-data'; import { useSelect } from '@wordpress/data'; +import { useMemo } from '@wordpress/element'; + +/** + * Internal dependencies + */ +import { unlock } from '../../private-apis'; +import { store as editSiteStore } from '../../store'; export default function usePatternCategories() { - return useSelect( ( select ) => { - const { __experimentalGetAllowedPatterns, getSettings } = - select( blockEditorStore ); - const patterns = __experimentalGetAllowedPatterns(); - const patternCategories = {}; - - getSettings().__experimentalBlockPatternCategories.forEach( - ( category ) => { + const { blockPatterns, blockPatternCategories } = useSelect( ( select ) => { + const { getSettings } = unlock( select( editSiteStore ) ); + const settings = getSettings(); + + return { + blockPatterns: + settings.__experimentalAdditionalBlockPatterns ?? + settings.__experimentalBlockPatterns, + blockPatternCategories: + settings.__experimentalAdditionalBlockPatternCategories ?? + settings.__experimentalBlockPatternCategories, + }; + } ); + + const { restBlockPatterns, restBlockPatternCategories } = useSelect( + ( select ) => ( { + restBlockPatterns: select( coreStore ).getBlockPatterns(), + restBlockPatternCategories: + select( coreStore ).getBlockPatternCategories(), + } ) + ); + + const patterns = useMemo( + () => + [ + ...( blockPatterns || [] ), + ...( restBlockPatterns || [] ), + ].filter( + ( x, index, arr ) => + index === arr.findIndex( ( y ) => x.name === y.name ) + ), + [ blockPatterns, restBlockPatterns ] + ); + + const categories = useMemo( () => { + const combinedCategories = [ + ...( blockPatternCategories || [] ), + ...( restBlockPatternCategories || [] ), + ]; + + const categoryMap = {}; + + combinedCategories.forEach( ( category ) => { + if ( ! categoryMap[ category.name ] ) { category.count = 0; - patternCategories[ category.name ] = category; + categoryMap[ category.name ] = category; } - ); + } ); patterns.forEach( ( pattern ) => { - pattern.categories.forEach( ( patternCategory ) => { - if ( patternCategories[ patternCategory ] ) { - patternCategories[ patternCategory ].count += 1; + pattern.categories?.forEach( ( patternCategory ) => { + if ( categoryMap[ patternCategory ] ) { + categoryMap[ patternCategory ].count += 1; } } ); } ); - return { - hasPatterns: !! patterns.length, - patternCategories: Object.values( patternCategories ), - }; - }, [] ); + return categoryMap; + }, [ blockPatternCategories, restBlockPatternCategories, patterns ] ); + + return { + hasPatterns: !! patterns.length, + patternCategories: Object.values( categories ), + }; } diff --git a/packages/edit-site/src/components/sidebar-navigation-screen-library/use-template-part-areas.js b/packages/edit-site/src/components/sidebar-navigation-screen-library/use-template-part-areas.js index 795af3144470a3..aa258344d132da 100644 --- a/packages/edit-site/src/components/sidebar-navigation-screen-library/use-template-part-areas.js +++ b/packages/edit-site/src/components/sidebar-navigation-screen-library/use-template-part-areas.js @@ -8,11 +8,11 @@ const getTemplatePartAreas = ( items ) => { const groupedByArea = allItems.reduce( ( accumulator, item ) => { - const key = accumulator[ item.area ] ? item.area : 'rest'; + const key = accumulator[ item.area ] ? item.area : 'uncategorized'; accumulator[ key ].push( item ); return accumulator; }, - { header: [], footer: [], sidebar: [], rest: [] } + { header: [], footer: [], sidebar: [], uncategorized: [] } ); return groupedByArea; From b6172744b05eb4d71241ae7641415ea34086bc33 Mon Sep 17 00:00:00 2001 From: Aaron Robertshaw <60436221+aaronrobertshaw@users.noreply.github.com> Date: Mon, 29 May 2023 18:10:07 +1000 Subject: [PATCH 07/73] Highlight active category nav item --- .../edit-site/src/components/library/grid.js | 4 ++-- .../edit-site/src/components/library/index.js | 7 ++++++- .../category-item.js | 10 +++++++++- .../sidebar-navigation-screen-library/index.js | 17 +++++++++++++++++ .../style.scss | 4 ++++ 5 files changed, 38 insertions(+), 4 deletions(-) diff --git a/packages/edit-site/src/components/library/grid.js b/packages/edit-site/src/components/library/grid.js index 8775ca208f8fec..3ef8c389a3d4e5 100644 --- a/packages/edit-site/src/components/library/grid.js +++ b/packages/edit-site/src/components/library/grid.js @@ -49,8 +49,8 @@ const GridItem = ( { item } ) => { ); }; -export default function Grid( { type, name } ) { - const [ patterns, isResolving ] = usePatterns( type, name ); +export default function Grid( { type, category } ) { + const [ patterns, isResolving ] = usePatterns( type, category ); if ( ! patterns ) { return null; diff --git a/packages/edit-site/src/components/library/index.js b/packages/edit-site/src/components/library/index.js index c496e09a7d151b..c963530c5d61f9 100644 --- a/packages/edit-site/src/components/library/index.js +++ b/packages/edit-site/src/components/library/index.js @@ -14,8 +14,13 @@ import { getQueryArgs } from '@wordpress/url'; import Grid from './grid'; import useTitle from '../routes/use-title'; +const DEFAULT_TYPE = 'wp_template_part'; +const DEFAULT_CATEGORY = 'header'; + export default function Library() { const { categoryType, categoryName } = getQueryArgs( window.location.href ); + const type = categoryType || DEFAULT_TYPE; + const category = categoryName || DEFAULT_CATEGORY; // Do we need shortcuts if we aren't displaying a header? const { previousShortcut, nextShortcut } = useSelect( ( select ) => { @@ -40,7 +45,7 @@ export default function Library() { className="edit-site-library" labels={ regionLabels } notices={ } - content={ } + content={ } shortcuts={ { previous: previousShortcut, next: nextShortcut, diff --git a/packages/edit-site/src/components/sidebar-navigation-screen-library/category-item.js b/packages/edit-site/src/components/sidebar-navigation-screen-library/category-item.js index 229299237c8cfd..def480419326f6 100644 --- a/packages/edit-site/src/components/sidebar-navigation-screen-library/category-item.js +++ b/packages/edit-site/src/components/sidebar-navigation-screen-library/category-item.js @@ -4,7 +4,14 @@ import SidebarNavigationItem from '../sidebar-navigation-item'; import { useLink } from '../routes/link'; -export default function CategoryItem( { count, icon, label, name, type } ) { +export default function CategoryItem( { + count, + icon, + isActive, + label, + name, + type, +} ) { const linkInfo = useLink( { path: '/library', categoryType: type, @@ -20,6 +27,7 @@ export default function CategoryItem( { count, icon, label, name, type } ) { { ...linkInfo } icon={ icon } suffix={ { count } } + className={ isActive ? 'is-active-category' : undefined } > { label } diff --git a/packages/edit-site/src/components/sidebar-navigation-screen-library/index.js b/packages/edit-site/src/components/sidebar-navigation-screen-library/index.js index 5567bb18053e89..80b57d1ac6304a 100644 --- a/packages/edit-site/src/components/sidebar-navigation-screen-library/index.js +++ b/packages/edit-site/src/components/sidebar-navigation-screen-library/index.js @@ -9,6 +9,7 @@ import { useViewportMatch } from '@wordpress/compose'; import { useSelect } from '@wordpress/data'; import { getTemplatePartIcon } from '@wordpress/editor'; import { __ } from '@wordpress/i18n'; +import { getQueryArgs } from '@wordpress/url'; /** * Internal dependencies @@ -20,6 +21,9 @@ import usePatternCategories from './use-pattern-categories'; import useTemplatePartAreas from './use-template-part-areas'; import { store as editSiteStore } from '../../store'; +const DEFAULT_CATEGORY = 'header'; +const DEFAULT_TYPE = 'wp_template_part'; + const templatePartAreaLabels = { header: __( 'Headers' ), footer: __( 'Footers' ), @@ -29,6 +33,9 @@ const templatePartAreaLabels = { export default function SidebarNavigationScreenLibrary() { const isMobileViewport = useViewportMatch( 'medium', '<' ); + const { categoryType, categoryName } = getQueryArgs( window.location.href ); + const currentCategory = categoryName || DEFAULT_CATEGORY; + const currentType = categoryType || DEFAULT_TYPE; const { templatePartAreas, hasTemplateParts, isLoading } = useTemplatePartAreas(); @@ -78,6 +85,11 @@ export default function SidebarNavigationScreenLibrary() { } name={ area } type="wp_template_part" + isActive={ + currentCategory === area && + currentType === + 'wp_template_part' + } /> ) ) } @@ -92,6 +104,11 @@ export default function SidebarNavigationScreenLibrary() { label={ category.label } name={ category.name } type="pattern" + isActive={ + currentCategory === + category.name && + currentType === 'pattern' + } /> ) ) } diff --git a/packages/edit-site/src/components/sidebar-navigation-screen-library/style.scss b/packages/edit-site/src/components/sidebar-navigation-screen-library/style.scss index a054e62b34ad98..2f30d25e0c649a 100644 --- a/packages/edit-site/src/components/sidebar-navigation-screen-library/style.scss +++ b/packages/edit-site/src/components/sidebar-navigation-screen-library/style.scss @@ -3,3 +3,7 @@ border-bottom: 1px solid $gray-800; margin-bottom: $grid-unit-20; } + +.edit-site-sidebar-navigation-item.is-active-category { + background: $gray-800; +} From 4f15ff1bd83abe2f3c773fd1fddfc1a53e466eaa Mon Sep 17 00:00:00 2001 From: Aaron Robertshaw <60436221+aaronrobertshaw@users.noreply.github.com> Date: Tue, 30 May 2023 16:55:18 +1000 Subject: [PATCH 08/73] Add placeholder dropdown for deleting patterns --- .../edit-site/src/components/library/grid.js | 30 +++++++++++++++---- 1 file changed, 25 insertions(+), 5 deletions(-) diff --git a/packages/edit-site/src/components/library/grid.js b/packages/edit-site/src/components/library/grid.js index 3ef8c389a3d4e5..8f29f3f5bf7493 100644 --- a/packages/edit-site/src/components/library/grid.js +++ b/packages/edit-site/src/components/library/grid.js @@ -3,7 +3,9 @@ */ import { BlockPreview } from '@wordpress/block-editor'; import { - Button, + DropdownMenu, + MenuGroup, + MenuItem, VisuallyHidden, __experimentalHStack as HStack, } from '@wordpress/components'; @@ -39,11 +41,29 @@ const GridItem = ( { item } ) => { justify="space-between" > { item.title } - + + + + + + ); +} diff --git a/packages/edit-site/src/components/sidebar-navigation-screen-library/index.js b/packages/edit-site/src/components/sidebar-navigation-screen-library/index.js index 80b57d1ac6304a..269d67c3a1d968 100644 --- a/packages/edit-site/src/components/sidebar-navigation-screen-library/index.js +++ b/packages/edit-site/src/components/sidebar-navigation-screen-library/index.js @@ -14,12 +14,14 @@ import { getQueryArgs } from '@wordpress/url'; /** * Internal dependencies */ +import AddNewPattern from '../add-new-pattern'; import SidebarNavigationItem from '../sidebar-navigation-item'; import SidebarNavigationScreen from '../sidebar-navigation-screen'; import CategoryItem from './category-item'; +import SidebarButton from '../sidebar-button'; +import { store as editSiteStore } from '../../store'; import usePatternCategories from './use-pattern-categories'; import useTemplatePartAreas from './use-template-part-areas'; -import { store as editSiteStore } from '../../store'; const DEFAULT_CATEGORY = 'header'; const DEFAULT_TYPE = 'wp_template_part'; @@ -53,7 +55,14 @@ export default function SidebarNavigationScreenLibrary() { description={ __( 'Manage what patterns are available when editing your site.' ) } - // actions={ {} } + actions={ + + } content={ <> { isLoading && __( 'Loading library' ) } From 2fa73e0ec9add5cc5aae1c860d37108b6cbfafdc Mon Sep 17 00:00:00 2001 From: Aaron Robertshaw <60436221+aaronrobertshaw@users.noreply.github.com> Date: Wed, 31 May 2023 12:01:18 +1000 Subject: [PATCH 11/73] Add category select to create pattern modal --- .../components/create-pattern-modal/index.js | 33 +++++++++++++++++-- .../create-pattern-modal/style.scss | 3 ++ packages/edit-site/src/style.scss | 1 + 3 files changed, 35 insertions(+), 2 deletions(-) create mode 100644 packages/edit-site/src/components/create-pattern-modal/style.scss diff --git a/packages/edit-site/src/components/create-pattern-modal/index.js b/packages/edit-site/src/components/create-pattern-modal/index.js index a324553588eb17..86c35ee785d0d0 100644 --- a/packages/edit-site/src/components/create-pattern-modal/index.js +++ b/packages/edit-site/src/components/create-pattern-modal/index.js @@ -5,22 +5,42 @@ import { TextControl, Button, Modal, + SelectControl, __experimentalHStack as HStack, __experimentalVStack as VStack, } from '@wordpress/components'; import { __ } from '@wordpress/i18n'; import { useState } from '@wordpress/element'; +/** + * Internal dependencies + */ +import usePatternCategories from '../sidebar-navigation-screen-library/use-pattern-categories'; + export default function CreatePatternModal( { closeModal, onCreate } ) { const [ name, setName ] = useState( '' ); + const [ categoryName, setCategoryName ] = useState( '' ); const [ isSubmitting, setIsSubmitting ] = useState( false ); + const { patternCategories } = usePatternCategories(); + + const options = patternCategories.map( ( category ) => ( { + label: category.label, + value: category.name, + } ) ); + return ( +

+ { __( + 'Turn this block into a pattern for you to reuse later' + ) } +

+
{ event.preventDefault(); @@ -33,11 +53,20 @@ export default function CreatePatternModal( { closeModal, onCreate } ) { > +