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.jsx25
-rw-r--r--app/assets/javascripts/components/features/account/index.jsx5
-rw-r--r--app/assets/javascripts/components/features/compose/components/compose_form.jsx16
-rw-r--r--app/assets/javascripts/components/features/compose/containers/compose_form_container.jsx8
-rw-r--r--app/assets/javascripts/components/features/status/components/detailed_status.jsx4
6 files changed, 46 insertions, 14 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..d39a06062 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,6 +35,14 @@ 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)) };
 
@@ -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..5ad1ca172 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?' },
@@ -67,6 +68,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 +77,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 +142,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 +185,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/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/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} />;
       }
     }