207 lines
No EOL
6.7 KiB
TypeScript
207 lines
No EOL
6.7 KiB
TypeScript
import ReactDom from 'react-dom';
|
|
import React, { ReactNode, useState } from 'react';
|
|
import {
|
|
Button, CssBaseline, Divider, IconButton, List, ListItem, Drawer,
|
|
AppBar, Toolbar, Typography, InputBase, ListItemIcon, ListItemText, Menu, MenuItem,
|
|
Hidden, Tooltip, Link
|
|
} from '@material-ui/core';
|
|
import { makeStyles, Theme, useTheme, fade } from '@material-ui/core/styles';
|
|
import { ChevronLeft, ChevronRight, Menu as MenuIcon, Search as SearchIcon, AccountCircle } from '@material-ui/icons';
|
|
import { Link as RouterLink, useRouteMatch } from 'react-router-dom';
|
|
|
|
const drawerWidth = 240;
|
|
|
|
const useStyles = makeStyles((theme: Theme) => ({
|
|
root: {
|
|
display: 'flex'
|
|
},
|
|
appBar: {
|
|
zIndex: theme.zIndex.drawer + 1,
|
|
transition: theme.transitions.create(['width', 'margin'], {
|
|
easing: theme.transitions.easing.sharp,
|
|
duration: theme.transitions.duration.leavingScreen
|
|
})
|
|
},
|
|
menuButton: {
|
|
marginRight: 36
|
|
},
|
|
hide: {
|
|
display: "none"
|
|
},
|
|
drawer: {
|
|
flexShrink: 0,
|
|
whiteSpace: "nowrap",
|
|
[theme.breakpoints.up("sm")]: {
|
|
width: drawerWidth,
|
|
},
|
|
},
|
|
drawerPaper: {
|
|
width: drawerWidth
|
|
},
|
|
drawerClose: {
|
|
overflowX: 'hidden',
|
|
[theme.breakpoints.up("sm")]: {
|
|
width: theme.spacing(7) + 1,
|
|
},
|
|
},
|
|
toolbar: {
|
|
...theme.mixins.toolbar,
|
|
},
|
|
content: {
|
|
display: 'flex',
|
|
flexFlow: 'column',
|
|
flexGrow: 1,
|
|
padding: theme.spacing(3),
|
|
},
|
|
title: {
|
|
display: 'none',
|
|
[theme.breakpoints.up("sm")]: {
|
|
display: 'block'
|
|
}
|
|
},
|
|
search: {
|
|
position: 'relative',
|
|
borderRadius: theme.shape.borderRadius,
|
|
backgroundColor: fade(theme.palette.common.white, 0.15),
|
|
'&:hover': {
|
|
backgroundColor: fade(theme.palette.common.white, 0.25),
|
|
},
|
|
marginRight: theme.spacing(2),
|
|
marginLeft: 0,
|
|
width: '100%',
|
|
[theme.breakpoints.up('sm')]: {
|
|
marginLeft: theme.spacing(3),
|
|
width: 'auto',
|
|
},
|
|
},
|
|
searchIcon: {
|
|
padding: theme.spacing(0, 2),
|
|
height: '100%',
|
|
position: 'absolute',
|
|
pointerEvents: 'none',
|
|
display: 'flex',
|
|
alignItems: 'center',
|
|
justifyContent: 'center',
|
|
},
|
|
inputRoot: {
|
|
color: 'inherit'
|
|
},
|
|
inputInput: {
|
|
padding: theme.spacing(1, 1, 1, 0),
|
|
// vertical padding + font size from searchIcon
|
|
paddingLeft: `calc(1em + ${theme.spacing(4)}px)`,
|
|
transition: theme.transitions.create('width'),
|
|
width: '100%',
|
|
[theme.breakpoints.up('md')]: {
|
|
width: '20ch',
|
|
"&:hover": {
|
|
width: '25ch'
|
|
}
|
|
},
|
|
},
|
|
grow: {
|
|
flexGrow: 1,
|
|
},
|
|
}));
|
|
|
|
export const Headline = (prop: {
|
|
children?: React.ReactNode,
|
|
isLogin?: boolean,
|
|
classes?:{
|
|
content?:string,
|
|
toolbar?:string,
|
|
},
|
|
menu: React.ReactNode
|
|
}) => {
|
|
const [v, setv] = useState(false);
|
|
const [anchorEl, setAnchorEl] = React.useState<null | HTMLElement>(null);
|
|
const classes = useStyles();
|
|
const theme = useTheme();
|
|
const toggleV = () => setv(!v);
|
|
const handleProfileMenuOpen = (e: React.MouseEvent<HTMLElement>) => setAnchorEl(e.currentTarget);
|
|
const handleProfileMenuClose = () => setAnchorEl(null);
|
|
const isProfileMenuOpened = Boolean(anchorEl);
|
|
const menuId = 'primary-search-account-menu';
|
|
const isLogin = prop.isLogin || false;
|
|
const renderProfileMenu = (<Menu
|
|
anchorEl={anchorEl}
|
|
anchorOrigin={{ horizontal: 'right', vertical: "top" }}
|
|
id={menuId}
|
|
open={isProfileMenuOpened}
|
|
keepMounted
|
|
transformOrigin={{ horizontal: 'right', vertical: "top" }}
|
|
onClose={handleProfileMenuClose}
|
|
>
|
|
<MenuItem component={RouterLink} to='/profile'>Profile</MenuItem>
|
|
<MenuItem>Logout</MenuItem>
|
|
</Menu>);
|
|
const drawer_contents = (<>
|
|
<div className={classes.toolbar}>
|
|
<IconButton onClick={toggleV}>
|
|
{theme.direction === "ltr" ? <ChevronLeft /> : <ChevronRight />}
|
|
</IconButton>
|
|
</div>
|
|
<Divider />
|
|
{prop.menu}
|
|
</>);
|
|
return (<div className={classes.root}>
|
|
<CssBaseline />
|
|
<AppBar position="fixed" className={classes.appBar}>
|
|
<Toolbar>
|
|
<IconButton color="inherit"
|
|
aria-label="open drawer"
|
|
onClick={toggleV}
|
|
edge="start"
|
|
className={classes.menuButton}>
|
|
<MenuIcon></MenuIcon>
|
|
</IconButton>
|
|
<Link variant="h5" noWrap className={classes.title} color="inherit" component={RouterLink} to="/">
|
|
Ionian
|
|
</Link>
|
|
<div className={classes.grow}></div>
|
|
<div className={classes.search}>
|
|
<div className={classes.searchIcon}>
|
|
<SearchIcon />
|
|
</div>
|
|
<InputBase placeholder="search"
|
|
classes={{ root: classes.inputRoot, input: classes.inputInput }}></InputBase>
|
|
</div>
|
|
{
|
|
isLogin ?
|
|
<IconButton
|
|
edge="end"
|
|
aria-label="account of current user"
|
|
aria-controls={menuId}
|
|
aria-haspopup="true"
|
|
onClick={handleProfileMenuOpen}
|
|
color="inherit">
|
|
<AccountCircle />
|
|
</IconButton>
|
|
: <Button color="inherit" component={RouterLink} to="/login">Login</Button>
|
|
}
|
|
</Toolbar>
|
|
</AppBar>
|
|
{renderProfileMenu}
|
|
<nav>
|
|
<Hidden smUp implementation="css">
|
|
<Drawer variant="temporary" anchor='left' open={v} onClose={toggleV}
|
|
classes={{ paper: classes.drawerPaper }}>
|
|
{drawer_contents}
|
|
</Drawer>
|
|
</Hidden>
|
|
<Hidden xsDown implementation="css">
|
|
<Drawer variant='permanent' anchor='left' className={[classes.drawer, classes.drawerClose].join(" ").trim()} classes={{
|
|
paper: classes.drawerClose
|
|
}}>
|
|
{drawer_contents}
|
|
</Drawer>
|
|
</Hidden>
|
|
</nav>
|
|
<main className={prop.classes?.content || classes.content}>
|
|
<div className={prop.classes?.toolbar || classes.toolbar}></div>
|
|
{prop.children}
|
|
</main>
|
|
</div>);
|
|
};
|
|
|
|
export default Headline; |