diff --git a/packages/components/src/index.js b/packages/components/src/index.js index 5ecba807ac7b5a..28f119c9237ef4 100644 --- a/packages/components/src/index.js +++ b/packages/components/src/index.js @@ -6,6 +6,7 @@ export { Polygon, Rect, G, + Line, HorizontalRule, BlockQuotation, } from '@wordpress/primitives'; diff --git a/packages/e2e-tests/specs/editor/various/block-hierarchy-navigation.test.js b/packages/e2e-tests/specs/editor/various/block-hierarchy-navigation.test.js index 3a24203fecbf35..ea16ec75ffda2b 100644 --- a/packages/e2e-tests/specs/editor/various/block-hierarchy-navigation.test.js +++ b/packages/e2e-tests/specs/editor/various/block-hierarchy-navigation.test.js @@ -119,7 +119,7 @@ describe( 'Navigating the block hierarchy', () => { // Navigate to the third column in the columns block. await pressKeyWithModifier( 'ctrl', '`' ); await pressKeyWithModifier( 'ctrl', '`' ); - await pressKeyTimes( 'Tab', 2 ); + await pressKeyTimes( 'Tab', 4 ); await pressKeyTimes( 'ArrowDown', 4 ); await page.waitForSelector( '.is-highlighted[aria-label="Block: Column (3 of 3)"]' diff --git a/packages/edit-post/src/components/header/header-toolbar/index.js b/packages/edit-post/src/components/header/header-toolbar/index.js index edc44c9a201b65..bf22dec0822887 100644 --- a/packages/edit-post/src/components/header/header-toolbar/index.js +++ b/packages/edit-post/src/components/header/header-toolbar/index.js @@ -10,7 +10,6 @@ import { store as blockEditorStore, } from '@wordpress/block-editor'; import { - TableOfContents, EditorHistoryRedo, EditorHistoryUndo, store as editorStore, @@ -77,13 +76,6 @@ function HeaderToolbar() { ); const overflowItems = ( <> - + + + + + + + + + + + + + + + ); +} + +export default function ListViewOutline() { + const { headingCount } = useSelect( ( select ) => { + const { getGlobalBlockCount } = select( blockEditorStore ); + return { + headingCount: getGlobalBlockCount( 'core/heading' ), + }; + }, [] ); + return ( + <> + { headingCount > 0 ? ( + + ) : ( +
+ +

+ { __( + 'Navigate the structure of your document and address issues like empty or incorrect heading levels.' + ) } +

+
+ ) } +
+
+ { __( 'Characters:' ) } + + + +
+
+ { __( 'Words:' ) } + +
+
+ { __( 'Time to read:' ) } + +
+
+ + ); +} diff --git a/packages/edit-post/src/components/secondary-sidebar/list-view-sidebar.js b/packages/edit-post/src/components/secondary-sidebar/list-view-sidebar.js index 10ee573e6257c6..56f6fce6f17bf1 100644 --- a/packages/edit-post/src/components/secondary-sidebar/list-view-sidebar.js +++ b/packages/edit-post/src/components/secondary-sidebar/list-view-sidebar.js @@ -1,3 +1,8 @@ +/** + * External dependencies + */ +import classnames from 'classnames'; + /** * WordPress dependencies */ @@ -6,18 +11,19 @@ import { Button } from '@wordpress/components'; import { useFocusOnMount, useFocusReturn, - useInstanceId, useMergeRefs, } from '@wordpress/compose'; import { useDispatch } from '@wordpress/data'; import { __ } from '@wordpress/i18n'; import { closeSmall } from '@wordpress/icons'; import { ESCAPE } from '@wordpress/keycodes'; +import { useState } from '@wordpress/element'; /** * Internal dependencies */ import { store as editPostStore } from '../../store'; +import ListViewOutline from './list-view-outline'; export default function ListViewSidebar() { const { setIsListViewOpened } = useDispatch( editPostStore ); @@ -32,35 +38,68 @@ export default function ListViewSidebar() { } } - const instanceId = useInstanceId( ListViewSidebar ); - const labelId = `edit-post-editor__list-view-panel-label-${ instanceId }`; + const [ tab, setTab ] = useState( 'list-view' ); return ( // eslint-disable-next-line jsx-a11y/no-static-element-interactions
- { __( 'List View' ) } + +
  • + +
  • +
    - + { tab === 'list-view' && ( +
    + +
    + ) } + { tab === 'outline' && }
    ); diff --git a/packages/edit-post/src/components/secondary-sidebar/style.scss b/packages/edit-post/src/components/secondary-sidebar/style.scss index 1b350148038d55..507ba200bd9005 100644 --- a/packages/edit-post/src/components/secondary-sidebar/style.scss +++ b/packages/edit-post/src/components/secondary-sidebar/style.scss @@ -8,7 +8,12 @@ .edit-post-editor__list-view-panel { // Same width as the Inserter. // @see packages/block-editor/src/components/inserter/style.scss - min-width: 350px; + // Width of the list view panel. + width: 350px; + + .edit-post-sidebar__panel-tabs { + flex-direction: row-reverse; + } } .edit-post-editor__inserter-panel-header { @@ -18,30 +23,81 @@ justify-content: flex-end; } -.edit-post-editor__inserter-panel-content, -.edit-post-editor__list-view-panel-content { +.edit-post-editor__inserter-panel-content { // Leave space for the close button height: calc(100% - #{$button-size} - #{$grid-unit-10}); -} - -.edit-post-editor__inserter-panel-content { @include break-medium() { height: 100%; } } .edit-post-editor__list-view-panel-header { - align-items: center; border-bottom: $border-width solid $gray-300; display: flex; justify-content: space-between; height: $grid-unit-60; padding-left: $grid-unit-20; padding-right: $grid-unit-05; + ul { + width: calc(100% - #{ $grid-unit-50 }); + } + li { + width: 50%; + button { + width: 100%; + text-align: initial; + } + } + li:only-child { + width: 100%; + } } -.edit-post-editor__list-view-panel-content { +.edit-post-editor__list-view-panel-content, +.edit-post-editor__list-view-container > .document-outline, +.edit-post-editor__list-view-empty-headings { + overflow-x: hidden; overflow-y: auto; + height: 100%; // The table cells use an extra pixels of space left and right. We compensate for that here. padding: $grid-unit-10 ($grid-unit-10 - $border-width - $border-width); } + +.edit-post-editor__list-view-empty-headings { + & > svg { + margin-top: $grid-unit-30 + $grid-unit-05; + } + & > p { + padding-left: $grid-unit-40; + padding-right: $grid-unit-40; + } + text-align: center; + color: $gray-700; +} + +.edit-post-editor__list-view-overview { + & > div > span:first-child { + // Width of the text information fields. + width: 90px; + display: inline-block; + } + border-top: $border-width solid $gray-300; + width: calc(100% - #{ $grid-unit-40 }); + padding: $grid-unit-20; + & > div { + padding: 0 0 $grid-unit-10; + & > span { + font-size: $helptext-font-size; + line-height: $default-line-height; + color: $gray-700; + } + } + // Height of the overview container. + height: 72px; +} + +.edit-post-editor__list-view-container { + display: flex; + flex-direction: column; + height: calc(100% - #{$grid-unit-60}); +} diff --git a/packages/editor/src/components/index.js b/packages/editor/src/components/index.js index 3ea8aa0042ab73..3c1521f756554a 100644 --- a/packages/editor/src/components/index.js +++ b/packages/editor/src/components/index.js @@ -72,6 +72,8 @@ export { default as TableOfContents } from './table-of-contents'; export { default as ThemeSupportCheck } from './theme-support-check'; export { default as UnsavedChangesWarning } from './unsaved-changes-warning'; export { default as WordCount } from './word-count'; +export { default as TimeToRead } from './time-to-read'; +export { default as CharacterCount } from './character-count'; // State Related Components. export { default as EditorProvider } from './provider'; diff --git a/packages/editor/src/components/time-to-read/index.js b/packages/editor/src/components/time-to-read/index.js index 0ff85b2e717d0d..41b458124c6f3b 100644 --- a/packages/editor/src/components/time-to-read/index.js +++ b/packages/editor/src/components/time-to-read/index.js @@ -38,7 +38,7 @@ export default function TimeToRead() { const minutesToReadString = minutesToRead === 0 ? createInterpolateElement( __( '< 1 minute' ), { - span: , + span: , } ) : createInterpolateElement( sprintf( @@ -51,7 +51,7 @@ export default function TimeToRead() { minutesToRead ), { - span: , + span: , } ); diff --git a/packages/primitives/src/svg/index.js b/packages/primitives/src/svg/index.js index d5a03921ca53df..79a5e7f58e55d6 100644 --- a/packages/primitives/src/svg/index.js +++ b/packages/primitives/src/svg/index.js @@ -24,6 +24,13 @@ export const Circle = ( props ) => createElement( 'circle', props ); */ export const G = ( props ) => createElement( 'g', props ); +/** + * @param {import('react').ComponentPropsWithoutRef<'line'>} props + * + * @return {JSX.Element} Path component + */ +export const Line = ( props ) => createElement( 'line', props ); + /** * @param {import('react').ComponentPropsWithoutRef<'path'>} props * diff --git a/packages/primitives/src/svg/index.native.js b/packages/primitives/src/svg/index.native.js index 2035d56d8c7a24..79a0c33cde8d6e 100644 --- a/packages/primitives/src/svg/index.native.js +++ b/packages/primitives/src/svg/index.native.js @@ -24,6 +24,7 @@ export { RadialGradient, LinearGradient, Stop, + Line, } from 'react-native-svg'; const AnimatedSvg = Animated.createAnimatedComponent(