1
0
Fork 0
forked from fedi/mastodon

Fix reblogs of reblogs in UI, add follow form in UI

This commit is contained in:
Eugen Rochko 2016-09-03 14:01:10 +02:00
parent f24cb32e99
commit d0e2733f63
10 changed files with 113 additions and 21 deletions

View file

@ -6,41 +6,41 @@ export const FOLLOW_SUBMIT_REQUEST = 'FOLLOW_SUBMIT_REQUEST';
export const FOLLOW_SUBMIT_SUCCESS = 'FOLLOW_SUBMIT_SUCCESS'; export const FOLLOW_SUBMIT_SUCCESS = 'FOLLOW_SUBMIT_SUCCESS';
export const FOLLOW_SUBMIT_FAIL = 'FOLLOW_SUBMIT_FAIL'; export const FOLLOW_SUBMIT_FAIL = 'FOLLOW_SUBMIT_FAIL';
export function followChange(text) { export function changeFollow(text) {
return { return {
type: FOLLOW_CHANGE, type: FOLLOW_CHANGE,
text: text text: text
}; };
} }
export function followSubmit() { export function submitFollow() {
return function (dispatch, getState) { return function (dispatch, getState) {
dispatch(followSubmitRequest()); dispatch(submitFollowRequest());
api(getState).post('/api/follows', { api(getState).post('/api/follows', {
uri: getState().getIn(['follow', 'text']) uri: getState().getIn(['follow', 'text'])
}).then(function (response) { }).then(function (response) {
dispatch(followSubmitSuccess(response.data)); dispatch(submitFollowSuccess(response.data));
}).catch(function (error) { }).catch(function (error) {
dispatch(followSubmitFail(error)); dispatch(submitFollowFail(error));
}); });
}; };
} }
export function followSubmitRequest() { export function submitFollowRequest() {
return { return {
type: FOLLOW_SUBMIT_REQUEST type: FOLLOW_SUBMIT_REQUEST
}; };
} }
export function followSubmitSuccess(account) { export function submitFollowSuccess(account) {
return { return {
type: FOLLOW_SUBMIT_SUCCESS, type: FOLLOW_SUBMIT_SUCCESS,
account: account account: account
}; };
} }
export function followSubmitFail(error) { export function submitFollowFail(error) {
return { return {
type: FOLLOW_SUBMIT_FAIL, type: FOLLOW_SUBMIT_FAIL,
error: error error: error

View file

@ -4,7 +4,7 @@ import PureRenderMixin from 'react-addons-pure-render-mixin';
import ImmutablePropTypes from 'react-immutable-proptypes'; import ImmutablePropTypes from 'react-immutable-proptypes';
import ReplyIndicator from './reply_indicator'; import ReplyIndicator from './reply_indicator';
const ComposerDrawer = React.createClass({ const ComposeForm = React.createClass({
propTypes: { propTypes: {
text: React.PropTypes.string.isRequired, text: React.PropTypes.string.isRequired,
@ -39,10 +39,10 @@ const ComposerDrawer = React.createClass({
} }
return ( return (
<div style={{ width: '280px', boxSizing: 'border-box', background: '#454b5e', margin: '10px', marginRight: '0', padding: '10px' }}> <div style={{ marginBottom: '30px', padding: '10px' }}>
{replyArea} {replyArea}
<textarea disabled={this.props.is_submitting} placeholder='What is on your mind?' value={this.props.text} onKeyUp={this.handleKeyUp} onChange={this.handleChange} className='compose-drawer__textarea' style={{ display: 'block', boxSizing: 'border-box', width: '100%', height: '100px', resize: 'none', border: 'none', color: '#282c37', padding: '10px', fontFamily: 'Roboto', fontSize: '14px', margin: '0' }} /> <textarea disabled={this.props.is_submitting} placeholder='What is on your mind?' value={this.props.text} onKeyUp={this.handleKeyUp} onChange={this.handleChange} className='compose-form__textarea' style={{ display: 'block', boxSizing: 'border-box', width: '100%', height: '100px', resize: 'none', border: 'none', color: '#282c37', padding: '10px', fontFamily: 'Roboto', fontSize: '14px', margin: '0' }} />
<div style={{ marginTop: '10px', overflow: 'hidden' }}> <div style={{ marginTop: '10px', overflow: 'hidden' }}>
<div style={{ float: 'right' }}><Button text='Publish' onClick={this.handleSubmit} disabled={this.props.is_submitting} /></div> <div style={{ float: 'right' }}><Button text='Publish' onClick={this.handleSubmit} disabled={this.props.is_submitting} /></div>
@ -54,4 +54,4 @@ const ComposerDrawer = React.createClass({
}); });
export default ComposerDrawer; export default ComposeForm;

View file

@ -0,0 +1,17 @@
import PureRenderMixin from 'react-addons-pure-render-mixin';
const Drawer = React.createClass({
mixins: [PureRenderMixin],
render () {
return (
<div style={{ width: '280px', boxSizing: 'border-box', background: '#454b5e', margin: '10px', marginRight: '0', padding: '0', display: 'flex', flexDirection: 'column' }}>
{this.props.children}
</div>
);
}
});
export default Drawer;

View file

@ -0,0 +1,40 @@
import IconButton from './icon_button';
import PureRenderMixin from 'react-addons-pure-render-mixin';
const FollowForm = React.createClass({
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.props.onSubmit();
}
},
handleSubmit () {
this.props.onSubmit();
},
render () {
return (
<div style={{ display: 'flex', lineHeight: '20px', padding: '10px', background: '#373b4a' }}>
<input 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;

View file

@ -1,6 +1,8 @@
import ColumnsArea from './columns_area'; import ColumnsArea from './columns_area';
import ComposerDrawerContainer from '../containers/composer_drawer_container'; import Drawer from './drawer';
import PureRenderMixin from 'react-addons-pure-render-mixin'; import ComposeFormContainer from '../containers/compose_form_container';
import FollowFormContainer from '../containers/follow_form_container';
import PureRenderMixin from 'react-addons-pure-render-mixin';
const Frontend = React.createClass({ const Frontend = React.createClass({
@ -9,7 +11,14 @@ const Frontend = React.createClass({
render () { render () {
return ( return (
<div style={{ flex: '0 0 auto', display: 'flex', width: '100%', height: '100%', background: '#1a1c23' }}> <div style={{ flex: '0 0 auto', display: 'flex', width: '100%', height: '100%', background: '#1a1c23' }}>
<ComposerDrawerContainer /> <Drawer>
<div style={{ flex: '1 1 auto' }}>
<ComposeFormContainer />
</div>
<FollowFormContainer />
</Drawer>
<ColumnsArea /> <ColumnsArea />
</div> </div>
); );

View file

@ -1,5 +1,5 @@
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import ComposerDrawer from '../components/composer_drawer'; import ComposeForm from '../components/compose_form';
import { changeCompose, submitCompose, cancelReplyCompose } from '../actions/compose'; import { changeCompose, submitCompose, cancelReplyCompose } from '../actions/compose';
const mapStateToProps = function (state, props) { const mapStateToProps = function (state, props) {
@ -26,4 +26,4 @@ const mapDispatchToProps = function (dispatch) {
} }
}; };
export default connect(mapStateToProps, mapDispatchToProps)(ComposerDrawer); export default connect(mapStateToProps, mapDispatchToProps)(ComposeForm);

View file

@ -0,0 +1,24 @@
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 () {
dispatch(submitFollow());
}
}
};
export default connect(mapStateToProps, mapDispatchToProps)(FollowForm);

View file

@ -9,6 +9,8 @@ function updateMatchingStatuses(state, needle, callback) {
return list.map(function (status) { return list.map(function (status) {
if (status.get('id') === needle.get('id')) { if (status.get('id') === needle.get('id')) {
return callback(status); return callback(status);
} else if (status.getIn(['reblog', 'id'], null) === needle.get('id')) {
return status.set('reblog', callback(status.get('reblog')));
} }
return status; return status;

View file

@ -28,7 +28,7 @@
} }
} }
.compose-drawer__textarea { .compose-form__textarea, .follow-form__input {
background: #fff; background: #fff;
&:disabled { &:disabled {

View file

@ -59,11 +59,11 @@ class Account < ApplicationRecord
end end
def favourited?(status) def favourited?(status)
(status.reblog? ? status.reblog : status).favourites.where(account: self).count == 1 (status.reblog? ? status.reblog : status).favourites.where(account: self).count > 0
end end
def reblogged?(status) def reblogged?(status)
(status.reblog? ? status.reblog : status).reblogs.where(account: self).count == 1 (status.reblog? ? status.reblog : status).reblogs.where(account: self).count > 0
end end
def keypair def keypair