Skip to content
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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 50 additions & 0 deletions editor/components/block-mover/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
/**
* External dependencies
*/
import { connect } from 'react-redux';
import classnames from 'classnames';
import { first, last } from 'lodash';

/**
* Internal dependencies
*/
import './style.scss';
import IconButton from 'components/icon-button';

function BlockMover( { onMoveUp, onMoveDown, isFirst, isLast } ) {
return (
<div className="editor-block-mover">
<IconButton
className={ classnames( 'editor-block-mover__control', { 'is-disabled': isFirst } ) }
Copy link
Member

Choose a reason for hiding this comment

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

The classes should be block-mover__ only.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Maybe we should keep it this way in this PR and drop the editor prefix from all the components in a specific PR. (To avoid having a mix of conventions)

Copy link
Member

Choose a reason for hiding this comment

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

Right, this is following the fact I want to move these components out of the editor and make them only about blocks.

Copy link
Member

Choose a reason for hiding this comment

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

onClick={ onMoveUp }
icon="arrow-up-alt2"
/>
<IconButton
className={ classnames( 'editor-block-mover__control', { 'is-disabled': isLast } ) }
onClick={ onMoveDown }
icon="arrow-down-alt2"
/>
</div>
);
}

export default connect(
( state, ownProps ) => ( {
isFirst: first( state.blocks.order ) === ownProps.uid,
isLast: 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
} );
}
} )
)( BlockMover );
29 changes: 29 additions & 0 deletions editor/components/block-mover/style.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
.editor-block-mover {
position: absolute;
top: 10px;
left: 0;
}

.editor-block-mover__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;
}

&.is-disabled {
color: $light-gray-100;
}

.dashicon {
display: block;
}
}
Empty file.
2 changes: 2 additions & 0 deletions editor/modes/visual-editor/block.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import classnames from 'classnames';
* Internal dependencies
*/
import Toolbar from 'components/toolbar';
import BlockMover from 'components/block-mover';

function VisualEditorBlock( props ) {
const { block } = props;
Expand Down Expand Up @@ -62,6 +63,7 @@ function VisualEditorBlock( props ) {
onMouseLeave={ onMouseLeave }
className={ className }
>
{ ( isSelected || isHovered ) && <BlockMover uid={ block.uid } /> }
{ isSelected && settings.controls ? (
<Toolbar
controls={ settings.controls.map( ( control ) => ( {
Expand Down
25 changes: 19 additions & 6 deletions editor/modes/visual-editor/style.scss
Original file line number Diff line number Diff line change
Expand Up @@ -17,24 +17,37 @@

.editor-visual-editor__block {
position: relative;
padding: 15px;
border: 2px solid transparent;
transition: 0.2s border-color;
margin-left: -35px;
padding: 15px 15px 15px 50px;

&.is-hovered {
border-left: 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-selected {
border: 2px solid $light-gray-500;
&.is-hovered:before {
border-left-color: $light-gray-500;
}

&.is-selected:before {
border-color: $light-gray-500;
}
}

.editor-visual-editor__block .editor-toolbar {
position: absolute;
bottom: 100%;
margin-bottom: -4px;
left: 8px;
left: 43px;
}

.editor-visual-editor .editor-inserter {
Expand Down
30 changes: 29 additions & 1 deletion editor/state.js
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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':
Copy link
Member

Choose a reason for hiding this comment

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

I wonder if it would be easier to have only a single action, something like INCREMENT_BLOCK_POSITION, where an increment: 1 or increment: -1 property value could be passed to determine the increment effect.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I have a small preference for the explicit actions but I don't mind if we change this later.

Copy link
Member

Choose a reason for hiding this comment

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

Also need to consider drag and drop.

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;
Expand Down
104 changes: 104 additions & 0 deletions editor/test/state.js
Original file line number Diff line number Diff line change
Expand Up @@ -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()', () => {
Expand Down