Make layout responsive

This commit is contained in:
Yasa Akbulut 2020-03-13 02:01:49 +01:00 committed by Jannis Mattheis
parent e858d5ad3f
commit c46bbdc01f
3 changed files with 226 additions and 89 deletions

View File

@ -1,7 +1,7 @@
import AppBar from '@material-ui/core/AppBar';
import Button from '@material-ui/core/Button';
import IconButton from '@material-ui/core/IconButton';
import {Theme, WithStyles, withStyles} from '@material-ui/core/styles';
import {createStyles, Theme, WithStyles, withStyles} from '@material-ui/core/styles';
import Toolbar from '@material-ui/core/Toolbar';
import Typography from '@material-ui/core/Typography';
import AccountCircle from '@material-ui/icons/AccountCircle';
@ -10,18 +10,46 @@ import DevicesOther from '@material-ui/icons/DevicesOther';
import ExitToApp from '@material-ui/icons/ExitToApp';
import Highlight from '@material-ui/icons/Highlight';
import GitHubIcon from '@material-ui/icons/GitHub';
import MenuIcon from '@material-ui/icons/Menu';
import Apps from '@material-ui/icons/Apps';
import SupervisorAccount from '@material-ui/icons/SupervisorAccount';
import React, {Component, CSSProperties} from 'react';
import {Link} from 'react-router-dom';
import {observer} from 'mobx-react';
import {Hidden, PropTypes, withWidth} from '@material-ui/core';
import {Breakpoint} from '@material-ui/core/styles/createBreakpoints';
const styles = (theme: Theme) => ({
const styles = (theme: Theme) =>
createStyles({
appBar: {
zIndex: theme.zIndex.drawer + 1,
[theme.breakpoints.down('xs')]: {
paddingBottom: 10,
},
},
toolbar: {
justifyContent: 'space-between',
[theme.breakpoints.down('xs')]: {
flexWrap: 'wrap',
},
},
menuButtons: {
display: 'flex',
[theme.breakpoints.down('sm')]: {
flex: 1,
},
justifyContent: 'center',
[theme.breakpoints.down('xs')]: {
flexBasis: '100%',
marginTop: 5,
order: 1,
justifyContent: 'space-between',
},
},
title: {
[theme.breakpoints.up('md')]: {
flex: 1,
},
display: 'flex',
alignItems: 'center',
},
@ -34,7 +62,7 @@ const styles = (theme: Theme) => ({
},
});
type Styles = WithStyles<'link' | 'titleName' | 'title' | 'appBar'>;
type Styles = WithStyles<'link' | 'menuButtons' | 'toolbar' | 'titleName' | 'title' | 'appBar'>;
interface IProps extends Styles {
loggedIn: boolean;
@ -45,16 +73,31 @@ interface IProps extends Styles {
showSettings: VoidFunction;
logout: VoidFunction;
style: CSSProperties;
width: Breakpoint;
setNavOpen: (open: boolean) => void;
}
@observer
class Header extends Component<IProps> {
public render() {
const {classes, version, name, loggedIn, admin, toggleTheme, logout, style} = this.props;
const {
classes,
version,
name,
loggedIn,
admin,
toggleTheme,
logout,
style,
setNavOpen,
width,
} = this.props;
const position = width === 'xs' ? 'sticky' : 'fixed';
return (
<AppBar position="absolute" style={style} className={classes.appBar}>
<Toolbar>
<AppBar position={position} style={style} className={classes.appBar}>
<Toolbar className={classes.toolbar}>
<div className={classes.title}>
<Link to="/" className={classes.link}>
<Typography variant="h5" className={classes.titleName} color="inherit">
@ -69,7 +112,8 @@ class Header extends Component<IProps> {
</Typography>
</a>
</div>
{loggedIn && this.renderButtons(name, admin, logout)}
{loggedIn && this.renderButtons(name, admin, logout, width, setNavOpen)}
<div>
<IconButton onClick={toggleTheme} color="inherit">
<Highlight />
</IconButton>
@ -79,55 +123,97 @@ class Header extends Component<IProps> {
<GitHubIcon />
</IconButton>
</a>
</div>
</Toolbar>
</AppBar>
);
}
private renderButtons(name: string, admin: boolean, logout: VoidFunction) {
private renderButtons(
name: string,
admin: boolean,
logout: VoidFunction,
width: Breakpoint,
setNavOpen: (open: boolean) => void
) {
const {classes, showSettings} = this.props;
return (
<div>
{admin ? (
<div className={classes.menuButtons}>
<Hidden smUp implementation="css">
<ResponsiveButton
icon={<MenuIcon />}
onClick={() => setNavOpen(true)}
label="menu"
width={width}
color="inherit"
/>
</Hidden>
{admin && (
<Link className={classes.link} to="/users" id="navigate-users">
<Button color="inherit">
<SupervisorAccount />
&nbsp;users
</Button>
<ResponsiveButton
icon={<SupervisorAccount />}
label="users"
width={width}
color="inherit"
/>
</Link>
) : (
''
)}
<Link className={classes.link} to="/applications" id="navigate-apps">
<Button color="inherit">
<Chat />
&nbsp;apps
</Button>
<ResponsiveButton icon={<Chat />} label="apps" width={width} color="inherit" />
</Link>
<Link className={classes.link} to="/clients" id="navigate-clients">
<Button color="inherit">
<DevicesOther />
&nbsp;clients
</Button>
<ResponsiveButton
icon={<DevicesOther />}
label="clients"
width={width}
color="inherit"
/>
</Link>
<Link className={classes.link} to="/plugins" id="navigate-plugins">
<Button color="inherit">
<Apps />
&nbsp;plugins
</Button>
<ResponsiveButton
icon={<Apps />}
label="plugins"
width={width}
color="inherit"
/>
</Link>
<Button color="inherit" onClick={showSettings} id="changepw">
<AccountCircle />
&nbsp;
{name}
</Button>
<Button color="inherit" onClick={logout} id="logout">
<ExitToApp />
&nbsp;Logout
</Button>
<ResponsiveButton
icon={<AccountCircle />}
label={name}
onClick={showSettings}
id="changepw"
width={width}
color="inherit"
/>
<ResponsiveButton
icon={<ExitToApp />}
label="Logout"
onClick={logout}
id="logout"
width={width}
color="inherit"
/>
</div>
);
}
}
export default withStyles(styles, {withTheme: true})(Header);
const ResponsiveButton: React.FC<{
width: Breakpoint;
color: PropTypes.Color;
label: string;
id?: string;
onClick?: () => void;
icon: React.ReactNode;
}> = ({width, icon, children, label, ...rest}) => {
if (width === 'xs' || width === 'sm') {
return <IconButton {...rest}>{icon}</IconButton>;
}
return (
<Button startIcon={icon} {...rest}>
{label}
</Button>
);
};
export default withWidth()(withStyles(styles, {withTheme: true})(Header));

View File

@ -29,6 +29,9 @@ const styles = (theme: Theme) => ({
marginTop: 64,
padding: theme.spacing(4),
width: '100%',
[theme.breakpoints.down('xs')]: {
marginTop: 0,
},
},
});
@ -63,6 +66,12 @@ class Layout extends React.Component<
private showSettings = false;
@observable
private version = Layout.defaultVersion;
@observable
private navOpen = false;
private setNavOpen(open: boolean) {
this.navOpen = open;
}
public componentDidMount() {
if (this.version === Layout.defaultVersion) {
@ -105,7 +114,7 @@ class Layout extends React.Component<
message={connectionErrorMessage}
/>
)}
<div style={{display: 'flex'}}>
<div style={{display: 'flex', flexDirection: 'column'}}>
<CssBaseline />
<Header
style={{top: !connectionErrorMessage ? 0 : 64}}
@ -116,9 +125,14 @@ class Layout extends React.Component<
toggleTheme={this.toggleTheme.bind(this)}
showSettings={() => (this.showSettings = true)}
logout={logout}
setNavOpen={this.setNavOpen.bind(this)}
/>
<div style={{display: 'flex'}}>
<Navigation
loggedIn={loggedIn}
navOpen={this.navOpen}
setNavOpen={this.setNavOpen.bind(this)}
/>
<Navigation loggedIn={loggedIn} />
<main className={classes.content}>
<Switch>
{authenticating ? (
@ -130,13 +144,22 @@ class Layout extends React.Component<
{loggedIn ? null : <Redirect to="/login" />}
<Route exact path="/" component={Messages} />
<Route exact path="/messages/:id" component={Messages} />
<Route exact path="/applications" component={Applications} />
<Route
exact
path="/applications"
component={Applications}
/>
<Route exact path="/clients" component={Clients} />
<Route exact path="/users" component={Users} />
<Route exact path="/plugins" component={Plugins} />
<Route exact path="/plugins/:id" component={PluginDetailView} />
<Route
exact
path="/plugins/:id"
component={PluginDetailView}
/>
</Switch>
</main>
</div>
{showSettings && (
<SettingsDialog fClose={() => (this.showSettings = false)} />
)}

View File

@ -8,7 +8,9 @@ import {Link} from 'react-router-dom';
import {observer} from 'mobx-react';
import {inject, Stores} from '../inject';
import {mayAllowPermission, requestPermission} from '../snack/browserNotification';
import {Button, Typography} from '@material-ui/core';
import {Button, Hidden, IconButton, Typography} from '@material-ui/core';
import {DrawerProps} from '@material-ui/core/Drawer/Drawer';
import CloseIcon from '@material-ui/icons/Close';
const styles = (theme: Theme): StyleRules<'drawerPaper' | 'toolbar' | 'link'> => ({
drawerPaper: {
@ -28,6 +30,8 @@ type Styles = WithStyles<'drawerPaper' | 'toolbar' | 'link'>;
interface IProps {
loggedIn: boolean;
navOpen: boolean;
setNavOpen: (open: boolean) => void;
}
@observer
@ -38,7 +42,7 @@ class Navigation extends Component<
public state = {showRequestNotification: mayAllowPermission()};
public render() {
const {classes, loggedIn, appStore} = this.props;
const {classes, loggedIn, appStore, navOpen, setNavOpen} = this.props;
const {showRequestNotification} = this.state;
const apps = appStore.getItems();
@ -48,6 +52,7 @@ class Navigation extends Component<
: apps.map((app) => {
return (
<Link
onClick={() => setNavOpen(false)}
className={`${classes.link} item`}
to={'/messages/' + app.id}
key={app.id}>
@ -68,12 +73,13 @@ class Navigation extends Component<
];
return (
<Drawer
variant="permanent"
<ResponsiveDrawer
classes={{paper: classes.drawerPaper}}
navOpen={navOpen}
setNavOpen={setNavOpen}
id="message-navigation">
<div className={classes.toolbar} />
<Link className={classes.link} to="/">
<Link className={classes.link} to="/" onClick={() => setNavOpen(false)}>
<ListItem button disabled={!loggedIn} className="all">
<ListItemText primary="All Messages" />
</ListItem>
@ -92,9 +98,31 @@ class Navigation extends Component<
</Button>
) : null}
</Typography>
</Drawer>
</ResponsiveDrawer>
);
}
}
const ResponsiveDrawer: React.FC<
DrawerProps & {navOpen: boolean; setNavOpen: (open: boolean) => void}
> = ({navOpen, setNavOpen, children, ...rest}) => {
return (
<>
<Hidden smUp implementation="css">
<Drawer variant="temporary" open={navOpen} {...rest}>
<IconButton onClick={() => setNavOpen(false)}>
<CloseIcon />
</IconButton>
{children}
</Drawer>
</Hidden>
<Hidden xsDown implementation="css">
<Drawer variant="permanent" {...rest}>
{children}
</Drawer>
</Hidden>
</>
);
};
export default withStyles(styles, {withTheme: true})(inject('appStore')(Navigation));