Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Editor Chrome: Adding the editor mode switcher #339

Merged
merged 7 commits into from
Mar 29, 2017
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
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"
Copy link
Member

Choose a reason for hiding this comment

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

We should probably start thinking about localization sooner than later. I might focus on this today (for a separate pull request).

>
{ 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