Merge pull request #140 from sharetribe/topbar-mobile-menu

Topbar mobile menu
This commit is contained in:
Vesa Luusua 2017-05-04 16:27:25 +03:00 committed by GitHub
commit 7eb452c3ed
9 changed files with 237 additions and 33 deletions

View file

@ -72,3 +72,30 @@
cursor: auto;
}
}
.inlineButton {
display: inline-block;
padding: 0;
/* fill colors should be in sync with marketplace color palette */
background-color: transparent;
/* border-width should be in sync with marketplace strike-widths */
border-width: 0px;
/* Font configuration */
text-decoration: underline;
/* Hovers */
&:enabled {
cursor: pointer;
}
&:enabled:hover,
&:enabled:active {
background-color: transparent;
}
&:disabled {
background-color: transparent;
cursor: auto;
}
}

View file

@ -29,7 +29,9 @@ Button.propTypes = {
export default Button;
export const FlatButton = props => <Button {...props} rootClassName={css.flatButton} />;
FlatButton.defaultProps = { className: '' };
FlatButton.propTypes = { className: string };
export const InlineButton = props => <Button {...props} rootClassName={css.inlineButton} />;
InlineButton.defaultProps = { className: '' };
InlineButton.propTypes = { className: string };

View file

@ -0,0 +1,46 @@
.root {
display: flex;
flex-direction: column;
height: 100vh;
padding: 1rem;
}
.user {
display: flex;
flex-direction: row;
flex-basis: 80px;
}
.content {
flex-grow: 1;
}
.footer {
flex-basis: 80px;
}
.avatar {
width: 44px;
height: 44px;
margin-right: 1rem;
}
.createNewListingLink {
font-size: 14px;
}
.userInfo {
display: flex;
flex-direction: column;
}
.authenticationLinks {
display: flex;
flex-direction: row;
margin-bottom: 1rem;
font-size: 20px;
}
.signupLink {
margin-right: 1rem;
}

View file

@ -0,0 +1,69 @@
/**
* MobileMenu prints the menu content for authenticated user or
* shows login actions for those who are not authenticated.
*/
import React, { PropTypes } from 'react';
import { FormattedMessage } from 'react-intl';
import { Avatar, InlineButton, NamedLink } from '../../components';
import css from './MobileMenu.css';
const MobileMenu = props => {
const { isAuthenticated, name, onLogout } = props;
if (!isAuthenticated) {
return (
<div className={css.root}>
<div className={css.authenticationLinks}>
<NamedLink name="SignUpPage" className={css.signupLink}>
<FormattedMessage id="MobileMenu.signupLink" />
</NamedLink>
<NamedLink name="LogInPage">
<FormattedMessage id="MobileMenu.loginLink" />
</NamedLink>
</div>
<div className={css.createNewListingLink}>
<NamedLink name="NewListingPage">
<FormattedMessage id="MobileMenu.newListingLink" />
</NamedLink>
</div>
</div>
);
}
return (
<div className={css.root}>
<div className={css.user}>
<Avatar className={css.avatar} name={name} />
<div className={css.userInfo}>
<span>{name}</span>
<NamedLink className={css.createNewListingLink} name="NewListingPage">
<FormattedMessage id="MobileMenu.newListingLink" />
</NamedLink>
</div>
</div>
<div className={css.content}>
<NamedLink name="InboxPage" params={{ tab: 'orders' }}>
<FormattedMessage id="MobileMenu.inboxLink" />
</NamedLink>
</div>
<div className={css.footer}>
<InlineButton className={css.logoutButton} onClick={onLogout}>
<FormattedMessage id="MobileMenu.logoutLink" />
</InlineButton>
</div>
</div>
);
};
MobileMenu.defaultProps = { name: '' };
const { bool, func, string } = PropTypes;
MobileMenu.propTypes = {
isAuthenticated: bool.isRequired,
name: string,
onLogout: func.isRequired,
};
export default MobileMenu;

View file

@ -2,7 +2,7 @@ import AddImages from './AddImages/AddImages';
import AuthorInfo from './AuthorInfo/AuthorInfo';
import Avatar from './Avatar/Avatar';
import BookingInfo from './BookingInfo/BookingInfo';
import Button, { FlatButton } from './Button/Button';
import Button, { FlatButton, InlineButton } from './Button/Button';
import CurrencyInput from './CurrencyInput/CurrencyInput';
import DateInput from './DateInput/DateInput';
import Discussion from './Discussion/Discussion';
@ -17,6 +17,7 @@ import Map from './Map/Map';
import MapPanel from './MapPanel/MapPanel';
import Menu from './Menu/Menu';
import MobileFrame from './MobileFrame/MobileFrame';
import MobileMenu from './MobileMenu/MobileMenu';
import Modal from './Modal/Modal';
import ModalInMobile from './ModalInMobile/ModalInMobile';
import NamedLink from './NamedLink/NamedLink';
@ -43,6 +44,7 @@ export {
FilterPanel,
FlatButton,
HeroSection,
InlineButton,
Input,
LabeledField,
ListingCard,
@ -52,6 +54,7 @@ export {
MapPanel,
Menu,
MobileFrame,
MobileMenu,
Modal,
ModalInMobile,
NamedLink,

View file

@ -44,15 +44,39 @@ exports[`InboxPage matches snapshot 1`] = `
className="">
<div
className={undefined}>
<a
className=""
href="/inbox"
onClick={[Function]}
style={Object {}}>
<span>
Inbox
</span>
</a>
<div
className={undefined}>
<a
className=""
href="/signup"
onClick={[Function]}
style={Object {}}>
<span>
Sign up
</span>
</a>
<a
className=""
href="/login"
onClick={[Function]}
style={Object {}}>
<span>
Log in
</span>
</a>
</div>
<div
className={undefined}>
<a
className=""
href="/l/new"
onClick={[Function]}
style={Object {}}>
<span>
+ Add your sauna
</span>
</a>
</div>
</div>
</div>
</div>
@ -204,15 +228,39 @@ exports[`InboxPage matches snapshot 2`] = `
className="">
<div
className={undefined}>
<a
className=""
href="/inbox"
onClick={[Function]}
style={Object {}}>
<span>
Inbox
</span>
</a>
<div
className={undefined}>
<a
className=""
href="/signup"
onClick={[Function]}
style={Object {}}>
<span>
Sign up
</span>
</a>
<a
className=""
href="/login"
onClick={[Function]}
style={Object {}}>
<span>
Log in
</span>
</a>
</div>
<div
className={undefined}>
<a
className=""
href="/l/new"
onClick={[Function]}
style={Object {}}>
<span>
+ Add your sauna
</span>
</a>
</div>
</div>
</div>
</div>

View file

@ -46,7 +46,3 @@
.hamburgerMenu {
width: 44px;
}
.mobileMenuContent {
padding: 1rem;
}

View file

@ -1,11 +1,11 @@
import React, { Component, PropTypes } from 'react';
import { compose } from 'redux';
import { connect } from 'react-redux';
import { FormattedMessage } from 'react-intl';
import { logout, authenticationInProgress } from '../../ducks/Auth.duck';
import { Button, FlatButton, Modal, NamedLink } from '../../components';
import { Button, FlatButton, MobileMenu, Modal, NamedLink } from '../../components';
import { withFlattenedRoutes } from '../../util/contextHelpers';
import { parse, stringify } from '../../util/urlHelpers';
import { ensureUser } from '../../util/data';
import { pathByRouteName } from '../../util/routes';
import * as propTypes from '../../util/propTypes';
@ -53,7 +53,16 @@ class TopbarComponent extends Component {
}
render() {
const { isAuthenticated, authInProgress, location, togglePageClassNames } = this.props;
const {
isAuthenticated,
authInProgress,
currentUser,
location,
togglePageClassNames,
} = this.props;
const me = ensureUser(currentUser);
const profile = me.attributes.profile;
const name = me.id ? `${profile.firstName} ${profile.lastName}` : '';
const { mobilemenu } = parse(location.search);
const isMobileMenuOpen = mobilemenu === 'open';
@ -81,11 +90,7 @@ class TopbarComponent extends Component {
onClose={this.handleMobileMenuClose}
togglePageClassNames={togglePageClassNames}
>
<div className={css.mobileMenuContent}>
<NamedLink name="InboxBasePage">
<FormattedMessage id="Topbar.inboxLink" defaultMessage="Inbox" />
</NamedLink>
</div>
<MobileMenu isAuthenticated={isAuthenticated} name={name} onLogout={this.handleLogout} />
</Modal>
</div>
);
@ -97,6 +102,7 @@ const { arrayOf, bool, func, shape, string } = PropTypes;
TopbarComponent.propTypes = {
isAuthenticated: bool.isRequired,
authInProgress: bool.isRequired,
currentUser: propTypes.currentUser,
onLogout: func.isRequired,
togglePageClassNames: func.isRequired,
@ -114,9 +120,11 @@ TopbarComponent.propTypes = {
const mapStateToProps = state => {
const { isAuthenticated } = state.Auth;
const { currentUser } = state.user;
return {
isAuthenticated,
authInProgress: authenticationInProgress(state),
currentUser,
};
};

View file

@ -59,6 +59,11 @@
"LoginForm.emailLabel": "Email",
"LoginForm.logIn": "Log in",
"LoginForm.passwordLabel": "Password",
"MobileMenu.inboxLink": "Inbox",
"MobileMenu.loginLink": "Log in",
"MobileMenu.logoutLink": "Log out",
"MobileMenu.newListingLink": "+ Add your sauna",
"MobileMenu.signupLink": "Sign up",
"Modal.closeModal": "Close modal",
"OrderDetailsPanel.orderAcceptedStatus": "{providerName} accepted the booking.",
"OrderDetailsPanel.orderAcceptedTitle": "You have booked {title}.",