Skip to content

Commit

Permalink
Spotlight Mode and improved Unified Toolbar (#9394)
Browse files Browse the repository at this point in the history
* Adds new "Spotlight Mode" to highlight a single block at a time and eliminates block outlines.
* Reworks fixed toolbar as Unified Toolbar, also reducing block outlines.
* Groups them as "Writing" settings.
  • Loading branch information
youknowriad authored and mtias committed Aug 30, 2018
1 parent eac95b5 commit c5573b7
Show file tree
Hide file tree
Showing 14 changed files with 142 additions and 58 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -6,33 +6,30 @@ import { withSelect, withDispatch } from '@wordpress/data';
/**
* WordPress Dependencies
*/
import { __ } from '@wordpress/i18n';
import { compose } from '@wordpress/compose';
import { MenuItem } from '@wordpress/components';
import { ifViewportMatches } from '@wordpress/viewport';

function FixedToolbarToggle( { onToggle, isActive } ) {
function FeatureToggle( { onToggle, isActive, label } ) {
return (
<MenuItem
icon={ isActive && 'yes' }
isSelected={ isActive }
onClick={ onToggle }
role="menuitemcheckbox"
>
{ __( 'Fix Toolbar to Top' ) }
{ label }
</MenuItem>
);
}

export default compose( [
withSelect( ( select ) => ( {
isActive: select( 'core/edit-post' ).isFeatureActive( 'fixedToolbar' ),
withSelect( ( select, { feature } ) => ( {
isActive: select( 'core/edit-post' ).isFeatureActive( feature ),
} ) ),
withDispatch( ( dispatch, ownProps ) => ( {
onToggle() {
dispatch( 'core/edit-post' ).toggleFeature( 'fixedToolbar' );
dispatch( 'core/edit-post' ).toggleFeature( ownProps.feature );
ownProps.onToggle();
},
} ) ),
ifViewportMatches( 'medium' ),
] )( FixedToolbarToggle );
] )( FeatureToggle );
11 changes: 3 additions & 8 deletions edit-post/components/header/more-menu/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,10 @@ import { Fragment } from '@wordpress/element';
*/
import './style.scss';
import ModeSwitcher from '../mode-switcher';
import FixedToolbarToggle from '../fixed-toolbar-toggle';
import PluginMoreMenuGroup from '../plugins-more-menu-group';
import TipsToggle from '../tips-toggle';
import KeyboardShortcutsHelpMenuItem from '../keyboard-shortcuts-help-menu-item';
import WritingMenu from '../writing-menu';

const MoreMenu = () => (
<Dropdown
Expand All @@ -30,19 +30,14 @@ const MoreMenu = () => (
) }
renderContent={ ( { onClose } ) => (
<Fragment>
<WritingMenu onClose={ onClose } />
<ModeSwitcher onSelect={ onClose } />
<MenuGroup
label={ __( 'Settings' ) }
filterName="editPost.MoreMenu.settings"
>
<FixedToolbarToggle onToggle={ onClose } />
<TipsToggle onToggle={ onClose } />
</MenuGroup>
<PluginMoreMenuGroup.Slot fillProps={ { onClose } } />
<MenuGroup
label={ __( 'Tools' ) }
filterName="editPost.MoreMenu.tools"
>
<TipsToggle onToggle={ onClose } />
<KeyboardShortcutsHelpMenuItem onSelect={ onClose } />
</MenuGroup>
</Fragment>
Expand Down
25 changes: 25 additions & 0 deletions edit-post/components/header/writing-menu/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/**
* WordPress Dependencies
*/
import { MenuGroup } from '@wordpress/components';
import { __ } from '@wordpress/i18n';
import { ifViewportMatches } from '@wordpress/viewport';

/**
* Internal dependencies
*/
import FeatureToggle from '../feature-toggle';

function WritingMenu( { onClose } ) {
return (
<MenuGroup
label={ __( 'Writing' ) }
filterName="editPost.MoreMenu.writing"
>
<FeatureToggle feature="fixedToolbar" label={ __( 'Unified Toolbar' ) } onToggle={ onClose } />
<FeatureToggle feature="focusMode" label={ __( 'Spotlight Mode' ) } onToggle={ onClose } />
</MenuGroup>
);
}

export default ifViewportMatches( 'medium' )( WritingMenu );
18 changes: 16 additions & 2 deletions edit-post/editor.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,19 +10,32 @@ import { StrictMode } from '@wordpress/element';
*/
import Layout from './components/layout';

function Editor( { settings, hasFixedToolbar, post, overridePost, onError, ...props } ) {
function Editor( {
settings,
hasFixedToolbar,
focusMode,
post,
overridePost,
onError,
...props
} ) {
if ( ! post ) {
return null;
}

const editorSettings = {
...settings,
hasFixedToolbar,
focusMode,
};

return (
<StrictMode>
<EditorProvider settings={ editorSettings } post={ { ...post, ...overridePost } } { ...props }>
<EditorProvider
settings={ editorSettings }
post={ { ...post, ...overridePost } }
{ ...props }
>
<ErrorBoundary onError={ onError }>
<Layout />
</ErrorBoundary>
Expand All @@ -33,5 +46,6 @@ function Editor( { settings, hasFixedToolbar, post, overridePost, onError, ...pr

export default withSelect( ( select, { postId, postType } ) => ( {
hasFixedToolbar: select( 'core/edit-post' ).isFeatureActive( 'fixedToolbar' ),
focusMode: select( 'core/edit-post' ).isFeatureActive( 'focusMode' ),
post: select( 'core' ).getEntityRecord( 'postType', postType, postId ),
} ) )( Editor );
32 changes: 19 additions & 13 deletions packages/editor/src/components/block-list/block.js
Original file line number Diff line number Diff line change
Expand Up @@ -354,6 +354,7 @@ export class BlockListBlock extends Component {
block,
order,
mode,
isFocusMode,
hasFixedToolbar,
isLocked,
isFirst,
Expand All @@ -367,11 +368,11 @@ export class BlockListBlock extends Component {
isTypingWithinBlock,
isMultiSelecting,
hoverArea,
isLargeViewport,
isEmptyDefaultBlock,
isMovable,
isPreviousBlockADefaultEmptyBlock,
hasSelectedInnerBlock,
isParentOfSelectedBlock,
} = this.props;
const isHovered = this.state.isHovered && ! isMultiSelecting;
const { name: blockName, isValid } = block;
Expand All @@ -385,13 +386,14 @@ export class BlockListBlock extends Component {
// Empty paragraph blocks should always show up as unselected.
const showEmptyBlockSideInserter = ( isSelected || isHovered ) && isEmptyDefaultBlock;
const showSideInserter = ( isSelected || isHovered ) && isEmptyDefaultBlock;
const shouldAppearSelected = ! showSideInserter && isSelected && ! isTypingWithinBlock;
const shouldAppearSelectedParent = ! showSideInserter && hasSelectedInnerBlock && ! isTypingWithinBlock;
const shouldAppearSelected = ! isFocusMode && ! hasFixedToolbar && ! showSideInserter && isSelected && ! isTypingWithinBlock;
const shouldAppearSelectedParent = ! isFocusMode && ! hasFixedToolbar && ! showSideInserter && hasSelectedInnerBlock && ! isTypingWithinBlock;
const shouldAppearHovered = ! isFocusMode && ! hasFixedToolbar && isHovered && ! isEmptyDefaultBlock;
// We render block movers and block settings to keep them tabbale even if hidden
const shouldRenderMovers = ( isSelected || hoverArea === 'left' ) && ! showEmptyBlockSideInserter && ! isMultiSelecting && ! isPartOfMultiSelection && ! isTypingWithinBlock;
const shouldRenderMovers = ! isFocusMode && ( isSelected || hoverArea === 'left' ) && ! showEmptyBlockSideInserter && ! isMultiSelecting && ! isPartOfMultiSelection && ! isTypingWithinBlock;
const shouldRenderBlockSettings = ( isSelected || hoverArea === 'right' ) && ! isMultiSelecting && ! isPartOfMultiSelection;
const shouldShowBreadcrumb = isHovered && ! isEmptyDefaultBlock;
const shouldShowContextualToolbar = ! showSideInserter && ( ( isSelected && ! isTypingWithinBlock && isValid ) || isFirstMultiSelected ) && ( ! hasFixedToolbar || ! isLargeViewport );
const shouldShowBreadcrumb = ! isFocusMode && isHovered && ! isEmptyDefaultBlock;
const shouldShowContextualToolbar = ! hasFixedToolbar && ! showSideInserter && ( ( isSelected && ! isTypingWithinBlock && isValid ) || isFirstMultiSelected );
const shouldShowMobileToolbar = shouldAppearSelected;
const { error, dragging } = this.state;

Expand All @@ -407,10 +409,12 @@ export class BlockListBlock extends Component {
'is-selected': shouldAppearSelected,
'is-multi-selected': isPartOfMultiSelection,
'is-selected-parent': shouldAppearSelectedParent,
'is-hovered': isHovered && ! isEmptyDefaultBlock,
'is-hovered': shouldAppearHovered,
'is-reusable': isReusableBlock( blockType ),
'is-hidden': dragging,
'is-typing': isTypingWithinBlock,
'is-focused': isFocusMode && ( isSelected || isParentOfSelectedBlock ),
'is-focus-mode': isFocusMode,
} );

const { onReplace } = this.props;
Expand Down Expand Up @@ -584,7 +588,7 @@ export class BlockListBlock extends Component {
}
}

const applyWithSelect = withSelect( ( select, { clientId, rootClientId } ) => {
const applyWithSelect = withSelect( ( select, { clientId, rootClientId, isLargeViewport } ) => {
const {
isBlockSelected,
getPreviousBlockClientId,
Expand All @@ -605,19 +609,19 @@ const applyWithSelect = withSelect( ( select, { clientId, rootClientId } ) => {
getTemplateLock,
} = select( 'core/editor' );
const isSelected = isBlockSelected( clientId );
const isParentOfSelectedBlock = hasSelectedInnerBlock( clientId );
const { hasFixedToolbar } = getEditorSettings();
const { hasFixedToolbar, focusMode } = getEditorSettings();
const block = getBlock( clientId );
const previousBlockClientId = getPreviousBlockClientId( clientId );
const previousBlock = getBlock( previousBlockClientId );
const templateLock = getTemplateLock( rootClientId );
const isParentOfSelectedBlock = hasSelectedInnerBlock( clientId, true );

return {
nextBlockClientId: getNextBlockClientId( clientId ),
isPartOfMultiSelection: isBlockMultiSelected( clientId ) || isAncestorMultiSelected( clientId ),
isFirstMultiSelected: isFirstMultiSelectedBlock( clientId ),
isMultiSelecting: isMultiSelecting(),
hasSelectedInnerBlock: isParentOfSelectedBlock,
hasSelectedInnerBlock: hasSelectedInnerBlock( clientId, false ),
// We only care about this prop when the block is selected
// Thus to avoid unnecessary rerenders we avoid updating the prop if the block is not selected.
isTypingWithinBlock: ( isSelected || isParentOfSelectedBlock ) && isTyping(),
Expand All @@ -630,10 +634,12 @@ const applyWithSelect = withSelect( ( select, { clientId, rootClientId } ) => {
isPreviousBlockADefaultEmptyBlock: previousBlock && isUnmodifiedDefaultBlock( previousBlock ),
isMovable: 'all' !== templateLock,
isLocked: !! templateLock,
isFocusMode: focusMode && isLargeViewport,
hasFixedToolbar: hasFixedToolbar && isLargeViewport,
previousBlockClientId,
block,
isSelected,
hasFixedToolbar,
isParentOfSelectedBlock,
};
} );

Expand Down Expand Up @@ -689,9 +695,9 @@ const applyWithDispatch = withDispatch( ( dispatch, ownProps ) => {
} );

export default compose(
withViewportMatch( { isLargeViewport: 'medium' } ),
applyWithSelect,
applyWithDispatch,
withViewportMatch( { isLargeViewport: 'medium' } ),
withFilters( 'editor.BlockListBlock' ),
withHoverAreas,
)( BlockListBlock );
14 changes: 11 additions & 3 deletions packages/editor/src/components/block-list/breadcrumb.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
/**
* External dependencies
*/
import classnames from 'classnames';

/**
* WordPress dependencies
*/
Expand Down Expand Up @@ -48,10 +53,12 @@ export class BlockBreadcrumb extends Component {
}

render() {
const { clientId, rootClientId } = this.props;
const { clientId, rootClientId, isLight } = this.props;

return (
<div className={ 'editor-block-list__breadcrumb' }>
<div className={ classnames( 'editor-block-list__breadcrumb', {
'is-light': isLight,
} ) }>
<Toolbar>
{ rootClientId && (
<Fragment>
Expand All @@ -68,11 +75,12 @@ export class BlockBreadcrumb extends Component {

export default compose( [
withSelect( ( select, ownProps ) => {
const { getBlockRootClientId } = select( 'core/editor' );
const { getBlockRootClientId, getEditorSettings } = select( 'core/editor' );
const { clientId } = ownProps;

return {
rootClientId: getBlockRootClientId( clientId ),
isLight: getEditorSettings().hasFixedToolbar,
};
} ),
] )( BlockBreadcrumb );
20 changes: 19 additions & 1 deletion packages/editor/src/components/block-list/style.scss
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,16 @@
.editor-block-list__block-edit .reusable-block-edit-panel * {
z-index: z-index(".editor-block-list__block-edit .reusable-block-edit-panel *");
}

&.is-focus-mode:not(.is-multi-selected) {
opacity: 0.5;
transition: opacity 0.1s linear;

&:not(.is-focused) .editor-block-list__block,
&.is-focused {
opacity: 1;
}
}
}


Expand Down Expand Up @@ -852,7 +862,6 @@
.components-toolbar {
border-top: none;
border-bottom: none;

}

@include break-small() {
Expand Down Expand Up @@ -897,6 +906,10 @@
}
}

.editor-block-list__block.is-focus-mode:not(.is-multi-selected) > .editor-block-contextual-toolbar {
margin-left: -$block-side-ui-width;
}

// Enable toolbar footprint collapsing
.editor-block-contextual-toolbar {
// Position the contextual toolbar above the block.
Expand Down Expand Up @@ -1008,6 +1021,11 @@
@include fade_in(60ms, 0.5s);
}
}

&.is-light .components-toolbar {
background: rgba($white, 0.5);
color: $dark-gray-700;
}
}

.editor-block-list__descendant-arrow::before {
Expand Down
1 change: 0 additions & 1 deletion packages/editor/src/components/post-permalink/style.scss
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@

// Use opacity to work in various editor styles.
border: $border-width solid $dark-opacity-light-500;
border-bottom: none;
background-clip: padding-box;

// Put toolbar snugly to edge on mobile.
Expand Down
12 changes: 9 additions & 3 deletions packages/editor/src/components/post-title/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -88,9 +88,13 @@ class PostTitle extends Component {
}

render() {
const { title, placeholder, instanceId, isPostTypeViewable } = this.props;
const { title, placeholder, instanceId, isPostTypeViewable, isFocusMode, hasFixedToolbar } = this.props;
const { isSelected } = this.state;
const className = classnames( 'editor-post-title__block', { 'is-selected': isSelected } );
const className = classnames( 'editor-post-title__block', {
'is-selected': isSelected,
'is-focus-mode': isFocusMode,
'has-fixed-toolbar': hasFixedToolbar,
} );
const decodedPlaceholder = decodeEntities( placeholder );

return (
Expand Down Expand Up @@ -129,12 +133,14 @@ const applyWithSelect = withSelect( ( select ) => {
const { getEditedPostAttribute, getEditorSettings } = select( 'core/editor' );
const { getPostType } = select( 'core' );
const postType = getPostType( getEditedPostAttribute( 'type' ) );
const { titlePlaceholder } = getEditorSettings();
const { titlePlaceholder, focusMode, hasFixedToolbar } = getEditorSettings();

return {
title: getEditedPostAttribute( 'title' ),
isPostTypeViewable: get( postType, [ 'viewable' ], false ),
placeholder: titlePlaceholder,
isFocusMode: focusMode,
hasFixedToolbar,
};
} );

Expand Down
Loading

0 comments on commit c5573b7

Please sign in to comment.