diff --git a/lib/experimental/posts/load.php b/lib/experimental/posts/load.php index 3fff8a151dfef..87dea2dbb1b9a 100644 --- a/lib/experimental/posts/load.php +++ b/lib/experimental/posts/load.php @@ -7,22 +7,78 @@ add_action( 'admin_menu', 'gutenberg_replace_posts_dashboard' ); +// Default to is-fullscreen-mode to avoid jumps in the UI. +add_filter( + 'admin_body_class', + static function ( $classes ) { + return "$classes is-fullscreen-mode"; + } +); + /** * Renders the new posts dashboard page. */ function gutenberg_posts_dashboard() { + $block_editor_context = new WP_Block_Editor_Context( array( 'name' => 'core/edit-site' ) ); + $custom_settings = array( + 'siteUrl' => site_url(), + 'styles' => get_block_editor_theme_styles(), + 'supportsLayout' => wp_theme_has_theme_json(), + ); + + $editor_settings = get_block_editor_settings( $custom_settings, $block_editor_context ); + $active_global_styles_id = WP_Theme_JSON_Resolver::get_user_global_styles_post_id(); + $active_theme = get_stylesheet(); + + $preload_paths = array( + array( '/wp/v2/media', 'OPTIONS' ), + '/wp/v2/types?context=view', + '/wp/v2/global-styles/' . $active_global_styles_id . '?context=edit', + '/wp/v2/global-styles/' . $active_global_styles_id, + '/wp/v2/global-styles/themes/' . $active_theme, + ); + block_editor_rest_api_preload( $preload_paths, $block_editor_context ); + + // Preload server-registered block schemas. + wp_add_inline_script( + 'wp-blocks', + 'wp.blocks.unstable__bootstrapServerSideBlockDefinitions(' . wp_json_encode( get_block_editor_server_block_settings() ) . ');' + ); + + /** This action is documented in wp-admin/edit-form-blocks.php */ + do_action( 'enqueue_block_editor_assets' ); wp_register_style( 'wp-gutenberg-posts-dashboard', gutenberg_url( 'build/edit-site/posts.css', __FILE__ ), - array( 'wp-components', 'wp-commands' ) + array( 'wp-components', 'wp-commands', 'wp-edit-site' ) ); wp_enqueue_style( 'wp-gutenberg-posts-dashboard' ); - wp_add_inline_script( 'wp-edit-site', 'window.wp.editSite.initializePostsDashboard( "gutenberg-posts-dashboard" );', 'after' ); + wp_add_inline_script( + 'wp-edit-site', + sprintf( + 'wp.domReady( function() { + wp.editSite.initializePostsDashboard( "gutenberg-posts-dashboard", %s ); + } );', + wp_json_encode( $editor_settings ) + ) + ); wp_enqueue_script( 'wp-edit-site' ); - + wp_enqueue_media(); echo '
'; } +/** + * Redirects to the new posts dashboard page and adds the postType query arg. + */ +function gutenberg_add_post_type_arg() { + global $pagenow; + if ( 'admin.php' === $pagenow && isset( $_GET['page'] ) && 'gutenberg-posts-dashboard' === $_GET['page'] && empty( $_GET['postType'] ) ) { + wp_redirect( admin_url( '/admin.php?page=gutenberg-posts-dashboard&postType=post' ) ); + exit; + } +} +add_action( 'admin_init', 'gutenberg_add_post_type_arg' ); + /** * Replaces the default posts menu item with the new posts dashboard. */ diff --git a/packages/dataviews/src/dataviews.tsx b/packages/dataviews/src/dataviews.tsx index f179ee71dcf04..8dd81e9013af8 100644 --- a/packages/dataviews/src/dataviews.tsx +++ b/packages/dataviews/src/dataviews.tsx @@ -18,7 +18,10 @@ import Filters from './filters'; import Search from './search'; import { LAYOUT_TABLE, LAYOUT_GRID } from './constants'; import { VIEW_LAYOUTS } from './layouts'; -import BulkActions from './bulk-actions'; +import { + default as BulkActions, + useSomeItemHasAPossibleBulkAction, +} from './bulk-actions'; import { normalizeFields } from './normalize-fields'; import BulkActionsToolbar from './bulk-actions-toolbar'; import type { Action, Field, View, ViewBaseProps } from './types'; @@ -51,22 +54,6 @@ const defaultGetItemId = ( item: ItemWithId ) => item.id; const defaultOnSelectionChange = () => {}; -function useSomeItemHasAPossibleBulkAction< Item >( - actions: Action< Item >[], - data: Item[] -) { - return useMemo( () => { - return data.some( ( item ) => { - return actions.some( ( action ) => { - return ( - action.supportsBulk && - ( ! action.isEligible || action.isEligible( item ) ) - ); - } ); - } ); - }, [ actions, data ] ); -} - export default function DataViews< Item >( { view, onChangeView, diff --git a/packages/dataviews/src/style.scss b/packages/dataviews/src/style.scss index 5ea0c624bb3dc..76a9ab2dec494 100644 --- a/packages/dataviews/src/style.scss +++ b/packages/dataviews/src/style.scss @@ -196,7 +196,7 @@ text-transform: uppercase; font-weight: 500; - &:has(.dataviews-view-table-header-button) { + &:has(.dataviews-view-table-header-button):not(:first-child) { padding-left: $grid-unit-05; } } @@ -263,7 +263,6 @@ color: $gray-700; text-overflow: ellipsis; white-space: nowrap; - display: block; width: 100%; a { @@ -332,11 +331,6 @@ .dataviews-view-grid__fields .dataviews-view-grid__field .dataviews-view-grid__field-value { color: $gray-900; } - - .page-pages-preview-field__button::after { - box-shadow: inset 0 0 0 var(--wp-admin-border-width-focus) var(--wp-admin-theme-color); - background: rgba(var(--wp-admin-theme-color--rgb), 0.04); - } } } diff --git a/packages/edit-site/src/components/add-new-page/index.js b/packages/edit-site/src/components/add-new-post/index.js similarity index 66% rename from packages/edit-site/src/components/add-new-page/index.js rename to packages/edit-site/src/components/add-new-post/index.js index 9bd82fe217c60..7e75a47820fce 100644 --- a/packages/edit-site/src/components/add-new-page/index.js +++ b/packages/edit-site/src/components/add-new-post/index.js @@ -9,15 +9,19 @@ import { TextControl, } from '@wordpress/components'; import { __, sprintf } from '@wordpress/i18n'; -import { useDispatch, useRegistry } from '@wordpress/data'; +import { useDispatch, useRegistry, useSelect } from '@wordpress/data'; import { useState } from '@wordpress/element'; import { store as coreStore } from '@wordpress/core-data'; import { store as noticesStore } from '@wordpress/notices'; import { decodeEntities } from '@wordpress/html-entities'; import { serialize, synchronizeBlocksWithTemplate } from '@wordpress/blocks'; -export default function AddNewPageModal( { onSave, onClose } ) { - const [ isCreatingPage, setIsCreatingPage ] = useState( false ); +export default function AddNewPostModal( { postType, onSave, onClose } ) { + const labels = useSelect( + ( select ) => select( coreStore ).getPostType( postType )?.labels, + [ postType ] + ); + const [ isCreatingPost, setIsCreatingPost ] = useState( false ); const [ title, setTitle ] = useState( '' ); const { saveEntityRecord } = useDispatch( coreStore ); @@ -25,29 +29,30 @@ export default function AddNewPageModal( { onSave, onClose } ) { useDispatch( noticesStore ); const { resolveSelect } = useRegistry(); - async function createPage( event ) { + async function createPost( event ) { event.preventDefault(); - if ( isCreatingPage ) { + if ( isCreatingPost ) { return; } - setIsCreatingPage( true ); + setIsCreatingPost( true ); try { - const pagePostType = - await resolveSelect( coreStore ).getPostType( 'page' ); + const postTypeObject = + await resolveSelect( coreStore ).getPostType( postType ); const newPage = await saveEntityRecord( 'postType', - 'page', + postType, { status: 'draft', title, slug: title || __( 'No title' ), content: - !! pagePostType.template && pagePostType.template.length + !! postTypeObject.template && + postTypeObject.template.length ? serialize( synchronizeBlocksWithTemplate( [], - pagePostType.template + postTypeObject.template ) ) : undefined, @@ -59,40 +64,41 @@ export default function AddNewPageModal( { onSave, onClose } ) { createSuccessNotice( sprintf( - // translators: %s: Title of the created template e.g: "Category". + // translators: %s: Title of the created post e.g: "Hello world". __( '"%s" successfully created.' ), decodeEntities( newPage.title?.rendered || title ) ), - { - type: 'snackbar', - } + { type: 'snackbar' } ); } catch ( error ) { const errorMessage = error.message && error.code !== 'unknown_error' ? error.message - : __( 'An error occurred while creating the page.' ); + : __( 'An error occurred while creating the item.' ); createErrorNotice( errorMessage, { type: 'snackbar', } ); } finally { - setIsCreatingPage( false ); + setIsCreatingPost( false ); } } return ( -
+ { __( 'Create draft' ) } diff --git a/packages/edit-site/src/components/block-editor/use-site-editor-settings.js b/packages/edit-site/src/components/block-editor/use-site-editor-settings.js index 8e02f06d37edf..b89ed6075a4bd 100644 --- a/packages/edit-site/src/components/block-editor/use-site-editor-settings.js +++ b/packages/edit-site/src/components/block-editor/use-site-editor-settings.js @@ -114,35 +114,40 @@ function useNavigateToPreviousEntityRecord() { export function useSpecificEditorSettings() { const onNavigateToEntityRecord = useNavigateToEntityRecord(); - const { templateSlug, canvasMode, settings, postWithTemplate } = useSelect( - ( select ) => { - const { - getEditedPostType, - getEditedPostId, - getEditedPostContext, - getCanvasMode, - getSettings, - } = unlock( select( editSiteStore ) ); - const { getEditedEntityRecord } = select( coreStore ); - const usedPostType = getEditedPostType(); - const usedPostId = getEditedPostId(); - const _record = getEditedEntityRecord( - 'postType', - usedPostType, - usedPostId - ); - const _context = getEditedPostContext(); - return { - templateSlug: _record.slug, - canvasMode: getCanvasMode(), - settings: getSettings(), - postWithTemplate: _context?.postId, - }; - }, - [] - ); + const { + templateSlug, + canvasMode, + settings, + shouldUseTemplateAsDefaultRenderingMode, + } = useSelect( ( select ) => { + const { + getEditedPostType, + getEditedPostId, + getEditedPostContext, + getCanvasMode, + getSettings, + } = unlock( select( editSiteStore ) ); + const { getEditedEntityRecord } = select( coreStore ); + const usedPostType = getEditedPostType(); + const usedPostId = getEditedPostId(); + const _record = getEditedEntityRecord( + 'postType', + usedPostType, + usedPostId + ); + const _context = getEditedPostContext(); + return { + templateSlug: _record.slug, + canvasMode: getCanvasMode(), + settings: getSettings(), + // TODO: The `postType` check should be removed when the default rendering mode per post type is merged. + // @see https://github.com/WordPress/gutenberg/pull/62304/ + shouldUseTemplateAsDefaultRenderingMode: + _context?.postId && _context?.postType !== 'post', + }; + }, [] ); const archiveLabels = useArchiveLabel( templateSlug ); - const defaultRenderingMode = postWithTemplate + const defaultRenderingMode = shouldUseTemplateAsDefaultRenderingMode ? 'template-locked' : 'post-only'; const onNavigateToPreviousEntityRecord = diff --git a/packages/edit-site/src/components/editor/index.js b/packages/edit-site/src/components/editor/index.js index 85a9a428fe2f2..8615b3355b835 100644 --- a/packages/edit-site/src/components/editor/index.js +++ b/packages/edit-site/src/components/editor/index.js @@ -44,12 +44,15 @@ import SiteEditorMoreMenu from '../more-menu'; import SiteIcon from '../site-icon'; import useEditorIframeProps from '../block-editor/use-editor-iframe-props'; import useEditorTitle from './use-editor-title'; +import { useIsSiteEditorLoading } from '../layout/hooks'; const { Editor, BackButton } = unlock( editorPrivateApis ); -const { useHistory } = unlock( routerPrivateApis ); +const { useHistory, useLocation } = unlock( routerPrivateApis ); const { BlockKeyboardShortcuts } = unlock( blockLibraryPrivateApis ); -export default function EditSiteEditor( { isLoading } ) { +export default function EditSiteEditor( { isPostsList = false } ) { + const { params } = useLocation(); + const isLoading = useIsSiteEditorLoading(); const { editedPostType, editedPostId, @@ -215,9 +218,20 @@ export default function EditSiteEditor( { isLoading } ) { diff --git a/packages/edit-site/src/components/layout/router.js b/packages/edit-site/src/components/layout/router.js index 25ab81d9a173c..36ca52088f6a8 100644 --- a/packages/edit-site/src/components/layout/router.js +++ b/packages/edit-site/src/components/layout/router.js @@ -8,9 +8,8 @@ import { useEffect } from '@wordpress/element'; * Internal dependencies */ import { unlock } from '../../lock-unlock'; -import { useIsSiteEditorLoading } from './hooks'; import Editor from '../editor'; -import PagePages from '../page-pages'; +import PostsList from '../posts-app/posts-list'; import PagePatterns from '../page-patterns'; import PageTemplates from '../page-templates'; import SidebarNavigationScreen from '../sidebar-navigation-screen'; @@ -74,7 +73,6 @@ function useRedirectOldPaths() { } export default function useLayoutAreas() { - const isSiteEditorLoading = useIsSiteEditorLoading(); const { params } = useLocation(); const { postType, postId, path, layout, isCustom, canvas } = params; useRedirectOldPaths(); @@ -92,15 +90,13 @@ export default function useLayoutAreas() { content={ } /> ), - content: , - preview: ( isListLayout || canvas === 'edit' ) && ( - - ), + content: , + preview: ( isListLayout || canvas === 'edit' ) && , mobile: canvas === 'edit' ? ( - + ) : ( - + ), }, widths: { @@ -119,9 +115,7 @@ export default function useLayoutAreas() { ), content: , - preview: ( isListLayout || canvas === 'edit' ) && ( - - ), + preview: ( isListLayout || canvas === 'edit' ) && , mobile: , }, widths: { @@ -140,9 +134,7 @@ export default function useLayoutAreas() { sidebar: , content: , mobile: , - preview: canvas === 'edit' && ( - - ), + preview: canvas === 'edit' && , }, }; } @@ -155,10 +147,8 @@ export default function useLayoutAreas() { sidebar: ( ), - preview: , - mobile: canvas === 'edit' && ( - - ), + preview: , + mobile: canvas === 'edit' && , }, }; } @@ -174,10 +164,8 @@ export default function useLayoutAreas() { backPath={ { postType: NAVIGATION_POST_TYPE } } /> ), - preview: , - mobile: canvas === 'edit' && ( - - ), + preview: , + mobile: canvas === 'edit' && , }, }; } @@ -187,10 +175,8 @@ export default function useLayoutAreas() { sidebar: ( ), - preview: , - mobile: canvas === 'edit' && ( - - ), + preview: , + mobile: canvas === 'edit' && , }, }; } @@ -200,10 +186,8 @@ export default function useLayoutAreas() { key: 'default', areas: { sidebar: , - preview: , - mobile: canvas === 'edit' && ( - - ), + preview: , + mobile: canvas === 'edit' && , }, }; } diff --git a/packages/edit-site/src/components/posts-app/index.js b/packages/edit-site/src/components/posts-app/index.js index 3d803f0241d78..12bdf33711031 100644 --- a/packages/edit-site/src/components/posts-app/index.js +++ b/packages/edit-site/src/components/posts-app/index.js @@ -10,29 +10,27 @@ import { privateApis as routerPrivateApis } from '@wordpress/router'; /** * Internal dependencies */ +import useInitEditedEntityFromURL from '../sync-state-with-url/use-init-edited-entity-from-url'; import Layout from '../layout'; -import Page from '../page'; +import useLayoutAreas from './router'; import { unlock } from '../../lock-unlock'; const { RouterProvider } = unlock( routerPrivateApis ); const { GlobalStylesProvider } = unlock( editorPrivateApis ); -const defaultRoute = { - key: 'index', - areas: { - sidebar: 'Empty Sidebar', - content: Welcome to Posts, - preview: undefined, - mobile: Welcome to Posts, - }, -}; +function PostsLayout() { + // This ensures the edited entity id and type are initialized properly. + useInitEditedEntityFromURL(); + const route = useLayoutAreas(); + return ; +} export default function PostsApp() { return ( - + ); diff --git a/packages/edit-site/src/components/page-pages/index.js b/packages/edit-site/src/components/posts-app/posts-list.js similarity index 89% rename from packages/edit-site/src/components/page-pages/index.js rename to packages/edit-site/src/components/posts-app/posts-list.js index 01c056cdca33d..cf9b6f43ef9cf 100644 --- a/packages/edit-site/src/components/page-pages/index.js +++ b/packages/edit-site/src/components/posts-app/posts-list.js @@ -24,7 +24,7 @@ import { privateApis as editorPrivateApis } from '@wordpress/editor'; import Page from '../page'; import { default as Link, useLink } from '../routes/link'; import { - DEFAULT_VIEWS, + useDefaultViews, DEFAULT_CONFIG_PER_VIEW_TYPE, } from '../sidebar-dataviews/default-views'; import { @@ -35,7 +35,7 @@ import { OPERATOR_IS_NONE, } from '../../utils/constants'; -import AddNewPageModal from '../add-new-page'; +import AddNewPostModal from '../add-new-post'; import Media from '../media'; import { unlock } from '../../lock-unlock'; import { useEditPostAction } from '../dataviews-actions'; @@ -56,6 +56,7 @@ function useView( postType ) { params: { activeView = 'all', isCustom = 'false', layout }, } = useLocation(); const history = useHistory(); + const DEFAULT_VIEWS = useDefaultViews( { postType } ); const selectedDefaultView = useMemo( () => { const defaultView = isCustom === 'false' && @@ -72,7 +73,7 @@ function useView( postType ) { }; } return defaultView; - }, [ isCustom, activeView, layout, postType ] ); + }, [ isCustom, activeView, layout, postType, DEFAULT_VIEWS ] ); const [ view, setView ] = useState( selectedDefaultView ); useEffect( () => { @@ -176,7 +177,7 @@ function FeaturedImage( { item, viewType } ) { : [ 'thumbnail', 'medium', 'large', 'full' ]; const media = hasMedia ? ( @@ -184,11 +185,11 @@ function FeaturedImage( { item, viewType } ) { const renderButton = viewType !== LAYOUT_LIST && ! isDisabled; return (
{ renderButton ? ( - { showAddPageModal && ( - @@ -549,8 +555,8 @@ export default function PagePages() { paginationInfo={ paginationInfo } fields={ fields } actions={ actions } - data={ pages || EMPTY_ARRAY } - isLoading={ isLoadingPages || isLoadingAuthors } + data={ records || EMPTY_ARRAY } + isLoading={ isLoadingMainEntities || isLoadingAuthors } view={ view } onChangeView={ onChangeView } selection={ selection } diff --git a/packages/edit-site/src/components/posts-app/router.js b/packages/edit-site/src/components/posts-app/router.js new file mode 100644 index 0000000000000..a7ed6a639f8a4 --- /dev/null +++ b/packages/edit-site/src/components/posts-app/router.js @@ -0,0 +1,69 @@ +/** + * WordPress dependencies + */ +import { privateApis as routerPrivateApis } from '@wordpress/router'; +import { useSelect } from '@wordpress/data'; +import { store as coreStore } from '@wordpress/core-data'; + +/** + * Internal dependencies + */ +import { unlock } from '../../lock-unlock'; +import Editor from '../editor'; +import SidebarNavigationScreen from '../sidebar-navigation-screen'; +import SidebarNavigationScreenMain from '../sidebar-navigation-screen-main'; +import DataViewsSidebarContent from '../sidebar-dataviews'; +import PostsList from '../posts-app/posts-list'; + +const { useLocation } = unlock( routerPrivateApis ); + +export default function useLayoutAreas() { + const { params = {} } = useLocation(); + const { postType, layout, canvas } = params; + const labels = useSelect( + ( select ) => { + return select( coreStore ).getPostType( postType )?.labels; + }, + [ postType ] + ); + + // Posts list. + if ( [ 'post' ].includes( postType ) ) { + const isListLayout = layout === 'list' || ! layout; + return { + key: 'posts-list', + areas: { + sidebar: ( + } + /> + ), + content: , + preview: ( isListLayout || canvas === 'edit' ) && ( + + ), + mobile: + canvas === 'edit' ? ( + + ) : ( + + ), + }, + widths: { + content: isListLayout ? 380 : undefined, + }, + }; + } + + // Fallback shows the home page preview + return { + key: 'default', + areas: { + sidebar: , + preview: , + mobile: canvas === 'edit' && , + }, + }; +} diff --git a/packages/edit-site/src/components/page-pages/style.scss b/packages/edit-site/src/components/posts-app/style.scss similarity index 67% rename from packages/edit-site/src/components/page-pages/style.scss rename to packages/edit-site/src/components/posts-app/style.scss index 41dcac76e27b5..448edda983585 100644 --- a/packages/edit-site/src/components/page-pages/style.scss +++ b/packages/edit-site/src/components/posts-app/style.scss @@ -1,16 +1,16 @@ -.edit-site-page-pages__featured-image { +.posts-list-page__featured-image { height: 100%; object-fit: cover; width: 100%; } -.edit-site-page-pages__featured-image-wrapper { +.posts-list-page__featured-image-wrapper { height: 100%; width: 100%; border-radius: $grid-unit-05; - &.is-layout-table:not(:has(.page-pages-preview-field__button)), - &.is-layout-table .page-pages-preview-field__button { + &.is-layout-table:not(:has(.posts-list-page-preview-field__button)), + &.is-layout-table .posts-list-page-preview-field__button { width: $grid-unit-40; height: $grid-unit-40; display: block; @@ -33,7 +33,7 @@ } } -.page-pages-preview-field__button { +.posts-list-page-preview-field__button { box-shadow: none; border: none; padding: 0; @@ -52,12 +52,19 @@ } } -.edit-site-page-pages-title span { +.dataviews-view-grid__card.is-selected { + .posts-list-page-preview-field__button::after { + box-shadow: inset 0 0 0 var(--wp-admin-border-width-focus) var(--wp-admin-theme-color); + background: rgba(var(--wp-admin-theme-color--rgb), 0.04); + } +} + +.posts-list-page-title span { text-overflow: ellipsis; overflow: hidden; } -.edit-site-page-pages__title-badge { +.posts-list-page-title-badge { background: $gray-100; color: $gray-700; padding: 0 $grid-unit-05; diff --git a/packages/edit-site/src/components/sidebar-dataviews/add-new-view.js b/packages/edit-site/src/components/sidebar-dataviews/add-new-view.js index ffddddb9cad29..ceb2a11f2c523 100644 --- a/packages/edit-site/src/components/sidebar-dataviews/add-new-view.js +++ b/packages/edit-site/src/components/sidebar-dataviews/add-new-view.js @@ -19,7 +19,7 @@ import { privateApis as routerPrivateApis } from '@wordpress/router'; * Internal dependencies */ import SidebarNavigationItem from '../sidebar-navigation-item'; -import { DEFAULT_VIEWS } from './default-views'; +import { useDefaultViews } from './default-views'; import { unlock } from '../../lock-unlock'; const { useHistory } = unlock( routerPrivateApis ); @@ -29,6 +29,7 @@ function AddNewItemModalContent( { type, setIsAdding } ) { const { saveEntityRecord } = useDispatch( coreStore ); const [ title, setTitle ] = useState( '' ); const [ isSaving, setIsSaving ] = useState( false ); + const DEFAULT_VIEWS = useDefaultViews( { postType: type } ); return ( { diff --git a/packages/edit-site/src/components/sidebar-dataviews/default-views.js b/packages/edit-site/src/components/sidebar-dataviews/default-views.js index e7c2471fe44bc..6c98ec7346488 100644 --- a/packages/edit-site/src/components/sidebar-dataviews/default-views.js +++ b/packages/edit-site/src/components/sidebar-dataviews/default-views.js @@ -2,6 +2,7 @@ * WordPress dependencies */ import { __ } from '@wordpress/i18n'; + import { trash, pages, @@ -11,6 +12,9 @@ import { pending, notAllowed, } from '@wordpress/icons'; +import { useSelect } from '@wordpress/data'; +import { store as coreStore } from '@wordpress/core-data'; +import { useMemo } from '@wordpress/element'; /** * Internal dependencies @@ -36,7 +40,7 @@ export const DEFAULT_CONFIG_PER_VIEW_TYPE = { }, }; -const DEFAULT_PAGE_BASE = { +const DEFAULT_POST_BASE = { type: LAYOUT_LIST, search: '', filters: [], @@ -54,103 +58,114 @@ const DEFAULT_PAGE_BASE = { }, }; -export const DEFAULT_VIEWS = { - page: [ - { - title: __( 'All pages' ), - slug: 'all', - icon: pages, - view: DEFAULT_PAGE_BASE, +export function useDefaultViews( { postType } ) { + const labels = useSelect( + ( select ) => { + const { getPostType } = select( coreStore ); + return getPostType( postType )?.labels; }, - { - title: __( 'Published' ), - slug: 'published', - icon: published, - view: { - ...DEFAULT_PAGE_BASE, - filters: [ - { - field: 'status', - operator: OPERATOR_IS_ANY, - value: 'publish', + [ postType ] + ); + return useMemo( () => { + return { + [ postType ]: [ + { + title: labels?.all_items || __( 'All items' ), + slug: 'all', + icon: pages, + view: DEFAULT_POST_BASE, + }, + { + title: __( 'Published' ), + slug: 'published', + icon: published, + view: { + ...DEFAULT_POST_BASE, + filters: [ + { + field: 'status', + operator: OPERATOR_IS_ANY, + value: 'publish', + }, + ], }, - ], - }, - }, - { - title: __( 'Scheduled' ), - slug: 'future', - icon: scheduled, - view: { - ...DEFAULT_PAGE_BASE, - filters: [ - { - field: 'status', - operator: OPERATOR_IS_ANY, - value: 'future', + }, + { + title: __( 'Scheduled' ), + slug: 'future', + icon: scheduled, + view: { + ...DEFAULT_POST_BASE, + filters: [ + { + field: 'status', + operator: OPERATOR_IS_ANY, + value: 'future', + }, + ], }, - ], - }, - }, - { - title: __( 'Drafts' ), - slug: 'drafts', - icon: drafts, - view: { - ...DEFAULT_PAGE_BASE, - filters: [ - { - field: 'status', - operator: OPERATOR_IS_ANY, - value: 'draft', + }, + { + title: __( 'Drafts' ), + slug: 'drafts', + icon: drafts, + view: { + ...DEFAULT_POST_BASE, + filters: [ + { + field: 'status', + operator: OPERATOR_IS_ANY, + value: 'draft', + }, + ], }, - ], - }, - }, - { - title: __( 'Pending' ), - slug: 'pending', - icon: pending, - view: { - ...DEFAULT_PAGE_BASE, - filters: [ - { - field: 'status', - operator: OPERATOR_IS_ANY, - value: 'pending', + }, + { + title: __( 'Pending' ), + slug: 'pending', + icon: pending, + view: { + ...DEFAULT_POST_BASE, + filters: [ + { + field: 'status', + operator: OPERATOR_IS_ANY, + value: 'pending', + }, + ], }, - ], - }, - }, - { - title: __( 'Private' ), - slug: 'private', - icon: notAllowed, - view: { - ...DEFAULT_PAGE_BASE, - filters: [ - { - field: 'status', - operator: OPERATOR_IS_ANY, - value: 'private', + }, + { + title: __( 'Private' ), + slug: 'private', + icon: notAllowed, + view: { + ...DEFAULT_POST_BASE, + filters: [ + { + field: 'status', + operator: OPERATOR_IS_ANY, + value: 'private', + }, + ], }, - ], - }, - }, - { - title: __( 'Trash' ), - slug: 'trash', - icon: trash, - view: { - ...DEFAULT_PAGE_BASE, - filters: [ - { - field: 'status', - operator: OPERATOR_IS_ANY, - value: 'trash', + }, + { + title: __( 'Trash' ), + slug: 'trash', + icon: trash, + view: { + ...DEFAULT_POST_BASE, + filters: [ + { + field: 'status', + operator: OPERATOR_IS_ANY, + value: 'trash', + }, + ], }, - ], - }, - }, - ], -}; + }, + ], + }; + }, [ labels, postType ] ); +} diff --git a/packages/edit-site/src/components/sidebar-dataviews/index.js b/packages/edit-site/src/components/sidebar-dataviews/index.js index 9362308172f89..37f16b2e1f68b 100644 --- a/packages/edit-site/src/components/sidebar-dataviews/index.js +++ b/packages/edit-site/src/components/sidebar-dataviews/index.js @@ -2,13 +2,12 @@ * WordPress dependencies */ import { __experimentalItemGroup as ItemGroup } from '@wordpress/components'; - import { privateApis as routerPrivateApis } from '@wordpress/router'; + /** * Internal dependencies */ - -import { DEFAULT_VIEWS } from './default-views'; +import { useDefaultViews } from './default-views'; import { unlock } from '../../lock-unlock'; const { useLocation } = unlock( routerPrivateApis ); import DataViewItem from './dataview-item'; @@ -18,6 +17,7 @@ export default function DataViewsSidebarContent() { const { params: { postType, activeView = 'all', isCustom = 'false' }, } = useLocation(); + const DEFAULT_VIEWS = useDefaultViews( { postType } ); if ( ! postType ) { return null; } diff --git a/packages/edit-site/src/components/sync-state-with-url/use-init-edited-entity-from-url.js b/packages/edit-site/src/components/sync-state-with-url/use-init-edited-entity-from-url.js index 0b3eb14752787..5c8cdfd58f630 100644 --- a/packages/edit-site/src/components/sync-state-with-url/use-init-edited-entity-from-url.js +++ b/packages/edit-site/src/components/sync-state-with-url/use-init-edited-entity-from-url.js @@ -27,7 +27,7 @@ const postTypesWithoutParentTemplate = [ PATTERN_TYPES.user, ]; -const authorizedPostTypes = [ 'page' ]; +const authorizedPostTypes = [ 'page', 'post' ]; function useResolveEditedEntityAndContext( { postId, postType } ) { const { @@ -213,7 +213,8 @@ function useResolveEditedEntityAndContext( { postId, postType } ) { if ( postType && postId && authorizedPostTypes.includes( postType ) ) { return { postType, postId }; } - + // TODO: for post types lists we should probably not render the front page, but maybe a placeholder + // with a message like "Select a page" or something similar. if ( homepageId ) { return { postType: 'page', postId: homepageId }; } diff --git a/packages/edit-site/src/posts.js b/packages/edit-site/src/posts.js index 19e787fff4630..9e2582ac23328 100644 --- a/packages/edit-site/src/posts.js +++ b/packages/edit-site/src/posts.js @@ -1,7 +1,25 @@ /** * WordPress dependencies */ +import { store as blocksStore } from '@wordpress/blocks'; +import { + registerCoreBlocks, + __experimentalGetCoreBlocks, + __experimentalRegisterExperimentalCoreBlocks, +} from '@wordpress/block-library'; +import { dispatch } from '@wordpress/data'; import { createRoot, StrictMode } from '@wordpress/element'; +import { store as preferencesStore } from '@wordpress/preferences'; +import { + registerLegacyWidgetBlock, + registerWidgetGroupBlock, +} from '@wordpress/widgets'; + +/** + * Internal dependencies + */ +import './hooks'; +import { store as editSiteStore } from './store'; /** * Internal dependencies @@ -10,15 +28,58 @@ import PostsApp from './components/posts-app'; /** * Initializes the "Posts Dashboard" - * @param {string} id DOM element id. + * @param {string} id ID of the root element to render the screen in. + * @param {Object} settings Editor settings. */ -export function initializePostsDashboard( id ) { +export function initializePostsDashboard( id, settings ) { if ( ! globalThis.IS_GUTENBERG_PLUGIN ) { return; } const target = document.getElementById( id ); const root = createRoot( target ); + dispatch( blocksStore ).reapplyBlockTypeFilters(); + const coreBlocks = __experimentalGetCoreBlocks().filter( + ( { name } ) => name !== 'core/freeform' + ); + registerCoreBlocks( coreBlocks ); + dispatch( blocksStore ).setFreeformFallbackBlockName( 'core/html' ); + registerLegacyWidgetBlock( { inserter: false } ); + registerWidgetGroupBlock( { inserter: false } ); + if ( globalThis.IS_GUTENBERG_PLUGIN ) { + __experimentalRegisterExperimentalCoreBlocks( { + enableFSEBlocks: true, + } ); + } + + // We dispatch actions and update the store synchronously before rendering + // so that we won't trigger unnecessary re-renders with useEffect. + dispatch( preferencesStore ).setDefaults( 'core/edit-site', { + welcomeGuide: true, + welcomeGuideStyles: true, + welcomeGuidePage: true, + welcomeGuideTemplate: true, + } ); + + dispatch( preferencesStore ).setDefaults( 'core', { + allowRightClickOverrides: true, + distractionFree: false, + editorMode: 'visual', + fixedToolbar: false, + focusMode: false, + inactivePanels: [], + keepCaretInsideBlock: false, + openPanels: [ 'post-status' ], + showBlockBreadcrumbs: true, + showListViewByDefault: false, + } ); + + dispatch( editSiteStore ).updateSettings( settings ); + + // Prevent the default browser action for files dropped outside of dropzones. + window.addEventListener( 'dragover', ( e ) => e.preventDefault(), false ); + window.addEventListener( 'drop', ( e ) => e.preventDefault(), false ); + root.render( diff --git a/packages/edit-site/src/posts.scss b/packages/edit-site/src/posts.scss index 4150634913cb7..e27948159399c 100644 --- a/packages/edit-site/src/posts.scss +++ b/packages/edit-site/src/posts.scss @@ -7,6 +7,7 @@ @import "./components/site-hub/style.scss"; @import "./components/site-icon/style.scss"; @import "./components/editor-canvas-container/style.scss"; +@import "./components/posts-app/style.scss"; @import "./components/resizable-frame/style.scss"; @include wordpress-admin-schemes(); @@ -43,4 +44,12 @@ body { min-height: 0; position: static; } + + .components-editor-notices__snackbar { + position: fixed; + right: 0; + bottom: 16px; + padding-left: 16px; + padding-right: 16px; + } } diff --git a/packages/edit-site/src/style.scss b/packages/edit-site/src/style.scss index 36029fc1c51c4..23802cebc3a71 100644 --- a/packages/edit-site/src/style.scss +++ b/packages/edit-site/src/style.scss @@ -7,7 +7,6 @@ @import "./components/global-styles/screen-revisions/style.scss"; @import "./components/global-styles-sidebar/style.scss"; @import "./components/page/style.scss"; -@import "./components/page-pages/style.scss"; @import "./components/page-patterns/style.scss"; @import "./components/page-templates/style.scss"; @import "./components/table/style.scss"; @@ -30,6 +29,7 @@ @import "./components/site-icon/style.scss"; @import "./components/style-book/style.scss"; @import "./components/editor-canvas-container/style.scss"; +@import "./components/posts-app/style.scss"; @import "./components/resizable-frame/style.scss"; @import "./hooks/push-changes-to-global-styles/style.scss"; @import "./components/global-styles/font-library-modal/style.scss"; diff --git a/test/e2e/specs/site-editor/block-style-variations.spec.js b/test/e2e/specs/site-editor/block-style-variations.spec.js index 6d139dd755b29..122b42a571b07 100644 --- a/test/e2e/specs/site-editor/block-style-variations.spec.js +++ b/test/e2e/specs/site-editor/block-style-variations.spec.js @@ -304,8 +304,8 @@ async function draftNewPage( page ) { await page.getByRole( 'button', { name: 'Pages' } ).click(); await page.getByRole( 'button', { name: 'Add new page' } ).click(); await page - .locator( 'role=dialog[name="Draft a new page"i]' ) - .locator( 'role=textbox[name="Page title"i]' ) + .locator( 'role=dialog[name="Draft new: page"i]' ) + .locator( 'role=textbox[name="title"i]' ) .fill( TEST_PAGE_TITLE ); await page.keyboard.press( 'Enter' ); await expect( diff --git a/test/e2e/specs/site-editor/pages.spec.js b/test/e2e/specs/site-editor/pages.spec.js index a1891e7b9a7dd..7a76db40337c2 100644 --- a/test/e2e/specs/site-editor/pages.spec.js +++ b/test/e2e/specs/site-editor/pages.spec.js @@ -7,8 +7,8 @@ async function draftNewPage( page ) { await page.getByRole( 'button', { name: 'Pages' } ).click(); await page.getByRole( 'button', { name: 'Add new page' } ).click(); await page - .locator( 'role=dialog[name="Draft a new page"i]' ) - .locator( 'role=textbox[name="Page title"i]' ) + .locator( 'role=dialog[name="Draft new: page"i]' ) + .locator( 'role=textbox[name="title"i]' ) .fill( 'Test Page' ); await page.keyboard.press( 'Enter' ); await expect(