about summary refs log tree commit diff
path: root/app/assets/javascripts/components/features
diff options
context:
space:
mode:
Diffstat (limited to 'app/assets/javascripts/components/features')
-rw-r--r--app/assets/javascripts/components/features/account/components/action_bar.jsx2
-rw-r--r--app/assets/javascripts/components/features/account/components/header.jsx27
-rw-r--r--app/assets/javascripts/components/features/account/index.jsx5
-rw-r--r--app/assets/javascripts/components/features/compose/components/compose_form.jsx19
-rw-r--r--app/assets/javascripts/components/features/compose/components/suggestions_box.jsx86
-rw-r--r--app/assets/javascripts/components/features/compose/containers/compose_form_container.jsx8
-rw-r--r--app/assets/javascripts/components/features/compose/containers/suggestions_container.jsx8
-rw-r--r--app/assets/javascripts/components/features/compose/index.jsx15
-rw-r--r--app/assets/javascripts/components/features/status/components/detailed_status.jsx4
9 files changed, 53 insertions, 121 deletions
diff --git a/app/assets/javascripts/components/features/account/components/action_bar.jsx b/app/assets/javascripts/components/features/account/components/action_bar.jsx
index cd01de2e2..f09dea6ab 100644
--- a/app/assets/javascripts/components/features/account/components/action_bar.jsx
+++ b/app/assets/javascripts/components/features/account/components/action_bar.jsx
@@ -58,10 +58,8 @@ const ActionBar = React.createClass({
     } else if (account.getIn(['relationship', 'blocking'])) {
       menu.push({ text: intl.formatMessage(messages.unblock), action: this.props.onBlock });
     } else if (account.getIn(['relationship', 'following'])) {
-      menu.push({ text: intl.formatMessage(messages.unfollow), action: this.props.onFollow });
       menu.push({ text: intl.formatMessage(messages.block), action: this.props.onBlock });
     } else {
-      menu.push({ text: intl.formatMessage(messages.follow), action: this.props.onFollow });
       menu.push({ text: intl.formatMessage(messages.block), action: this.props.onBlock });
     }
 
diff --git a/app/assets/javascripts/components/features/account/components/header.jsx b/app/assets/javascripts/components/features/account/components/header.jsx
index b3e9e2a9f..b890e15c1 100644
--- a/app/assets/javascripts/components/features/account/components/header.jsx
+++ b/app/assets/javascripts/components/features/account/components/header.jsx
@@ -2,22 +2,30 @@ import PureRenderMixin from 'react-addons-pure-render-mixin';
 import ImmutablePropTypes from 'react-immutable-proptypes';
 import emojify from '../../../emoji';
 import escapeTextContentForBrowser from 'react/lib/escapeTextContentForBrowser';
-import { FormattedMessage } from 'react-intl';
+import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
+import IconButton from '../../../components/icon_button';
+
+const messages = defineMessages({
+  unfollow: { id: 'account.unfollow', defaultMessage: 'Unfollow' },
+  follow: { id: 'account.follow', defaultMessage: 'Follow' },
+});
 
 const Header = React.createClass({
 
   propTypes: {
     account: ImmutablePropTypes.map.isRequired,
-    me: React.PropTypes.number.isRequired
+    me: React.PropTypes.number.isRequired,
+    onFollow: React.PropTypes.func.isRequired
   },
 
   mixins: [PureRenderMixin],
 
   render () {
-    const { account, me } = this.props;
+    const { account, me, intl } = this.props;
 
     let displayName = account.get('display_name');
     let info        = '';
+    let actionBtn   = '';
 
     if (displayName.length === 0) {
       displayName = account.get('username');
@@ -27,11 +35,19 @@ const Header = React.createClass({
       info = <span style={{ position: 'absolute', top: '10px', right: '10px', opacity: '0.7', display: 'inline-block', verticalAlign: 'top', background: 'rgba(0, 0, 0, 0.4)', color: '#fff', textTransform: 'uppercase', fontSize: '11px', fontWeight: '500', padding: '4px', borderRadius: '4px' }}><FormattedMessage id='account.follows_you' defaultMessage='Follows you' /></span>
     }
 
+    if (me !== account.get('id')) {
+      actionBtn = (
+        <div style={{ position: 'absolute', top: '10px', left: '20px' }}>
+          <IconButton size={26} icon={account.getIn(['relationship', 'following']) ? 'user-times' : 'user-plus'} active={account.getIn(['relationship', 'following'])} title={intl.formatMessage(account.getIn(['relationship', 'following']) ? messages.unfollow : messages.follow)} onClick={this.props.onFollow} />
+        </div>
+      );
+    }
+
     const content         = { __html: emojify(account.get('note')) };
     const displayNameHTML = { __html: emojify(escapeTextContentForBrowser(displayName)) };
 
     return (
-      <div style={{ flex: '0 0 auto', background: '#2f3441', textAlign: 'center', backgroundImage: `url(${account.get('header')})`, backgroundSize: 'cover', position: 'relative' }}>
+      <div style={{ flex: '0 0 auto', background: '#2f3441', textAlign: 'center', backgroundImage: `url(${account.get('header')})`, backgroundSize: 'cover', backgroundPosition: 'center', position: 'relative' }}>
         <div style={{ background: 'rgba(47, 52, 65, 0.9)', padding: '20px 10px' }}>
           <a href={account.get('url')} target='_blank' rel='noopener' style={{ display: 'block', color: 'inherit', textDecoration: 'none' }}>
             <div style={{ width: '90px', margin: '0 auto', marginBottom: '10px' }}>
@@ -45,6 +61,7 @@ const Header = React.createClass({
           <div style={{ color: '#616b86', fontSize: '14px' }} className='account__header__content' dangerouslySetInnerHTML={content} />
 
           {info}
+          {actionBtn}
         </div>
       </div>
     );
@@ -52,4 +69,4 @@ const Header = React.createClass({
 
 });
 
-export default Header;
+export default injectIntl(Header);
diff --git a/app/assets/javascripts/components/features/account/index.jsx b/app/assets/javascripts/components/features/account/index.jsx
index 818979f8f..c2cc58bb2 100644
--- a/app/assets/javascripts/components/features/account/index.jsx
+++ b/app/assets/javascripts/components/features/account/index.jsx
@@ -87,9 +87,8 @@ const Account = React.createClass({
     return (
       <Column>
         <ColumnBackButton />
-        <Header account={account} me={me} />
-
-        <ActionBar account={account} me={me} onFollow={this.handleFollow} onBlock={this.handleBlock} onMention={this.handleMention} />
+        <Header account={account} me={me} onFollow={this.handleFollow} />
+        <ActionBar account={account} me={me} onBlock={this.handleBlock} onMention={this.handleMention} />
 
         {this.props.children}
       </Column>
diff --git a/app/assets/javascripts/components/features/compose/components/compose_form.jsx b/app/assets/javascripts/components/features/compose/components/compose_form.jsx
index 32bdeaeca..b16731c05 100644
--- a/app/assets/javascripts/components/features/compose/components/compose_form.jsx
+++ b/app/assets/javascripts/components/features/compose/components/compose_form.jsx
@@ -8,7 +8,8 @@ import Autosuggest from 'react-autosuggest';
 import AutosuggestAccountContainer from '../../compose/containers/autosuggest_account_container';
 import { debounce } from 'react-decoration';
 import UploadButtonContainer from '../containers/upload_button_container';
-import { defineMessages, injectIntl } from 'react-intl';
+import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
+import Toggle from 'react-toggle';
 
 const messages = defineMessages({
   placeholder: { id: 'compose_form.placeholder', defaultMessage: 'What is on your mind?' },
@@ -54,7 +55,8 @@ const textareaStyle = {
   padding: '10px',
   fontFamily: 'Roboto',
   fontSize: '14px',
-  margin: '0'
+  margin: '0',
+  resize: 'vertical'
 };
 
 const renderInputComponent = inputProps => (
@@ -67,6 +69,7 @@ const ComposeForm = React.createClass({
     text: React.PropTypes.string.isRequired,
     suggestion_token: React.PropTypes.string,
     suggestions: React.PropTypes.array,
+    sensitive: React.PropTypes.bool,
     is_submitting: React.PropTypes.bool,
     is_uploading: React.PropTypes.bool,
     in_reply_to: ImmutablePropTypes.map,
@@ -75,7 +78,8 @@ const ComposeForm = React.createClass({
     onCancelReply: React.PropTypes.func.isRequired,
     onClearSuggestions: React.PropTypes.func.isRequired,
     onFetchSuggestions: React.PropTypes.func.isRequired,
-    onSuggestionSelected: React.PropTypes.func.isRequired
+    onSuggestionSelected: React.PropTypes.func.isRequired,
+    onChangeSensitivity: React.PropTypes.func.isRequired
   },
 
   mixins: [PureRenderMixin],
@@ -139,6 +143,10 @@ const ComposeForm = React.createClass({
     this.autosuggest = c;
   },
 
+  handleChangeSensitivity (e) {
+    this.props.onChangeSensitivity(e.target.checked);
+  },
+
   render () {
     const { intl } = this.props;
     let replyArea  = '';
@@ -178,6 +186,11 @@ const ComposeForm = React.createClass({
           <div style={{ float: 'right', marginRight: '16px', lineHeight: '36px' }}><CharacterCounter max={500} text={this.props.text} /></div>
           <UploadButtonContainer style={{ paddingTop: '4px' }} />
         </div>
+
+        <label style={{ display: 'block', lineHeight: '24px', verticalAlign: 'middle', marginTop: '10px', borderTop: '1px solid #616b86', paddingTop: '10px' }}>
+          <Toggle checked={this.props.sensitive} onChange={this.handleChangeSensitivity} />
+          <span style={{ display: 'inline-block', verticalAlign: 'middle', marginBottom: '14px', marginLeft: '8px', color: '#9baec8' }}><FormattedMessage id='compose_form.sensitive' defaultMessage='Mark content as sensitive' /></span>
+        </label>
       </div>
     );
   }
diff --git a/app/assets/javascripts/components/features/compose/components/suggestions_box.jsx b/app/assets/javascripts/components/features/compose/components/suggestions_box.jsx
deleted file mode 100644
index 6850629ba..000000000
--- a/app/assets/javascripts/components/features/compose/components/suggestions_box.jsx
+++ /dev/null
@@ -1,86 +0,0 @@
-import PureRenderMixin from 'react-addons-pure-render-mixin';
-import ImmutablePropTypes from 'react-immutable-proptypes';
-import AccountContainer from '../../../containers/account_container';
-import { FormattedMessage } from 'react-intl';
-
-const outerStyle = {
-  position: 'relative'
-};
-
-const headerStyle = {
-  fontSize: '14px',
-  fontWeight: '500',
-  display: 'block',
-  padding: '10px',
-  color: '#9baec8',
-  background: '#454b5e',
-  overflow: 'hidden'
-};
-
-const nextStyle = {
-  display: 'inline-block',
-  float: 'right',
-  fontWeight: '400',
-  color: '#2b90d9'
-};
-
-const SuggestionsBox = React.createClass({
-
-  propTypes: {
-    accountIds: ImmutablePropTypes.list,
-    perWindow: React.PropTypes.number
-  },
-
-  getInitialState () {
-    return {
-      index: 0
-    };
-  },
-
-  getDefaultProps () {
-    return {
-      perWindow: 2
-    };
-  },
-
-  mixins: [PureRenderMixin],
-
-  handleNextClick (e) {
-    e.preventDefault();
-
-    let newIndex = this.state.index + 1;
-
-    if (this.props.accountIds.skip(this.props.perWindow * newIndex).size === 0) {
-      newIndex = 0;
-    }
-
-    this.setState({ index: newIndex });
-  },
-
-  render () {
-    const { accountIds, perWindow } = this.props;
-
-    if (!accountIds || accountIds.size === 0) {
-      return <div />;
-    }
-
-    let nextLink = '';
-
-    if (accountIds.size > perWindow) {
-      nextLink = <a href='#' style={nextStyle} onClick={this.handleNextClick}><FormattedMessage id='suggestions_box.refresh' defaultMessage='Refresh' /></a>;
-    }
-
-    return (
-      <div style={outerStyle}>
-        <strong style={headerStyle}>
-          <FormattedMessage id='suggestions_box.who_to_follow' defaultMessage='Who to follow' /> {nextLink}
-        </strong>
-
-        {accountIds.skip(perWindow * this.state.index).take(perWindow).map(accountId => <AccountContainer key={accountId} id={accountId} withNote={false} />)}
-      </div>
-    );
-  }
-
-});
-
-export default SuggestionsBox;
diff --git a/app/assets/javascripts/components/features/compose/containers/compose_form_container.jsx b/app/assets/javascripts/components/features/compose/containers/compose_form_container.jsx
index 87bcd6b99..9897f6505 100644
--- a/app/assets/javascripts/components/features/compose/containers/compose_form_container.jsx
+++ b/app/assets/javascripts/components/features/compose/containers/compose_form_container.jsx
@@ -6,7 +6,8 @@ import {
   cancelReplyCompose,
   clearComposeSuggestions,
   fetchComposeSuggestions,
-  selectComposeSuggestion
+  selectComposeSuggestion,
+  changeComposeSensitivity
 } from '../../../actions/compose';
 import { makeGetStatus } from '../../../selectors';
 
@@ -18,6 +19,7 @@ const makeMapStateToProps = () => {
       text: state.getIn(['compose', 'text']),
       suggestion_token: state.getIn(['compose', 'suggestion_token']),
       suggestions: state.getIn(['compose', 'suggestions']).toJS(),
+      sensitive: state.getIn(['compose', 'sensitive']),
       is_submitting: state.getIn(['compose', 'is_submitting']),
       is_uploading: state.getIn(['compose', 'is_uploading']),
       in_reply_to: getStatus(state, state.getIn(['compose', 'in_reply_to']))
@@ -51,6 +53,10 @@ const mapDispatchToProps = function (dispatch) {
 
     onSuggestionSelected (position, accountId) {
       dispatch(selectComposeSuggestion(position, accountId));
+    },
+
+    onChangeSensitivity (checked) {
+      dispatch(changeComposeSensitivity(checked));
     }
   }
 };
diff --git a/app/assets/javascripts/components/features/compose/containers/suggestions_container.jsx b/app/assets/javascripts/components/features/compose/containers/suggestions_container.jsx
deleted file mode 100644
index 944ceed85..000000000
--- a/app/assets/javascripts/components/features/compose/containers/suggestions_container.jsx
+++ /dev/null
@@ -1,8 +0,0 @@
-import { connect }           from 'react-redux';
-import SuggestionsBox        from '../components/suggestions_box';
-
-const mapStateToProps = (state) => ({
-  accountIds: state.getIn(['user_lists', 'suggestions'])
-});
-
-export default connect(mapStateToProps)(SuggestionsBox);
diff --git a/app/assets/javascripts/components/features/compose/index.jsx b/app/assets/javascripts/components/features/compose/index.jsx
index 5c1b22e00..4017c8949 100644
--- a/app/assets/javascripts/components/features/compose/index.jsx
+++ b/app/assets/javascripts/components/features/compose/index.jsx
@@ -3,9 +3,7 @@ import ComposeFormContainer from './containers/compose_form_container';
 import UploadFormContainer from './containers/upload_form_container';
 import NavigationContainer from './containers/navigation_container';
 import PureRenderMixin from 'react-addons-pure-render-mixin';
-import SuggestionsContainer from './containers/suggestions_container';
 import SearchContainer from './containers/search_container';
-import { fetchSuggestions } from '../../actions/suggestions';
 import { connect } from 'react-redux';
 import { mountCompose, unmountCompose } from '../../actions/compose';
 
@@ -19,7 +17,6 @@ const Compose = React.createClass({
 
   componentDidMount () {
     this.props.dispatch(mountCompose());
-    this.props.dispatch(fetchSuggestions());
   },
 
   componentWillUnmount () {
@@ -29,14 +26,10 @@ const Compose = React.createClass({
   render () {
     return (
       <Drawer>
-        <div style={{ flex: '1 1 auto' }}>
-          <SearchContainer />
-          <NavigationContainer />
-          <ComposeFormContainer />
-          <UploadFormContainer />
-        </div>
-
-        <SuggestionsContainer />
+        <SearchContainer />
+        <NavigationContainer />
+        <ComposeFormContainer />
+        <UploadFormContainer />
       </Drawer>
     );
   }
diff --git a/app/assets/javascripts/components/features/status/components/detailed_status.jsx b/app/assets/javascripts/components/features/status/components/detailed_status.jsx
index 76ddafb3b..b967d966f 100644
--- a/app/assets/javascripts/components/features/status/components/detailed_status.jsx
+++ b/app/assets/javascripts/components/features/status/components/detailed_status.jsx
@@ -36,9 +36,9 @@ const DetailedStatus = React.createClass({
 
     if (status.get('media_attachments').size > 0) {
       if (status.getIn(['media_attachments', 0, 'type']) === 'video') {
-        media = <VideoPlayer media={status.getIn(['media_attachments', 0])} width={317} height={178} />;
+        media = <VideoPlayer sensitive={status.get('sensitive')} media={status.getIn(['media_attachments', 0])} width={317} height={178} />;
       } else {
-        media = <MediaGallery media={status.get('media_attachments')} height={300} onOpenMedia={this.props.onOpenMedia} />;
+        media = <MediaGallery sensitive={status.get('sensitive')} media={status.get('media_attachments')} height={300} onOpenMedia={this.props.onOpenMedia} />;
       }
     }