From 53d2444d595e59bf00c407d140b03f36e6a2510e Mon Sep 17 00:00:00 2001 From: Riad Benguella Date: Wed, 12 Apr 2017 15:35:12 +0100 Subject: [PATCH 1/6] Visual Editor: Adding the arrangement toolbar (up/down arrows) --- .../components/arrangement-toolbar/index.js | 52 +++++++++ .../components/arrangement-toolbar/style.scss | 23 ++++ editor/modes/visual-editor/block.js | 12 +- editor/modes/visual-editor/style.scss | 28 ++++- editor/state.js | 30 ++++- editor/test/state.js | 104 ++++++++++++++++++ 6 files changed, 238 insertions(+), 11 deletions(-) create mode 100644 editor/components/arrangement-toolbar/index.js create mode 100644 editor/components/arrangement-toolbar/style.scss diff --git a/editor/components/arrangement-toolbar/index.js b/editor/components/arrangement-toolbar/index.js new file mode 100644 index 00000000000000..c763e6e1eafe1b --- /dev/null +++ b/editor/components/arrangement-toolbar/index.js @@ -0,0 +1,52 @@ +/** + * External dependencies + */ +import { connect } from 'react-redux'; +import classnames from 'classnames'; +import { first, last } from 'lodash'; + +/** + * Internal dependencies + */ +import './style.scss'; +import Dashicon from 'components/dashicon'; + +function BlockArrangement( { onMoveUp, onMoveDown, isFirst, isLast } ) { + return ( +
+ + +
+ ); +} + +export default connect( + ( state, ownProps ) => ( { + isFirst: first( state.blocks.order ) === ownProps.uid, + isLirst: last( state.blocks.order ) === ownProps.uid + } ), + ( dispatch, ownProps ) => ( { + onMoveDown() { + dispatch( { + type: 'MOVE_BLOCK_DOWN', + uid: ownProps.uid + } ); + }, + onMoveUp() { + dispatch( { + type: 'MOVE_BLOCK_UP', + uid: ownProps.uid + } ); + } + } ) +)( BlockArrangement ); diff --git a/editor/components/arrangement-toolbar/style.scss b/editor/components/arrangement-toolbar/style.scss new file mode 100644 index 00000000000000..6ef27b74ab391a --- /dev/null +++ b/editor/components/arrangement-toolbar/style.scss @@ -0,0 +1,23 @@ +.editor-arrangement-toolbar { + position: absolute; + top: 10px; + left: 0; + + .editor-arrangement-toolbar__control { + display: block; + padding: 0; + border: none; + outline: none; + background: none; + color: $light-gray-600; + cursor: pointer; + + &.is-disabled { + color: $light-gray-100; + } + + .dashicon { + display: block; + } + } +} diff --git a/editor/modes/visual-editor/block.js b/editor/modes/visual-editor/block.js index b4f19e1a80b10b..bac10fdd909142 100644 --- a/editor/modes/visual-editor/block.js +++ b/editor/modes/visual-editor/block.js @@ -8,6 +8,7 @@ import classnames from 'classnames'; * Internal dependencies */ import Toolbar from 'components/toolbar'; +import ArrangementToolbar from 'components/arrangement-toolbar'; function VisualEditorBlock( props ) { const { block } = props; @@ -62,6 +63,7 @@ function VisualEditorBlock( props ) { onMouseLeave={ onMouseLeave } className={ className } > + { ( isSelected || isHovered ) && } { isSelected && settings.controls ? ( ( { @@ -70,10 +72,12 @@ function VisualEditorBlock( props ) { isActive: () => control.isActive( block.attributes ) } ) ) } /> ) : null } - +
+ +
); /* eslint-enable jsx-a11y/no-static-element-interactions */ diff --git a/editor/modes/visual-editor/style.scss b/editor/modes/visual-editor/style.scss index 72ce0571eb8bd1..c5c27cd320301a 100644 --- a/editor/modes/visual-editor/style.scss +++ b/editor/modes/visual-editor/style.scss @@ -17,16 +17,32 @@ .editor-visual-editor__block { position: relative; - padding: 15px; border: 2px solid transparent; transition: 0.2s border-color; + margin-left: -35px; - &.is-hovered { - border-left: 2px solid $light-gray-500; + .editor-visual-editor__block-edit { + padding: 15px 15px 15px 50px; } - &.is-selected { - border: 2px solid $light-gray-500; + &:before { + z-index: -1; + content: ''; + position: absolute; + top: 0; + bottom: 0; + left: 33px; + right: 0; + border: 2px solid transparent; + transition: 0.2s border-color; + } + + &.is-hovered:before { + border-left-color: $light-gray-500; + } + + &.is-selected:before { + border-color: $light-gray-500; } } @@ -34,7 +50,7 @@ position: absolute; bottom: 100%; margin-bottom: -4px; - left: 8px; + left: 43px; } .editor-visual-editor .editor-inserter { diff --git a/editor/state.js b/editor/state.js index 0cac26cb44b366..96ab1cea733190 100644 --- a/editor/state.js +++ b/editor/state.js @@ -2,7 +2,7 @@ * External dependencies */ import { combineReducers, createStore } from 'redux'; -import { keyBy } from 'lodash'; +import { keyBy, last } from 'lodash'; /** * Reducer returning editor blocks state, an combined reducer of keys byUid, @@ -31,9 +31,37 @@ export const blocks = combineReducers( { return state; }, order( state = [], action ) { + let index; + let swappedUid; switch ( action.type ) { case 'REPLACE_BLOCKS': return action.blockNodes.map( ( { uid } ) => uid ); + + case 'MOVE_BLOCK_UP': + if ( action.uid === state[ 0 ] ) { + return state; + } + index = state.indexOf( action.uid ); + swappedUid = state[ index - 1 ]; + return [ + ...state.slice( 0, index - 1 ), + action.uid, + swappedUid, + ...state.slice( index + 1 ) + ]; + + case 'MOVE_BLOCK_DOWN': + if ( action.uid === last( state ) ) { + return state; + } + index = state.indexOf( action.uid ); + swappedUid = state[ index + 1 ]; + return [ + ...state.slice( 0, index ), + swappedUid, + action.uid, + ...state.slice( index + 2 ) + ]; } return state; diff --git a/editor/test/state.js b/editor/test/state.js index b63df493da14d9..4ba6d8fcb41d68 100644 --- a/editor/test/state.js +++ b/editor/test/state.js @@ -124,6 +124,110 @@ describe( 'state', () => { expect( state.hovered.kumquat ).to.be.false(); expect( state.selected.kumquat ).to.be.true(); } ); + + it( 'should move the block up', () => { + const original = deepFreeze( { + byUid: { + chicken: { + uid: 'chicken', + blockType: 'core/test-block', + attributes: {} + }, + ribs: { + uid: 'ribs', + blockType: 'core/test-block', + attributes: {} + } + }, + order: [ 'chicken', 'ribs' ], + selected: {}, + hovered: {} + } ); + const state = blocks( original, { + type: 'MOVE_BLOCK_UP', + uid: 'ribs' + } ); + + expect( state.order ).to.eql( [ 'ribs', 'chicken' ] ); + } ); + + it( 'should not move the first block up', () => { + const original = deepFreeze( { + byUid: { + chicken: { + uid: 'chicken', + blockType: 'core/test-block', + attributes: {} + }, + ribs: { + uid: 'ribs', + blockType: 'core/test-block', + attributes: {} + } + }, + order: [ 'chicken', 'ribs' ], + selected: {}, + hovered: {} + } ); + const state = blocks( original, { + type: 'MOVE_BLOCK_UP', + uid: 'chicken' + } ); + + expect( state.order ).to.equal( original.order ); + } ); + + it( 'should move the block down', () => { + const original = deepFreeze( { + byUid: { + chicken: { + uid: 'chicken', + blockType: 'core/test-block', + attributes: {} + }, + ribs: { + uid: 'ribs', + blockType: 'core/test-block', + attributes: {} + } + }, + order: [ 'chicken', 'ribs' ], + selected: {}, + hovered: {} + } ); + const state = blocks( original, { + type: 'MOVE_BLOCK_DOWN', + uid: 'chicken' + } ); + + expect( state.order ).to.eql( [ 'ribs', 'chicken' ] ); + } ); + + it( 'should not move the last block down', () => { + const original = deepFreeze( { + byUid: { + chicken: { + uid: 'chicken', + blockType: 'core/test-block', + attributes: {} + }, + ribs: { + uid: 'ribs', + blockType: 'core/test-block', + attributes: {} + } + }, + order: [ 'chicken', 'ribs' ], + selected: {}, + hovered: {} + } ); + const state = blocks( original, { + type: 'MOVE_BLOCK_DOWN', + uid: 'ribs' + } ); + + expect( state.order ).to.equal( original.order ); + } ); } ); describe( 'mode()', () => { From 8b6ad11572dacb2bfc97e49e7aac5ccfb3291b88 Mon Sep 17 00:00:00 2001 From: Riad Benguella Date: Wed, 12 Apr 2017 15:46:49 +0100 Subject: [PATCH 2/6] Adding the hover color on the arrangement arrows --- editor/components/arrangement-toolbar/style.scss | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/editor/components/arrangement-toolbar/style.scss b/editor/components/arrangement-toolbar/style.scss index 6ef27b74ab391a..4710746b40b6df 100644 --- a/editor/components/arrangement-toolbar/style.scss +++ b/editor/components/arrangement-toolbar/style.scss @@ -12,6 +12,10 @@ color: $light-gray-600; cursor: pointer; + &:hover { + color: $dark-gray-900; + } + &.is-disabled { color: $light-gray-100; } From 9ef582e31cff477f6a0603359a835e58fa84ff4c Mon Sep 17 00:00:00 2001 From: Riad Benguella Date: Thu, 13 Apr 2017 10:03:51 +0100 Subject: [PATCH 3/6] Fix typo isLast and use IconButton component --- .../components/arrangement-toolbar/index.js | 18 +++++----- .../components/arrangement-toolbar/style.scss | 36 ++++++++++--------- editor/modes/visual-editor/block.js | 2 +- 3 files changed, 28 insertions(+), 28 deletions(-) diff --git a/editor/components/arrangement-toolbar/index.js b/editor/components/arrangement-toolbar/index.js index c763e6e1eafe1b..c7c64d77873ad2 100644 --- a/editor/components/arrangement-toolbar/index.js +++ b/editor/components/arrangement-toolbar/index.js @@ -9,23 +9,21 @@ import { first, last } from 'lodash'; * Internal dependencies */ import './style.scss'; -import Dashicon from 'components/dashicon'; +import IconButton from 'components/icon-button'; function BlockArrangement( { onMoveUp, onMoveDown, isFirst, isLast } ) { return (
- - + icon="arrow-down-alt2" + />
); } @@ -33,7 +31,7 @@ function BlockArrangement( { onMoveUp, onMoveDown, isFirst, isLast } ) { export default connect( ( state, ownProps ) => ( { isFirst: first( state.blocks.order ) === ownProps.uid, - isLirst: last( state.blocks.order ) === ownProps.uid + isLast: last( state.blocks.order ) === ownProps.uid } ), ( dispatch, ownProps ) => ( { onMoveDown() { diff --git a/editor/components/arrangement-toolbar/style.scss b/editor/components/arrangement-toolbar/style.scss index 4710746b40b6df..a873075c3d07a7 100644 --- a/editor/components/arrangement-toolbar/style.scss +++ b/editor/components/arrangement-toolbar/style.scss @@ -2,26 +2,28 @@ position: absolute; top: 10px; left: 0; +} - .editor-arrangement-toolbar__control { - display: block; - padding: 0; - border: none; - outline: none; - background: none; - color: $light-gray-600; - cursor: pointer; +.editor-arrangement-toolbar__control { + display: block; + padding: 0; + border: none; + outline: none; + background: none; + color: $light-gray-600; + cursor: pointer; + width: 20px; + height: 20px; - &:hover { - color: $dark-gray-900; - } + &:hover { + color: $dark-gray-900; + } - &.is-disabled { - color: $light-gray-100; - } + &.is-disabled { + color: $light-gray-100; + } - .dashicon { - display: block; - } + .dashicon { + display: block; } } diff --git a/editor/modes/visual-editor/block.js b/editor/modes/visual-editor/block.js index bac10fdd909142..c2962b9f180f09 100644 --- a/editor/modes/visual-editor/block.js +++ b/editor/modes/visual-editor/block.js @@ -63,7 +63,7 @@ function VisualEditorBlock( props ) { onMouseLeave={ onMouseLeave } className={ className } > - { ( isSelected || isHovered ) && } + { ( isSelected || isHovered || true ) && } { isSelected && settings.controls ? ( ( { From 49881522c720eeff76dade98927d59db90632293 Mon Sep 17 00:00:00 2001 From: Riad Benguella Date: Thu, 13 Apr 2017 10:06:40 +0100 Subject: [PATCH 4/6] Dropping the block edit wrapper --- editor/modes/visual-editor/block.js | 10 ++++------ editor/modes/visual-editor/style.scss | 5 +---- 2 files changed, 5 insertions(+), 10 deletions(-) diff --git a/editor/modes/visual-editor/block.js b/editor/modes/visual-editor/block.js index c2962b9f180f09..21f476b22d9e70 100644 --- a/editor/modes/visual-editor/block.js +++ b/editor/modes/visual-editor/block.js @@ -72,12 +72,10 @@ function VisualEditorBlock( props ) { isActive: () => control.isActive( block.attributes ) } ) ) } /> ) : null } -
- -
+ ); /* eslint-enable jsx-a11y/no-static-element-interactions */ diff --git a/editor/modes/visual-editor/style.scss b/editor/modes/visual-editor/style.scss index c5c27cd320301a..60c27fb03eac4e 100644 --- a/editor/modes/visual-editor/style.scss +++ b/editor/modes/visual-editor/style.scss @@ -20,10 +20,7 @@ border: 2px solid transparent; transition: 0.2s border-color; margin-left: -35px; - - .editor-visual-editor__block-edit { - padding: 15px 15px 15px 50px; - } + padding: 15px 15px 15px 50px; &:before { z-index: -1; From e15327e26511ec179452c6b0f3dc136437ce112f Mon Sep 17 00:00:00 2001 From: Riad Benguella Date: Thu, 13 Apr 2017 10:08:00 +0100 Subject: [PATCH 5/6] Drop testing condition --- editor/modes/visual-editor/block.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/editor/modes/visual-editor/block.js b/editor/modes/visual-editor/block.js index 21f476b22d9e70..7624c3de0f33eb 100644 --- a/editor/modes/visual-editor/block.js +++ b/editor/modes/visual-editor/block.js @@ -63,7 +63,7 @@ function VisualEditorBlock( props ) { onMouseLeave={ onMouseLeave } className={ className } > - { ( isSelected || isHovered || true ) && } + { ( isSelected || isHovered ) && } { isSelected && settings.controls ? ( ( { From 99865dc4f0f716bb85241a1d3c5d47d4e7d726c3 Mon Sep 17 00:00:00 2001 From: Riad Benguella Date: Thu, 13 Apr 2017 11:53:57 +0100 Subject: [PATCH 6/6] Rename BlockArrangement to BlockMover --- .../{arrangement-toolbar => block-mover}/index.js | 10 +++++----- .../{arrangement-toolbar => block-mover}/style.scss | 4 ++-- editor/components/click-outside/index.js | 0 editor/modes/visual-editor/block.js | 4 ++-- 4 files changed, 9 insertions(+), 9 deletions(-) rename editor/components/{arrangement-toolbar => block-mover}/index.js (70%) rename editor/components/{arrangement-toolbar => block-mover}/style.scss (82%) create mode 100644 editor/components/click-outside/index.js diff --git a/editor/components/arrangement-toolbar/index.js b/editor/components/block-mover/index.js similarity index 70% rename from editor/components/arrangement-toolbar/index.js rename to editor/components/block-mover/index.js index c7c64d77873ad2..f4e422723e5d33 100644 --- a/editor/components/arrangement-toolbar/index.js +++ b/editor/components/block-mover/index.js @@ -11,16 +11,16 @@ import { first, last } from 'lodash'; import './style.scss'; import IconButton from 'components/icon-button'; -function BlockArrangement( { onMoveUp, onMoveDown, isFirst, isLast } ) { +function BlockMover( { onMoveUp, onMoveDown, isFirst, isLast } ) { return ( -
+
@@ -47,4 +47,4 @@ export default connect( } ); } } ) -)( BlockArrangement ); +)( BlockMover ); diff --git a/editor/components/arrangement-toolbar/style.scss b/editor/components/block-mover/style.scss similarity index 82% rename from editor/components/arrangement-toolbar/style.scss rename to editor/components/block-mover/style.scss index a873075c3d07a7..8d78a818f091c2 100644 --- a/editor/components/arrangement-toolbar/style.scss +++ b/editor/components/block-mover/style.scss @@ -1,10 +1,10 @@ -.editor-arrangement-toolbar { +.editor-block-mover { position: absolute; top: 10px; left: 0; } -.editor-arrangement-toolbar__control { +.editor-block-mover__control { display: block; padding: 0; border: none; diff --git a/editor/components/click-outside/index.js b/editor/components/click-outside/index.js new file mode 100644 index 00000000000000..e69de29bb2d1d6 diff --git a/editor/modes/visual-editor/block.js b/editor/modes/visual-editor/block.js index 7624c3de0f33eb..45ec27159d86e3 100644 --- a/editor/modes/visual-editor/block.js +++ b/editor/modes/visual-editor/block.js @@ -8,7 +8,7 @@ import classnames from 'classnames'; * Internal dependencies */ import Toolbar from 'components/toolbar'; -import ArrangementToolbar from 'components/arrangement-toolbar'; +import BlockMover from 'components/block-mover'; function VisualEditorBlock( props ) { const { block } = props; @@ -63,7 +63,7 @@ function VisualEditorBlock( props ) { onMouseLeave={ onMouseLeave } className={ className } > - { ( isSelected || isHovered ) && } + { ( isSelected || isHovered ) && } { isSelected && settings.controls ? ( ( {