[Improvement] Using material-ui drawer

This commit is contained in:
Qolzam
2018-02-21 17:44:32 +07:00
parent c81cfa9c44
commit cacb940b15
10 changed files with 226 additions and 177 deletions

View File

@@ -7,7 +7,10 @@ import { connect } from 'react-redux'
import { push } from 'react-router-redux' import { push } from 'react-router-redux'
import { getTranslate, getActiveLanguage } from 'react-localize-redux' import { getTranslate, getActiveLanguage } from 'react-localize-redux'
import config from 'src/config' import config from 'src/config'
import classNames from 'classnames'
import { withStyles } from 'material-ui/styles'
import Drawer from 'material-ui/Drawer'
import Menu from 'material-ui/Menu' import Menu from 'material-ui/Menu'
import { MenuList, MenuItem } from 'material-ui/Menu' import { MenuList, MenuItem } from 'material-ui/Menu'
import { ListItemIcon, ListItemText } from 'material-ui/List' import { ListItemIcon, ListItemText } from 'material-ui/List'
@@ -18,6 +21,11 @@ import SvgFeedback from 'material-ui-icons/Feedback'
import SvgSettings from 'material-ui-icons/Settings' import SvgSettings from 'material-ui-icons/Settings'
import SvgAccountCircle from 'material-ui-icons/AccountCircle' import SvgAccountCircle from 'material-ui-icons/AccountCircle'
import SvgPeople from 'material-ui-icons/People' import SvgPeople from 'material-ui-icons/People'
import List from 'material-ui/List'
import Typography from 'material-ui/Typography'
import IconButton from 'material-ui/IconButton'
import Hidden from 'material-ui/Hidden'
import MenuIcon from 'material-ui-icons/Menu'
// - Import app components // - Import app components
import Sidebar from 'components/sidebar' import Sidebar from 'components/sidebar'
@@ -48,67 +56,115 @@ import {
import { IHomeComponentProps } from './IHomeComponentProps' import { IHomeComponentProps } from './IHomeComponentProps'
import { IHomeComponentState } from './IHomeComponentState' import { IHomeComponentState } from './IHomeComponentState'
const drawerWidth = 240
const styles = (theme: any) => ({
root: {
width: '100%',
marginTop: theme.spacing.unit * 3,
zIndex: 1,
overflow: 'hidden',
},
appFrame: {
position: 'relative',
display: 'flex',
width: '100%',
height: '100%',
},
navIconHide: {
[theme.breakpoints.up('md')]: {
display: 'none',
},
},
drawerHeader: theme.mixins.toolbar,
drawerPaper: {
width: drawerWidth,
[theme.breakpoints.up('md')]: {
width: drawerWidth,
position: 'relative',
height: '100%',
},
},
drawerPaperLarge: {
width: drawerWidth,
[theme.breakpoints.up('md')]: {
width: drawerWidth,
height: '100%',
},
top: 70,
backgroundColor: 'transparent',
borderRight: 0
},
menu: {
height: '100%',
backgroundColor: '#EEEEEE'
},
content: {
backgroundColor: 'transparent',
width: '100%',
flexGrow: 1,
padding: theme.spacing.unit * 1,
transition: theme.transitions.create('margin', {
easing: theme.transitions.easing.sharp,
duration: theme.transitions.duration.leavingScreen,
}),
height: 'calc(100% - 56px)',
marginTop: 56,
[theme.breakpoints.up('sm')]: {
height: 'calc(100% - 64px)',
marginTop: 64,
},
},
'content-left': {
marginLeft: 0,
},
'content-right': {
marginRight: 0,
},
contentShift: {
transition: theme.transitions.create('margin', {
easing: theme.transitions.easing.easeOut,
duration: theme.transitions.duration.enteringScreen,
}),
},
'contentShift-left': {
marginLeft: 0,
[theme.breakpoints.up('md')]: {
marginLeft: drawerWidth
}
},
'contentShift-right': {
marginRight: 0,
[theme.breakpoints.up('md')]: {
marginRight: drawerWidth
}
}
})
// - Create Home component class // - Create Home component class
export class HomeComponent extends Component<IHomeComponentProps, IHomeComponentState> { export class HomeComponent extends Component<IHomeComponentProps, IHomeComponentState> {
// Constructor // Constructor
constructor (props: IHomeComponentProps) { constructor(props: IHomeComponentProps) {
super(props) super(props)
// Default state // Default state
this.state = { this.state = {
sidebarOpen: () => _, drawerOpen: false
sidebarStatus: true,
sidebarOverlay: false
} }
// Binding function to `this` // Binding function to `this`
this.sidebar = this.sidebar.bind(this)
this.sidebarStatus = this.sidebarStatus.bind(this)
this.sidebarOverlay = this.sidebarOverlay.bind(this)
this.handleCloseSidebar = this.handleCloseSidebar.bind(this)
} }
/** /**
* handle close sidebar * Handle drawer toggle
*/ */
handleCloseSidebar = () => { handleDrawerToggle = () => {
this.state.sidebarOpen!(false, 'overlay') console.trace('toggle')
this.setState({ drawerOpen: !this.state.drawerOpen })
} }
/** componentWillMount() {
* Change sidebar overlay status
* @param {boolean} status if is true, the sidebar is on overlay status
*/
sidebarOverlay = (status: boolean) => {
this.setState({
sidebarOverlay: status
})
}
/**
* Pass the function to change sidebar status
* @param {boolean} open is a function callback to change sidebar status out of sidebar component
*/
sidebar = (open: (status: boolean, source: string) => void) => {
this.setState({
sidebarOpen: open
})
}
/**
* Change sidebar status if is open or not
* @param {boolean} status is true, if the sidebar is open
*/
sidebarStatus = (status: boolean) => {
this.setState({
sidebarStatus: status
})
}
componentWillMount () {
const { global, clearData, loadData, authed, defaultDataEnable, isVerifide, goTo } = this.props const { global, clearData, loadData, authed, defaultDataEnable, isVerifide, goTo } = this.props
if (!authed) { if (!authed) {
goTo!('/login') goTo!('/login')
@@ -132,76 +188,106 @@ export class HomeComponent extends Component<IHomeComponentProps, IHomeComponent
* *
* @memberof Home * @memberof Home
*/ */
render () { render() {
const HR = HomeRouter as any const HR = HomeRouter as any
const { loaded, authed, loadDataStream, mergedPosts, hasMorePosts, showSendFeedback, translate } = this.props const { loaded, authed, loadDataStream, mergedPosts, hasMorePosts, showSendFeedback, translate, classes, theme } = this.props
const {drawerOpen} = this.state
const drawer = (
<>
<NavLink to='/'>
<MenuItem style={{ color: 'rgb(117, 117, 117)' }}>
<ListItemIcon>
<SvgHome />
</ListItemIcon>
<ListItemText inset primary={translate!('sidebar.home')} />
</MenuItem>
</NavLink>
<NavLink to={`/${this.props.uid}`}>
<MenuItem style={{ color: 'rgb(117, 117, 117)' }}>
<ListItemIcon>
<SvgAccountCircle />
</ListItemIcon>
<ListItemText inset primary={translate!('sidebar.profile')} />
</MenuItem>
</NavLink>
<NavLink to='/people'>
<MenuItem style={{ color: 'rgb(117, 117, 117)' }}>
<ListItemIcon>
<SvgPeople />
</ListItemIcon>
<ListItemText inset primary={translate!('sidebar.people')} />
</MenuItem>
</NavLink>
<Divider />
<NavLink to='/settings'>
<MenuItem style={{ color: 'rgb(117, 117, 117)' }}>
<ListItemIcon>
<SvgSettings />
</ListItemIcon>
<ListItemText inset primary={translate!('sidebar.settings')} />
</MenuItem>
</NavLink>
<MenuItem onClick={() => showSendFeedback!()} style={{ color: 'rgb(117, 117, 117)' }}>
<ListItemIcon>
<SvgFeedback />
</ListItemIcon>
<ListItemText inset primary={translate!('sidebar.sendFeedback')} />
</MenuItem>
</>
)
const anchor = theme.direction === 'rtl' ? 'right' : 'left'
return ( return (
<div id='home'> <div className={classes.root}>
<HomeHeader sidebar={this.state.sidebarOpen} sidebarStatus={this.state.sidebarStatus} /> <div className={classes.appFrame}>
<Sidebar overlay={this.sidebarOverlay} open={this.sidebar} status={this.sidebarStatus}> <HomeHeader onToggleDrawer={this.handleDrawerToggle} drawerStatus={this.state.drawerOpen} />
<SidebarContent> <Hidden mdUp>
<MenuList style={{ color: 'rgb(117, 117, 117)', width: '210px' }}> <Drawer
{this.state.sidebarOverlay variant='temporary'
? <div> anchor={anchor}
<MenuItem style={{ color: 'rgb(117, 117, 117)' }}> open={this.state.drawerOpen}
<ListItemIcon> classes={{
<SvgArrowLeft viewBox='0 3 24 24' style={{ color: '#fff', marginLeft: '15px', width: '32px', height: '32px', cursor: 'pointer' }} /> paper: classes.drawerPaper,
</ListItemIcon> }}
<ListItemText inset onClose={this.handleDrawerToggle}
primary={<span style={{ color: 'rgb(117, 117, 117)' }} ModalProps={{
className='sidebar__title'>{config.settings.appName}</span>} /> keepMounted: true, // Better open performance on mobile.
</MenuItem> }}
<Divider /></div> >
: '' <div>
} <div className={classes.drawerHeader} />
<MenuList style={{ color: 'rgb(117, 117, 117)', width: '210px' }}>
<NavLink to='/'> <Divider />
<MenuItem style={{ color: 'rgb(117, 117, 117)' }}> {drawer}
<ListItemIcon> </MenuList>
<SvgHome /> </div>
</ListItemIcon> </Drawer>
<ListItemText inset primary={translate!('sidebar.home')} /> </Hidden>
</MenuItem> <Hidden smDown implementation='js'>
</NavLink> <Drawer
<NavLink to={`/${this.props.uid}`}> variant='persistent'
<MenuItem style={{ color: 'rgb(117, 117, 117)' }}> open={this.state.drawerOpen}
<ListItemIcon> classes={{
<SvgAccountCircle /> paper: classes.drawerPaperLarge,
</ListItemIcon> }}
<ListItemText inset primary={translate!('sidebar.profile')} /> >
</MenuItem> <div>
</NavLink> <MenuList className={classes.menu} style={{ color: 'rgb(117, 117, 117)', width: '210px' }}>
<NavLink to='/people'> {drawer}
<MenuItem style={{ color: 'rgb(117, 117, 117)' }}> </MenuList>
<ListItemIcon> </div>
<SvgPeople /> </Drawer>
</ListItemIcon> </Hidden>
<ListItemText inset primary={translate!('sidebar.people')} /> <main
</MenuItem> className={classNames(classes.content, classes[`content-${anchor}`], {
</NavLink> [classes.contentShift]: drawerOpen,
<Divider /> [classes[`contentShift-${anchor}`]]: drawerOpen,
<NavLink to='/settings'> })}
<MenuItem style={{ color: 'rgb(117, 117, 117)' }}> >
<ListItemIcon>
<SvgSettings />
</ListItemIcon>
<ListItemText inset primary={translate!('sidebar.settings')} />
</MenuItem>
</NavLink>
<MenuItem onClick={() => showSendFeedback!()} style={{ color: 'rgb(117, 117, 117)' }}>
<ListItemIcon>
<SvgFeedback />
</ListItemIcon>
<ListItemText inset primary={translate!('sidebar.sendFeedback')} />
</MenuItem>
</MenuList>
</SidebarContent>
<SidebarMain>
<HR enabled={loaded!} data={{ mergedPosts, loadDataStream, hasMorePosts }} /> <HR enabled={loaded!} data={{ mergedPosts, loadDataStream, hasMorePosts }} />
</SidebarMain> </main>
</Sidebar> </div>
</div> </div>
) )
@@ -280,4 +366,4 @@ const mapStateToProps = (state: any, ownProps: IHomeComponentProps) => {
} }
// - Connect component to redux store // - Connect component to redux store
export default withRouter<any>(connect(mapStateToProps, mapDispatchToProps)(HomeComponent as any)) as typeof HomeComponent export default withRouter<any>(connect(mapStateToProps, mapDispatchToProps)(withStyles(styles as any, { withTheme: true })(HomeComponent as any) as any)) as typeof HomeComponent

View File

@@ -113,4 +113,14 @@ export interface IHomeComponentProps {
*/ */
translate?: (state: any) => any translate?: (state: any) => any
/**
* Styles
*/
classes?: any
/**
* Theme
*/
theme?: any
} }

View File

@@ -2,26 +2,7 @@
export interface IHomeComponentState { export interface IHomeComponentState {
/** /**
* Change sidebar status to {open(status:true)/close(status:false)} * Whether drawer is open
*
* @type {(status: boolean, state: string)}
* @memberof IHomeComponentState
*/ */
sidebarOpen: (status: boolean, source: string) => void drawerOpen: boolean
/**
* Sidebar status
*
* @type {boolean}
* @memberof IHomeComponentState
*/
sidebarStatus: boolean
/**
* Sidebar overlay status
*
* @type {boolean}
* @memberof IHomeComponentState
*/
sidebarOverlay: boolean
} }

View File

@@ -2,6 +2,8 @@
import React, { Component } from 'react' import React, { Component } from 'react'
import { NavLink } from 'react-router-dom' import { NavLink } from 'react-router-dom'
import { connect } from 'react-redux' import { connect } from 'react-redux'
// - Material UI
import SvgDehaze from 'material-ui-icons/Dehaze' import SvgDehaze from 'material-ui-icons/Dehaze'
import { grey, blue } from 'material-ui/colors' import { grey, blue } from 'material-ui/colors'
import Toolbar from 'material-ui/Toolbar' import Toolbar from 'material-ui/Toolbar'
@@ -10,8 +12,8 @@ import Popover from 'material-ui/Popover'
import AppBar from 'material-ui/AppBar' import AppBar from 'material-ui/AppBar'
import Menu, { MenuList, MenuItem } from 'material-ui/Menu' import Menu, { MenuList, MenuItem } from 'material-ui/Menu'
import Paper from 'material-ui/Paper' import Paper from 'material-ui/Paper'
import Hidden from 'material-ui/Hidden'
import NotificationsIcon from 'material-ui-icons/Notifications' import NotificationsIcon from 'material-ui-icons/Notifications'
import EventListener, { withOptions } from 'react-event-listener'
import Tooltip from 'material-ui/Tooltip' import Tooltip from 'material-ui/Tooltip'
import Typography from 'material-ui/Typography' import Typography from 'material-ui/Typography'
import { Manager, Target, Popper } from 'react-popper' import { Manager, Target, Popper } from 'react-popper'
@@ -92,13 +94,8 @@ export class HomeHeaderComponent extends Component<IHomeHeaderComponentProps, IH
// On click toggle sidebar // On click toggle sidebar
onToggleSidebar = () => { onToggleSidebar = () => {
if (this.props.sidebarStatus) { const {onToggleDrawer} = this.props
this.props.sidebar!(false, 'onToggle') onToggleDrawer()
} else {
this.props.sidebar!(true, 'onToggle')
}
} }
/** /**
@@ -153,29 +150,19 @@ export class HomeHeaderComponent extends Component<IHomeHeaderComponentProps, IH
}) })
} }
handleKeyUp = () => {
// TODO: Handle key up on press ESC to close menu
}
/** /**
* Handle resize event for window to manipulate home header status * Handle resize event for window to manipulate home header status
* @param {event} evt is the event is passed by winodw resize event * @param {event} evt is the event is passed by winodw resize event
*/ */
handleResize = (event: any) => { handleResize = (event: any) => {
const {drawerStatus} = this.props
// Set initial state // Set initial state
let width = window.innerWidth let width = window.innerWidth
if (width >= 600 && !this.state.showTitle) { if (width >= 600 && !drawerStatus) {
this.setState({ this.onToggleSidebar()
showTitle: true } else if (width < 600) {
})
} else if (width < 600 && this.state.showTitle) {
this.setState({
showTitle: false
})
} }
} }
@@ -190,11 +177,6 @@ export class HomeHeaderComponent extends Component<IHomeHeaderComponentProps, IH
<AppBar position='fixed' color='secondary'> <AppBar position='fixed' color='secondary'>
<Toolbar> <Toolbar>
<EventListener
target='window'
onResize={this.handleResize}
onKeyUp={this.handleKeyUp}
/>
{/* Left side */} {/* Left side */}
<IconButton onClick={this.onToggleSidebar} > <IconButton onClick={this.onToggleSidebar} >
@@ -205,7 +187,9 @@ export class HomeHeaderComponent extends Component<IHomeHeaderComponentProps, IH
{config.settings.appName} {config.settings.appName}
</Typography> </Typography>
<div className='homeHeader__title-root'> <div className='homeHeader__title-root'>
{this.state.showTitle ? <div className='homeHeader__title'>{this.props.title}</div> : ''} <Hidden smDown>
<div className='homeHeader__title'>{this.props.title}</div>
</Hidden>
</div> </div>
{/* Notification */} {/* Notification */}

View File

@@ -7,7 +7,7 @@ export interface IHomeHeaderComponentProps {
* @type {boolean} * @type {boolean}
* @memberof IHomeHeaderComponentProps * @memberof IHomeHeaderComponentProps
*/ */
sidebarStatus?: boolean drawerStatus: boolean
/** /**
* Logout user * Logout user
@@ -59,7 +59,7 @@ export interface IHomeHeaderComponentProps {
* *
* @memberof IHomeHeaderComponentProps * @memberof IHomeHeaderComponentProps
*/ */
sidebar?: (status: boolean, source: string) => void onToggleDrawer: () => void
/** /**
* Material ui theme style * Material ui theme style

View File

@@ -112,8 +112,7 @@ export class PeopleComponent extends Component<IPeopleComponentProps,IPeopleComp
*/ */
const styles = { const styles = {
people: { people: {
margin: '0 auto', margin: '0 auto'
width: '90%'
}, },
headline: { headline: {
fontSize: 24, fontSize: 24,

View File

@@ -62,8 +62,6 @@ export class ProfileComponent extends Component<IProfileComponentProps,IProfileC
*/ */
const styles = { const styles = {
profile: { profile: {
margin: '0 auto',
width: '90%'
}, },
header: { header: {

View File

@@ -27,12 +27,12 @@ export class HomeRouter extends Component<IRouterProps, any> {
<PrivateRoute path='/people/:tab?' component={<People />} /> <PrivateRoute path='/people/:tab?' component={<People />} />
<PrivateRoute path='/tag/:tag' component={( <PrivateRoute path='/tag/:tag' component={(
<div className='blog'><St displayWriting={false} homeTitle={`#${match.params.tag}`} posts={data.mergedPosts} /></div> <div><St displayWriting={false} homeTitle={`#${match.params.tag}`} posts={data.mergedPosts} /></div>
)} /> )} />
<Route path='/:userId/posts/:postId/:tag?' component={PostPage} /> <Route path='/:userId/posts/:postId/:tag?' component={PostPage} />
<Route path='/:userId' component={Profile} /> <Route path='/:userId' component={Profile} />
<PrivateRoute path='/' component={( <PrivateRoute path='/' component={(
<div className='blog'> <div>
<St <St
homeTitle={translate!('header.home')} homeTitle={translate!('header.home')}
posts={data.mergedPosts} posts={data.mergedPosts}

View File

@@ -837,10 +837,6 @@ g__input-underline::after {
overflow: hidden; overflow: hidden;
margin-left: 15px; } margin-left: 15px; }
.blog {
margin: 0 auto;
width: 90%; }
@media (min-width: 993px) { @media (min-width: 993px) {
.blog__right-list { .blog__right-list {
margin-left: 2%; } } margin-left: 2%; } }

View File

@@ -1,8 +1,3 @@
.blog{
margin: 0 auto;
width: 90%;
}
.blog__right-list{ .blog__right-list{
@media (min-width: 993px) { @media (min-width: 993px) {