Added sidebar menu feature
This commit is contained in:
14
app/javascript/gabsocial/actions/sidebar.js
Normal file
14
app/javascript/gabsocial/actions/sidebar.js
Normal file
@@ -0,0 +1,14 @@
|
||||
export const SIDEBAR_OPEN = 'SIDEBAR_OPEN';
|
||||
export const SIDEBAR_CLOSE = 'SIDEBAR_CLOSE';
|
||||
|
||||
export function openSidebar() {
|
||||
return {
|
||||
type: SIDEBAR_OPEN,
|
||||
};
|
||||
};
|
||||
|
||||
export function closeSidebar() {
|
||||
return {
|
||||
type: SIDEBAR_CLOSE,
|
||||
};
|
||||
};
|
||||
161
app/javascript/gabsocial/components/sidebar_menu.js
Normal file
161
app/javascript/gabsocial/components/sidebar_menu.js
Normal file
@@ -0,0 +1,161 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { connect } from 'react-redux';
|
||||
import { Link, NavLink } from 'react-router-dom';
|
||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||
import ImmutablePureComponent from 'react-immutable-pure-component';
|
||||
import { injectIntl, defineMessages } from 'react-intl';
|
||||
import classNames from 'classnames';
|
||||
import Avatar from './avatar';
|
||||
import IconButton from './icon_button';
|
||||
import Icon from './icon';
|
||||
import DisplayName from './display_name';
|
||||
import { closeSidebar } from '../actions/sidebar';
|
||||
import { shortNumberFormat } from '../utils/numbers';
|
||||
import { me } from '../initial_state';
|
||||
import { makeGetAccount } from '../selectors';
|
||||
|
||||
const messages = defineMessages({
|
||||
followers: { id: 'account.followers', defaultMessage: 'Followers' },
|
||||
follows: { id: 'account.follows', defaultMessage: 'Follows' },
|
||||
profile: { id: 'account.profile', defaultMessage: 'Profile' },
|
||||
preferences: { id: 'navigation_bar.preferences', defaultMessage: 'Preferences' },
|
||||
follow_requests: { id: 'navigation_bar.follow_requests', defaultMessage: 'Follow requests' },
|
||||
blocks: { id: 'navigation_bar.blocks', defaultMessage: 'Blocked users' },
|
||||
domain_blocks: { id: 'navigation_bar.domain_blocks', defaultMessage: 'Hidden domains' },
|
||||
mutes: { id: 'navigation_bar.mutes', defaultMessage: 'Muted users' },
|
||||
filters: { id: 'navigation_bar.filters', defaultMessage: 'Muted words' },
|
||||
logout: { id: 'navigation_bar.logout', defaultMessage: 'Logout' },
|
||||
lists: { id: 'column.lists', defaultMessage: 'Lists', },
|
||||
apps: { id: 'tabs_bar.apps', defaultMessage: 'Apps' },
|
||||
news: { id: 'tabs_bar.news', defaultMessage: 'News' },
|
||||
})
|
||||
|
||||
const mapStateToProps = state => {
|
||||
const getAccount = makeGetAccount();
|
||||
|
||||
return {
|
||||
account: getAccount(state, me),
|
||||
sidebarOpen: state.get('sidebar').sidebarOpen,
|
||||
};
|
||||
};
|
||||
|
||||
const mapDispatchToProps = (dispatch) => ({
|
||||
onClose () {
|
||||
dispatch(closeSidebar());
|
||||
},
|
||||
});
|
||||
|
||||
export default @connect(mapStateToProps, mapDispatchToProps)
|
||||
@injectIntl
|
||||
class SidebarMenu extends ImmutablePureComponent {
|
||||
|
||||
static propTypes = {
|
||||
intl: PropTypes.object.isRequired,
|
||||
account: ImmutablePropTypes.map,
|
||||
sidebarOpen: PropTypes.bool,
|
||||
onClose: PropTypes.func.isRequired,
|
||||
};
|
||||
|
||||
render () {
|
||||
const { sidebarOpen, onClose, intl, account } = this.props;
|
||||
const acct = account.get('acct');
|
||||
|
||||
const classes = classNames('sidebar-menu__root', {
|
||||
'sidebar-menu__root--visible': sidebarOpen,
|
||||
});
|
||||
|
||||
return (
|
||||
<div className={classes}>
|
||||
<div className='sidebar-menu__wrapper' role='button' onClick={onClose} />
|
||||
<div className='sidebar-menu'>
|
||||
|
||||
<div className='sidebar-menu-header'>
|
||||
<span className='sidebar-menu-header__title'>Account Info</span>
|
||||
<IconButton title='close' onClick={onClose} icon='close' className='sidebar-menu-header__btn' />
|
||||
</div>
|
||||
|
||||
<div className='sidebar-menu__content'>
|
||||
|
||||
<div className='sidebar-menu-profile'>
|
||||
<div className='sidebar-menu-profile__avatar'>
|
||||
<Link to={`/${acct}}`} title={acct} onClick={onClose}>
|
||||
<Avatar account={account} />
|
||||
</Link>
|
||||
</div>
|
||||
<div className='sidebar-menu-profile__name'>
|
||||
<DisplayName account={account}/>
|
||||
</div>
|
||||
|
||||
<div className='sidebar-menu-profile__stats'>
|
||||
<NavLink className='sidebar-menu-profile-stat' to={`/${acct}/followers`} onClick={onClose} title={intl.formatNumber(account.get('followers_count'))}>
|
||||
<strong className='sidebar-menu-profile-stat__value'>{shortNumberFormat(account.get('followers_count'))}</strong>
|
||||
<span className='sidebar-menu-profile-stat__label'>{intl.formatMessage(messages.followers)}</span>
|
||||
</NavLink>
|
||||
<NavLink className='sidebar-menu-profile-stat' to={`/${acct}/following`} onClick={onClose} title={intl.formatNumber(account.get('following_count'))}>
|
||||
<strong className='sidebar-menu-profile-stat__value'>{shortNumberFormat(account.get('following_count'))}</strong>
|
||||
<span className='sidebar-menu-profile-stat__label'>{intl.formatMessage(messages.follows)}</span>
|
||||
</NavLink>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div className='sidebar-menu__section sidebar-menu__section--borderless'>
|
||||
<NavLink className='sidebar-menu-item' to={`/${acct}`} onClick={onClose}>
|
||||
<Icon id='user' />
|
||||
<span className='sidebar-menu-item__title'>{intl.formatMessage(messages.profile)}</span>
|
||||
</NavLink>
|
||||
<NavLink className='sidebar-menu-item' to='/lists' onClick={onClose}>
|
||||
<Icon id='list' />
|
||||
<span className='sidebar-menu-item__title'>{intl.formatMessage(messages.lists)}</span>
|
||||
</NavLink>
|
||||
<a className='sidebar-menu-item' href='https://apps.gab.com'>
|
||||
<Icon id='th' />
|
||||
<span className='sidebar-menu-item__title'>{intl.formatMessage(messages.apps)}</span>
|
||||
</a>
|
||||
<a className='sidebar-menu-item' href='https://blog.gab.com'>
|
||||
<Icon id='align-left' />
|
||||
<span className='sidebar-menu-item__title'>{intl.formatMessage(messages.news)}</span>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div className='sidebar-menu__section'>
|
||||
<NavLink className='sidebar-menu-item' to='/follow_requests' onClick={onClose}>
|
||||
<Icon id='user-plus' />
|
||||
<span className='sidebar-menu-item__title'>{intl.formatMessage(messages.follow_requests)}</span>
|
||||
</NavLink>
|
||||
<NavLink className='sidebar-menu-item' to='/blocks' onClick={onClose}>
|
||||
<Icon id='ban' />
|
||||
<span className='sidebar-menu-item__title'>{intl.formatMessage(messages.blocks)}</span>
|
||||
</NavLink>
|
||||
<NavLink className='sidebar-menu-item' to='/domain_blocks' onClick={onClose}>
|
||||
<Icon id='ban' />
|
||||
<span className='sidebar-menu-item__title'>{intl.formatMessage(messages.domain_blocks)}</span>
|
||||
</NavLink>
|
||||
<NavLink className='sidebar-menu-item' to='/mutes' onClick={onClose}>
|
||||
<Icon id='times-circle' />
|
||||
<span className='sidebar-menu-item__title'>{intl.formatMessage(messages.mutes)}</span>
|
||||
</NavLink>
|
||||
<a className='sidebar-menu-item' href='/filters'>
|
||||
<Icon id='filter' />
|
||||
<span className='sidebar-menu-item__title'>{intl.formatMessage(messages.filters)}</span>
|
||||
</a>
|
||||
<a className='sidebar-menu-item' href='/settings/preferences'>
|
||||
<Icon id='cog' />
|
||||
<span className='sidebar-menu-item__title'>{intl.formatMessage(messages.preferences)}</span>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div className='sidebar-menu__section'>
|
||||
<a className='sidebar-menu-item' href='/auth/sign_out' data-method='delete'>
|
||||
<span className='sidebar-menu-item__title'>{intl.formatMessage(messages.logout)}</span>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -11,6 +11,7 @@ import SearchContainer from 'gabsocial/features/compose/containers/search_contai
|
||||
import Avatar from '../../../components/avatar';
|
||||
import ActionBar from 'gabsocial/features/compose/components/action_bar';
|
||||
import { openModal } from '../../../actions/modal';
|
||||
import { openSidebar } from '../../../actions/sidebar';
|
||||
|
||||
export const privateLinks = [
|
||||
<NavLink key='pr0' className='tabs-bar__link--logo' to='/home#' data-preview-title-id='column.home' style={{ padding: '0' }}>
|
||||
@@ -60,6 +61,7 @@ class TabsBar extends React.PureComponent {
|
||||
intl: PropTypes.object.isRequired,
|
||||
history: PropTypes.object.isRequired,
|
||||
onOpenCompose: PropTypes.func,
|
||||
onOpenSidebar: PropTypes.func.isRequired,
|
||||
}
|
||||
|
||||
state = {
|
||||
@@ -182,6 +184,7 @@ class TabsBar extends React.PureComponent {
|
||||
<div className='flex'>
|
||||
<div className='tabs-bar__profile'>
|
||||
<Avatar account={account} />
|
||||
<button className='tabs-bar__sidebar-btn' onClick={onOpenSidebar}></button>
|
||||
<ActionBar account={account} size={34} />
|
||||
</div>
|
||||
<span className='tabs-bar__page-name'>{pathTitle}</span>
|
||||
@@ -218,6 +221,9 @@ const mapDispatchToProps = (dispatch) => ({
|
||||
onOpenCompose() {
|
||||
dispatch(openModal('COMPOSE'));
|
||||
},
|
||||
onOpenSidebar() {
|
||||
dispatch(openSidebar());
|
||||
},
|
||||
});
|
||||
|
||||
export default injectIntl(
|
||||
|
||||
@@ -30,6 +30,7 @@ import GroupPage from 'gabsocial/pages/group_page';
|
||||
import SearchPage from 'gabsocial/pages/search_page';
|
||||
import HomePage from 'gabsocial/pages/home_page';
|
||||
import GroupSidebarPanel from '../groups/sidebar_panel';
|
||||
import SidebarMenu from '../../components/sidebar_menu';
|
||||
|
||||
import {
|
||||
Status,
|
||||
@@ -539,6 +540,7 @@ class UI extends React.PureComponent {
|
||||
<LoadingBarContainer className='loading-bar' />
|
||||
<ModalContainer />
|
||||
<UploadArea active={draggingOver} onClose={this.closeUploadModal} />
|
||||
<SidebarMenu />
|
||||
</div>
|
||||
</HotKeys>
|
||||
);
|
||||
|
||||
@@ -36,6 +36,7 @@ import groups from './groups';
|
||||
import group_relationships from './group_relationships';
|
||||
import group_lists from './group_lists';
|
||||
import group_editor from './group_editor';
|
||||
import sidebar from './sidebar';
|
||||
|
||||
const reducers = {
|
||||
dropdown_menu,
|
||||
@@ -75,6 +76,7 @@ const reducers = {
|
||||
group_relationships,
|
||||
group_lists,
|
||||
group_editor,
|
||||
sidebar,
|
||||
};
|
||||
|
||||
export default combineReducers(reducers);
|
||||
|
||||
12
app/javascript/gabsocial/reducers/sidebar.js
Normal file
12
app/javascript/gabsocial/reducers/sidebar.js
Normal file
@@ -0,0 +1,12 @@
|
||||
import { SIDEBAR_OPEN, SIDEBAR_CLOSE } from '../actions/sidebar';
|
||||
|
||||
export default function sidebar(state={}, action) {
|
||||
switch(action.type) {
|
||||
case SIDEBAR_OPEN:
|
||||
return { sidebarOpen: true };
|
||||
case SIDEBAR_CLOSE:
|
||||
return { sidebarOpen: false };
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
};
|
||||
Reference in New Issue
Block a user