Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Editor: move around wordcount, post status and last edited info in page summary #61235

Merged
merged 6 commits into from
May 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
46 changes: 35 additions & 11 deletions packages/edit-post/src/components/sidebar/post-status/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand All @@ -28,16 +29,20 @@ 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
*/
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.
Expand All @@ -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',
Expand All @@ -77,13 +82,32 @@ export default function PostStatus() {
<PluginPostStatusInfo.Slot>
{ ( fills ) => (
<>
<PostStatusPanel />
<PostFeaturedImagePanel withPanelBody={ false } />
{ showPostExcerptPanel && <PrivatePostExcerptPanel /> }
<PostSchedulePanel />
<PostTemplatePanel />
<PostURLPanel />
<PostSyncStatus />
{ showPostContentPanels && (
<VStack
spacing={ 3 }
// TODO: this needs to be consolidated with the panel in site editor, when we unify them.
style={ { marginBlockEnd: '24px' } }
>
<PostFeaturedImagePanel
withPanelBody={ false }
/>
<PrivatePostExcerptPanel />
<VStack spacing={ 1 }>
<PostContentInformation />
<PostLastEditedPanel />
</VStack>
</VStack>
) }
<VStack
spacing={ 1 }
style={ { marginBlockEnd: '12px' } }
>
<PostStatusPanel />
<PostSchedulePanel />
<PostTemplatePanel />
<PostURLPanel />
<PostSyncStatus />
</VStack>
<PostSticky />
<PostFormat />
<PostSlug />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,20 +17,40 @@ import {
*/
import { unlock } from '../../../lock-unlock';

const { PrivatePostExcerptPanel, PostStatus } = unlock( editorPrivateApis );
const {
PrivatePostExcerptPanel,
PostStatus,
PostContentInformation,
PostLastEditedPanel,
} = unlock( editorPrivateApis );

export default function PageSummary() {
return (
<VStack spacing={ 0 }>
<PluginPostStatusInfo.Slot>
{ ( fills ) => (
<>
<PostStatus />
<PostFeaturedImagePanel withPanelBody={ false } />
<PrivatePostExcerptPanel />
<PostSchedulePanel />
<PostTemplatePanel />
<PostURLPanel />
<VStack
spacing={ 3 }
// TODO: this needs to be consolidated with the panel in post editor, when we unify them.
style={ { marginBlockEnd: '24px' } }
>
<PostFeaturedImagePanel withPanelBody={ false } />
<PrivatePostExcerptPanel />
<VStack spacing={ 1 }>
<PostContentInformation />
<PostLastEditedPanel />
</VStack>
</VStack>
<VStack
spacing={ 1 }
style={ { marginBlockEnd: '12px' } }
>
<PostStatus />
<PostSchedulePanel />
<PostTemplatePanel />
<PostURLPanel />
</VStack>
<PostAuthorPanel />
{ fills }
</>
Expand Down
160 changes: 49 additions & 111 deletions packages/editor/src/components/post-card-panel/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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' ),
Comment on lines +53 to +54
Copy link
Member

Choose a reason for hiding this comment

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

Nit: We can use _record?.title here.

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 (
<PanelBody>
<div
className={ classnames( 'editor-post-card-panel', className ) }
className={ classnames( 'editor-post-card-panel', className, {
'has-description': showPostContentPanels,
} ) }
>
<HStack
spacing={ 2 }
Expand All @@ -111,65 +96,18 @@ export default function PostCardPanel( { className, actions } ) {
{ actions }
</HStack>
<VStack className="editor-post-card-panel__content">
<VStack
className="editor-post-card-panel__description"
spacing={ 2 }
>
{ showPostExcerptPanel && <PrivatePostExcerptPanel /> }
{ showPostContentInfo && <PostContentInfo /> }
{ lastEditedText && <Text>{ lastEditedText }</Text> }
</VStack>
{ showPostContentPanels && (
<VStack
className="editor-post-card-panel__description"
spacing={ 2 }
>
<PrivatePostExcerptPanel />
<PostLastEditedPanel />
</VStack>
) }
{ postType === TEMPLATE_POST_TYPE && <TemplateAreas /> }
</VStack>
</div>
</PanelBody>
);
}

// 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 (
<Text>
{ 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
) }
</Text>
);
}
8 changes: 2 additions & 6 deletions packages/editor/src/components/post-card-panel/style.scss
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
}