Webatrice: Update nav (#4380)

* wip: subnav debug

* nav redesign

* remove unnecessary code

* remove subnav

* add leaveRoom button

Co-authored-by: Jeremy Letto <jeremy.letto@datasite.com>
This commit is contained in:
Jeremy Letto 2021-06-15 02:12:04 -05:00 committed by GitHub
parent da9222929b
commit c9ddd042fc
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 205 additions and 115 deletions

View file

@ -38,11 +38,74 @@
.Header-nav { .Header-nav {
width: 100%; width: 100%;
display: flex; display: flex;
justify-content: flex-end; justify-content: space-between;
} }
.Header-nav__menu { .Header-nav__links {
margin-left: 10px; width: 100%;
display: flex;
padding-left: 50px;
align-items: center;
}
.Header-nav__link {
position: relative;
height: 100%;
}
.Header-nav__link:hover {
background: rgba(0, 0, 0, .125);
}
.Header-nav__link:hover .Header-nav__link-menu {
display: block;
}
.Header-nav__link-btn {
display: flex;
height: 100%;
width: 100%;
align-items: center;
padding: 5px 10px;
font-weight: bold;
}
.Header-nav__link-btn__icon {
margin-left: 5px;
}
.Header-nav__link-menu {
display: none;
position: absolute;
bottom: 0;
transform: translateY(100%);
min-width: 150px;
background: #3f51b5;
box-shadow: 1px 1px 2px 0px black;
}
.Header-nav__link-menu__item {
padding: 0 !important;
}
.Header-nav__link-menu__btn {
padding: 6px 16px;
width: 100%;
color: white;
display: flex;
justify-content: space-between;
}
.Header-nav__actions {
display: flex;
}
.Header-nav__action {
}
.Header-nav__action button {
color: white;
} }
.temp-subnav__rooms { .temp-subnav__rooms {

View file

@ -2,11 +2,13 @@ import React, { Component } from "react";
import { connect } from "react-redux"; import { connect } from "react-redux";
import { NavLink, withRouter, generatePath } from "react-router-dom"; import { NavLink, withRouter, generatePath } from "react-router-dom";
import AppBar from "@material-ui/core/AppBar"; import AppBar from "@material-ui/core/AppBar";
import Chip from "@material-ui/core/Chip";
import IconButton from "@material-ui/core/IconButton"; import IconButton from "@material-ui/core/IconButton";
import Menu from "@material-ui/core/Menu"; import Menu from "@material-ui/core/Menu";
import MenuItem from "@material-ui/core/MenuItem"; import MenuItem from "@material-ui/core/MenuItem";
import Toolbar from "@material-ui/core/Toolbar"; import Toolbar from "@material-ui/core/Toolbar";
import ArrowDropDownIcon from '@material-ui/icons/ArrowDropDown';
import CloseIcon from '@material-ui/icons/Close';
import MailOutlineRoundedIcon from '@material-ui/icons/MailOutline';
import MenuRoundedIcon from '@material-ui/icons/MenuRounded'; import MenuRoundedIcon from '@material-ui/icons/MenuRounded';
import * as _ from "lodash"; import * as _ from "lodash";
@ -21,20 +23,18 @@ class Header extends Component<HeaderProps> {
state: HeaderState; state: HeaderState;
options: string[] = [ options: string[] = [
'Account', 'Account',
'Decks',
'Replays', 'Replays',
]; ];
constructor(props) { constructor(props) {
super(props); super(props);
this.state = { this.state = { anchorEl: null };
anchorEl: null,
};
this.handleMenuClick = this.handleMenuClick.bind(this); this.handleMenuOpen = this.handleMenuOpen.bind(this);
this.handleMenuItemClick = this.handleMenuItemClick.bind(this); this.handleMenuItemClick = this.handleMenuItemClick.bind(this);
this.handleMenuClose = this.handleMenuClose.bind(this); this.handleMenuClose = this.handleMenuClose.bind(this);
this.leaveRoom = this.leaveRoom.bind(this);
} }
componentDidUpdate(prevProps) { componentDidUpdate(prevProps) {
@ -47,24 +47,28 @@ class Header extends Component<HeaderProps> {
} }
} }
handleMenuClick({ target }) { handleMenuOpen(event) {
this.setState({ anchorEl: target }); this.setState({ anchorEl: event.target });
} }
handleMenuItemClick(option: string) { handleMenuItemClick(option: string) {
const route = RouteEnum[option.toUpperCase()]; const route = RouteEnum[option.toUpperCase()];
this.props.history.push(generatePath(route)); this.props.history.push(generatePath(route));
this.handleMenuClose();
} }
handleMenuClose() { handleMenuClose() {
this.setState({ anchorEl: null }); this.setState({ anchorEl: null });
} }
leaveRoom(event, roomId) {
event.preventDefault();
RoomsService.leaveRoom(roomId);
};
render() { render() {
const { joinedRooms, server, state, user } = this.props; const { joinedRooms, state, user } = this.props;
const anchorEl = this.state.anchorEl; const { anchorEl } = this.state;
let options = [ ...this.options ]; let options = [ ...this.options ];
if (user && AuthenticationService.isModerator(user)) { if (user && AuthenticationService.isModerator(user)) {
@ -76,36 +80,70 @@ class Header extends Component<HeaderProps> {
} }
return ( return (
<div> <AppBar className="Header" position="static">
{/*<header className="Header">*/} <Toolbar variant="dense">
<AppBar position="static"> <div className="Header__logo">
<Toolbar variant="dense"> <NavLink to={RouteEnum.SERVER}>
<div className="Header__logo"> <img src={logo} alt="logo" />
<NavLink to={RouteEnum.SERVER}> </NavLink>
<img src={logo} alt="logo" />
</NavLink>
{ AuthenticationService.isConnected(state) && (
<span className="Header-server__indicator"></span>
) }
</div>
{ AuthenticationService.isConnected(state) && ( { AuthenticationService.isConnected(state) && (
<div className="Header-content"> <span className="Header-server__indicator"></span>
<nav className="Header-nav"> ) }
<div className="Header-nav__menu"> </div>
<IconButton { AuthenticationService.isConnected(state) && (
aria-label="more" <div className="Header-content">
aria-controls="long-menu" <nav className="Header-nav">
aria-haspopup="true" <nav className="Header-nav__links">
onClick={this.handleMenuClick} <div className="Header-nav__link">
<NavLink
className="Header-nav__link-btn"
to={ joinedRooms.length ? generatePath(RouteEnum.ROOM, { roomId: joinedRooms[0].roomId }) : RouteEnum.SERVER }
> >
<MenuRoundedIcon /> Rooms
<ArrowDropDownIcon className="Header-nav__link-btn__icon" fontSize="small" />
</NavLink>
<div className="Header-nav__link-menu">
{joinedRooms.map(({ name, roomId }) => (
<MenuItem className="Header-nav__link-menu__item" key={roomId}>
<NavLink className="Header-nav__link-menu__btn" to={ generatePath(RouteEnum.ROOM, { roomId: roomId }) }>
{name}
<IconButton size="small" edge="end" onClick={event => this.leaveRoom(event, roomId)}>
<CloseIcon style={{ fontSize: 10, color: 'white' }} />
</IconButton>
</NavLink>
</MenuItem>
))}
</div>
</div>
<div className="Header-nav__link">
<NavLink className="Header-nav__link-btn" to={ RouteEnum.GAME }>
Games
<ArrowDropDownIcon className="Header-nav__link-btn__icon" fontSize="small" />
</NavLink>
</div>
<div className="Header-nav__link">
<NavLink className="Header-nav__link-btn" to={ RouteEnum.DECKS }>
Decks
<ArrowDropDownIcon className="Header-nav__link-btn__icon" fontSize="small" />
</NavLink>
</div>
</nav>
<div className="Header-nav__actions">
<div className="Header-nav__action">
<IconButton>
<MailOutlineRoundedIcon style={{ color: 'inherit' }} />
</IconButton>
</div>
<div className="Header-nav__action">
<IconButton onClick={this.handleMenuOpen}>
<MenuRoundedIcon style={{ color: 'inherit' }} />
</IconButton> </IconButton>
<Menu <Menu
id="long-menu"
anchorEl={anchorEl} anchorEl={anchorEl}
keepMounted keepMounted
open={!!anchorEl} open={!!anchorEl}
onClose={this.handleMenuClose} onClose={() => this.handleMenuClose()}
PaperProps={{ PaperProps={{
style: { style: {
marginTop: '32px', marginTop: '32px',
@ -114,55 +152,22 @@ class Header extends Component<HeaderProps> {
}} }}
> >
{options.map((option) => ( {options.map((option) => (
<MenuItem key={option} onClick={() => this.handleMenuItemClick(option)}> <MenuItem key={option} onClick={(event) => this.handleMenuItemClick(option)}>
{option} {option}
</MenuItem> </MenuItem>
))} ))}
</Menu> </Menu>
</div> </div>
</nav> </div>
</div> </nav>
) } </div>
</Toolbar> ) }
</AppBar> </Toolbar>
<div className="temp-subnav"> </AppBar>
{
!!joinedRooms.length && (
<Rooms rooms={joinedRooms} />
)
}
<div className="temp-subnav__games">
</div>
<div className="temp-subnav__chats">
</div>
</div>
</div>
) )
} }
} }
const Rooms = props => {
const onLeaveRoom = (event, roomId) => {
event.preventDefault();
RoomsService.leaveRoom(roomId);
};
return <div className="temp-subnav__rooms">
<span>Rooms: </span>
{
_.reduce(props.rooms, (rooms, { name, roomId}) => {
rooms.push(
<NavLink to={generatePath(RouteEnum.ROOM, { roomId })} className="temp-chip" key={roomId}>
<Chip label={name} color="primary" onDelete={(event) => onLeaveRoom(event, roomId)} />
</NavLink>
);
return rooms;
}, [])
}
</div>
};
interface HeaderProps { interface HeaderProps {
state: number; state: number;
server: string; server: string;
@ -172,7 +177,7 @@ interface HeaderProps {
} }
interface HeaderState { interface HeaderState {
anchorEl: Element; anchorEl: Element
} }
const mapStateToProps = state => ({ const mapStateToProps = state => ({

View file

@ -26,9 +26,11 @@
height: 100%; height: 100%;
width: 100%; width: 100%;
flex-shrink: 1; flex-shrink: 1;
overflow: hidden;
} }
.three-pane-layout .grid-main__top.fixedHeight, .three-pane-layout .grid-main__top.fixedHeight,
.three-pane-layout .grid-main__bottom.fixedHeight { .three-pane-layout .grid-main__bottom.fixedHeight {
height: 50%; height: 50%;
overflow: visible;
} }

View file

@ -1,4 +1,5 @@
.room-view, .room-view,
.room-view__main,
.room-view__games, .room-view__games,
.room-view__messages, .room-view__messages,
.room-view__messages-content, .room-view__messages-content,
@ -6,12 +7,17 @@
height: 100%; height: 100%;
} }
.room-view,
.room-view__messages, .room-view__messages,
.room-view__side { .room-view__side {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
} }
.room-view__main {
overflow: hidden;
}
.room-view__messages-sayMessage { .room-view__messages-sayMessage {
width: 100%; width: 100%;
margin: 10px auto 2px; margin: 10px auto 2px;

View file

@ -53,45 +53,48 @@ class Room extends Component<any> {
return ( return (
<div className="room-view"> <div className="room-view">
<AuthGuard /> <AuthGuard />
<ThreePaneLayout
fixedHeight
top={( <div className="room-view__main">
<Paper className="room-view__games overflow-scroll"> <ThreePaneLayout
<Games room={room} /> fixedHeight
</Paper>
)}
bottom={( top={(
<div className="room-view__messages"> <Paper className="room-view__games overflow-scroll">
<Paper className="room-view__messages-content overflow-scroll"> <Games room={room} />
<ScrollToBottomOnChanges changes={messages} content={( </Paper>
<Messages messages={messages} /> )}
)} />
</Paper>
<Paper className="room-view__messages-sayMessage">
<SayMessage onSubmit={this.handleRoomSay} />
</Paper>
</div>
)}
side={( bottom={(
<Paper className="room-view__side overflow-scroll"> <div className="room-view__messages">
<div className="room-view__side-label"> <Paper className="room-view__messages-content overflow-scroll">
Users in this room: {users.length} <ScrollToBottomOnChanges changes={messages} content={(
<Messages messages={messages} />
)} />
</Paper>
<Paper className="room-view__messages-sayMessage">
<SayMessage onSubmit={this.handleRoomSay} />
</Paper>
</div> </div>
<VirtualList )}
className="room-view__side-list"
itemKey={(index, data) => users[index].name } side={(
items={ users.map(user => ( <Paper className="room-view__side overflow-scroll">
<ListItem button className="room-view__side-list__item"> <div className="room-view__side-label">
<UserDisplay user={user} /> Users in this room: {users.length}
</ListItem> </div>
) ) } <VirtualList
/> className="room-view__side-list"
</Paper> itemKey={(index, data) => users[index].name }
)} items={ users.map(user => (
/> <ListItem button className="room-view__side-list__item">
<UserDisplay user={user} />
</ListItem>
) ) }
/>
</Paper>
)}
/>
</div>
</div> </div>
); );
} }

View file

@ -95,7 +95,9 @@ const ServerRooms = ({ rooms, joinedRooms, history, message, users}) => (
)} )}
bottom={( bottom={(
<Paper className="serverMessage overflow-scroll" dangerouslySetInnerHTML={{ __html: message }} /> <Paper className="serverMessage overflow-scroll">
<div className="serverMessage__content" dangerouslySetInnerHTML={{ __html: message }} />
</Paper>
)} )}
side={( side={(

View file

@ -40,6 +40,11 @@ b {
font-weight: bold; font-weight: bold;
} }
a {
color: inherit;
text-decoration: none;
}
.overflow-scroll { .overflow-scroll {
overflow-y: scroll; /* has to be scroll, not auto */ overflow-y: scroll; /* has to be scroll, not auto */
-webkit-overflow-scrolling: touch; -webkit-overflow-scrolling: touch;
@ -54,4 +59,8 @@ b {
text-overflow: ellipsis; text-overflow: ellipsis;
white-space: nowrap; white-space: nowrap;
overflow: hidden; overflow: hidden;
}
.disabled-link {
pointer-events: none;
} }