From 2c44fcbe5b83f62d9b831c0d2b5fa0e9cf6d31f1 Mon Sep 17 00:00:00 2001 From: Riad Benguella Date: Thu, 18 May 2017 11:53:06 +0100 Subject: [PATCH 1/4] Chrome: Adding the visibility selector --- editor/selectors.js | 22 ++++- editor/sidebar/post-status/index.js | 5 + editor/sidebar/post-status/style.scss | 2 +- editor/sidebar/post-visibility/index.js | 110 ++++++++++++++++++++++ editor/sidebar/post-visibility/style.scss | 56 +++++++++++ editor/test/selectors.js | 60 ++++++++++++ 6 files changed, 251 insertions(+), 4 deletions(-) create mode 100644 editor/sidebar/post-visibility/index.js create mode 100644 editor/sidebar/post-visibility/style.scss diff --git a/editor/selectors.js b/editor/selectors.js index ff40ed9906bff..0b5a054806959 100644 --- a/editor/selectors.js +++ b/editor/selectors.js @@ -36,10 +36,26 @@ export function getPostEdits( state ) { return state.editor.edits; } +export function getEditedPostAttribute( state, attributeName ) { + return state.editor.edits[ attributeName ] === undefined + ? state.currentPost[ attributeName ] + : state.editor.edits[ attributeName ]; +} + export function getEditedPostStatus( state ) { - return state.editor.edits.status === undefined - ? state.currentPost.status - : state.editor.edits.status; + return getEditedPostAttribute( state, 'status' ); +} + +export function getEditedPostVisibility( state ) { + const status = getEditedPostStatus( state ); + const password = getEditedPostAttribute( state, 'password' ); + + if ( status === 'private' ) { + return 'private'; + } else if ( password !== undefined && password !== null ) { + return 'password'; + } + return 'public'; } export function getEditedPostTitle( state ) { diff --git a/editor/sidebar/post-status/index.js b/editor/sidebar/post-status/index.js index 462fe1d96cc62..abb884f938c2d 100644 --- a/editor/sidebar/post-status/index.js +++ b/editor/sidebar/post-status/index.js @@ -14,6 +14,7 @@ import FormToggle from 'components/form-toggle'; * Internal Dependencies */ import './style.scss'; +import PostVisibility from '../post-visibility'; import { getEditedPostStatus } from '../../selectors'; import { editPost } from '../../actions'; @@ -34,6 +35,10 @@ function PostStatus( { status, onUpdateStatus } ) { onChange={ onToggle } /> + +
+ +
); /* eslint-enable jsx-a11y/label-has-for */ diff --git a/editor/sidebar/post-status/style.scss b/editor/sidebar/post-status/style.scss index 0936a56190f64..41a1bc1d2e833 100644 --- a/editor/sidebar/post-status/style.scss +++ b/editor/sidebar/post-status/style.scss @@ -2,5 +2,5 @@ display: flex; justify-content: space-between; align-items: center; - padding-top: 10px; + padding-top: 20px; } diff --git a/editor/sidebar/post-visibility/index.js b/editor/sidebar/post-visibility/index.js new file mode 100644 index 0000000000000..dc1edca2d5fa2 --- /dev/null +++ b/editor/sidebar/post-visibility/index.js @@ -0,0 +1,110 @@ +/** + * External dependencies + */ +import { connect } from 'react-redux'; +import clickOutside from 'react-click-outside'; + +/** + * WordPress dependencies + */ +import { __ } from 'i18n'; +import { Component } from 'element'; + +/** + * Internal Dependencies + */ +import './style.scss'; +import { + getEditedPostAttribute, + getEditedPostStatus, + getEditedPostVisibility, +} from '../../selectors'; +import { editPost } from '../../actions'; + +class PostVisibility extends Component { + constructor() { + super( ...arguments ); + this.state = { + opened: false, + }; + this.toggleDialog = this.toggleDialog.bind( this ); + } + + toggleDialog( event ) { + event.preventDefault(); + this.setState( { opened: ! this.state.opened } ); + } + + handleClickOutside() { + this.setState( { opened: false } ); + } + + render() { + const { status, visibility, password, onUpdateVisibility } = this.props; + const visibilityLabels = { + 'public': __( 'Public' ), + 'private': __( 'Private' ), + password: __( 'Password Protected' ), + }; + + const setPublic = () => onUpdateVisibility( visibility === 'private' ? 'draft' : status ); + const setPrivate = () => onUpdateVisibility( 'private' ); + const setPasswordProtected = () => onUpdateVisibility( visibility === 'private' ? 'draft' : status, password || '' ); + const updatePassword = ( event ) => onUpdateVisibility( status, event.target.value ); + + // Disable Reason: The input is inside the label, we shouldn't need the htmlFor + /* eslint-disable jsx-a11y/label-has-for */ + return ( +
+ { __( 'Visibility' ) } + { visibilityLabels[ visibility ] } + + { this.state.opened && +
+
+
+ { __( 'Post Visibility' ) } +
+ + + + { visibility === 'password' && + + } +
+ } +
+ ); + /* eslint-enable jsx-a11y/label-has-for */ + } +} + +export default connect( + ( state ) => ( { + status: getEditedPostStatus( state ), + visibility: getEditedPostVisibility( state ), + password: getEditedPostAttribute( state, 'password' ), + } ), + ( dispatch ) => { + return { + onUpdateVisibility( status, password = null ) { + dispatch( editPost( { status, password } ) ); + }, + }; + } +)( clickOutside( PostVisibility ) ); + diff --git a/editor/sidebar/post-visibility/style.scss b/editor/sidebar/post-visibility/style.scss new file mode 100644 index 0000000000000..c5f0e0d98264f --- /dev/null +++ b/editor/sidebar/post-visibility/style.scss @@ -0,0 +1,56 @@ +.editor-post-visibility { + display: flex; + justify-content: space-between; + align-items: center; + width: 100%; + position: relative; +} + +.editor-post-visibility__dialog { + position: absolute; + top: 30px; + right: 0; + box-shadow: $shadow-popover; + border: 1px solid $light-gray-500; + background: $white; + padding: 10px; + min-width: 240px; +} + +.editor-post-visibility__dialog-arrow { + position: absolute; + border: 10px dashed $light-gray-500; + height: 0; + width: 0; + line-height: 0; + top: -10px; + right: 5px; + 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-post-visibility__dialog-legend { + font-weight: 600; + font-size: 0.9em; +} + +.editor-post-visibility__dialog-label { + display: block; + margin: 10px 0; +} diff --git a/editor/test/selectors.js b/editor/test/selectors.js index 98a487a30cc7c..1a90b4042e4bc 100644 --- a/editor/test/selectors.js +++ b/editor/test/selectors.js @@ -16,6 +16,7 @@ import { getPostEdits, getEditedPostStatus, getEditedPostTitle, + getEditedPostVisibility, getEditedPostPreviewLink, getBlock, getBlocks, @@ -220,6 +221,65 @@ describe( 'selectors', () => { } ); } ); + describe( 'getEditedPostVisibility', () => { + it( 'should return public by default', () => { + const state = { + currentPost: { + status: 'draft', + }, + editor: { + edits: {}, + }, + }; + + expect( getEditedPostVisibility( state ) ).to.equal( 'public' ); + } ); + + it( 'should return private for private posts', () => { + const state = { + currentPost: { + status: 'private', + }, + editor: { + edits: {}, + }, + }; + + expect( getEditedPostVisibility( state ) ).to.equal( 'private' ); + } ); + + it( 'should return private for password for password protected posts', () => { + const state = { + currentPost: { + status: 'draft', + password: 'chicken', + }, + editor: { + edits: {}, + }, + }; + + expect( getEditedPostVisibility( state ) ).to.equal( 'password' ); + } ); + + it( 'should use the edited status and password if edits present', () => { + const state = { + currentPost: { + status: 'draft', + password: 'chicken', + }, + editor: { + edits: { + status: 'private', + password: null, + }, + }, + }; + + expect( getEditedPostVisibility( state ) ).to.equal( 'private' ); + } ); + } ); + describe( 'getEditedPostPreviewLink', () => { it( 'should return null if the post has not link yet', () => { const state = { From 9e2ad76809ddb2de4863796cc93889368c6c603d Mon Sep 17 00:00:00 2001 From: Riad Benguella Date: Thu, 18 May 2017 13:34:32 +0100 Subject: [PATCH 2/4] Chrome: Adding visibility information --- editor/sidebar/post-visibility/index.js | 64 ++++++++++++++++------- editor/sidebar/post-visibility/style.scss | 34 ++++++++++++ 2 files changed, 80 insertions(+), 18 deletions(-) diff --git a/editor/sidebar/post-visibility/index.js b/editor/sidebar/post-visibility/index.js index dc1edca2d5fa2..b071193e91dd6 100644 --- a/editor/sidebar/post-visibility/index.js +++ b/editor/sidebar/post-visibility/index.js @@ -3,12 +3,14 @@ */ import { connect } from 'react-redux'; import clickOutside from 'react-click-outside'; +import { find } from 'lodash'; /** * WordPress dependencies */ import { __ } from 'i18n'; import { Component } from 'element'; +import Dashicon from 'components/dashicon'; /** * Internal Dependencies @@ -26,8 +28,10 @@ class PostVisibility extends Component { super( ...arguments ); this.state = { opened: false, + showInfo: false, }; this.toggleDialog = this.toggleDialog.bind( this ); + this.toggleVisibilityInfo = this.toggleVisibilityInfo.bind( this ); } toggleDialog( event ) { @@ -35,50 +39,74 @@ class PostVisibility extends Component { this.setState( { opened: ! this.state.opened } ); } + toggleVisibilityInfo( event ) { + event.preventDefault(); + this.setState( { showInfo: ! this.state.showInfo } ); + } + handleClickOutside() { this.setState( { opened: false } ); } render() { const { status, visibility, password, onUpdateVisibility } = this.props; - const visibilityLabels = { - 'public': __( 'Public' ), - 'private': __( 'Private' ), - password: __( 'Password Protected' ), - }; const setPublic = () => onUpdateVisibility( visibility === 'private' ? 'draft' : status ); const setPrivate = () => onUpdateVisibility( 'private' ); const setPasswordProtected = () => onUpdateVisibility( visibility === 'private' ? 'draft' : status, password || '' ); const updatePassword = ( event ) => onUpdateVisibility( status, event.target.value ); + const visibilityOptions = [ + { + value: 'public', + label: __( 'Public' ), + info: __( 'Visible to everyone.' ), + changeHandler: setPublic, + }, + { + value: 'private', + label: __( 'Private' ), + info: __( 'Only visible to site admins and editors.' ), + changeHandler: setPrivate, + }, + { + value: 'password', + label: __( 'Password Protected' ), + info: __( 'Protected with a password you choose. Only those with the password can view this post.' ), + changeHandler: setPasswordProtected, + }, + ]; + const getVisibilityLabel = () => find( visibilityOptions, { value: visibility } ).label; + + // Disable Reason: The input is inside the label, we shouldn't need the htmlFor /* eslint-disable jsx-a11y/label-has-for */ return (
{ __( 'Visibility' ) } - { visibilityLabels[ visibility ] } + + { getVisibilityLabel( visibility ) } + { this.state.opened &&
{ __( 'Post Visibility' ) } + + +
- - - + { visibilityOptions.map( ( { value, label, info, changeHandler } ) => ( + + ) ) } { visibility === 'password' && Date: Thu, 18 May 2017 14:58:58 +0100 Subject: [PATCH 3/4] Chrome: Drop the Post visibility info toggle --- editor/sidebar/post-visibility/index.js | 14 +------------- editor/sidebar/post-visibility/style.scss | 21 ++------------------- 2 files changed, 3 insertions(+), 32 deletions(-) diff --git a/editor/sidebar/post-visibility/index.js b/editor/sidebar/post-visibility/index.js index b071193e91dd6..a44372e618034 100644 --- a/editor/sidebar/post-visibility/index.js +++ b/editor/sidebar/post-visibility/index.js @@ -10,7 +10,6 @@ import { find } from 'lodash'; */ import { __ } from 'i18n'; import { Component } from 'element'; -import Dashicon from 'components/dashicon'; /** * Internal Dependencies @@ -28,10 +27,8 @@ class PostVisibility extends Component { super( ...arguments ); this.state = { opened: false, - showInfo: false, }; this.toggleDialog = this.toggleDialog.bind( this ); - this.toggleVisibilityInfo = this.toggleVisibilityInfo.bind( this ); } toggleDialog( event ) { @@ -39,11 +36,6 @@ class PostVisibility extends Component { this.setState( { opened: ! this.state.opened } ); } - toggleVisibilityInfo( event ) { - event.preventDefault(); - this.setState( { showInfo: ! this.state.showInfo } ); - } - handleClickOutside() { this.setState( { opened: false } ); } @@ -78,7 +70,6 @@ class PostVisibility extends Component { ]; const getVisibilityLabel = () => find( visibilityOptions, { value: visibility } ).label; - // Disable Reason: The input is inside the label, we shouldn't need the htmlFor /* eslint-disable jsx-a11y/label-has-for */ return ( @@ -93,15 +84,12 @@ class PostVisibility extends Component {
{ __( 'Post Visibility' ) } - - -
{ visibilityOptions.map( ( { value, label, info, changeHandler } ) => ( ) ) } { visibility === 'password' && diff --git a/editor/sidebar/post-visibility/style.scss b/editor/sidebar/post-visibility/style.scss index e8976473de873..c34444fc62627 100644 --- a/editor/sidebar/post-visibility/style.scss +++ b/editor/sidebar/post-visibility/style.scss @@ -55,31 +55,14 @@ } -.editor-post-visibility__dialog-info-toggle { - display: inline-block; - margin-left: 5px; - color: $dark-gray-100; - - .dashicon { - vertical-align: middle; - } - - &:hover { - color: $dark-gray-300; - } - - &:focus { - box-shadow: none; - } -} - .editor-post-visibility__dialog-label { display: block; margin: 10px 0; } .editor-post-visibility__dialog-password-input { - width: 100%; + width: calc( 100% - 20px ); + margin-left: 20px; } .editor-post-visibility__dialog-info { From 3883e71dc02454f8f5bfe5a9944f5ca563457a33 Mon Sep 17 00:00:00 2001 From: Riad Benguella Date: Thu, 18 May 2017 15:43:41 +0100 Subject: [PATCH 4/4] Chrome: Transform the visibility selector link to a button --- editor/sidebar/post-visibility/index.js | 6 +++--- editor/sidebar/post-visibility/style.scss | 14 ++++++++++++-- 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/editor/sidebar/post-visibility/index.js b/editor/sidebar/post-visibility/index.js index a44372e618034..ea54944f81e94 100644 --- a/editor/sidebar/post-visibility/index.js +++ b/editor/sidebar/post-visibility/index.js @@ -75,9 +75,9 @@ class PostVisibility extends Component { return (
{ __( 'Visibility' ) } - + { this.state.opened &&
@@ -88,7 +88,7 @@ class PostVisibility extends Component { { visibilityOptions.map( ( { value, label, info, changeHandler } ) => ( ) ) } diff --git a/editor/sidebar/post-visibility/style.scss b/editor/sidebar/post-visibility/style.scss index c34444fc62627..a1a7dfd294d23 100644 --- a/editor/sidebar/post-visibility/style.scss +++ b/editor/sidebar/post-visibility/style.scss @@ -6,8 +6,18 @@ position: relative; } -.editor-post-visibility__toggle:focus { - box-shadow: none; +.editor-post-visibility__toggle.button-link { + text-decoration: underline; + color: $blue-wordpress; + + &:focus { + box-shadow: none; + outline: none; + } + + &:hover { + color: $blue-medium; + } } .editor-post-visibility__dialog {