From 58ffd61884b7597fdb4672d552dfc2c8a235c15d Mon Sep 17 00:00:00 2001 From: Benjamin Goering Date: Mon, 10 Apr 2017 16:13:53 -0700 Subject: [PATCH] Move TopRightMenu component out of Comment and into own file --- client/coral-embed-stream/src/Comment.css | 64 +------ client/coral-embed-stream/src/Comment.js | 166 +----------------- .../coral-embed-stream/src/TopRightMenu.css | 39 ++++ client/coral-embed-stream/src/TopRightMenu.js | 156 ++++++++++++++++ 4 files changed, 197 insertions(+), 228 deletions(-) create mode 100644 client/coral-embed-stream/src/TopRightMenu.css create mode 100644 client/coral-embed-stream/src/TopRightMenu.js diff --git a/client/coral-embed-stream/src/Comment.css b/client/coral-embed-stream/src/Comment.css index 6f89208bc..b463aa247 100644 --- a/client/coral-embed-stream/src/Comment.css +++ b/client/coral-embed-stream/src/Comment.css @@ -16,71 +16,9 @@ .topRightMenu { float: right; text-align: right; + cursor: pointer; } .topRightMenu > * { text-align: initial; } - -.topRightMenu .toggler { - cursor: pointer; -} - -.topRightMenu .Menu { - background-color: white; - text-align: initial; -} - -.Toggleable:focus { - outline: none; -} - -.Menu { - border: 1px solid #ddd; - margin: 0; -} -ul.Menu { - list-style-type: none; - padding: 0; -} - -.MenuItem { - cursor: pointer; - padding: 1em; -} - -.IgnoreUserWizard { - background-color: #2E343B; - color: white; - padding: 1em; - max-width: 220px; -} - -.IgnoreUserWizard header { - font-weight: bold; -} - -.IgnoreUserWizard .textAlignRight { - text-align: right; -} - -/** - * Up/Down Chevrons for the top right menu - */ -.chevron { -} -.chevron:before { - content: '⌃'; - display: inline-block; - position: relative; - top: 0.25em; -} - -/* Down Arrow */ -.chevron.down:before { - display: inline-block; - position: relative; - transform: rotate(180deg); - top: 0; - /*top: -0.25em;*/ -} diff --git a/client/coral-embed-stream/src/Comment.js b/client/coral-embed-stream/src/Comment.js index 9ed0bee23..4b01e19a7 100644 --- a/client/coral-embed-stream/src/Comment.js +++ b/client/coral-embed-stream/src/Comment.js @@ -11,7 +11,6 @@ import PermalinkButton from 'coral-plugin-permalinks/PermalinkButton'; import AuthorName from 'coral-plugin-author-name/AuthorName'; -import {Button} from 'coral-ui'; import TagLabel from 'coral-plugin-tag-label/TagLabel'; import Content from 'coral-plugin-commentcontent/CommentContent'; import PubDate from 'coral-plugin-pubdate/PubDate'; @@ -22,9 +21,9 @@ import {BestButton, IfUserCanModifyBest, BEST_TAG, commentIsBest, BestIndicator} import LoadMore from 'coral-embed-stream/src/LoadMore'; import {Slot} from 'coral-framework'; import IgnoredCommentTombstone from './IgnoredCommentTombstone'; +import {TopRightMenu} from './TopRightMenu'; import styles from './Comment.css'; -import classnames from 'classnames'; const getActionSummary = (type, comment) => comment.action_summaries .filter((a) => a.__typename === type)[0]; @@ -152,126 +151,6 @@ class Comment extends React.Component { tag: BEST_TAG, }), () => 'Failed to remove best comment tag'); - class IgnoreUserWizard extends React.Component { - static propTypes = { - - // comment on which this menu appears - user: PropTypes.shape({ - id: PropTypes.string.isRequired, - name: PropTypes.string.isRequired - }).isRequired, - cancel: PropTypes.func.isRequired, - - // actually submit the ignore. Provide {id: user id to ignore} - ignoreUser: PropTypes.func.isRequired, - } - constructor(props) { - super(props); - this.state = { - - // what step of the wizard is the user on - step: 1 - }; - this.onClickCancel = this.onClickCancel.bind(this); - } - onClickCancel() { - this.props.cancel(); - } - render() { - const {user, ignoreUser} = this.props; - const goToStep = (stepNum) => this.setState({step: stepNum}); - const step1 = ( -
-
Ignore User
-

When you ignore a user, all comments they wrote on the site will be hidden from you. You can undo this later from the Profile tab.

-
- - -
-
- ); - const onClickIgnoreUser = async () => { - await ignoreUser({id: user.id}); - }; - const step2Confirmation = ( -
-
Ignore User
-

Are you sure you want to ignore { user.name }?

-
- - -
-
- ); - const elsForStep = [step1, step2Confirmation]; - const {step} = this.state; - const elForThisStep = elsForStep[step - 1]; - return ( -
- { elForThisStep } -
- ); - } - } - - // TopRightMenu appears as a dropdown in the top right of the comment. - // when you click the down cehvron, it expands and shows IgnoreUserWizard - // when you click 'cancel' in the wizard, it closes the menu - class TopRightMenu extends React.Component { - static propTypes = { - - // comment on which this menu appears - comment: PropTypes.shape({ - user: PropTypes.shape({ - id: PropTypes.string.isRequired, - name: PropTypes.string.isRequired - }).isRequired - }).isRequired, - ignoreUser: PropTypes.func, - - // show notification to the user (e.g. for errors) - addNotification: PropTypes.func.isRequired, - } - constructor(props) { - super(props); - this.state = { - timesReset: 0 - }; - } - render() { - const {comment, ignoreUser, addNotification} = this.props; - - // timesReset is used as Toggleable key so it re-renders on reset (closing the toggleable) - const reset = () => this.setState({timesReset: this.state.timesReset + 1}); - const ignoreUserAndCloseMenuAndNotifyOnError = async ({id}) => { - - // close menu - reset(); - - // ignore user - let errorToThrow; - try { - await ignoreUser({id}); - } catch (error) { - addNotification('error', 'Failed to ignore user'); - errorToThrow = error; - } - throw errorToThrow; - }; - return ( - -
- -
-
- ); - } - } - return (
; -const downArrow = ; -class Toggleable extends React.Component { - constructor(props) { - super(props); - this.toggle = this.toggle.bind(this); - this.close = this.close.bind(this); - this.state = { - isOpen: false - }; - } - toggle() { - this.setState({isOpen: ! this.state.isOpen}); - } - close() { - this.setState({isOpen: false}); - } - render() { - const {children} = this.props; - const {isOpen} = this.state; - return ( - - // /*onBlur={ this.close } */ - - {isOpen ? upArrow : downArrow} - {isOpen ? children : null} - - ); - } -} -const Menu = ({children}) => ( - -); -Menu.Item = ({children, onClick}) => ( -
  • - { children } -
  • -); - export default Comment; diff --git a/client/coral-embed-stream/src/TopRightMenu.css b/client/coral-embed-stream/src/TopRightMenu.css new file mode 100644 index 000000000..587920c5f --- /dev/null +++ b/client/coral-embed-stream/src/TopRightMenu.css @@ -0,0 +1,39 @@ +.Toggleable:focus { + outline: none; +} + +.IgnoreUserWizard { + background-color: #2E343B; + color: white; + padding: 1em; + max-width: 220px; +} + +.IgnoreUserWizard header { + font-weight: bold; +} + +.IgnoreUserWizard .textAlignRight { + text-align: right; +} + +/** + * Up/Down Chevrons for the top right menu + */ +.chevron { +} +.chevron:before { + content: '⌃'; + display: inline-block; + position: relative; + top: 0.25em; +} + +/* Down Arrow */ +.chevron.down:before { + display: inline-block; + position: relative; + transform: rotate(180deg); + top: 0; + /*top: -0.25em;*/ +} diff --git a/client/coral-embed-stream/src/TopRightMenu.js b/client/coral-embed-stream/src/TopRightMenu.js new file mode 100644 index 000000000..1e06997dd --- /dev/null +++ b/client/coral-embed-stream/src/TopRightMenu.js @@ -0,0 +1,156 @@ +import React, {PropTypes} from 'react'; +import classnames from 'classnames'; + +import {Button} from 'coral-ui'; +import styles from './TopRightMenu.css'; + +// TopRightMenu appears as a dropdown in the top right of the comment. +// when you click the down cehvron, it expands and shows IgnoreUserWizard +// when you click 'cancel' in the wizard, it closes the menu +export class TopRightMenu extends React.Component { + static propTypes = { + + // comment on which this menu appears + comment: PropTypes.shape({ + user: PropTypes.shape({ + id: PropTypes.string.isRequired, + name: PropTypes.string.isRequired + }).isRequired + }).isRequired, + ignoreUser: PropTypes.func, + + // show notification to the user (e.g. for errors) + addNotification: PropTypes.func.isRequired, + } + constructor(props) { + super(props); + this.state = { + timesReset: 0 + }; + } + render() { + const {comment, ignoreUser, addNotification} = this.props; + + // timesReset is used as Toggleable key so it re-renders on reset (closing the toggleable) + const reset = () => this.setState({timesReset: this.state.timesReset + 1}); + const ignoreUserAndCloseMenuAndNotifyOnError = async ({id}) => { + + // close menu + reset(); + + // ignore user + try { + await ignoreUser({id}); + } catch (error) { + addNotification('error', 'Failed to ignore user'); + throw error; + } + }; + return ( + +
    + +
    +
    + ); + } +} + +class IgnoreUserWizard extends React.Component { + static propTypes = { + + // comment on which this menu appears + user: PropTypes.shape({ + id: PropTypes.string.isRequired, + name: PropTypes.string.isRequired + }).isRequired, + cancel: PropTypes.func.isRequired, + + // actually submit the ignore. Provide {id: user id to ignore} + ignoreUser: PropTypes.func.isRequired, + } + constructor(props) { + super(props); + this.state = { + + // what step of the wizard is the user on + step: 1 + }; + this.onClickCancel = this.onClickCancel.bind(this); + } + onClickCancel() { + this.props.cancel(); + } + render() { + const {user, ignoreUser} = this.props; + const goToStep = (stepNum) => this.setState({step: stepNum}); + const step1 = ( +
    +
    Ignore User
    +

    When you ignore a user, all comments they wrote on the site will be hidden from you. You can undo this later from the Profile tab.

    +
    + + +
    +
    + ); + const onClickIgnoreUser = async () => { + await ignoreUser({id: user.id}); + }; + const step2Confirmation = ( +
    +
    Ignore User
    +

    Are you sure you want to ignore { user.name }?

    +
    + + +
    +
    + ); + const elsForStep = [step1, step2Confirmation]; + const {step} = this.state; + const elForThisStep = elsForStep[step - 1]; + return ( +
    + { elForThisStep } +
    + ); + } +} + +const upArrow = ; +const downArrow = ; +class Toggleable extends React.Component { + constructor(props) { + super(props); + this.toggle = this.toggle.bind(this); + this.close = this.close.bind(this); + this.state = { + isOpen: false + }; + } + toggle() { + this.setState({isOpen: ! this.state.isOpen}); + } + close() { + this.setState({isOpen: false}); + } + render() { + const {children} = this.props; + const {isOpen} = this.state; + return ( + + // /*onBlur={ this.close } */ + + {isOpen ? upArrow : downArrow} + {isOpen ? children : null} + + ); + } +} +