forked from treehouse/mastodon
Making upload button into a smaller icon button
parent
d42ed78aa4
commit
50d3083cbd
|
@ -1,48 +0,0 @@
|
||||||
import api from '../api'
|
|
||||||
|
|
||||||
export const FOLLOW_CHANGE = 'FOLLOW_CHANGE';
|
|
||||||
export const FOLLOW_SUBMIT_REQUEST = 'FOLLOW_SUBMIT_REQUEST';
|
|
||||||
export const FOLLOW_SUBMIT_SUCCESS = 'FOLLOW_SUBMIT_SUCCESS';
|
|
||||||
export const FOLLOW_SUBMIT_FAIL = 'FOLLOW_SUBMIT_FAIL';
|
|
||||||
|
|
||||||
export function changeFollow(text) {
|
|
||||||
return {
|
|
||||||
type: FOLLOW_CHANGE,
|
|
||||||
text: text
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
export function submitFollow(router) {
|
|
||||||
return function (dispatch, getState) {
|
|
||||||
dispatch(submitFollowRequest());
|
|
||||||
|
|
||||||
api(getState).post('/api/v1/follows', {
|
|
||||||
uri: getState().getIn(['follow', 'text'])
|
|
||||||
}).then(function (response) {
|
|
||||||
dispatch(submitFollowSuccess(response.data));
|
|
||||||
router.push(`/accounts/${response.data.id}`);
|
|
||||||
}).catch(function (error) {
|
|
||||||
dispatch(submitFollowFail(error));
|
|
||||||
});
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
export function submitFollowRequest() {
|
|
||||||
return {
|
|
||||||
type: FOLLOW_SUBMIT_REQUEST
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
export function submitFollowSuccess(account) {
|
|
||||||
return {
|
|
||||||
type: FOLLOW_SUBMIT_SUCCESS,
|
|
||||||
account: account
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
export function submitFollowFail(error) {
|
|
||||||
return {
|
|
||||||
type: FOLLOW_SUBMIT_FAIL,
|
|
||||||
error: error
|
|
||||||
};
|
|
||||||
};
|
|
|
@ -7,6 +7,7 @@ import UploadButton from './upload_button';
|
||||||
import Autosuggest from 'react-autosuggest';
|
import Autosuggest from 'react-autosuggest';
|
||||||
import AutosuggestAccountContainer from '../../compose/containers/autosuggest_account_container';
|
import AutosuggestAccountContainer from '../../compose/containers/autosuggest_account_container';
|
||||||
import { debounce } from 'react-decoration';
|
import { debounce } from 'react-decoration';
|
||||||
|
import UploadButtonContainer from '../containers/upload_button_container';
|
||||||
|
|
||||||
const getTokenForSuggestions = (str, caretPosition) => {
|
const getTokenForSuggestions = (str, caretPosition) => {
|
||||||
let word;
|
let word;
|
||||||
|
@ -168,6 +169,7 @@ const ComposeForm = React.createClass({
|
||||||
<div style={{ marginTop: '10px', overflow: 'hidden' }}>
|
<div style={{ marginTop: '10px', overflow: 'hidden' }}>
|
||||||
<div style={{ float: 'right' }}><Button text='Publish' onClick={this.handleSubmit} disabled={disabled} /></div>
|
<div style={{ float: 'right' }}><Button text='Publish' onClick={this.handleSubmit} disabled={disabled} /></div>
|
||||||
<div style={{ float: 'right', marginRight: '16px', lineHeight: '36px' }}><CharacterCounter max={500} text={this.props.text} /></div>
|
<div style={{ float: 'right', marginRight: '16px', lineHeight: '36px' }}><CharacterCounter max={500} text={this.props.text} /></div>
|
||||||
|
<UploadButtonContainer style={{ paddingTop: '4px' }} />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
|
@ -1,11 +1,12 @@
|
||||||
import PureRenderMixin from 'react-addons-pure-render-mixin';
|
import PureRenderMixin from 'react-addons-pure-render-mixin';
|
||||||
import Button from '../../../components/button';
|
import IconButton from '../../../components/icon_button';
|
||||||
|
|
||||||
const UploadButton = React.createClass({
|
const UploadButton = React.createClass({
|
||||||
|
|
||||||
propTypes: {
|
propTypes: {
|
||||||
disabled: React.PropTypes.bool,
|
disabled: React.PropTypes.bool,
|
||||||
onSelectFile: React.PropTypes.func.isRequired
|
onSelectFile: React.PropTypes.func.isRequired,
|
||||||
|
style: React.PropTypes.object
|
||||||
},
|
},
|
||||||
|
|
||||||
mixins: [PureRenderMixin],
|
mixins: [PureRenderMixin],
|
||||||
|
@ -17,17 +18,18 @@ const UploadButton = React.createClass({
|
||||||
},
|
},
|
||||||
|
|
||||||
handleClick () {
|
handleClick () {
|
||||||
this.refs.fileElement.click();
|
this.fileElement.click();
|
||||||
|
},
|
||||||
|
|
||||||
|
setRef (c) {
|
||||||
|
this.fileElement = c;
|
||||||
},
|
},
|
||||||
|
|
||||||
render () {
|
render () {
|
||||||
return (
|
return (
|
||||||
<div>
|
<div style={this.props.style}>
|
||||||
<Button disabled={this.props.disabled} onClick={this.handleClick} block={true}>
|
<IconButton icon='photo' title='Add media' disabled={this.props.disabled} onClick={this.handleClick} size={24} />
|
||||||
<i className='fa fa-fw fa-photo' /> Add media
|
<input ref={this.setRef} type='file' multiple={false} onChange={this.handleChange} disabled={this.props.disabled} style={{ display: 'none' }} />
|
||||||
</Button>
|
|
||||||
|
|
||||||
<input ref='fileElement' type='file' multiple={false} onChange={this.handleChange} disabled={this.props.disabled} style={{ display: 'none' }} />
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
|
@ -0,0 +1,34 @@
|
||||||
|
import PureRenderMixin from 'react-addons-pure-render-mixin';
|
||||||
|
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||||
|
import IconButton from '../../../components/icon_button';
|
||||||
|
|
||||||
|
const UploadForm = React.createClass({
|
||||||
|
|
||||||
|
propTypes: {
|
||||||
|
media: ImmutablePropTypes.list.isRequired,
|
||||||
|
is_uploading: React.PropTypes.bool,
|
||||||
|
onSelectFile: React.PropTypes.func.isRequired,
|
||||||
|
onRemoveFile: React.PropTypes.func.isRequired
|
||||||
|
},
|
||||||
|
|
||||||
|
mixins: [PureRenderMixin],
|
||||||
|
|
||||||
|
render () {
|
||||||
|
const uploads = this.props.media.map(attachment => (
|
||||||
|
<div key={attachment.get('id')} style={{ borderRadius: '4px', marginBottom: '10px' }} className='transparent-background'>
|
||||||
|
<div style={{ width: '100%', height: '100px', borderRadius: '4px', background: `url(${attachment.get('preview_url')}) no-repeat center`, backgroundSize: 'cover' }}>
|
||||||
|
<IconButton icon='times' title='Undo' size={36} onClick={this.props.onRemoveFile.bind(this, attachment.get('id'))} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
));
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div style={{ marginBottom: '20px', padding: '10px', overflow: 'hidden' }}>
|
||||||
|
{uploads}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
export default UploadForm;
|
|
@ -0,0 +1,17 @@
|
||||||
|
import { connect } from 'react-redux';
|
||||||
|
import UploadButton from '../components/upload_button';
|
||||||
|
import { uploadCompose } from '../../../actions/compose';
|
||||||
|
|
||||||
|
const mapStateToProps = state => ({
|
||||||
|
disabled: state.getIn(['compose', 'is_uploading']) || (state.getIn(['compose', 'media_attachments']).size > 3 || state.getIn(['compose', 'media_attachments']).some(m => m.get('type') === 'video')),
|
||||||
|
});
|
||||||
|
|
||||||
|
const mapDispatchToProps = dispatch => ({
|
||||||
|
|
||||||
|
onSelectFile (files) {
|
||||||
|
dispatch(uploadCompose(files));
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
export default connect(mapStateToProps, mapDispatchToProps)(UploadButton);
|
|
@ -0,0 +1,17 @@
|
||||||
|
import { connect } from 'react-redux';
|
||||||
|
import UploadForm from '../components/upload_form';
|
||||||
|
import { undoUploadCompose } from '../../../actions/compose';
|
||||||
|
|
||||||
|
const mapStateToProps = (state, props) => ({
|
||||||
|
media: state.getIn(['compose', 'media_attachments']),
|
||||||
|
});
|
||||||
|
|
||||||
|
const mapDispatchToProps = dispatch => ({
|
||||||
|
|
||||||
|
onRemoveFile (media_id) {
|
||||||
|
dispatch(undoUploadCompose(media_id));
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
export default connect(mapStateToProps, mapDispatchToProps)(UploadForm);
|
|
@ -1,8 +1,7 @@
|
||||||
import Drawer from '../ui/components/drawer';
|
import Drawer from './components/drawer';
|
||||||
import ComposeFormContainer from '../ui/containers/compose_form_container';
|
import ComposeFormContainer from './containers/compose_form_container';
|
||||||
import FollowFormContainer from '../ui/containers/follow_form_container';
|
import UploadFormContainer from './containers/upload_form_container';
|
||||||
import UploadFormContainer from '../ui/containers/upload_form_container';
|
import NavigationContainer from './containers/navigation_container';
|
||||||
import NavigationContainer from '../ui/containers/navigation_container';
|
|
||||||
import PureRenderMixin from 'react-addons-pure-render-mixin';
|
import PureRenderMixin from 'react-addons-pure-render-mixin';
|
||||||
import SuggestionsContainer from './containers/suggestions_container';
|
import SuggestionsContainer from './containers/suggestions_container';
|
||||||
import SearchContainer from './containers/search_container';
|
import SearchContainer from './containers/search_container';
|
||||||
|
|
|
@ -1,44 +0,0 @@
|
||||||
import IconButton from '../../../components/icon_button';
|
|
||||||
import PureRenderMixin from 'react-addons-pure-render-mixin';
|
|
||||||
|
|
||||||
const FollowForm = React.createClass({
|
|
||||||
|
|
||||||
contextTypes: {
|
|
||||||
router: React.PropTypes.object
|
|
||||||
},
|
|
||||||
|
|
||||||
propTypes: {
|
|
||||||
text: React.PropTypes.string.isRequired,
|
|
||||||
is_submitting: React.PropTypes.bool,
|
|
||||||
onChange: React.PropTypes.func.isRequired,
|
|
||||||
onSubmit: React.PropTypes.func.isRequired
|
|
||||||
},
|
|
||||||
|
|
||||||
mixins: [PureRenderMixin],
|
|
||||||
|
|
||||||
handleChange (e) {
|
|
||||||
this.props.onChange(e.target.value);
|
|
||||||
},
|
|
||||||
|
|
||||||
handleKeyUp (e) {
|
|
||||||
if (e.keyCode === 13) {
|
|
||||||
this.handleSubmit();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
handleSubmit () {
|
|
||||||
this.props.onSubmit(this.context.router);
|
|
||||||
},
|
|
||||||
|
|
||||||
render () {
|
|
||||||
return (
|
|
||||||
<div style={{ display: 'flex', lineHeight: '20px', padding: '10px', background: '#373b4a' }}>
|
|
||||||
<input autoComplete='off' type='text' disabled={this.props.is_submitting} placeholder='username@domain' value={this.props.text} onKeyUp={this.handleKeyUp} onChange={this.handleChange} className='follow-form__input' style={{ flex: '1 1 auto', boxSizing: 'border-box', display: 'block', border: 'none', padding: '10px', fontFamily: 'Roboto', color: '#282c37', fontSize: '14px', margin: '0' }} />
|
|
||||||
<div style={{ padding: '10px', paddingRight: '0' }}><IconButton title='Follow' size={20} icon='user-plus' onClick={this.handleSubmit} disabled={this.props.is_submitting} /></div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
export default FollowForm;
|
|
|
@ -1,43 +0,0 @@
|
||||||
import PureRenderMixin from 'react-addons-pure-render-mixin';
|
|
||||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
|
||||||
import UploadButton from './upload_button';
|
|
||||||
import IconButton from '../../../components/icon_button';
|
|
||||||
|
|
||||||
const UploadForm = React.createClass({
|
|
||||||
|
|
||||||
propTypes: {
|
|
||||||
media: ImmutablePropTypes.list.isRequired,
|
|
||||||
is_uploading: React.PropTypes.bool,
|
|
||||||
onSelectFile: React.PropTypes.func.isRequired,
|
|
||||||
onRemoveFile: React.PropTypes.func.isRequired
|
|
||||||
},
|
|
||||||
|
|
||||||
mixins: [PureRenderMixin],
|
|
||||||
|
|
||||||
render () {
|
|
||||||
let uploads = this.props.media.map(function (attachment) {
|
|
||||||
return (
|
|
||||||
<div key={attachment.get('id')} style={{ borderRadius: '4px', marginBottom: '10px' }} className='transparent-background'>
|
|
||||||
<div style={{ width: '100%', height: '100px', borderRadius: '4px', background: `url(${attachment.get('preview_url')}) no-repeat center`, backgroundSize: 'cover' }}>
|
|
||||||
<IconButton icon='times' title='Undo' size={36} onClick={() => this.props.onRemoveFile(attachment.get('id'))} />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}.bind(this));
|
|
||||||
|
|
||||||
const noMoreAllowed = (this.props.media.some(m => m.get('type') === 'video')) || (this.props.media.size > 3);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div style={{ marginBottom: '20px', padding: '10px', paddingTop: '0' }}>
|
|
||||||
<UploadButton onSelectFile={this.props.onSelectFile} disabled={this.props.is_uploading || noMoreAllowed } />
|
|
||||||
|
|
||||||
<div style={{ marginTop: '10px', overflow: 'hidden' }}>
|
|
||||||
{uploads}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
export default UploadForm;
|
|
|
@ -1,24 +0,0 @@
|
||||||
import { connect } from 'react-redux';
|
|
||||||
import FollowForm from '../components/follow_form';
|
|
||||||
import { changeFollow, submitFollow } from '../../../actions/follow';
|
|
||||||
|
|
||||||
const mapStateToProps = function (state, props) {
|
|
||||||
return {
|
|
||||||
text: state.getIn(['follow', 'text']),
|
|
||||||
is_submitting: state.getIn(['follow', 'is_submitting'])
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
const mapDispatchToProps = function (dispatch) {
|
|
||||||
return {
|
|
||||||
onChange: function (text) {
|
|
||||||
dispatch(changeFollow(text));
|
|
||||||
},
|
|
||||||
|
|
||||||
onSubmit: function (router) {
|
|
||||||
dispatch(submitFollow(router));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
export default connect(mapStateToProps, mapDispatchToProps)(FollowForm);
|
|
|
@ -1,25 +0,0 @@
|
||||||
import { connect } from 'react-redux';
|
|
||||||
import UploadForm from '../components/upload_form';
|
|
||||||
import { uploadCompose, undoUploadCompose } from '../../../actions/compose';
|
|
||||||
|
|
||||||
const mapStateToProps = function (state, props) {
|
|
||||||
return {
|
|
||||||
media: state.getIn(['compose', 'media_attachments']),
|
|
||||||
progress: state.getIn(['compose', 'progress']),
|
|
||||||
is_uploading: state.getIn(['compose', 'is_uploading'])
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
const mapDispatchToProps = function (dispatch) {
|
|
||||||
return {
|
|
||||||
onSelectFile: function (files) {
|
|
||||||
dispatch(uploadCompose(files));
|
|
||||||
},
|
|
||||||
|
|
||||||
onRemoveFile: function (media_id) {
|
|
||||||
dispatch(undoUploadCompose(media_id));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
export default connect(mapStateToProps, mapDispatchToProps)(UploadForm);
|
|
|
@ -1,29 +0,0 @@
|
||||||
import {
|
|
||||||
FOLLOW_CHANGE,
|
|
||||||
FOLLOW_SUBMIT_REQUEST,
|
|
||||||
FOLLOW_SUBMIT_SUCCESS,
|
|
||||||
FOLLOW_SUBMIT_FAIL
|
|
||||||
} from '../actions/follow';
|
|
||||||
import Immutable from 'immutable';
|
|
||||||
|
|
||||||
const initialState = Immutable.Map({
|
|
||||||
text: '',
|
|
||||||
is_submitting: false
|
|
||||||
});
|
|
||||||
|
|
||||||
export default function follow(state = initialState, action) {
|
|
||||||
switch(action.type) {
|
|
||||||
case FOLLOW_CHANGE:
|
|
||||||
return state.set('text', action.text);
|
|
||||||
case FOLLOW_SUBMIT_REQUEST:
|
|
||||||
return state.set('is_submitting', true);
|
|
||||||
case FOLLOW_SUBMIT_SUCCESS:
|
|
||||||
return state.withMutations(map => {
|
|
||||||
map.set('text', '').set('is_submitting', false);
|
|
||||||
});
|
|
||||||
case FOLLOW_SUBMIT_FAIL:
|
|
||||||
return state.set('is_submitting', false);
|
|
||||||
default:
|
|
||||||
return state;
|
|
||||||
}
|
|
||||||
};
|
|
|
@ -2,7 +2,6 @@ import { combineReducers } from 'redux-immutable';
|
||||||
import timelines from './timelines';
|
import timelines from './timelines';
|
||||||
import meta from './meta';
|
import meta from './meta';
|
||||||
import compose from './compose';
|
import compose from './compose';
|
||||||
import follow from './follow';
|
|
||||||
import notifications from './notifications';
|
import notifications from './notifications';
|
||||||
import { loadingBarReducer } from 'react-redux-loading-bar';
|
import { loadingBarReducer } from 'react-redux-loading-bar';
|
||||||
import modal from './modal';
|
import modal from './modal';
|
||||||
|
@ -16,7 +15,6 @@ export default combineReducers({
|
||||||
timelines,
|
timelines,
|
||||||
meta,
|
meta,
|
||||||
compose,
|
compose,
|
||||||
follow,
|
|
||||||
notifications,
|
notifications,
|
||||||
loadingBar: loadingBarReducer,
|
loadingBar: loadingBarReducer,
|
||||||
modal,
|
modal,
|
||||||
|
|
Loading…
Reference in New Issue