ionian/src/client/component/headline.tsx
2021-02-22 23:08:30 +09:00

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;