Skip to content

Commit

Permalink
Add forceSingleColumn prop to <UI /> (mastodon#10807) [Monsterfor…
Browse files Browse the repository at this point in the history
…k adjustment: keep ordering]

* Move TabsBar rendering logic from CSS to the ColumnsArea component

* Add forceSingleColumn mode

* Add unread notifications counter to tabs bar

* Add toggle to control `forceSingleColumn`

* Increase paddings in mobile layout responsively at large sizes
  • Loading branch information
Gargron authored and multiple creatures committed Nov 19, 2019
1 parent 22e1150 commit 918b786
Show file tree
Hide file tree
Showing 9 changed files with 296 additions and 118 deletions.
2 changes: 1 addition & 1 deletion app/javascript/mastodon/components/autosuggest_input.js
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ export default class AutosuggestInput extends ImmutablePureComponent {
autoFocus: PropTypes.bool,
className: PropTypes.string,
id: PropTypes.string,
searchTokens: PropTypes.list,
searchTokens: ImmutablePropTypes.list,
maxLength: PropTypes.number,
};

Expand Down
10 changes: 5 additions & 5 deletions app/javascript/mastodon/features/compose/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -106,12 +106,12 @@ class Compose extends React.PureComponent {
<div className='drawer__pager'>
{!isSearchPage && <div className='drawer__inner' onFocus={this.onFocus}>
<NavigationContainer onClose={this.onBlur} />

<ComposeFormContainer />
{multiColumn && (
<div className='drawer__inner__mastodon'>
<img alt='' draggable='false' src={mascot || elephantUIPlane} />
</div>
)}

<div className='drawer__inner__mastodon'>
<img alt='' draggable='false' src={mascot || elephantUIPlane} />
</div>
</div>}

<Motion defaultStyle={{ x: isSearchPage ? 0 : -100 }} style={{ x: spring(showSearch || isSearchPage ? 0 : -100, { stiffness: 210, damping: 20 }) }}>
Expand Down
19 changes: 17 additions & 2 deletions app/javascript/mastodon/features/getting_started/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,13 @@ import PropTypes from 'prop-types';
import ImmutablePropTypes from 'react-immutable-proptypes';
import ImmutablePureComponent from 'react-immutable-pure-component';
import { me, invitesEnabled, version, profile_directory, repository, source_url } from '../../initial_state';
import { fetchFollowRequests } from '../../actions/accounts';
import { fetchFollowRequests } from 'mastodon/actions/accounts';
import { changeSetting } from 'mastodon/actions/settings';
import { List as ImmutableList } from 'immutable';
import { Link } from 'react-router-dom';
import NavigationBar from '../compose/components/navigation_bar';
import Icon from 'mastodon/components/icon';
import Toggle from 'react-toggle';

const messages = defineMessages({
home_timeline: { id: 'tabs_bar.home', defaultMessage: 'Home' },
Expand All @@ -39,10 +41,12 @@ const messages = defineMessages({
const mapStateToProps = state => ({
myAccount: state.getIn(['accounts', me]),
unreadFollowRequests: state.getIn(['user_lists', 'follow_requests', 'items'], ImmutableList()).size,
forceSingleColumn: state.getIn(['settings', 'forceSingleColumn'], false),
});

const mapDispatchToProps = dispatch => ({
fetchFollowRequests: () => dispatch(fetchFollowRequests()),
changeForceSingleColumn: checked => dispatch(changeSetting(['forceSingleColumn'], checked)),
});

const badgeDisplay = (number, limit) => {
Expand All @@ -67,6 +71,8 @@ class GettingStarted extends ImmutablePureComponent {
fetchFollowRequests: PropTypes.func.isRequired,
unreadFollowRequests: PropTypes.number,
unreadNotifications: PropTypes.number,
forceSingleColumn: PropTypes.bool,
changeForceSingleColumn: PropTypes.func.isRequired,
};

componentDidMount () {
Expand All @@ -77,8 +83,12 @@ class GettingStarted extends ImmutablePureComponent {
}
}

handleForceSingleColumnChange = ({ target }) => {
this.props.changeForceSingleColumn(target.checked);
}

render () {
const { intl, myAccount, multiColumn, unreadFollowRequests } = this.props;
const { intl, myAccount, multiColumn, unreadFollowRequests, forceSingleColumn } = this.props;

const navItems = [];
let i = 1;
Expand Down Expand Up @@ -177,6 +187,11 @@ class GettingStarted extends ImmutablePureComponent {
</p>
</div>
</div>

<label className='navigational-toggle'>
<FormattedMessage id='getting_started.use_simple_layout' defaultMessage='Use simple layout' />
<Toggle checked={forceSingleColumn} onChange={this.handleForceSingleColumnChange} />
</label>
</Column>
);
}
Expand Down
10 changes: 7 additions & 3 deletions app/javascript/mastodon/features/ui/components/columns_area.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import ImmutablePropTypes from 'react-immutable-proptypes';
import ImmutablePureComponent from 'react-immutable-pure-component';

import ReactSwipeableViews from 'react-swipeable-views';
import { links, getIndex, getLink } from './tabs_bar';
import TabsBar, { links, getIndex, getLink } from './tabs_bar';
import { Link } from 'react-router-dom';

import BundleContainer from '../containers/bundle_container';
Expand Down Expand Up @@ -139,7 +139,7 @@ class ColumnsArea extends ImmutablePureComponent {
<ColumnLoading title={title} icon={icon} />;

return (
<div className='columns-area' key={index}>
<div className='columns-area columns-area--mobile' key={index}>
{view}
</div>
);
Expand All @@ -164,13 +164,17 @@ class ColumnsArea extends ImmutablePureComponent {
const floatingActionButton = shouldHideFAB(this.context.router.history.location.pathname) ? null : <Link key='floating-action-button' to='/statuses/new' className='floating-action-button' aria-label={intl.formatMessage(messages.publish)}><Icon id='pencil' /></Link>;

return columnIndex !== -1 ? [
<TabsBar key='tabs' />,

<ReactSwipeableViews key='content' index={columnIndex} onChangeIndex={this.handleSwipe} onTransitionEnd={this.handleAnimationEnd} animateTransitions={shouldAnimate} springConfig={{ duration: '400ms', delay: '0s', easeFunction: 'ease' }} style={{ height: '100%' }}>
{links.map(this.renderView)}
</ReactSwipeableViews>,

floatingActionButton,
] : [
<div className='columns-area'>{children}</div>,
<TabsBar key='tabs' />,

<div key='content' className='columns-area columns-area--mobile'>{children}</div>,

floatingActionButton,
];
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import React from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import Icon from 'mastodon/components/icon';

const mapStateToProps = state => ({
count: state.getIn(['notifications', 'unread']),
});

const formatNumber = num => num > 99 ? '99+' : num;

const NotificationsCounterIcon = ({ count }) => (
<i className='icon-with-badge'>
<Icon id='bell' fixedWidth />
{count > 0 && <i className='icon-with-badge__badge'>{formatNumber(count)}</i>}
</i>
);

NotificationsCounterIcon.propTypes = {
count: PropTypes.number.isRequired,
};

export default connect(mapStateToProps)(NotificationsCounterIcon);
3 changes: 2 additions & 1 deletion app/javascript/mastodon/features/ui/components/tabs_bar.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,10 @@ import { FormattedMessage, injectIntl } from 'react-intl';
import { debounce } from 'lodash';
import { isUserTouching } from '../../../is_mobile';
import Icon from 'mastodon/components/icon';
import NotificationsCounterIcon from './notifications_counter_icon';

export const links = [
<NavLink className='tabs-bar__link primary' to='/notifications' data-preview-title-id='column.notifications' data-preview-icon='bell' ><Icon id='bell' fixedWidth /><FormattedMessage id='tabs_bar.notifications' defaultMessage='Notifications' /></NavLink>,
<NavLink className='tabs-bar__link primary' to='/notifications' data-preview-title-id='column.notifications' data-preview-icon='bell' ><NotificationsCounterIcon /><FormattedMessage id='tabs_bar.notifications' defaultMessage='Notifications' /></NavLink>,
<NavLink className='tabs-bar__link primary' to='/timelines/home' data-preview-title-id='column.home' data-preview-icon='home' ><Icon id='home' fixedWidth /><FormattedMessage id='tabs_bar.home' defaultMessage='Home' /></NavLink>,

<NavLink className='tabs-bar__link secondary' to='/timelines/public/local' data-preview-title-id='column.community' data-preview-icon='users' ><Icon id='users' fixedWidth /><FormattedMessage id='tabs_bar.local_timeline' defaultMessage='Local' /></NavLink>,
Expand Down
17 changes: 9 additions & 8 deletions app/javascript/mastodon/features/ui/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import { Redirect, withRouter } from 'react-router-dom';
import PropTypes from 'prop-types';
import NotificationsContainer from './containers/notifications_container';
import LoadingBarContainer from './containers/loading_bar_container';
import TabsBar from './components/tabs_bar';
import ModalContainer from './containers/modal_container';
import { isMobile } from '../../is_mobile';
import { debounce } from 'lodash';
Expand Down Expand Up @@ -63,6 +62,7 @@ const mapStateToProps = state => ({
hasComposingText: state.getIn(['compose', 'text']).trim().length !== 0,
hasMediaAttachments: state.getIn(['compose', 'media_attachments']).size > 0,
dropdownMenuIsOpen: state.getIn(['dropdown_menu', 'openId']) !== null,
forceSingleColumn: state.getIn(['settings', 'forceSingleColumn'], false),
});

const keyMap = {
Expand Down Expand Up @@ -101,6 +101,7 @@ class SwitchingColumnsArea extends React.PureComponent {
children: PropTypes.node,
location: PropTypes.object,
onLayoutChange: PropTypes.func.isRequired,
forceSingleColumn: PropTypes.bool,
};

state = {
Expand Down Expand Up @@ -139,12 +140,13 @@ class SwitchingColumnsArea extends React.PureComponent {
}

render () {
const { children } = this.props;
const { children, forceSingleColumn } = this.props;
const { mobile } = this.state;
const redirect = mobile ? <Redirect from='/' to='/timelines/home' exact /> : <Redirect from='/' to='/getting-started' exact />;
const singleColumn = forceSingleColumn || mobile;
const redirect = singleColumn ? <Redirect from='/' to='/timelines/home' exact /> : <Redirect from='/' to='/getting-started' exact />;

return (
<ColumnsAreaContainer ref={this.setRef} singleColumn={mobile}>
<ColumnsAreaContainer ref={this.setRef} singleColumn={singleColumn}>
<WrappedSwitch>
{redirect}
<WrappedRoute path='/getting-started' component={GettingStarted} content={children} />
Expand Down Expand Up @@ -205,6 +207,7 @@ class UI extends React.PureComponent {
location: PropTypes.object,
intl: PropTypes.object.isRequired,
dropdownMenuIsOpen: PropTypes.bool,
forceSingleColumn: PropTypes.bool,
};

state = {
Expand Down Expand Up @@ -453,7 +456,7 @@ class UI extends React.PureComponent {

render () {
const { draggingOver } = this.state;
const { children, isComposing, location, dropdownMenuIsOpen } = this.props;
const { children, isComposing, location, dropdownMenuIsOpen, forceSingleColumn } = this.props;

const handlers = {
help: this.handleHotkeyToggleHelp,
Expand All @@ -479,9 +482,7 @@ class UI extends React.PureComponent {
return (
<HotKeys keyMap={keyMap} handlers={handlers} ref={this.setHotkeysRef} attach={window} focused>
<div className={classNames('ui', { 'is-composing': isComposing })} ref={this.setRef} style={{ pointerEvents: dropdownMenuIsOpen ? 'none' : null }}>
<TabsBar />

<SwitchingColumnsArea location={location} onLayoutChange={this.handleLayoutChange}>
<SwitchingColumnsArea location={location} onLayoutChange={this.handleLayoutChange} forceSingleColumn={forceSingleColumn}>
{children}
</SwitchingColumnsArea>

Expand Down
2 changes: 2 additions & 0 deletions app/javascript/mastodon/reducers/settings.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ const initialState = ImmutableMap({

skinTone: 1,

forceSingleColumn: false,

home: ImmutableMap({
shows: ImmutableMap({
reblog: true,
Expand Down
Loading

0 comments on commit 918b786

Please sign in to comment.