diff options
author | Eugen Rochko <eugen@zeonfederated.com> | 2016-11-23 18:53:23 +0100 |
---|---|---|
committer | Eugen Rochko <eugen@zeonfederated.com> | 2016-11-23 18:53:23 +0100 |
commit | 2112a81e869fe342d7351b1fb1951df754a5d255 (patch) | |
tree | 5c06c40a97594aada843a429fb26137194ec048b /app | |
parent | 5434ad3002b95f194a013fc327f1fdcabacf649a (diff) |
Adding content sensitivity toggle, spoilers for media
Diffstat (limited to 'app')
8 files changed, 159 insertions, 12 deletions
diff --git a/app/assets/javascripts/components/actions/compose.jsx b/app/assets/javascripts/components/actions/compose.jsx index af3cdbf30..b97cb7b12 100644 --- a/app/assets/javascripts/components/actions/compose.jsx +++ b/app/assets/javascripts/components/actions/compose.jsx @@ -22,6 +22,8 @@ export const COMPOSE_SUGGESTION_SELECT = 'COMPOSE_SUGGESTION_SELECT'; export const COMPOSE_MOUNT = 'COMPOSE_MOUNT'; export const COMPOSE_UNMOUNT = 'COMPOSE_UNMOUNT'; +export const COMPOSE_SENSITIVITY_CHANGE = 'COMPOSE_SENSITIVITY_CHANGE'; + export function changeCompose(text) { return { type: COMPOSE_CHANGE, @@ -62,7 +64,8 @@ export function submitCompose() { api(getState).post('/api/v1/statuses', { status: getState().getIn(['compose', 'text'], ''), in_reply_to_id: getState().getIn(['compose', 'in_reply_to'], null), - media_ids: getState().getIn(['compose', 'media_attachments']).map(item => item.get('id')) + media_ids: getState().getIn(['compose', 'media_attachments']).map(item => item.get('id')), + sensitive: getState().getIn(['compose', 'sensitive']) }).then(function (response) { dispatch(submitComposeSuccess(response.data)); dispatch(updateTimeline('home', response.data)); @@ -197,3 +200,10 @@ export function unmountCompose() { type: COMPOSE_UNMOUNT }; }; + +export function changeComposeSensitivity(checked) { + return { + type: COMPOSE_SENSITIVITY_CHANGE, + checked + }; +}; diff --git a/app/assets/javascripts/components/components/media_gallery.jsx b/app/assets/javascripts/components/components/media_gallery.jsx index e46933f7b..d04c7c869 100644 --- a/app/assets/javascripts/components/components/media_gallery.jsx +++ b/app/assets/javascripts/components/components/media_gallery.jsx @@ -14,16 +14,20 @@ const spoilerStyle = { color: '#fff', textAlign: 'center', height: '100%', - cursor: 'pointer' + cursor: 'pointer', + display: 'flex', + alignItems: 'center', + justifyContent: 'center', + flexDirection: 'column' }; const spoilerSpanStyle = { display: 'block', fontSize: '14px', - paddingTop: '45%' }; const spoilerSubSpanStyle = { + display: 'block', fontSize: '11px', fontWeight: '500' }; diff --git a/app/assets/javascripts/components/components/video_player.jsx b/app/assets/javascripts/components/components/video_player.jsx index a789f65e4..61c1995a7 100644 --- a/app/assets/javascripts/components/components/video_player.jsx +++ b/app/assets/javascripts/components/components/video_player.jsx @@ -26,20 +26,25 @@ const muteStyle = { }; const spoilerStyle = { + marginTop: '8px', background: '#000', color: '#fff', textAlign: 'center', height: '100%', - cursor: 'pointer' + cursor: 'pointer', + display: 'flex', + alignItems: 'center', + justifyContent: 'center', + flexDirection: 'column' }; const spoilerSpanStyle = { display: 'block', - fontSize: '14px', - paddingTop: '45%' + fontSize: '14px' }; const spoilerSubSpanStyle = { + display: 'block', fontSize: '11px', fontWeight: '500' }; @@ -92,7 +97,7 @@ const VideoPlayer = React.createClass({ if (sensitive && !this.state.visible) { return ( - <div style={spoilerStyle} onClick={this.handleOpen}> + <div style={{...spoilerStyle, width: `${width}px`, height: `${height}px` }} onClick={this.handleOpen}> <span style={spoilerSpanStyle}><FormattedMessage id='status.sensitive_warning' defaultMessage='Sensitive content' /></span> <span style={spoilerSubSpanStyle}><FormattedMessage id='status.sensitive_toggle' defaultMessage='Click to view' /></span> </div> 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..7c42e481d 100644 --- a/app/assets/javascripts/components/features/compose/components/compose_form.jsx +++ b/app/assets/javascripts/components/features/compose/components/compose_form.jsx @@ -9,6 +9,7 @@ import AutosuggestAccountContainer from '../../compose/containers/autosuggest_ac import { debounce } from 'react-decoration'; import UploadButtonContainer from '../containers/upload_button_container'; import { defineMessages, injectIntl } 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' }}>Sensitive content</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} />; } } diff --git a/app/assets/javascripts/components/reducers/compose.jsx b/app/assets/javascripts/components/reducers/compose.jsx index e6e86d4f5..4abc3e6aa 100644 --- a/app/assets/javascripts/components/reducers/compose.jsx +++ b/app/assets/javascripts/components/reducers/compose.jsx @@ -15,7 +15,8 @@ import { COMPOSE_UPLOAD_PROGRESS, COMPOSE_SUGGESTIONS_CLEAR, COMPOSE_SUGGESTIONS_READY, - COMPOSE_SUGGESTION_SELECT + COMPOSE_SUGGESTION_SELECT, + COMPOSE_SENSITIVITY_CHANGE } from '../actions/compose'; import { TIMELINE_DELETE } from '../actions/timelines'; import { ACCOUNT_SET_SELF } from '../actions/accounts'; @@ -23,6 +24,7 @@ import Immutable from 'immutable'; const initialState = Immutable.Map({ mounted: false, + sensitive: false, text: '', in_reply_to: null, is_submitting: false, @@ -87,6 +89,8 @@ export default function compose(state = initialState, action) { return state.set('mounted', true); case COMPOSE_UNMOUNT: return state.set('mounted', false); + case COMPOSE_SENSITIVITY_CHANGE: + return state.set('sensitive', action.checked); case COMPOSE_CHANGE: return state.set('text', action.text); case COMPOSE_REPLY: diff --git a/app/assets/stylesheets/components.scss b/app/assets/stylesheets/components.scss index adf0db990..cc9f0eb3b 100644 --- a/app/assets/stylesheets/components.scss +++ b/app/assets/stylesheets/components.scss @@ -405,3 +405,109 @@ text-decoration: underline; } } + +.react-toggle { + display: inline-block; + position: relative; + cursor: pointer; + background-color: transparent; + border: 0; + padding: 0; + user-select: none; + -webkit-tap-highlight-color: rgba(0,0,0,0); + -webkit-tap-highlight-color: transparent; +} + +.react-toggle-screenreader-only { + border: 0; + clip: rect(0 0 0 0); + height: 1px; + margin: -1px; + overflow: hidden; + padding: 0; + position: absolute; + width: 1px; +} + +.react-toggle--disabled { + cursor: not-allowed; + opacity: 0.5; + transition: opacity 0.25s; +} + +.react-toggle-track { + width: 50px; + height: 24px; + padding: 0; + border-radius: 30px; + background-color: #282c37; + transition: all 0.2s ease; +} + +.react-toggle:hover:not(.react-toggle--disabled) .react-toggle-track { + background-color: darken(#282c37, 10%); +} + +.react-toggle--checked .react-toggle-track { + background-color: #2b90d9; +} + +.react-toggle--checked:hover:not(.react-toggle--disabled) .react-toggle-track { + background-color: lighten(#2b90d9, 10%); +} + +.react-toggle-track-check { + position: absolute; + width: 14px; + height: 10px; + top: 0px; + bottom: 0px; + margin-top: auto; + margin-bottom: auto; + line-height: 0; + left: 8px; + opacity: 0; + transition: opacity 0.25s ease; +} + +.react-toggle--checked .react-toggle-track-check { + opacity: 1; + transition: opacity 0.25s ease; +} + +.react-toggle-track-x { + position: absolute; + width: 10px; + height: 10px; + top: 0px; + bottom: 0px; + margin-top: auto; + margin-bottom: auto; + line-height: 0; + right: 10px; + opacity: 1; + transition: opacity 0.25s ease; +} + +.react-toggle--checked .react-toggle-track-x { + opacity: 0; +} + +.react-toggle-thumb { + transition: all 0.5s cubic-bezier(0.23, 1, 0.32, 1) 0ms; + position: absolute; + top: 1px; + left: 1px; + width: 22px; + height: 22px; + border: 1px solid #282c37; + border-radius: 50%; + background-color: #FAFAFA; + box-sizing: border-box; + transition: all 0.25s ease; +} + +.react-toggle--checked .react-toggle-thumb { + left: 27px; + border-color: #2b90d9; +} |