Skip to content

Commit

Permalink
Editor Chrome: Adding the editor mode switcher (#339)
Browse files Browse the repository at this point in the history
 - Adding the `onChange` content handler
 - v1 of the editor header
 - Adding a v1 the text editor
  • Loading branch information
youknowriad authored Mar 29, 2017
1 parent ee44f22 commit 001ec39
Show file tree
Hide file tree
Showing 13 changed files with 293 additions and 72 deletions.
17 changes: 12 additions & 5 deletions editor/assets/stylesheets/main.scss
Original file line number Diff line number Diff line change
@@ -1,21 +1,28 @@
@import './variables';
@import '../../inserter/style';
@import '../../editor/style';

body.toplevel_page_gutenberg {
background: #fff;

#update-nag, .update-nag {
position: absolute;
right: 0;
top: 50px;
}

#wpcontent {
padding-left: 0;
}
}

.gutenberg {
margin: -20px 0 0 -20px;
padding: 60px;

* {
box-sizing: border-box;
}
}

.gutenberg__editor {
max-width: 700px;
margin: 0 auto;
position: relative;
img {
max-width: 100%;
Expand Down
2 changes: 2 additions & 0 deletions editor/assets/stylesheets/variables.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
$gray: #575D65;
$light-gray: #e0e5e9;
21 changes: 0 additions & 21 deletions editor/editor/editor.js

This file was deleted.

21 changes: 2 additions & 19 deletions editor/editor/index.js
Original file line number Diff line number Diff line change
@@ -1,35 +1,18 @@
/**
* Internal dependencies
*/
import EditorComponent from './editor';
import EditorLayout from './layout';

export default class Editor {
constructor( id, settings ) {
this.toggleInserter = this.toggleInserter.bind( this );
this.id = id;
this.settings = settings;
this.state = {
inserter: { opened: false },
blocks: wp.blocks.parse( settings.content )
};
console.log( this.state.blocks ); // eslint-disable-line no-console
this.render();
}

setState( newState ) {
this.state = Object.assign( {}, this.state, newState );
this.render();
}

toggleInserter() {
this.setState( {
inserter: { opened: ! this.state.inserter.opened }
} );
}

render() {
wp.element.render(
<EditorComponent state={ this.state} toggleInserter={ this.toggleInserter } />,
<EditorLayout initialContent={ this.settings.content } />,
document.getElementById( this.id )
);
}
Expand Down
50 changes: 50 additions & 0 deletions editor/editor/layout.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
/**
* Internal dependencies
*/
import ModeSwitcher from './mode-switcher';
import EditorText from './mode/text';
import EditorVisual from './mode/visual';

class Layout extends wp.element.Component {
constructor( props ) {
super( ...arguments );
this.switchMode = this.switchMode.bind( this );
this.state = {
mode: 'visual',
html: props.initialContent,
blocks: wp.blocks.parse( this.props.initialContent )
};
}

switchMode( newMode ) {
// TODO: we need a serializer from blocks here
const html = this.state.html;
const blocks = this.mode === 'visual' ? this.state.blocks : wp.blocks.parse( this.state.html );
this.setState( {
mode: newMode,
html,
blocks
} );
}

createChangeHandler( type ) {
return ( value ) => this.setState( { [ type ]: value } );
}

render() {
const { mode, html, blocks } = this.state;
return (
<div>
<div className="editor__header">
<ModeSwitcher mode={ mode } onSwitch={ this.switchMode } />
</div>
<div className="editor__body">
{ mode === 'text' && <EditorText html={ html } onChange={ this.createChangeHandler( 'html' ) } /> }
{ mode === 'visual' && <EditorVisual blocks={ blocks } onChange={ this.createChangeHandler( 'blocks' ) } /> }
</div>
</div>
);
}
}

export default Layout;
53 changes: 53 additions & 0 deletions editor/editor/mode-switcher.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
class ModeSwitcher extends wp.element.Component {
constructor() {
super( ...arguments );
this.toggle = this.toggle.bind( this );
this.state = {
opened: false
};
}

toggle() {
this.setState( {
opened: ! this.state.opened
} );
}

render() {
const { opened } = this.state;
const modes = [
{ value: 'visual', label: 'Visual' },
{ value: 'text', label: 'Text' },
];
const switchMode = ( mode ) => () => {
this.setState( { opened: false } );
this.props.onSwitch( mode );
};
const currentMode = modes.find( ( { value } ) => value === this.props.mode );

return (
<div className="editor-mode-switcher">
<button
className="editor-mode-switcher__toggle"
onClick={ this.toggle }
aria-label="Switch the editor mode"
>
{ currentMode.label }
<span className="dashicons dashicons-arrow-down" />
</button>
{ opened &&
<div className="editor-mode-switcher__content">
<div className="editor-mode-switcher__arrow" />
{ modes.map( ( mode ) =>
<button key={ mode.value } type="button" onClick={ switchMode( mode.value ) }>
{ mode.label }
</button>
) }
</div>
}
</div>
);
}
}

export default ModeSwitcher;
13 changes: 13 additions & 0 deletions editor/editor/mode/text.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
function Text( { html, onChange } ) {
const changeValue = ( event ) => {
onChange( event.target.value );
};

return (
<div className="editor-mode-text">
<textarea value={ html } onChange={ changeValue } />
</div>
);
}

export default Text;
34 changes: 34 additions & 0 deletions editor/editor/mode/visual.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
/**
* Internal dependencies
*/
import InserterButton from '../../inserter/button';

function Blocks( { blocks, onChange } ) {
const onChangeBlock = ( index ) => ( changes ) => {
const newBlock = {
...blocks[ index ],
changes
};

onChange( [
...blocks.slice( 0, index ),
newBlock,
...blocks.slice( index + 1 )
] );
};

return (
<div className="editor-mode-visual">
<div>
{ blocks.map( ( block, index ) =>
<div key={ index }>
{ wp.blocks.getBlockSettings( block.blockType ).edit( block.attributes, onChangeBlock( index ) ) }
</div>
) }
</div>
<InserterButton />
</div>
);
}

export default Blocks;
85 changes: 85 additions & 0 deletions editor/editor/style.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
.editor__header {
padding: 10px;
border-bottom: 1px solid $light-gray;
}

.editor-mode-switcher {
position: relative;
}

.editor-mode-switcher__toggle {
color: $gray;
padding: 8px;
align-items: center;
cursor: pointer;
border: none;
background: none;
border-right: 1px solid $light-gray;
vertical-align: middle;
line-height: 20px;
outline: none;
}

.editor-mode-switcher__content {
position: absolute;
top: 40px;
border: 1px solid $light-gray;
color: $gray;
min-width: 100px;

button {
padding: 8px;
display: block;
border: none;
background: white;
outline: none;
cursor: pointer;
width: 100%;
}
}

.editor-mode-switcher__arrow {
border: 10px dashed $light-gray;
height: 0;
line-height: 0;
position: absolute;
width: 0;
z-index: 1;
top: -10px;
left: 50%;
margin-left: -10px;
border-bottom-style: solid;
border-top: none;
border-left-color: transparent;
border-right-color: transparent;

&:before {
top: 2px;
border: 10px solid white;
content: " ";
position: absolute;
left: 50%;
margin-left: -10px;
border-bottom-style: solid;
border-top: none;
border-left-color: transparent;
border-right-color: transparent;
}
}

.editor-mode-text {
padding: 60px;
width: 700px;
margin: 0 auto;

textarea {
width: 100%;
min-height: 300px;
}
}

.editor-mode-visual {
padding: 60px;
width: 700px;
margin: 0 auto;
}
51 changes: 33 additions & 18 deletions editor/inserter/button.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,23 +3,38 @@
*/
import Inserter from './';

const InserterButton = ( { opened, onClick } ) => {
const toggle = ( event ) => {
event.preventDefault();
onClick();
};
return (
<div className="inserter__button">
<button
className="inserter__button-toggle"
onClick={ toggle }
aria-label="Add a block"
>
<span className="dashicons dashicons-plus" />
</button>
{ opened && <Inserter /> }
</div>
);
};
class InserterButton extends wp.element.Component {
constructor() {
super( ...arguments );
this.toggle = this.toggle.bind( this );
this.state = {
opened: false
};
}

toggle() {
this.setState( {
opened: ! this.state.opened
} );
}

render() {
const { opened } = this.state;

return (
<div className="inserter__button">
<button
className="inserter__button-toggle"
onClick={ this.toggle }
type="button"
aria-label="Add a block"
>
<span className="dashicons dashicons-plus" />
</button>
{ opened && <Inserter /> }
</div>
);
}
}

export default InserterButton;
Loading

0 comments on commit 001ec39

Please sign in to comment.