diff --git a/packages/edit-post/src/components/sidebar/post-status/index.js b/packages/edit-post/src/components/sidebar/post-status/index.js index dab8ec2688b3a..99c202463162d 100644 --- a/packages/edit-post/src/components/sidebar/post-status/index.js +++ b/packages/edit-post/src/components/sidebar/post-status/index.js @@ -4,6 +4,7 @@ import { __ } from '@wordpress/i18n'; import { __experimentalHStack as HStack, + __experimentalVStack as VStack, PanelBody, } from '@wordpress/components'; import { useDispatch, useSelect } from '@wordpress/data'; @@ -28,8 +29,12 @@ import PostSlug from '../post-slug'; import PostFormat from '../post-format'; import { unlock } from '../../../lock-unlock'; -const { PostStatus: PostStatusPanel, PrivatePostExcerptPanel } = - unlock( editorPrivateApis ); +const { + PostStatus: PostStatusPanel, + PrivatePostExcerptPanel, + PostContentInformation, + PostLastEditedPanel, +} = unlock( editorPrivateApis ); /** * Module Constants @@ -37,7 +42,7 @@ const { PostStatus: PostStatusPanel, PrivatePostExcerptPanel } = const PANEL_NAME = 'post-status'; export default function PostStatus() { - const { isOpened, isRemoved, showPostExcerptPanel } = useSelect( + const { isOpened, isRemoved, showPostContentPanels } = useSelect( ( select ) => { // We use isEditorPanelRemoved to hide the panel if it was programatically removed. We do // not use isEditorPanelEnabled since this panel should not be disabled through the UI. @@ -52,7 +57,7 @@ export default function PostStatus() { isOpened: isEditorPanelOpened( PANEL_NAME ), // Post excerpt panel is rendered in different place depending on the post type. // So we cannot make this check inside the PostExcerpt component based on the current edited entity. - showPostExcerptPanel: ! [ + showPostContentPanels: ! [ 'wp_template', 'wp_template_part', 'wp_block', @@ -77,13 +82,32 @@ export default function PostStatus() { { ( fills ) => ( <> - - - { showPostExcerptPanel && } - - - - + { showPostContentPanels && ( + + + + + + + + + ) } + + + + + + + diff --git a/packages/edit-site/src/components/sidebar-edit-mode/page-panels/page-summary.js b/packages/edit-site/src/components/sidebar-edit-mode/page-panels/page-summary.js index b0bee04d0f75c..0830ff8364c8a 100644 --- a/packages/edit-site/src/components/sidebar-edit-mode/page-panels/page-summary.js +++ b/packages/edit-site/src/components/sidebar-edit-mode/page-panels/page-summary.js @@ -17,7 +17,12 @@ import { */ import { unlock } from '../../../lock-unlock'; -const { PrivatePostExcerptPanel, PostStatus } = unlock( editorPrivateApis ); +const { + PrivatePostExcerptPanel, + PostStatus, + PostContentInformation, + PostLastEditedPanel, +} = unlock( editorPrivateApis ); export default function PageSummary() { return ( @@ -25,12 +30,27 @@ export default function PageSummary() { { ( fills ) => ( <> - - - - - - + + + + + + + + + + + + + + { fills } diff --git a/packages/editor/src/components/post-card-panel/index.js b/packages/editor/src/components/post-card-panel/index.js index 0da08ed07e977..811c53ec05cb8 100644 --- a/packages/editor/src/components/post-card-panel/index.js +++ b/packages/editor/src/components/post-card-panel/index.js @@ -15,11 +15,8 @@ import { } from '@wordpress/components'; import { store as coreStore } from '@wordpress/core-data'; import { useSelect } from '@wordpress/data'; -import { __, _x, _n, sprintf } from '@wordpress/i18n'; -import { humanTimeDiff } from '@wordpress/date'; +import { __ } from '@wordpress/i18n'; import { decodeEntities } from '@wordpress/html-entities'; -import { count as wordCount } from '@wordpress/wordcount'; -import { useMemo } from '@wordpress/element'; /** * Internal dependencies @@ -31,64 +28,52 @@ import { PATTERN_POST_TYPE, } from '../../store/constants'; import { PrivatePostExcerptPanel } from '../post-excerpt/panel'; +import PostLastEditedPanel from '../post-last-edited-panel'; import { unlock } from '../../lock-unlock'; import TemplateAreas from '../template-areas'; export default function PostCardPanel( { className, actions } ) { - const { - modified, - title, - showPostExcerptPanel, - icon, - postType, - isPostsPage, - } = useSelect( ( select ) => { - const { - getEditedPostAttribute, - getCurrentPostType, - getCurrentPostId, - __experimentalGetTemplateInfo, - } = select( editorStore ); - const { getEditedEntityRecord, getEntityRecord } = select( coreStore ); - const siteSettings = getEntityRecord( 'root', 'site' ); - const _type = getCurrentPostType(); - const _id = getCurrentPostId(); - const _record = getEditedEntityRecord( 'postType', _type, _id ); - const _templateInfo = - [ TEMPLATE_POST_TYPE, TEMPLATE_PART_POST_TYPE ].includes( _type ) && - __experimentalGetTemplateInfo( _record ); - return { - title: _templateInfo?.title || getEditedPostAttribute( 'title' ), - modified: getEditedPostAttribute( 'modified' ), - id: _id, - postType: _type, - icon: unlock( select( editorStore ) ).getPostIcon( _type, { - area: _record?.area, - } ), - isPostsPage: +_id === siteSettings?.page_for_posts, - // Post excerpt panel is rendered in different place depending on the post type. - // So we cannot make this check inside the PostExcerpt component based on the current edited entity. - showPostExcerptPanel: [ - TEMPLATE_POST_TYPE, - TEMPLATE_PART_POST_TYPE, - PATTERN_POST_TYPE, - ].includes( _type ), - }; - }, [] ); - const lastEditedText = - modified && - sprintf( - // translators: %s: Human-readable time difference, e.g. "2 days ago". - __( 'Last edited %s.' ), - humanTimeDiff( modified ) - ); - const showPostContentInfo = - ! isPostsPage && - ! [ TEMPLATE_POST_TYPE, TEMPLATE_PART_POST_TYPE ].includes( postType ); + const { title, showPostContentPanels, icon, postType } = useSelect( + ( select ) => { + const { + getEditedPostAttribute, + getCurrentPostType, + getCurrentPostId, + __experimentalGetTemplateInfo, + } = select( editorStore ); + const { getEditedEntityRecord } = select( coreStore ); + const _type = getCurrentPostType(); + const _id = getCurrentPostId(); + const _record = getEditedEntityRecord( 'postType', _type, _id ); + const _templateInfo = + [ TEMPLATE_POST_TYPE, TEMPLATE_PART_POST_TYPE ].includes( + _type + ) && __experimentalGetTemplateInfo( _record ); + return { + title: + _templateInfo?.title || getEditedPostAttribute( 'title' ), + id: _id, + postType: _type, + icon: unlock( select( editorStore ) ).getPostIcon( _type, { + area: _record?.area, + } ), + // Post excerpt panel and Last Edited info are rendered in different place depending on the post type. + // So we cannot make this check inside the PostExcerpt or PostLastEditedPanel component based on the current edited entity. + showPostContentPanels: [ + TEMPLATE_POST_TYPE, + TEMPLATE_PART_POST_TYPE, + PATTERN_POST_TYPE, + ].includes( _type ), + }; + }, + [] + ); return (
- - { showPostExcerptPanel && } - { showPostContentInfo && } - { lastEditedText && { lastEditedText } } - + { showPostContentPanels && ( + + + + + ) } { postType === TEMPLATE_POST_TYPE && }
); } - -// Taken from packages/editor/src/components/time-to-read/index.js. -const AVERAGE_READING_RATE = 189; - -// This component renders the wordcount and reading time for the post. -function PostContentInfo() { - const postContent = useSelect( - ( select ) => select( editorStore ).getEditedPostAttribute( 'content' ), - [] - ); - /* - * translators: If your word count is based on single characters (e.g. East Asian characters), - * enter 'characters_excluding_spaces' or 'characters_including_spaces'. Otherwise, enter 'words'. - * Do not translate into your own language. - */ - const wordCountType = _x( 'words', 'Word count type. Do not translate!' ); - const wordsCounted = useMemo( - () => ( postContent ? wordCount( postContent, wordCountType ) : 0 ), - [ postContent, wordCountType ] - ); - if ( ! wordsCounted ) { - return null; - } - const readingTime = Math.round( wordsCounted / AVERAGE_READING_RATE ); - const wordsCountText = sprintf( - // translators: %s: the number of words in the post. - _n( '%s word', '%s words', wordsCounted ), - wordsCounted.toLocaleString() - ); - const minutesText = - readingTime <= 1 - ? __( '1 minute' ) - : sprintf( - // translators: %s: the number of minutes to read the post. - _n( '%s minute', '%s minutes', readingTime ), - readingTime.toLocaleString() - ); - return ( - - { sprintf( - /* translators: 1: How many words a post has. 2: the number of minutes to read the post (e.g. 130 words, 2 minutes read time.) */ - __( '%1$s, %2$s read time.' ), - wordsCountText, - minutesText - ) } - - ); -} diff --git a/packages/editor/src/components/post-card-panel/style.scss b/packages/editor/src/components/post-card-panel/style.scss index 78c0ab55e6c1f..a6928a6efb1e3 100644 --- a/packages/editor/src/components/post-card-panel/style.scss +++ b/packages/editor/src/components/post-card-panel/style.scss @@ -20,13 +20,9 @@ &__header { display: flex; justify-content: space-between; - margin: 0 0 $grid-unit-10; } - &__description { - color: $gray-700; - & .components-text { - color: inherit; - } + &.has-description &__header { + margin-bottom: $grid-unit-10; } } diff --git a/packages/editor/src/components/post-content-information/index.js b/packages/editor/src/components/post-content-information/index.js new file mode 100644 index 0000000000000..7597a6b4697dc --- /dev/null +++ b/packages/editor/src/components/post-content-information/index.js @@ -0,0 +1,83 @@ +/** + * WordPress dependencies + */ +import { __experimentalText as Text } from '@wordpress/components'; +import { useSelect } from '@wordpress/data'; +import { __, _x, _n, sprintf } from '@wordpress/i18n'; +import { count as wordCount } from '@wordpress/wordcount'; +import { useMemo } from '@wordpress/element'; +import { store as coreStore } from '@wordpress/core-data'; + +/** + * Internal dependencies + */ +import { store as editorStore } from '../../store'; +import { + TEMPLATE_POST_TYPE, + TEMPLATE_PART_POST_TYPE, +} from '../../store/constants'; + +// Taken from packages/editor/src/components/time-to-read/index.js. +const AVERAGE_READING_RATE = 189; + +// This component renders the wordcount and reading time for the post. +export default function PostContentInformation() { + const { postContent } = useSelect( ( select ) => { + const { getEditedPostAttribute, getCurrentPostType, getCurrentPostId } = + select( editorStore ); + const { getEntityRecord } = select( coreStore ); + const siteSettings = getEntityRecord( 'root', 'site' ); + const postType = getCurrentPostType(); + const _id = getCurrentPostId(); + const isPostsPage = +_id === siteSettings?.page_for_posts; + const showPostContentInfo = + ! isPostsPage && + ! [ TEMPLATE_POST_TYPE, TEMPLATE_PART_POST_TYPE ].includes( + postType + ); + return { + postContent: + showPostContentInfo && getEditedPostAttribute( 'content' ), + }; + }, [] ); + + /* + * translators: If your word count is based on single characters (e.g. East Asian characters), + * enter 'characters_excluding_spaces' or 'characters_including_spaces'. Otherwise, enter 'words'. + * Do not translate into your own language. + */ + const wordCountType = _x( 'words', 'Word count type. Do not translate!' ); + const wordsCounted = useMemo( + () => ( postContent ? wordCount( postContent, wordCountType ) : 0 ), + [ postContent, wordCountType ] + ); + if ( ! wordsCounted ) { + return null; + } + const readingTime = Math.round( wordsCounted / AVERAGE_READING_RATE ); + const wordsCountText = sprintf( + // translators: %s: the number of words in the post. + _n( '%s word', '%s words', wordsCounted ), + wordsCounted.toLocaleString() + ); + const minutesText = + readingTime <= 1 + ? __( '1 minute' ) + : sprintf( + // translators: %s: the number of minutes to read the post. + _n( '%s minute', '%s minutes', readingTime ), + readingTime.toLocaleString() + ); + return ( +
+ + { sprintf( + /* translators: 1: How many words a post has. 2: the number of minutes to read the post (e.g. 130 words, 2 minutes read time.) */ + __( '%1$s, %2$s read time.' ), + wordsCountText, + minutesText + ) } + +
+ ); +} diff --git a/packages/editor/src/components/post-content-information/style.scss b/packages/editor/src/components/post-content-information/style.scss new file mode 100644 index 0000000000000..1b88392cc76ec --- /dev/null +++ b/packages/editor/src/components/post-content-information/style.scss @@ -0,0 +1,6 @@ +.editor-post-content-information { + color: $gray-700; + & .components-text { + color: inherit; + } +} diff --git a/packages/editor/src/components/post-featured-image/index.js b/packages/editor/src/components/post-featured-image/index.js index b4f4bfe4ee151..5407cac15b542 100644 --- a/packages/editor/src/components/post-featured-image/index.js +++ b/packages/editor/src/components/post-featured-image/index.js @@ -32,7 +32,7 @@ const ALLOWED_MEDIA_TYPES = [ 'image' ]; // Used when labels from post type were not yet loaded or when they are not present. const DEFAULT_FEATURE_IMAGE_LABEL = __( 'Featured image' ); -const DEFAULT_SET_FEATURE_IMAGE_LABEL = __( 'Set featured image' ); +const DEFAULT_SET_FEATURE_IMAGE_LABEL = __( 'Add a featured image' ); const instructions = (

diff --git a/packages/editor/src/components/post-featured-image/style.scss b/packages/editor/src/components/post-featured-image/style.scss index c554c4905f272..052f694301259 100644 --- a/packages/editor/src/components/post-featured-image/style.scss +++ b/packages/editor/src/components/post-featured-image/style.scss @@ -31,8 +31,7 @@ box-shadow: 0 0 0 0 var(--wp-admin-theme-color); overflow: hidden; // Ensure the focus style properly encapsulates the image. outline-offset: -#{$border-width}; - min-height: $grid-unit-50 * 2; - margin-bottom: $grid-unit-20; + min-height: $grid-unit-50; display: flex; justify-content: center; @@ -52,16 +51,11 @@ .editor-post-featured-image__toggle { border-radius: $radius-block-ui; - background-color: $gray-100; height: 100%; line-height: 20px; padding: $grid-unit-10 0; text-align: center; - - &:hover { - background: $gray-300; - color: $gray-900; - } + box-shadow: inset 0 0 0 $border-width $gray-400; } .editor-post-featured-image__actions { diff --git a/packages/editor/src/components/post-last-edited-panel/index.js b/packages/editor/src/components/post-last-edited-panel/index.js new file mode 100644 index 0000000000000..a9797747876fb --- /dev/null +++ b/packages/editor/src/components/post-last-edited-panel/index.js @@ -0,0 +1,35 @@ +/** + * WordPress dependencies + */ +import { __experimentalText as Text } from '@wordpress/components'; +import { useSelect } from '@wordpress/data'; +import { __, sprintf } from '@wordpress/i18n'; +import { humanTimeDiff } from '@wordpress/date'; + +/** + * Internal dependencies + */ +import { store as editorStore } from '../../store'; + +export default function PostLastEditedPanel() { + const modified = useSelect( + ( select ) => + select( editorStore ).getEditedPostAttribute( 'modified' ), + [] + ); + const lastEditedText = + modified && + sprintf( + // translators: %s: Human-readable time difference, e.g. "2 days ago". + __( 'Last edited %s.' ), + humanTimeDiff( modified ) + ); + if ( ! lastEditedText ) { + return null; + } + return ( +

+ { lastEditedText } +
+ ); +} diff --git a/packages/editor/src/components/post-last-edited-panel/style.scss b/packages/editor/src/components/post-last-edited-panel/style.scss new file mode 100644 index 0000000000000..01392fe7c8fcd --- /dev/null +++ b/packages/editor/src/components/post-last-edited-panel/style.scss @@ -0,0 +1,6 @@ +.editor-post-last-edited-panel { + color: $gray-700; + & .components-text { + color: inherit; + } +} diff --git a/packages/editor/src/components/post-panel-row/style.scss b/packages/editor/src/components/post-panel-row/style.scss index 89f78637c89ab..22d0cbbb644d8 100644 --- a/packages/editor/src/components/post-panel-row/style.scss +++ b/packages/editor/src/components/post-panel-row/style.scss @@ -1,6 +1,6 @@ .editor-post-panel__row { width: 100%; - min-height: $button-size-next-default-40px; + min-height: $grid-unit-40; justify-content: flex-start !important; align-items: flex-start !important; } @@ -8,14 +8,14 @@ .editor-post-panel__row-label { width: 30%; flex-shrink: 0; - min-height: $button-size-next-default-40px; + min-height: $grid-unit-40; display: flex; align-items: center; } .editor-post-panel__row-control { flex-grow: 1; - min-height: $button-size-next-default-40px; + min-height: $grid-unit-40; display: flex; align-items: center; } diff --git a/packages/editor/src/components/post-schedule/panel.js b/packages/editor/src/components/post-schedule/panel.js index ca995dbc095cf..af7488561a1de 100644 --- a/packages/editor/src/components/post-schedule/panel.js +++ b/packages/editor/src/components/post-schedule/panel.js @@ -62,7 +62,7 @@ export default function PostSchedulePanel() { contentClassName="editor-post-schedule__dialog" renderToggle={ ( { onToggle, isOpen } ) => ( - ) } - renderContent={ ( { onClose } ) => ( - <> - -
- - + { canEdit ? ( + ( + + ) } + renderContent={ ( { onClose } ) => ( + <> + - { status !== 'private' && ( - - + + - { showPassword && ( -
- - updatePost( { - password: value, - } ) - } - value={ password } - placeholder={ __( - 'Use a secure password' - ) } - type="text" - id={ passwordInputId } - __next40pxDefaultSize + { status !== 'private' && ( + + -
+ { showPassword && ( +
+ + updatePost( { + password: value, + } ) + } + value={ password } + placeholder={ __( + 'Use a secure password' + ) } + type="text" + id={ passwordInputId } + __next40pxDefaultSize + __nextHasNoMarginBottom + /> +
+ ) } +
) }
- ) } -
-
- + + + ) } + /> + ) : ( +
+ +
) } - /> + ); } diff --git a/packages/editor/src/components/post-status/style.scss b/packages/editor/src/components/post-status/style.scss index 650f5551113f6..5c4e3f9758bcd 100644 --- a/packages/editor/src/components/post-status/style.scss +++ b/packages/editor/src/components/post-status/style.scss @@ -1,6 +1,5 @@ .editor-post-status { max-width: 100%; - margin-bottom: $grid-unit-20; .editor-post-status-trigger { padding: 1px; diff --git a/packages/editor/src/components/post-template/block-theme.js b/packages/editor/src/components/post-template/block-theme.js index c89c8b2000198..9abacc0de3a7f 100644 --- a/packages/editor/src/components/post-template/block-theme.js +++ b/packages/editor/src/components/post-template/block-theme.js @@ -76,7 +76,7 @@ export default function BlockThemeControl( { id } ) { popoverProps={ POPOVER_PROPS } focusOnMount toggleProps={ { - __next40pxDefaultSize: true, + size: 'compact', variant: 'tertiary', } } label={ __( 'Template options' ) } diff --git a/packages/editor/src/components/post-url/panel.js b/packages/editor/src/components/post-url/panel.js index 3e5ea6cd8ba47..c4a1cbba935c7 100644 --- a/packages/editor/src/components/post-url/panel.js +++ b/packages/editor/src/components/post-url/panel.js @@ -60,7 +60,7 @@ function PostURLToggle( { isOpen, onClick } ) { const decodedSlug = safeDecodeURIComponent( slug ); return (