[Glitch] Add single-column mode
Port 9ddeb30f90 to glitch-soc
Signed-off-by: Thibaut Girka <thib@sitedethib.com>
This commit is contained in:
@@ -61,12 +61,12 @@ class Compose extends React.PureComponent {
|
||||
<div className='drawer__pager'>
|
||||
{!isSearchPage && <div className='drawer__inner'>
|
||||
<NavigationContainer />
|
||||
|
||||
<ComposeFormContainer />
|
||||
{multiColumn && (
|
||||
<div className='drawer__inner__mastodon'>
|
||||
{mascot ? <img alt='' draggable='false' src={mascot} /> : <button className='mastodon' onClick={onClickElefriend} />}
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className='drawer__inner__mastodon'>
|
||||
{mascot ? <img alt='' draggable='false' src={mascot} /> : <button className='mastodon' onClick={onClickElefriend} />}
|
||||
</div>
|
||||
</div>}
|
||||
|
||||
<Motion defaultStyle={{ x: isSearchPage ? 0 : -100 }} style={{ x: spring(showSearch || isSearchPage ? 0 : -100, { stiffness: 210, damping: 20 }) }}>
|
||||
|
||||
@@ -10,10 +10,12 @@ import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||
import ImmutablePureComponent from 'react-immutable-pure-component';
|
||||
import { me, invitesEnabled, version } from 'flavours/glitch/util/initial_state';
|
||||
import { fetchFollowRequests } from 'flavours/glitch/actions/accounts';
|
||||
import { changeSetting } from 'flavours/glitch/actions/settings';
|
||||
import { List as ImmutableList } from 'immutable';
|
||||
import { createSelector } from 'reselect';
|
||||
import { fetchLists } from 'flavours/glitch/actions/lists';
|
||||
import { preferencesLink, profileLink, signOutLink } from 'flavours/glitch/util/backend_links';
|
||||
import Toggle from 'react-toggle';
|
||||
|
||||
const messages = defineMessages({
|
||||
heading: { id: 'getting_started.heading', defaultMessage: 'Getting started' },
|
||||
@@ -52,6 +54,7 @@ const makeMapStateToProps = () => {
|
||||
columns: state.getIn(['settings', 'columns']),
|
||||
unreadFollowRequests: state.getIn(['user_lists', 'follow_requests', 'items'], ImmutableList()).size,
|
||||
unreadNotifications: state.getIn(['notifications', 'unread']),
|
||||
forceSingleColumn: state.getIn(['settings', 'forceSingleColumn'], false),
|
||||
});
|
||||
|
||||
return mapStateToProps;
|
||||
@@ -61,6 +64,7 @@ const mapDispatchToProps = dispatch => ({
|
||||
fetchFollowRequests: () => dispatch(fetchFollowRequests()),
|
||||
fetchLists: () => dispatch(fetchLists()),
|
||||
openSettings: () => dispatch(openModal('SETTINGS', {})),
|
||||
changeForceSingleColumn: checked => dispatch(changeSetting(['forceSingleColumn'], checked)),
|
||||
});
|
||||
|
||||
const badgeDisplay = (number, limit) => {
|
||||
@@ -88,6 +92,8 @@ export default class GettingStarted extends ImmutablePureComponent {
|
||||
lists: ImmutablePropTypes.list,
|
||||
fetchLists: PropTypes.func.isRequired,
|
||||
openSettings: PropTypes.func.isRequired,
|
||||
forceSingleColumn: PropTypes.bool,
|
||||
changeForceSingleColumn: PropTypes.func.isRequired,
|
||||
};
|
||||
|
||||
componentWillMount () {
|
||||
@@ -102,8 +108,12 @@ export default class GettingStarted extends ImmutablePureComponent {
|
||||
}
|
||||
}
|
||||
|
||||
handleForceSingleColumnChange = ({ target }) => {
|
||||
this.props.changeForceSingleColumn(target.checked);
|
||||
}
|
||||
|
||||
render () {
|
||||
const { intl, myAccount, columns, multiColumn, unreadFollowRequests, unreadNotifications, lists, openSettings } = this.props;
|
||||
const { intl, myAccount, columns, multiColumn, unreadFollowRequests, unreadNotifications, lists, openSettings, forceSingleColumn } = this.props;
|
||||
|
||||
const navItems = [];
|
||||
let listItems = [];
|
||||
@@ -183,6 +193,11 @@ export default 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>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -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';
|
||||
@@ -139,7 +139,7 @@ export default 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>
|
||||
);
|
||||
@@ -164,13 +164,17 @@ export default 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)}><i className='fa fa-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%' }} disabled={!swipeToChangeColumns}>
|
||||
{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,
|
||||
];
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { connect } from 'react-redux';
|
||||
import Icon from 'flavours/glitch/components/icon';
|
||||
|
||||
const mapStateToProps = state => ({
|
||||
count: state.getIn(['notifications', 'unread']),
|
||||
showBadge: state.getIn(['local_settings', 'notifications', 'tab_badge']),
|
||||
});
|
||||
|
||||
const formatNumber = num => num > 99 ? '99+' : num;
|
||||
|
||||
const NotificationsCounterIcon = ({ count, showBadge }) => (
|
||||
<i className='icon-with-badge'>
|
||||
<Icon icon='bell' fixedWidth />
|
||||
{showBadge && count > 0 && <i className='icon-with-badge__badge'>{formatNumber(count)}</i>}
|
||||
</i>
|
||||
);
|
||||
|
||||
NotificationsCounterIcon.propTypes = {
|
||||
count: PropTypes.number.isRequired,
|
||||
};
|
||||
|
||||
export default connect(mapStateToProps)(NotificationsCounterIcon);
|
||||
@@ -4,34 +4,11 @@ import { NavLink, withRouter } from 'react-router-dom';
|
||||
import { FormattedMessage, injectIntl } from 'react-intl';
|
||||
import { debounce } from 'lodash';
|
||||
import { isUserTouching } from 'flavours/glitch/util/is_mobile';
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
const mapStateToProps = state => ({
|
||||
unreadNotifications: state.getIn(['notifications', 'unread']),
|
||||
showBadge: state.getIn(['local_settings', 'notifications', 'tab_badge']),
|
||||
});
|
||||
|
||||
@connect(mapStateToProps)
|
||||
class NotificationsIcon extends React.PureComponent {
|
||||
static propTypes = {
|
||||
unreadNotifications: PropTypes.number,
|
||||
showBadge: PropTypes.bool,
|
||||
};
|
||||
|
||||
render() {
|
||||
const { unreadNotifications, showBadge } = this.props;
|
||||
return (
|
||||
<span className='icon-badge-wrapper'>
|
||||
<i className='fa fa-fw fa-bell' />
|
||||
{ showBadge && unreadNotifications > 0 && <div className='icon-badge' />}
|
||||
</span>
|
||||
);
|
||||
}
|
||||
}
|
||||
import NotificationsCounterIcon from './notifications_counter_icon';
|
||||
|
||||
export const links = [
|
||||
<NavLink className='tabs-bar__link primary' to='/timelines/home' data-preview-title-id='column.home' data-preview-icon='home' ><i className='fa fa-fw fa-home' /><FormattedMessage id='tabs_bar.home' defaultMessage='Home' /></NavLink>,
|
||||
<NavLink className='tabs-bar__link primary' to='/notifications' data-preview-title-id='column.notifications' data-preview-icon='bell' ><NotificationsIcon /><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 secondary' to='/timelines/public/local' data-preview-title-id='column.community' data-preview-icon='users' ><i className='fa fa-fw fa-users' /><FormattedMessage id='tabs_bar.local_timeline' defaultMessage='Local' /></NavLink>,
|
||||
<NavLink className='tabs-bar__link secondary' exact to='/timelines/public' data-preview-title-id='column.public' data-preview-icon='globe' ><i className='fa fa-fw fa-globe' /><FormattedMessage id='tabs_bar.federated_timeline' defaultMessage='Federated' /></NavLink>,
|
||||
|
||||
@@ -2,7 +2,6 @@ import React from 'react';
|
||||
import NotificationsContainer from './containers/notifications_container';
|
||||
import PropTypes from 'prop-types';
|
||||
import LoadingBarContainer from './containers/loading_bar_container';
|
||||
import TabsBar from './components/tabs_bar';
|
||||
import ModalContainer from './containers/modal_container';
|
||||
import { connect } from 'react-redux';
|
||||
import { Redirect, withRouter } from 'react-router-dom';
|
||||
@@ -69,6 +68,7 @@ const mapStateToProps = state => ({
|
||||
unreadNotifications: state.getIn(['notifications', 'unread']),
|
||||
showFaviconBadge: state.getIn(['local_settings', 'notifications', 'favicon_badge']),
|
||||
hicolorPrivacyIcons: state.getIn(['local_settings', 'hicolor_privacy_icons']),
|
||||
forceSingleColumn: state.getIn(['settings', 'forceSingleColumn'], false),
|
||||
});
|
||||
|
||||
const keyMap = {
|
||||
@@ -126,6 +126,7 @@ export default class UI extends React.Component {
|
||||
dropdownMenuIsOpen: PropTypes.bool,
|
||||
unreadNotifications: PropTypes.number,
|
||||
showFaviconBadge: PropTypes.bool,
|
||||
forceSingleColumn: PropTypes.bool,
|
||||
};
|
||||
|
||||
state = {
|
||||
@@ -431,7 +432,9 @@ export default class UI extends React.Component {
|
||||
|
||||
render () {
|
||||
const { width, draggingOver } = this.state;
|
||||
const { children, layout, isWide, navbarUnder, dropdownMenuIsOpen } = this.props;
|
||||
const { children, layout, isWide, navbarUnder, dropdownMenuIsOpen, forceSingleColumn } = this.props;
|
||||
const singleColumn = forceSingleColumn || isMobile(width, layout);
|
||||
const redirect = singleColumn ? <Redirect from='/' to='/timelines/home' exact /> : <Redirect from='/' to='/getting-started' exact />;
|
||||
|
||||
const columnsClass = layout => {
|
||||
switch (layout) {
|
||||
@@ -475,11 +478,9 @@ export default class UI extends React.Component {
|
||||
return (
|
||||
<HotKeys keyMap={keyMap} handlers={handlers} ref={this.setHotkeysRef} attach={window} focused>
|
||||
<div className={className} ref={this.setRef} style={{ pointerEvents: dropdownMenuIsOpen ? 'none' : null }}>
|
||||
{navbarUnder ? null : (<TabsBar />)}
|
||||
|
||||
<ColumnsAreaContainer ref={this.setColumnsAreaRef} singleColumn={isMobile(width, layout)}>
|
||||
<ColumnsAreaContainer ref={this.setColumnsAreaRef} singleColumn={singleColumn}>
|
||||
<WrappedSwitch>
|
||||
<Redirect from='/' to='/getting-started' exact />
|
||||
{redirect}
|
||||
<WrappedRoute path='/getting-started' component={GettingStarted} content={children} />
|
||||
<WrappedRoute path='/keyboard-shortcuts' component={KeyboardShortcuts} content={children} />
|
||||
<WrappedRoute path='/timelines/home' component={HomeTimeline} content={children} />
|
||||
@@ -518,7 +519,6 @@ export default class UI extends React.Component {
|
||||
</ColumnsAreaContainer>
|
||||
|
||||
<NotificationsContainer />
|
||||
{navbarUnder ? (<TabsBar />) : null}
|
||||
<LoadingBarContainer className='loading-bar' />
|
||||
<ModalContainer />
|
||||
<UploadArea active={draggingOver} onClose={this.closeUploadModal} />
|
||||
|
||||
Reference in New Issue
Block a user