export const COMPOSE_SPOILER_TEXT_CHANGE = 'COMPOSE_SPOILER_TEXT_CHANGE';
export const COMPOSE_VISIBILITY_CHANGE = 'COMPOSE_VISIBILITY_CHANGE';
export const COMPOSE_LISTABILITY_CHANGE = 'COMPOSE_LISTABILITY_CHANGE';
+export const COMPOSE_COMPOSING_CHANGE = 'COMPOSE_COMPOSING_CHANGE';
export const COMPOSE_EMOJI_INSERT = 'COMPOSE_EMOJI_INSERT';
emoji,
};
};
+
+export function changeComposing(value) {
+ return {
+ type: COMPOSE_COMPOSING_CHANGE,
+ value,
+ };
+}
import React from 'react';
+import PropTypes from 'prop-types';
import ImmutablePropTypes from 'react-immutable-proptypes';
import Avatar from '../../../components/avatar';
+import IconButton from '../../../components/icon_button';
import Permalink from '../../../components/permalink';
import { FormattedMessage } from 'react-intl';
import ImmutablePureComponent from 'react-immutable-pure-component';
static propTypes = {
account: ImmutablePropTypes.map.isRequired,
+ onClose: PropTypes.func.isRequired,
};
render () {
<a href='/settings/profile' className='navigation-bar__profile-edit'><FormattedMessage id='navigation_bar.edit_profile' defaultMessage='Edit profile' /></a>
</div>
+
+ <IconButton title='' icon='close' onClick={this.props.onClose} />
</div>
);
}
import Motion from 'react-motion/lib/Motion';
import spring from 'react-motion/lib/spring';
import SearchResultsContainer from './containers/search_results_container';
+import { changeComposing } from '../../actions/compose';
const messages = defineMessages({
start: { id: 'getting_started.heading', defaultMessage: 'Getting started' },
this.props.dispatch(unmountCompose());
}
+ onFocus = () => {
+ this.props.dispatch(changeComposing(true));
+ }
+
+ onBlur = () => {
+ this.props.dispatch(changeComposing(false));
+ }
+
render () {
const { multiColumn, showSearch, intl } = this.props;
<SearchContainer />
<div className='drawer__pager'>
- <div className='drawer__inner'>
- <NavigationContainer />
+ <div className='drawer__inner' onFocus={this.onFocus}>
+ <NavigationContainer onClose={this.onBlur} />
<ComposeFormContainer />
</div>
const mapStateToProps = state => ({
systemFontUi: state.getIn(['meta', 'system_font_ui']),
+ isComposing: state.getIn(['compose', 'is_composing']),
});
@connect(mapStateToProps)
dispatch: PropTypes.func.isRequired,
children: PropTypes.node,
systemFontUi: PropTypes.bool,
+ isComposing: PropTypes.bool,
};
state = {
this.props.dispatch(refreshNotifications());
}
+ shouldComponentUpdate (nextProps) {
+ if (nextProps.isComposing !== this.props.isComposing) {
+ // Avoid expensive update just to toggle a class
+ this.node.classList.toggle('is-composing', nextProps.isComposing);
+
+ return false;
+ }
+
+ // Why isn't this working?!?
+ // return super.shouldComponentUpdate(nextProps, nextState);
+ return true;
+ }
+
componentWillUnmount () {
window.removeEventListener('resize', this.handleResize);
document.removeEventListener('dragenter', this.handleDragEnter);
COMPOSE_SPOILERNESS_CHANGE,
COMPOSE_SPOILER_TEXT_CHANGE,
COMPOSE_VISIBILITY_CHANGE,
+ COMPOSE_COMPOSING_CHANGE,
COMPOSE_EMOJI_INSERT,
} from '../actions/compose';
import { TIMELINE_DELETE } from '../actions/timelines';
focusDate: null,
preselectDate: null,
in_reply_to: null,
+ is_composing: false,
is_submitting: false,
is_uploading: false,
progress: 0,
case COMPOSE_MOUNT:
return state.set('mounted', true);
case COMPOSE_UNMOUNT:
- return state.set('mounted', false);
+ return state
+ .set('mounted', false)
+ .set('is_composing', false);
case COMPOSE_SENSITIVITY_CHANGE:
return state
.set('sensitive', !state.get('sensitive'))
return state
.set('text', action.text)
.set('idempotencyKey', uuid());
+ case COMPOSE_COMPOSING_CHANGE:
+ return state.set('is_composing', action.value);
case COMPOSE_REPLY:
return state.withMutations(map => {
map.set('in_reply_to', action.status.get('id'));
.permalink {
text-decoration: none;
}
+
+ .icon-button {
+ pointer-events: none;
+ opacity: 0;
+ }
}
.navigation-bar__profile {
margin: 20px 0;
}
}
+
+@media screen and (max-width: 1024px) and (max-height: 600px) {
+ $duration: 400ms;
+ $delay: 100ms;
+
+ .tabs-bar,
+ .search {
+ will-change: margin-top;
+ transition: margin-top $duration $delay;
+ }
+
+ .navigation-bar {
+ will-change: padding-bottom;
+ transition: padding-bottom $duration $delay;
+ }
+
+ .navigation-bar {
+ & > a:first-child {
+ will-change: margin-top, margin-left, width;
+ transition: margin-top $duration $delay, margin-left $duration ($duration + $delay);
+ }
+
+ & > .navigation-bar__profile-edit {
+ will-change: margin-top;
+ transition: margin-top $duration $delay;
+ }
+
+ & > .icon-button {
+ will-change: opacity;
+ transition: opacity $duration $delay;
+ }
+ }
+
+ .is-composing {
+ .tabs-bar,
+ .search {
+ margin-top: -50px;
+ }
+
+ .navigation-bar {
+ padding-bottom: 0;
+
+ & > a:first-child {
+ margin-top: -50px;
+ margin-left: -40px;
+ }
+
+ .navigation-bar__profile {
+ padding-top: 2px;
+ }
+
+ .navigation-bar__profile-edit {
+ position: absolute;
+ margin-top: -50px;
+ }
+
+ .icon-button {
+ pointer-events: auto;
+ opacity: 1;
+ }
+ }
+ }
+}