From 52072770fb1772abb2de909cd7bee292186d5086 Mon Sep 17 00:00:00 2001 From: ramon Date: Mon, 22 May 2023 16:32:39 +1000 Subject: [PATCH] This commit: - exports `getMediaDetails()` from the post-featured-image sidebar component and uses it if there's a featured image in the post record - cleans up components and unused functions - uses available wordcount and readtime functions - implements i18n strings - shuffles page-specific styles around --- packages/date/src/test/index.js | 31 +- packages/edit-site/package.json | 1 + .../sidebar-navigation-screen-page/index.js | 360 ++++++------------ .../sidebar-navigation-screen-page/style.scss | 27 ++ .../sidebar-navigation-screen-pages/index.js | 3 +- .../sidebar-navigation-screen/style.scss | 25 -- packages/edit-site/src/style.scss | 1 + packages/editor/src/components/index.js | 5 +- .../components/post-featured-image/index.js | 2 +- 9 files changed, 181 insertions(+), 274 deletions(-) create mode 100644 packages/edit-site/src/components/sidebar-navigation-screen-page/style.scss diff --git a/packages/date/src/test/index.js b/packages/date/src/test/index.js index ff82748e02f23a..1832d4c7c55a2b 100644 --- a/packages/date/src/test/index.js +++ b/packages/date/src/test/index.js @@ -623,7 +623,7 @@ describe( 'Moment.js Localization', () => { } ); describe( 'humanTimeDiff', () => { - it( 'should return human readable time differences', () => { + it( 'should return human readable time differences in the past', () => { expect( humanTimeDiff( '2023-04-28T11:00:00.000Z', @@ -642,6 +642,35 @@ describe( 'Moment.js Localization', () => { '2023-04-30T13:00:00.000Z' ) ).toBe( '2 days ago' ); + + expect( + humanTimeDiff( + '2023-04-28T11:00:00.000Z', + '2023-04-28T13:00:00.000Z' + ) + ).toBe( '2 hours ago' ); + + expect( + humanTimeDiff( + '2023-04-26T13:00:00.000Z', + '2023-04-28T13:00:00.000Z' + ) + ).toBe( '2 days ago' ); + } ); + + it( 'should return human readable time differences in the future', () => { + // Future. + const now = new Date(); + const twoHoursLater = new Date( + now.getTime() + 2 * 60 * 60 * 1000 + ); + expect( humanTimeDiff( twoHoursLater ) ).toBe( 'in 2 hours' ); + + const twoDaysLater = new Date( + now.getTime() + 2 * 24 * 60 * 60 * 1000 + ); // Adding 2 days in milliseconds + + expect( humanTimeDiff( twoDaysLater ) ).toBe( 'in 2 days' ); } ); } ); } ); diff --git a/packages/edit-site/package.json b/packages/edit-site/package.json index efbc8349fe8d9f..b0ff16a697f81d 100644 --- a/packages/edit-site/package.json +++ b/packages/edit-site/package.json @@ -61,6 +61,7 @@ "@wordpress/url": "file:../url", "@wordpress/viewport": "file:../viewport", "@wordpress/widgets": "file:../widgets", + "@wordpress/wordcount": "file:../wordcount", "classnames": "^2.3.1", "colord": "^2.9.2", "downloadjs": "^1.4.7", diff --git a/packages/edit-site/src/components/sidebar-navigation-screen-page/index.js b/packages/edit-site/src/components/sidebar-navigation-screen-page/index.js index 4cda481b2832c4..7b5b19b5729c81 100644 --- a/packages/edit-site/src/components/sidebar-navigation-screen-page/index.js +++ b/packages/edit-site/src/components/sidebar-navigation-screen-page/index.js @@ -1,7 +1,7 @@ /** * WordPress dependencies */ -import { __ } from '@wordpress/i18n'; +import { __, _x, sprintf } from '@wordpress/i18n'; import { useDispatch, useSelect } from '@wordpress/data'; import { __experimentalUseNavigator as useNavigator, @@ -9,6 +9,7 @@ import { __experimentalVStack as VStack, __experimentalText as Text, ExternalLink, + ResponsiveWrapper, } from '@wordpress/components'; import { store as coreStore, @@ -17,6 +18,9 @@ import { } from '@wordpress/core-data'; import { decodeEntities } from '@wordpress/html-entities'; import { pencil } from '@wordpress/icons'; +import { humanTimeDiff } from '@wordpress/date'; +import { count as wordCount } from '@wordpress/wordcount'; +import { getMediaDetails } from '@wordpress/editor'; /** * Internal dependencies @@ -28,63 +32,64 @@ import SidebarButton from '../sidebar-button'; import SidebarNavigationSubtitle from '../sidebar-navigation-subtitle'; import SidebarDetails from '../sidebar-navigation-data-list'; -function countWordsInHTML( htmlString ) { - const parser = new window.DOMParser(); - const doc = parser.parseFromString( htmlString, 'text/html' ); - - let wordCount = 0; - - function countWords( node ) { - if ( node.nodeType === 3 ) { - const text = node.textContent.trim(); - - if ( text !== '' ) { - const words = text.split( /\s+/ ); - wordCount += words.length; - } - } else if ( node.nodeType === 1 ) { - const children = node.childNodes; - for ( let i = 0; i < children.length; i++ ) { - countWords( children[ i ] ); - } - } - } - - countWords( doc.body ); - return wordCount; -} -const estimateReadingTime = ( wordCount, wordsPerMinute = 200 ) => - Math.ceil( wordCount / wordsPerMinute ); +// Taken from packages/editor/src/components/time-to-read/index.js. +const AVERAGE_READING_RATE = 189; +const POST_STATUS_LABELS = { + publish: __( 'Published' ), + future: __( 'Scheduled' ), + draft: __( 'Draft' ), + pending: __( 'Pending' ), +}; function getPageDetails( page ) { if ( ! page ) { return []; } - - const wordCount = countWordsInHTML( page?.content?.rendered ) || 0; - const readingTime = estimateReadingTime( wordCount ); - - return [ - { - label: 'Template', - value: page?.templateTitle, - }, + const details = [ { label: 'Parent', value: page?.parentTitle, }, - { - label: 'Words', - value: wordCount.toLocaleString() || 'Unknown', - }, - { - label: 'Time to read', - value: - readingTime > 1 - ? `${ readingTime.toLocaleString() } mins` - : '1 min', - }, ]; + + if ( page?.templateTitle ) { + details.push( { + label: 'Template', + value: page.templateTitle, + } ); + } + + /* + * 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 = page?.content?.raw + ? wordCount( page.content.raw, wordCountType ) + : 0; + const readingTime = Math.round( wordsCounted / AVERAGE_READING_RATE ); + + if ( wordsCounted ) { + details.push( + { + label: 'Words', + value: wordsCounted.toLocaleString() || __( 'Unknown' ), + }, + { + label: 'Time to read', + value: + readingTime > 1 + ? sprintf( + /* translators: %s: is the number of minutes. */ + __( '%s mins' ), + readingTime.toLocaleString() + ) + : __( '< 1 min' ), + } + ); + } + return details; } export default function SidebarNavigationScreenPage() { @@ -94,18 +99,32 @@ export default function SidebarNavigationScreenPage() { } = useNavigator(); const { record } = useEntityRecord( 'postType', 'page', postId ); + + /* + * Only custom template slugs are available in the post entity record + * Pages using theme templates will not have a template slug. + */ const { records: templates, isResolving: areTemplatesLoading } = useEntityRecords( 'postType', 'wp_template', { per_page: -1, } ); - const templateTitle = areTemplatesLoading ? '' : templates?.find( ( template ) => template?.slug === record?.template ) - ?.title?.rendered || 'Default'; + ?.title?.rendered || ''; - const parentTitle = useSelect( + const { + parentTitle, + featuredMediaDetails: { mediaWidth, mediaHeight, mediaSourceUrl }, + } = useSelect( ( select ) => { + // Featured image. + const { getMedia } = select( coreStore ); + const featuredMedia = record?.featured_media + ? getMedia( record?.featured_media, { context: 'view' } ) + : null; + + // Parent page title. const parent = record?.parent ? select( coreStore ).getEntityRecord( 'postType', @@ -113,14 +132,17 @@ export default function SidebarNavigationScreenPage() { record.parent ) : null; - + let _parentTitle = __( 'Top level' ); if ( parent ) { - return parent?.title?.rendered + _parentTitle = parent?.title?.rendered ? decodeEntities( parent.title.rendered ) - : 'No title'; + : __( 'Untitled' ); } - return 'Top level'; + return { + parentTitle: _parentTitle, + featuredMediaDetails: getMediaDetails( featuredMedia, postId ), + }; }, [ record ] ); @@ -146,30 +168,54 @@ export default function SidebarNavigationScreenPage() { { record.link } ) } - + + + { POST_STATUS_LABELS?.[ record.status ] || + __( 'Unknown' ) } + + { humanTimeDiff( record.date ) } + ) : null } footer={ record && ( - + +