add responsive sidebar

pull/350/head
slowbackspace 5 years ago
parent bc38fd3ade
commit d80e108754

@ -40,6 +40,8 @@ export type WalletAction = {
devices: Array<TrezorDevice>
} | {
type: typeof WALLET.SHOW_BETA_DISCLAIMER | typeof WALLET.HIDE_BETA_DISCLAIMER | typeof WALLET.SET_FIRST_LOCATION_CHANGE,
} | {
type: typeof WALLET.TOGGLE_SIDEBAR,
}
export const init = (): ThunkAction => (dispatch: Dispatch): void => {
@ -62,6 +64,10 @@ export const toggleDeviceDropdown = (opened: boolean): WalletAction => ({
opened,
});
export const toggleSidebar = (): WalletAction => ({
type: WALLET.TOGGLE_SIDEBAR,
});
// This method will be called after each DEVICE.CONNECT action
// if connected device has different "passphrase_protection" settings than saved instances
// all saved instances will be removed immediately inside DevicesReducer

@ -10,4 +10,6 @@ export const UPDATE_SELECTED_DEVICE: 'wallet__update_selected_device' = 'wallet_
export const SHOW_BETA_DISCLAIMER: 'wallet__show_beta_disclaimer' = 'wallet__show_beta_disclaimer';
export const HIDE_BETA_DISCLAIMER: 'wallet__hide_beta_disclaimer' = 'wallet__hide_beta_disclaimer';
export const CLEAR_UNAVAILABLE_DEVICE_DATA: 'wallet__clear_unavailable_device_data' = 'wallet__clear_unavailable_device_data';
export const CLEAR_UNAVAILABLE_DEVICE_DATA: 'wallet__clear_unavailable_device_data' = 'wallet__clear_unavailable_device_data';
export const TOGGLE_SIDEBAR: 'wallet__toggle_sidebar' = 'wallet__toggle_sidebar';

@ -3,11 +3,15 @@ import React from 'react';
import styled from 'styled-components';
import { NavLink } from 'react-router-dom';
import colors from 'config/colors';
import { SCREEN_SIZE } from 'config/variables';
import type { toggleSidebar as toggleSidebarType } from 'actions/WalletActions';
const Wrapper = styled.header`
width: 100%;
height: 52px;
background: ${colors.HEADER};
overflow: hidden;
z-index: 200;
svg {
fill: ${colors.WHITE};
@ -30,13 +34,47 @@ const LayoutWrapper = styled.div`
}
`;
const Left = styled.div`
const MenuToggler = styled.div`
display: none;
flex: 0 0 33%;
white-space: nowrap;
color: ${colors.WHITE};
align-self: center;
cursor: pointer;
user-select: none;
padding: 10px 0px;
transition: all .1s ease-in;
@media screen and (max-width: ${SCREEN_SIZE.SM}) {
display: initial;
}
`;
const Logo = styled.div`
flex: 1;
display: flex;
justify-content: flex-start;
display: flex;
@media screen and (max-width: ${SCREEN_SIZE.SM}) {
flex: 1 0 33%;
justify-content: center;
}
`;
const Right = styled.div``;
const MenuLinks = styled.div`
flex: 0;
@media screen and (max-width: ${SCREEN_SIZE.SM}) {
flex: 0 1 33%;
}
`;
const Projects = styled.div`
@media screen and (max-width: ${SCREEN_SIZE.SM}) {
display: none;
}
`;
const A = styled.a`
color: ${colors.WHITE};
@ -58,10 +96,17 @@ const A = styled.a`
}
`;
const Header = (): React$Element<string> => (
type Props = {
sidebarOpened?: boolean,
toggleSidebar?: toggleSidebarType,
};
const Header = ({ sidebarOpened, toggleSidebar }: Props) => (
<Wrapper>
<LayoutWrapper>
<Left>
<MenuToggler onClick={toggleSidebar}>{sidebarOpened ? '✕ Close' : '☰ Menu'}</MenuToggler>
<Logo>
<NavLink to="/">
<svg xmlns="http://www.w3.org/2000/svg" x="0px" y="0px" viewBox="0 0 163.7 41.9" width="100%" height="100%" preserveAspectRatio="xMinYMin meet">
<polygon points="101.1,12.8 118.2,12.8 118.2,17.3 108.9,29.9 118.2,29.9 118.2,35.2 101.1,35.2 101.1,30.7 110.4,18.1 101.1,18.1" />
@ -73,13 +118,15 @@ const Header = (): React$Element<string> => (
<polygon points="40.5,12.8 58.6,12.8 58.6,18.1 52.4,18.1 52.4,35.2 46.6,35.2 46.6,18.1 40.5,18.1 " />
</svg>
</NavLink>
</Left>
<Right>
<A href="https://trezor.io/" target="_blank" rel="noreferrer noopener">Trezor</A>
<A href="https://wiki.trezor.io/" target="_blank" rel="noreferrer noopener">Wiki</A>
<A href="https://blog.trezor.io/" target="_blank" rel="noreferrer noopener">Blog</A>
<A href="https://trezor.io/support/" target="_blank" rel="noreferrer noopener">Support</A>
</Right>
</Logo>
<MenuLinks>
<Projects>
<A href="https://trezor.io/" target="_blank" rel="noreferrer noopener">Trezor</A>
<A href="https://wiki.trezor.io/" target="_blank" rel="noreferrer noopener">Wiki</A>
<A href="https://blog.trezor.io/" target="_blank" rel="noreferrer noopener">Blog</A>
<A href="https://trezor.io/support/" target="_blank" rel="noreferrer noopener">Support</A>
</Projects>
</MenuLinks>
</LayoutWrapper>
</Wrapper>
);

@ -6,6 +6,7 @@ import { DEVICE, TRANSPORT } from 'trezor-connect';
import * as MODAL from 'actions/constants/modal';
import * as WALLET from 'actions/constants/wallet';
import * as CONNECT from 'actions/constants/TrezorConnect';
import * as ACCOUNT from 'actions/constants/account';
import type { Action, RouterLocationState, TrezorDevice } from 'flowtype';
@ -14,6 +15,7 @@ type State = {
online: boolean;
dropdownOpened: boolean;
showBetaDisclaimer: boolean;
showSidebar: boolean;
initialParams: ?RouterLocationState;
initialPathname: ?string;
firstLocationChange: boolean;
@ -27,6 +29,7 @@ const initialState: State = {
dropdownOpened: false,
firstLocationChange: true,
showBetaDisclaimer: false,
showSidebar: true,
initialParams: null,
initialPathname: null,
disconnectRequest: null,
@ -71,6 +74,11 @@ export default function wallet(state: State = initialState, action: Action): Sta
...state,
dropdownOpened: false,
};
case ACCOUNT.UPDATE_SELECTED_ACCOUNT:
return {
...state,
showSidebar: false,
};
case CONNECT.DISCONNECT_REQUEST:
return {
@ -94,6 +102,12 @@ export default function wallet(state: State = initialState, action: Action): Sta
selectedDevice: action.device,
};
case WALLET.TOGGLE_SIDEBAR:
return {
...state,
showSidebar: !state.showSidebar,
};
case WALLET.SHOW_BETA_DISCLAIMER:
return {
...state,

@ -4,7 +4,7 @@ import * as React from 'react';
import PropTypes from 'prop-types';
import styled from 'styled-components';
import Loader from 'components/Loader';
import { FONT_SIZE, FONT_WEIGHT } from 'config/variables';
import { FONT_SIZE, FONT_WEIGHT, SCREEN_SIZE } from 'config/variables';
import { H1 } from 'components/Heading';
import P from 'components/Paragraph';
import colors from 'config/colors';
@ -26,6 +26,10 @@ const Wrapper = styled.div`
flex: 1;
flex-direction: column;
padding: 40px 35px 40px 35px;
@media screen and (max-width: ${SCREEN_SIZE.SM}){
padding: 20px 35px;
}
`;
const Loading = styled.div`

@ -0,0 +1,69 @@
/* @flow */
import * as React from 'react';
import styled from 'styled-components';
import colors from 'config/colors';
import { SCREEN_SIZE } from 'config/variables';
import { SLIDE_RIGHT, SLIDE_LEFT } from 'config/animations';
type Props = {
children?: React.Node,
isOpen: boolean,
}
type State = {
footerFixed: boolean,
}
const AbsoluteWrapper = styled.aside`
width: 320px;
position: relative;
overflow-y: auto;
background: ${colors.MAIN};
border-top-left-radius: 4px;
border-right: 1px solid ${colors.DIVIDER};
@media screen and (max-width: ${SCREEN_SIZE.SM}) {
position: absolute;
height: calc(100% - 52px);
z-index: 200;
top: 52px;
animation: ${props => (props.isOpen ? SLIDE_RIGHT : SLIDE_LEFT)} 0.25s cubic-bezier(0.17, 0.04, 0.03, 0.94) forwards;
}
@media screen and (max-width: ${SCREEN_SIZE.LG}) {
border-top-left-radius: 0px;
}
`;
const MobileSidebarWrapper = styled.div`
height: 100%;
display: flex;
flex-direction: column;
`;
export default class MobileSidebar extends React.PureComponent<Props, State> {
constructor(props: Props) {
super(props);
this.state = {
footerFixed: false,
};
}
render() {
return (
<AbsoluteWrapper isOpen={this.props.isOpen}>
<MobileSidebarWrapper>
{React.Children.map(this.props.children, (child) => { // eslint-disable-line arrow-body-style
return child.key === 'sticky-footer' ? React.cloneElement(child, {
position: this.state.footerFixed ? 'fixed' : 'relative',
}) : child;
})}
</MobileSidebarWrapper>
</AbsoluteWrapper>
);
}
}

@ -15,12 +15,13 @@ import * as deviceUtils from 'utils/device';
import AccountMenu from './components/AccountMenu';
import CoinMenu from './components/CoinMenu';
import DeviceMenu from './components/DeviceMenu';
import StickyContainer from './components/StickyContainer';
import MobileSidebar from './components/MobileSidebar';
import type { Props } from './components/common';
const Header = styled(DeviceHeader)`
border-right: 1px solid ${colors.BACKGROUND};
flex: 0 0 auto;
`;
const Counter = styled.div`
@ -56,6 +57,7 @@ const Footer = styled.div.attrs(props => ({
`;
const Body = styled.div`
flex: 1 0 auto;
width: 320px;
min-height: ${props => (props.minHeight ? `${props.minHeight}px` : '0px')};
`;
@ -201,8 +203,10 @@ class LeftNavigation extends React.PureComponent<Props, State> {
const { selectedDevice, dropdownOpened } = props.wallet;
const isDeviceAccessible = deviceUtils.isDeviceAccessible(selectedDevice);
const SidebarComponent = MobileSidebar;
return (
<StickyContainer
<SidebarComponent
isOpen={props.wallet.showSidebar}
location={props.router.location.pathname}
deviceSelection={this.props.wallet.dropdownOpened}
>
@ -249,7 +253,7 @@ class LeftNavigation extends React.PureComponent<Props, State> {
</A>
</Help>
</Footer>
</StickyContainer>
</SidebarComponent>
);
}
}

@ -6,35 +6,44 @@ import styled from 'styled-components';
import { connect } from 'react-redux';
import { Route, withRouter } from 'react-router-dom';
import type { MapStateToProps } from 'react-redux';
import type { MapStateToProps, MapDispatchToProps } from 'react-redux';
import type { State } from 'flowtype';
import type { WalletAction } from 'actions/WalletActions';
import { toggleSidebar } from 'actions/WalletActions';
import { bindActionCreators } from 'redux';
import Header from 'components/Header';
import Footer from 'components/Footer';
import ModalContainer from 'components/modals/Container';
import AppNotifications from 'components/notifications/App';
import ContextNotifications from 'components/notifications/Context';
import { SCREEN_SIZE } from 'config/variables';
import Log from 'components/Log';
import Backdrop from 'components/Backdrop';
import LeftNavigation from './components/LeftNavigation/Container';
import TopNavigationAccount from './components/TopNavigationAccount';
import TopNavigationDeviceSettings from './components/TopNavigationDeviceSettings';
type WalletContainerProps = {
type StateProps = {
wallet: $ElementType<State, 'wallet'>,
children?: React.Node
children?: React.Node,
}
// type ContentProps = {
// children?: React.Node
// }
type DispatchProps = {
toggleSidebar: WalletAction,
};
type OwnProps = {};
export type Props = StateProps & DispatchProps;
const AppWrapper = styled.div`
position: relative;
min-height: 100%;
min-width: 720px;
display: flex;
flex-direction: column;
background: ${colors.BACKGROUND};
@ -87,11 +96,20 @@ const Body = styled.div`
flex-direction: column;
`;
const Wallet = (props: WalletContainerProps) => (
const StyledBackdrop = styled(Backdrop)`
display: none;
@media screen and (max-width: ${SCREEN_SIZE.SM}) {
display: initial;
}
`;
const Wallet = (props: Props) => (
<AppWrapper>
<Header />
<Header sidebarOpened={props.wallet.showSidebar} toggleSidebar={props.toggleSidebar} />
<AppNotifications />
<WalletWrapper>
<StyledBackdrop show={props.wallet.showSidebar} onClick={props.toggleSidebar} animated />
{props.wallet.selectedDevice && <LeftNavigation />}
<MainContent>
<Navigation>
@ -110,10 +128,14 @@ const Wallet = (props: WalletContainerProps) => (
</AppWrapper>
);
const mapStateToProps: MapStateToProps<State, {}, WalletContainerProps> = (state: State): WalletContainerProps => ({
const mapStateToProps: MapStateToProps<State, OwnProps, StateProps> = (state: State): StateProps => ({
wallet: state.wallet,
});
const mapDispatchToProps: MapDispatchToProps<Dispatch, OwnProps, DispatchProps> = (dispatch: Dispatch): DispatchProps => ({
toggleSidebar: bindActionCreators(toggleSidebar, dispatch),
});
export default withRouter(
connect(mapStateToProps, null)(Wallet),
connect(mapStateToProps, mapDispatchToProps)(Wallet),
);

Loading…
Cancel
Save