Add left nav (#4705)
* Automated translation update ( bf08a04cda
)
* Add Layout component wip
* finish layout implementation
* convert header to left nav
* better nav item spacing
* return source files to original glory
* lint fix
* Remove height limit on login screen
* fix top spacing on 3-panel layout
---------
Co-authored-by: github-actions <github-actions@github.com>
Co-authored-by: Brent Clark <brent@backboneiq.com>
This commit is contained in:
parent
cab5f29b57
commit
cef99cba71
18 changed files with 280 additions and 201 deletions
|
@ -33,4 +33,5 @@
|
||||||
.three-pane-layout .grid-main__bottom.fixedHeight {
|
.three-pane-layout .grid-main__bottom.fixedHeight {
|
||||||
height: 50%;
|
height: 50%;
|
||||||
overflow: visible;
|
overflow: visible;
|
||||||
|
padding: 0 0 16px;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
// eslint-disable-next-line
|
import { Component, CElement } from "react";
|
||||||
import React, { Component, CElement } from "react";
|
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import Grid from '@mui/material/Grid';
|
import Grid from '@mui/material/Grid';
|
||||||
import Hidden from '@mui/material/Hidden';
|
import Hidden from '@mui/material/Hidden';
|
||||||
|
@ -12,7 +11,7 @@ class ThreePaneLayout extends Component<ThreePaneLayoutProps> {
|
||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<div className="three-pane-layout">
|
<div className="three-pane-layout">
|
||||||
<Grid container spacing={2} className="grid">
|
<Grid container rowSpacing={0} columnSpacing={2} className="grid">
|
||||||
<Grid item xs={12} md={9} lg={10} className="grid-main">
|
<Grid item xs={12} md={9} lg={10} className="grid-main">
|
||||||
<Grid item className={
|
<Grid item className={
|
||||||
'grid-main__top'
|
'grid-main__top'
|
||||||
|
|
|
@ -2,7 +2,6 @@
|
||||||
export { default as Card } from './Card/Card';
|
export { default as Card } from './Card/Card';
|
||||||
export { default as CardDetails } from './CardDetails/CardDetails';
|
export { default as CardDetails } from './CardDetails/CardDetails';
|
||||||
export { default as CountryDropdown } from './CountryDropdown/CountryDropdown';
|
export { default as CountryDropdown } from './CountryDropdown/CountryDropdown';
|
||||||
export { default as Header } from './Header/Header';
|
|
||||||
export { default as InputField } from './InputField/InputField';
|
export { default as InputField } from './InputField/InputField';
|
||||||
export { default as InputAction } from './InputAction/InputAction';
|
export { default as InputAction } from './InputAction/InputAction';
|
||||||
export { default as KnownHosts } from './KnownHosts/KnownHosts';
|
export { default as KnownHosts } from './KnownHosts/KnownHosts';
|
||||||
|
|
|
@ -11,6 +11,7 @@ import { UserDisplay, VirtualList, AuthGuard, LanguageDropdown } from 'component
|
||||||
import { AuthenticationService, SessionService } from 'api';
|
import { AuthenticationService, SessionService } from 'api';
|
||||||
import { ServerSelectors } from 'store';
|
import { ServerSelectors } from 'store';
|
||||||
import { User } from 'types';
|
import { User } from 'types';
|
||||||
|
import Layout from 'containers/Layout/Layout';
|
||||||
|
|
||||||
import AddToBuddies from './AddToBuddies';
|
import AddToBuddies from './AddToBuddies';
|
||||||
import AddToIgnore from './AddToIgnore';
|
import AddToIgnore from './AddToIgnore';
|
||||||
|
@ -33,7 +34,7 @@ const Account = (props: AccountProps) => {
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="account">
|
<Layout className="account">
|
||||||
<AuthGuard />
|
<AuthGuard />
|
||||||
<div className="account-column">
|
<div className="account-column">
|
||||||
<Paper className="account-list">
|
<Paper className="account-list">
|
||||||
|
@ -96,7 +97,7 @@ const Account = (props: AccountProps) => {
|
||||||
</div>
|
</div>
|
||||||
</Paper>
|
</Paper>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</Layout>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,6 @@ import { Provider } from 'react-redux';
|
||||||
import { MemoryRouter as Router } from 'react-router-dom';
|
import { MemoryRouter as Router } from 'react-router-dom';
|
||||||
import CssBaseline from '@mui/material/CssBaseline';
|
import CssBaseline from '@mui/material/CssBaseline';
|
||||||
import { store } from 'store';
|
import { store } from 'store';
|
||||||
import { Header } from 'components';
|
|
||||||
import Routes from './AppShellRoutes';
|
import Routes from './AppShellRoutes';
|
||||||
import FeatureDetection from './FeatureDetection';
|
import FeatureDetection from './FeatureDetection';
|
||||||
|
|
||||||
|
@ -29,8 +28,6 @@ class AppShell extends Component {
|
||||||
<ToastProvider>
|
<ToastProvider>
|
||||||
<div className="AppShell" onContextMenu={this.handleContextMenu}>
|
<div className="AppShell" onContextMenu={this.handleContextMenu}>
|
||||||
<Router>
|
<Router>
|
||||||
<Header />
|
|
||||||
|
|
||||||
<FeatureDetection />
|
<FeatureDetection />
|
||||||
<Routes />
|
<Routes />
|
||||||
</Router>
|
</Router>
|
||||||
|
|
|
@ -2,16 +2,17 @@
|
||||||
import React, { Component } from "react";
|
import React, { Component } from "react";
|
||||||
|
|
||||||
import { AuthGuard } from 'components/index';
|
import { AuthGuard } from 'components/index';
|
||||||
|
import Layout from 'containers/Layout/Layout';
|
||||||
|
|
||||||
import './Decks.css';
|
import './Decks.css';
|
||||||
|
|
||||||
class Decks extends Component {
|
class Decks extends Component {
|
||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<div>
|
<Layout>
|
||||||
<AuthGuard />
|
<AuthGuard />
|
||||||
<span>"Decks"</span>
|
<span>"Decks"</span>
|
||||||
</div>
|
</Layout>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,16 +2,17 @@
|
||||||
import React, { Component } from "react";
|
import React, { Component } from "react";
|
||||||
|
|
||||||
import { AuthGuard } from 'components';
|
import { AuthGuard } from 'components';
|
||||||
|
import Layout from 'containers/Layout/Layout';
|
||||||
|
|
||||||
import './Game.css';
|
import './Game.css';
|
||||||
|
|
||||||
class Game extends Component {
|
class Game extends Component {
|
||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<div>
|
<Layout>
|
||||||
<AuthGuard />
|
<AuthGuard />
|
||||||
<span>"Game"</span>
|
<span>"Game"</span>
|
||||||
</div>
|
</Layout>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,6 +8,7 @@ import Typography from '@mui/material/Typography';
|
||||||
import { Images } from 'images';
|
import { Images } from 'images';
|
||||||
import { ServerSelectors } from 'store';
|
import { ServerSelectors } from 'store';
|
||||||
import { RouteEnum } from 'types';
|
import { RouteEnum } from 'types';
|
||||||
|
import Layout from 'containers/Layout/Layout';
|
||||||
|
|
||||||
import './Initialize.css';
|
import './Initialize.css';
|
||||||
|
|
||||||
|
@ -35,25 +36,27 @@ const Initialize = ({ initialized }: InitializeProps) => {
|
||||||
return initialized
|
return initialized
|
||||||
? <Navigate to={RouteEnum.LOGIN} />
|
? <Navigate to={RouteEnum.LOGIN} />
|
||||||
: (
|
: (
|
||||||
<Root className={'Initialize ' + classes.root}>
|
<Layout>
|
||||||
<div className='Initialize-content'>
|
<Root className={'Initialize ' + classes.root}>
|
||||||
<img src={Images.Logo} alt="logo" />
|
<div className='Initialize-content'>
|
||||||
<Typography variant="subtitle1" className='subtitle'>{ t('InitializeContainer.title') }</Typography>
|
<img src={Images.Logo} alt="logo" />
|
||||||
<Trans i18nKey="InitializeContainer.subtitle">
|
<Typography variant="subtitle1" className='subtitle'>{ t('InitializeContainer.title') }</Typography>
|
||||||
<Typography variant="subtitle2"></Typography>
|
<Trans i18nKey="InitializeContainer.subtitle">
|
||||||
<Typography variant="subtitle2"></Typography>
|
<Typography variant="subtitle2"></Typography>
|
||||||
</Trans>
|
<Typography variant="subtitle2"></Typography>
|
||||||
</div>
|
</Trans>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div className="Initialize-graphics">
|
<div className="Initialize-graphics">
|
||||||
<div className="topLeft Initialize-graphics__square" />
|
<div className="topLeft Initialize-graphics__square" />
|
||||||
<div className="topRight Initialize-graphics__square" />
|
<div className="topRight Initialize-graphics__square" />
|
||||||
<div className="bottomRight Initialize-graphics__square" />
|
<div className="bottomRight Initialize-graphics__square" />
|
||||||
<div className="bottomLeft Initialize-graphics__square" />
|
<div className="bottomLeft Initialize-graphics__square" />
|
||||||
<div className="topBar Initialize-graphics__bar" />
|
<div className="topBar Initialize-graphics__bar" />
|
||||||
<div className="bottomBar Initialize-graphics__bar" />
|
<div className="bottomBar Initialize-graphics__bar" />
|
||||||
</div>
|
</div>
|
||||||
</Root>
|
</Root>
|
||||||
|
</Layout>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
31
webclient/src/containers/Layout/Layout.css
Normal file
31
webclient/src/containers/Layout/Layout.css
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
.layout {
|
||||||
|
height: 100%;
|
||||||
|
max-height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
max-width: 100%;
|
||||||
|
display: flex;
|
||||||
|
flex-flow: row nowrap;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.layout--no-height-limit {
|
||||||
|
height: initial;
|
||||||
|
max-height: initial;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bottom-bar__container {
|
||||||
|
background: #555;
|
||||||
|
height: 50px;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.page__body {
|
||||||
|
flex: 1;
|
||||||
|
max-height: calc(100% - 50px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.page {
|
||||||
|
display: flex;
|
||||||
|
flex-flow: column;
|
||||||
|
width: 100%;
|
||||||
|
}
|
39
webclient/src/containers/Layout/Layout.tsx
Normal file
39
webclient/src/containers/Layout/Layout.tsx
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
import LeftNav from './LeftNav';
|
||||||
|
|
||||||
|
import './Layout.css'
|
||||||
|
|
||||||
|
function Layout(props:LayoutProps) {
|
||||||
|
const { children, className, showNav = true, noHeightLimit = false } = props;
|
||||||
|
const containerClasses = ['layout']
|
||||||
|
if (noHeightLimit === true) {
|
||||||
|
containerClasses.push('layout--no-height-limit')
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={containerClasses.join(" ")}>
|
||||||
|
{showNav && <LeftNav />}
|
||||||
|
<section className="page">
|
||||||
|
<div className={`page__body ${className}`}>
|
||||||
|
{children}
|
||||||
|
</div>
|
||||||
|
{showNav && <BottomBar />}
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
function BottomBar(props) {
|
||||||
|
return (
|
||||||
|
<div className="bottom-bar__container">
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
interface LayoutProps {
|
||||||
|
showNav?: boolean;
|
||||||
|
children: any;
|
||||||
|
className?: string;
|
||||||
|
noHeightLimit?: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Layout;
|
|
@ -1,31 +1,34 @@
|
||||||
.Header {
|
.LeftNav__container {
|
||||||
|
background: #7033DB;
|
||||||
|
width: 100px;
|
||||||
|
min-width: 100px;
|
||||||
|
height: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.Header__logo {
|
.LeftNav__logo {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
padding: 16px 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.Header__logo a {
|
.LeftNav__logo a {
|
||||||
line-height: 1;
|
line-height: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
.Header__logo img {
|
.LeftNav__logo img {
|
||||||
height: 32px;
|
height: 32px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.Header-content {
|
.LeftNav-content {
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
width: 100%;
|
|
||||||
color: white;
|
color: white;
|
||||||
}
|
}
|
||||||
|
|
||||||
.Header-serverDetails {
|
.LeftNav-serverDetails {
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.Header-server__indicator {
|
.LeftNav-server__indicator {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
height: 12px;
|
height: 12px;
|
||||||
width: 12px;
|
width: 12px;
|
||||||
|
@ -35,46 +38,43 @@
|
||||||
margin-left: 10px;
|
margin-left: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.Header-nav {
|
.LeftNav-nav {
|
||||||
width: 100%;
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-between;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.Header-nav__links {
|
.LeftNav-nav__links {
|
||||||
width: 100%;
|
|
||||||
display: flex;
|
display: flex;
|
||||||
padding-left: 50px;
|
flex-flow: column;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
gap: 16px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.Header-nav__link {
|
.LeftNav-nav__link {
|
||||||
position: relative;
|
position: relative;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.Header-nav__link:hover {
|
.LeftNav-nav__link:hover {
|
||||||
background: rgba(0, 0, 0, .125);
|
background: rgba(0, 0, 0, .125);
|
||||||
}
|
}
|
||||||
|
|
||||||
.Header-nav__link:hover .Header-nav__link-menu {
|
.LeftNav-nav__link:hover .LeftNav-nav__link-menu {
|
||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
|
|
||||||
.Header-nav__link-btn {
|
.LeftNav-nav__link-btn {
|
||||||
display: flex;
|
display: flex;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
padding: 5px 10px;
|
padding: 5px 20px;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
}
|
}
|
||||||
|
|
||||||
.Header-nav__link-btn__icon {
|
.LeftNav-nav__link-btn__icon {
|
||||||
margin-left: 5px;
|
margin-left: 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.Header-nav__link-menu {
|
.LeftNav-nav__link-menu {
|
||||||
display: none;
|
display: none;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
|
@ -82,13 +82,14 @@
|
||||||
min-width: 150px;
|
min-width: 150px;
|
||||||
background: #3f51b5;
|
background: #3f51b5;
|
||||||
box-shadow: 1px 1px 2px 0px black;
|
box-shadow: 1px 1px 2px 0px black;
|
||||||
|
z-index: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
.Header-nav__link-menu__item {
|
.LeftNav-nav__link-menu__item {
|
||||||
padding: 0 !important;
|
padding: 0 !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.Header-nav__link-menu__btn {
|
.LeftNav-nav__link-menu__btn {
|
||||||
padding: 6px 16px;
|
padding: 6px 16px;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
color: white;
|
color: white;
|
||||||
|
@ -96,15 +97,16 @@
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
}
|
}
|
||||||
|
|
||||||
.Header-nav__actions {
|
.LeftNav-nav__actions {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.Header-nav__action {
|
.LeftNav-nav__action {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.Header-nav__action button {
|
.LeftNav-nav__action button {
|
||||||
color: white;
|
color: white;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -124,4 +126,3 @@
|
||||||
.temp-chip > div {
|
.temp-chip > div {
|
||||||
cursor: inherit;
|
cursor: inherit;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,9 @@
|
||||||
import React, { useState, useEffect } from 'react';
|
import React, { useState, useEffect } from 'react';
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import { NavLink, useNavigate, generatePath } from 'react-router-dom';
|
import { NavLink, useNavigate, generatePath } from 'react-router-dom';
|
||||||
import AppBar from '@mui/material/AppBar';
|
|
||||||
import IconButton from '@mui/material/IconButton';
|
import IconButton from '@mui/material/IconButton';
|
||||||
import Menu from '@mui/material/Menu';
|
import Menu from '@mui/material/Menu';
|
||||||
import MenuItem from '@mui/material/MenuItem';
|
import MenuItem from '@mui/material/MenuItem';
|
||||||
import Toolbar from '@mui/material/Toolbar';
|
|
||||||
import ArrowDropDownIcon from '@mui/icons-material/ArrowDropDown';
|
import ArrowDropDownIcon from '@mui/icons-material/ArrowDropDown';
|
||||||
import CloseIcon from '@mui/icons-material/Close';
|
import CloseIcon from '@mui/icons-material/Close';
|
||||||
import MailOutlineRoundedIcon from '@mui/icons-material/MailOutline';
|
import MailOutlineRoundedIcon from '@mui/icons-material/MailOutline';
|
||||||
|
@ -18,11 +16,11 @@ import { Images } from 'images';
|
||||||
import { RoomsSelectors, ServerSelectors } from 'store';
|
import { RoomsSelectors, ServerSelectors } from 'store';
|
||||||
import { Room, RouteEnum, User } from 'types';
|
import { Room, RouteEnum, User } from 'types';
|
||||||
|
|
||||||
import './Header.css';
|
import './LeftNav.css';
|
||||||
|
|
||||||
const Header = ({ joinedRooms, serverState, user }: HeaderProps) => {
|
const LeftNav = ({ joinedRooms, serverState, user }: LeftNavProps) => {
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const [state, setState] = useState<HeaderState>({
|
const [state, setState] = useState<LeftNavState>({
|
||||||
anchorEl: null,
|
anchorEl: null,
|
||||||
showCardImportDialog: false,
|
showCardImportDialog: false,
|
||||||
options: [],
|
options: [],
|
||||||
|
@ -73,23 +71,23 @@ const Header = ({ joinedRooms, serverState, user }: HeaderProps) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<AppBar className="Header" position="static">
|
<div className="LeftNav__container">
|
||||||
<Toolbar variant="dense">
|
<div>
|
||||||
<div className="Header__logo">
|
<div className="LeftNav__logo">
|
||||||
<NavLink to={RouteEnum.SERVER}>
|
<NavLink to={RouteEnum.SERVER}>
|
||||||
<img src={Images.Logo} alt="logo" />
|
<img src={Images.Logo} alt="logo" />
|
||||||
</NavLink>
|
</NavLink>
|
||||||
{ AuthenticationService.isConnected(serverState) && (
|
{ AuthenticationService.isConnected(serverState) && (
|
||||||
<span className="Header-server__indicator"></span>
|
<span className="LeftNav-server__indicator"></span>
|
||||||
) }
|
) }
|
||||||
</div>
|
</div>
|
||||||
{ AuthenticationService.isConnected(serverState) && (
|
{ AuthenticationService.isConnected(serverState) && (
|
||||||
<div className="Header-content">
|
<div className="LeftNav-content">
|
||||||
<nav className="Header-nav">
|
<nav className="LeftNav-nav">
|
||||||
<nav className="Header-nav__links">
|
<nav className="LeftNav-nav__links">
|
||||||
<div className="Header-nav__link">
|
<div className="LeftNav-nav__link">
|
||||||
<NavLink
|
<NavLink
|
||||||
className="Header-nav__link-btn"
|
className="LeftNav-nav__link-btn"
|
||||||
to={
|
to={
|
||||||
joinedRooms.length
|
joinedRooms.length
|
||||||
? generatePath(RouteEnum.ROOM, { roomId: joinedRooms[0].roomId.toString() })
|
? generatePath(RouteEnum.ROOM, { roomId: joinedRooms[0].roomId.toString() })
|
||||||
|
@ -97,42 +95,42 @@ const Header = ({ joinedRooms, serverState, user }: HeaderProps) => {
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
Rooms
|
Rooms
|
||||||
<ArrowDropDownIcon className="Header-nav__link-btn__icon" fontSize="small" />
|
<ArrowDropDownIcon className="LeftNav-nav__link-btn__icon" fontSize="small" />
|
||||||
</NavLink>
|
</NavLink>
|
||||||
<div className="Header-nav__link-menu">
|
<div className="LeftNav-nav__link-menu">
|
||||||
{joinedRooms.map(({ name, roomId }) => (
|
{joinedRooms.map(({ name, roomId }) => (
|
||||||
<MenuItem className="Header-nav__link-menu__item" key={roomId}>
|
<div className="LeftNav-nav__link-menu__item" key={roomId}>
|
||||||
<NavLink className="Header-nav__link-menu__btn" to={ generatePath(RouteEnum.ROOM, { roomId: roomId.toString() }) }>
|
<NavLink className="LeftNav-nav__link-menu__btn" to={ generatePath(RouteEnum.ROOM, { roomId: roomId.toString() }) }>
|
||||||
{name}
|
{name}
|
||||||
|
|
||||||
<IconButton size="small" edge="end" onClick={event => leaveRoom(event, roomId)}>
|
<IconButton size="small" edge="end" onClick={event => leaveRoom(event, roomId)}>
|
||||||
<CloseIcon style={{ fontSize: 10, color: 'white' }} />
|
<CloseIcon style={{ fontSize: 10, color: 'white' }} />
|
||||||
</IconButton>
|
</IconButton>
|
||||||
</NavLink>
|
</NavLink>
|
||||||
</MenuItem>
|
</div>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="Header-nav__link">
|
<div className="LeftNav-nav__link">
|
||||||
<NavLink className="Header-nav__link-btn" to={ RouteEnum.GAME }>
|
<NavLink className="LeftNav-nav__link-btn" to={ RouteEnum.GAME }>
|
||||||
Games
|
Games
|
||||||
<ArrowDropDownIcon className="Header-nav__link-btn__icon" fontSize="small" />
|
<ArrowDropDownIcon className="LeftNav-nav__link-btn__icon" fontSize="small" />
|
||||||
</NavLink>
|
</NavLink>
|
||||||
</div>
|
</div>
|
||||||
<div className="Header-nav__link">
|
<div className="LeftNav-nav__link">
|
||||||
<NavLink className="Header-nav__link-btn" to={ RouteEnum.DECKS }>
|
<NavLink className="LeftNav-nav__link-btn" to={ RouteEnum.DECKS }>
|
||||||
Decks
|
Decks
|
||||||
<ArrowDropDownIcon className="Header-nav__link-btn__icon" fontSize="small" />
|
<ArrowDropDownIcon className="LeftNav-nav__link-btn__icon" fontSize="small" />
|
||||||
</NavLink>
|
</NavLink>
|
||||||
</div>
|
</div>
|
||||||
</nav>
|
</nav>
|
||||||
<div className="Header-nav__actions">
|
<div className="LeftNav-nav__actions">
|
||||||
<div className="Header-nav__action">
|
<div className="LeftNav-nav__action">
|
||||||
<IconButton size="large">
|
<IconButton size="large">
|
||||||
<MailOutlineRoundedIcon style={{ color: 'inherit' }} />
|
<MailOutlineRoundedIcon style={{ color: 'inherit' }} />
|
||||||
</IconButton>
|
</IconButton>
|
||||||
</div>
|
</div>
|
||||||
<div className="Header-nav__action">
|
<div className="LeftNav-nav__action">
|
||||||
<IconButton onClick={handleMenuOpen} size="large">
|
<IconButton onClick={handleMenuOpen} size="large">
|
||||||
<MenuRoundedIcon style={{ color: 'inherit' }} />
|
<MenuRoundedIcon style={{ color: 'inherit' }} />
|
||||||
</IconButton>
|
</IconButton>
|
||||||
|
@ -163,24 +161,25 @@ const Header = ({ joinedRooms, serverState, user }: HeaderProps) => {
|
||||||
</nav>
|
</nav>
|
||||||
</div>
|
</div>
|
||||||
) }
|
) }
|
||||||
</Toolbar>
|
</div>
|
||||||
|
|
||||||
<CardImportDialog
|
<CardImportDialog
|
||||||
isOpen={state.showCardImportDialog}
|
isOpen={state.showCardImportDialog}
|
||||||
handleClose={closeImportCardWizard}
|
handleClose={closeImportCardWizard}
|
||||||
></CardImportDialog>
|
></CardImportDialog>
|
||||||
</AppBar>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
interface HeaderProps {
|
interface LeftNavProps {
|
||||||
serverState: number;
|
serverState: number;
|
||||||
server: string;
|
server: string;
|
||||||
user: User;
|
user: User;
|
||||||
joinedRooms: Room[];
|
joinedRooms: Room[];
|
||||||
|
showNav?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface HeaderState {
|
interface LeftNavState {
|
||||||
anchorEl: Element;
|
anchorEl: Element;
|
||||||
showCardImportDialog: boolean;
|
showCardImportDialog: boolean;
|
||||||
options: string[];
|
options: string[];
|
||||||
|
@ -193,4 +192,4 @@ const mapStateToProps = state => ({
|
||||||
joinedRooms: RoomsSelectors.getJoinedRooms(state),
|
joinedRooms: RoomsSelectors.getJoinedRooms(state),
|
||||||
});
|
});
|
||||||
|
|
||||||
export default connect(mapStateToProps)(Header);
|
export default connect(mapStateToProps)(LeftNav);
|
Before Width: | Height: | Size: 25 KiB After Width: | Height: | Size: 25 KiB |
|
@ -16,6 +16,7 @@ import { Images } from 'images';
|
||||||
import { HostDTO, serverProps } from 'services';
|
import { HostDTO, serverProps } from 'services';
|
||||||
import { RouteEnum, WebSocketConnectOptions, getHostPort } from 'types';
|
import { RouteEnum, WebSocketConnectOptions, getHostPort } from 'types';
|
||||||
import { ServerSelectors, ServerTypes } from 'store';
|
import { ServerSelectors, ServerTypes } from 'store';
|
||||||
|
import Layout from 'containers/Layout/Layout';
|
||||||
|
|
||||||
import './Login.css';
|
import './Login.css';
|
||||||
import { useToast } from 'components/Toast';
|
import { useToast } from 'components/Toast';
|
||||||
|
@ -225,120 +226,122 @@ const Login = ({ state, description, connectOptions }: LoginProps) => {
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Root className={'login overflow-scroll ' + classes.root}>
|
<Layout showNav={false} noHeightLimit={true}>
|
||||||
{ isConnected && <Navigate to={RouteEnum.SERVER} />}
|
<Root className={'login overflow-scroll ' + classes.root}>
|
||||||
|
{ isConnected && <Navigate to={RouteEnum.SERVER} />}
|
||||||
|
|
||||||
<div className="login__wrapper">
|
<div className="login__wrapper">
|
||||||
<Paper className="login-content">
|
<Paper className="login-content">
|
||||||
<div className="login-content__form">
|
<div className="login-content__form">
|
||||||
<div className="login-content__header">
|
<div className="login-content__header">
|
||||||
<img src={Images.Logo} alt="logo" />
|
<img src={Images.Logo} alt="logo" />
|
||||||
<span>COCKATRICE</span>
|
<span>COCKATRICE</span>
|
||||||
</div>
|
</div>
|
||||||
<Typography variant="h1">{ t('LoginContainer.header.title') }</Typography>
|
<Typography variant="h1">{ t('LoginContainer.header.title') }</Typography>
|
||||||
<Typography variant="subtitle1">{ t('LoginContainer.header.subtitle') }</Typography>
|
<Typography variant="subtitle1">{ t('LoginContainer.header.subtitle') }</Typography>
|
||||||
<div className="login-form">
|
<div className="login-form">
|
||||||
<LoginForm
|
<LoginForm
|
||||||
onSubmit={handleLogin}
|
onSubmit={handleLogin}
|
||||||
onResetPassword={openRequestPasswordResetDialog}
|
onResetPassword={openRequestPasswordResetDialog}
|
||||||
disableSubmitButton={submitButtonDisabled}
|
disableSubmitButton={submitButtonDisabled}
|
||||||
/>
|
/>
|
||||||
</div>
|
|
||||||
|
|
||||||
{
|
|
||||||
showDescription() && (
|
|
||||||
<Paper className="login-content__connectionStatus">
|
|
||||||
{description}
|
|
||||||
</Paper>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
<div className="login-footer">
|
|
||||||
<div className="login-footer__register">
|
|
||||||
<span>{ t('LoginContainer.footer.registerPrompt') }</span>
|
|
||||||
<Button color="primary" onClick={openRegistrationDialog}>{ t('LoginContainer.footer.registerAction') }</Button>
|
|
||||||
</div>
|
</div>
|
||||||
<Typography variant="subtitle2">
|
|
||||||
{ t('LoginContainer.footer.credit') } - { new Date().getUTCFullYear() }
|
|
||||||
</Typography>
|
|
||||||
|
|
||||||
{
|
{
|
||||||
serverProps.REACT_APP_VERSION && (
|
showDescription() && (
|
||||||
<Typography variant="subtitle2">
|
<Paper className="login-content__connectionStatus">
|
||||||
{ t('LoginContainer.footer.version') }: { serverProps.REACT_APP_VERSION }
|
{description}
|
||||||
</Typography>
|
</Paper>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
<div className="login-footer__language">
|
<div className="login-footer">
|
||||||
<LanguageDropdown />
|
<div className="login-footer__register">
|
||||||
</div>
|
<span>{ t('LoginContainer.footer.registerPrompt') }</span>
|
||||||
</div>
|
<Button color="primary" onClick={openRegistrationDialog}>{ t('LoginContainer.footer.registerAction') }</Button>
|
||||||
</div>
|
|
||||||
<div className="login-content__description">
|
|
||||||
<div className="login-content__description-graphics">
|
|
||||||
<div className="topLeft login-content__description-square" />
|
|
||||||
<div className="topRight login-content__description-square" />
|
|
||||||
<div className="bottomRight login-content__description-square" />
|
|
||||||
<div className="bottomLeft login-content__description-square" />
|
|
||||||
<div className="topBar login-content__description-bar" />
|
|
||||||
<div className="bottomBar login-content__description-bar" />
|
|
||||||
</div>
|
|
||||||
<div className="login-content__description-wrapper">
|
|
||||||
<div className="login-content__description-cards">
|
|
||||||
<div className="login-content__description-cards__card leftCard">
|
|
||||||
<div className="login-content__description-cards__card-wrapper">
|
|
||||||
<img src={Images.Faces.face1} alt='Stock Player' />
|
|
||||||
<span>1mrlee</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
<div className="login-content__description-cards__card rightCard">
|
<Typography variant="subtitle2">
|
||||||
<div className="login-content__description-cards__card-wrapper">
|
{ t('LoginContainer.footer.credit') } - { new Date().getUTCFullYear() }
|
||||||
<img src={Images.Faces.face2} alt='Stock Player' />
|
</Typography>
|
||||||
<span>CyberX</span>
|
|
||||||
</div>
|
{
|
||||||
</div>
|
serverProps.REACT_APP_VERSION && (
|
||||||
<div className="login-content__description-cards__card topCard">
|
<Typography variant="subtitle2">
|
||||||
<div className="login-content__description-cards__card-wrapper">
|
{ t('LoginContainer.footer.version') }: { serverProps.REACT_APP_VERSION }
|
||||||
<img src={Images.Faces.face3} alt='Stock Player' />
|
</Typography>
|
||||||
<span>Gamer69</span>
|
)
|
||||||
</div>
|
}
|
||||||
|
|
||||||
|
<div className="login-footer__language">
|
||||||
|
<LanguageDropdown />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{ /*<img src={loginGraphic} className="login-content__description-image"/>*/}
|
|
||||||
<p className="login-content__description-subtitle1">{ t('LoginContainer.content.subtitle1') }</p>
|
|
||||||
<p className="login-content__description-subtitle2">{ t('LoginContainer.content.subtitle2') }</p>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<div className="login-content__description">
|
||||||
</Paper>
|
<div className="login-content__description-graphics">
|
||||||
</div>
|
<div className="topLeft login-content__description-square" />
|
||||||
|
<div className="topRight login-content__description-square" />
|
||||||
|
<div className="bottomRight login-content__description-square" />
|
||||||
|
<div className="bottomLeft login-content__description-square" />
|
||||||
|
<div className="topBar login-content__description-bar" />
|
||||||
|
<div className="bottomBar login-content__description-bar" />
|
||||||
|
</div>
|
||||||
|
<div className="login-content__description-wrapper">
|
||||||
|
<div className="login-content__description-cards">
|
||||||
|
<div className="login-content__description-cards__card leftCard">
|
||||||
|
<div className="login-content__description-cards__card-wrapper">
|
||||||
|
<img src={Images.Faces.face1} alt='Stock Player' />
|
||||||
|
<span>1mrlee</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="login-content__description-cards__card rightCard">
|
||||||
|
<div className="login-content__description-cards__card-wrapper">
|
||||||
|
<img src={Images.Faces.face2} alt='Stock Player' />
|
||||||
|
<span>CyberX</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="login-content__description-cards__card topCard">
|
||||||
|
<div className="login-content__description-cards__card-wrapper">
|
||||||
|
<img src={Images.Faces.face3} alt='Stock Player' />
|
||||||
|
<span>Gamer69</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{ /*<img src={loginGraphic} className="login-content__description-image"/>*/}
|
||||||
|
<p className="login-content__description-subtitle1">{ t('LoginContainer.content.subtitle1') }</p>
|
||||||
|
<p className="login-content__description-subtitle2">{ t('LoginContainer.content.subtitle2') }</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Paper>
|
||||||
|
</div>
|
||||||
|
|
||||||
<RegistrationDialog
|
<RegistrationDialog
|
||||||
isOpen={dialogState.registrationDialog}
|
isOpen={dialogState.registrationDialog}
|
||||||
onSubmit={handleRegistrationDialogSubmit}
|
onSubmit={handleRegistrationDialogSubmit}
|
||||||
handleClose={closeRegistrationDialog}
|
handleClose={closeRegistrationDialog}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<RequestPasswordResetDialog
|
<RequestPasswordResetDialog
|
||||||
isOpen={dialogState.passwordResetRequestDialog}
|
isOpen={dialogState.passwordResetRequestDialog}
|
||||||
onSubmit={handleRequestPasswordResetDialogSubmit}
|
onSubmit={handleRequestPasswordResetDialogSubmit}
|
||||||
handleClose={closeRequestPasswordResetDialog}
|
handleClose={closeRequestPasswordResetDialog}
|
||||||
skipTokenRequest={skipTokenRequest}
|
skipTokenRequest={skipTokenRequest}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<ResetPasswordDialog
|
<ResetPasswordDialog
|
||||||
isOpen={dialogState.resetPasswordDialog}
|
isOpen={dialogState.resetPasswordDialog}
|
||||||
onSubmit={handleResetPasswordDialogSubmit}
|
onSubmit={handleResetPasswordDialogSubmit}
|
||||||
handleClose={closeResetPasswordDialog}
|
handleClose={closeResetPasswordDialog}
|
||||||
userName={userToResetPassword}
|
userName={userToResetPassword}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<AccountActivationDialog
|
<AccountActivationDialog
|
||||||
isOpen={dialogState.activationDialog}
|
isOpen={dialogState.activationDialog}
|
||||||
onSubmit={handleAccountActivationDialogSubmit}
|
onSubmit={handleAccountActivationDialogSubmit}
|
||||||
handleClose={closeActivateAccountDialog}
|
handleClose={closeActivateAccountDialog}
|
||||||
/>
|
/>
|
||||||
</Root>
|
</Root>
|
||||||
|
</Layout>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,15 +1,16 @@
|
||||||
// eslint-disable-next-line
|
// eslint-disable-next-line
|
||||||
import React, { Component } from "react";
|
import React, { Component } from "react";
|
||||||
|
import Layout from 'containers/Layout/Layout';
|
||||||
|
|
||||||
import { AuthGuard } from 'components';
|
import { AuthGuard } from 'components';
|
||||||
|
|
||||||
class Player extends Component {
|
class Player extends Component {
|
||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<div>
|
<Layout>
|
||||||
<AuthGuard />
|
<AuthGuard />
|
||||||
<span>"Player"</span>
|
<span>"Player"</span>
|
||||||
</div>
|
</Layout>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,6 +9,7 @@ import { RoomsService } from 'api';
|
||||||
import { ScrollToBottomOnChanges, ThreePaneLayout, UserDisplay, VirtualList, AuthGuard } from 'components';
|
import { ScrollToBottomOnChanges, ThreePaneLayout, UserDisplay, VirtualList, AuthGuard } from 'components';
|
||||||
import { RoomsStateMessages, RoomsStateRooms, JoinedRooms, RoomsSelectors, RoomsTypes } from 'store';
|
import { RoomsStateMessages, RoomsStateRooms, JoinedRooms, RoomsSelectors, RoomsTypes } from 'store';
|
||||||
import { RouteEnum } from 'types';
|
import { RouteEnum } from 'types';
|
||||||
|
import Layout from 'containers/Layout/Layout';
|
||||||
|
|
||||||
import OpenGames from './OpenGames';
|
import OpenGames from './OpenGames';
|
||||||
import Messages from './Messages';
|
import Messages from './Messages';
|
||||||
|
@ -40,7 +41,7 @@ const Room = (props) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="room-view">
|
<Layout className="room-view">
|
||||||
<AuthGuard />
|
<AuthGuard />
|
||||||
|
|
||||||
<div className="room-view__main">
|
<div className="room-view__main">
|
||||||
|
@ -84,7 +85,7 @@ const Room = (props) => {
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</Layout>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -11,6 +11,7 @@ import { useReduxEffect } from 'hooks';
|
||||||
import { RoomsSelectors, RoomsTypes, ServerSelectors } from 'store';
|
import { RoomsSelectors, RoomsTypes, ServerSelectors } from 'store';
|
||||||
import { Room, RouteEnum, User } from 'types';
|
import { Room, RouteEnum, User } from 'types';
|
||||||
import Rooms from './Rooms';
|
import Rooms from './Rooms';
|
||||||
|
import Layout from 'containers/Layout/Layout';
|
||||||
|
|
||||||
import './Server.css';
|
import './Server.css';
|
||||||
|
|
||||||
|
@ -23,7 +24,7 @@ const Server = ({ message, rooms, joinedRooms, users }: ServerProps) => {
|
||||||
}, RoomsTypes.JOIN_ROOM, []);
|
}, RoomsTypes.JOIN_ROOM, []);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="server-rooms">
|
<Layout className="server-rooms">
|
||||||
<AuthGuard />
|
<AuthGuard />
|
||||||
|
|
||||||
<ThreePaneLayout
|
<ThreePaneLayout
|
||||||
|
@ -55,7 +56,7 @@ const Server = ({ message, rooms, joinedRooms, users }: ServerProps) => {
|
||||||
</Paper>
|
</Paper>
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
</div>
|
</Layout>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,7 @@ import { connect } from 'react-redux';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import Paper from '@mui/material/Paper';
|
import Paper from '@mui/material/Paper';
|
||||||
import Typography from '@mui/material/Typography';
|
import Typography from '@mui/material/Typography';
|
||||||
|
import Layout from 'containers/Layout/Layout';
|
||||||
|
|
||||||
import './Unsupported.css';
|
import './Unsupported.css';
|
||||||
|
|
||||||
|
@ -9,7 +10,7 @@ const Unsupported = () => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='Unsupported'>
|
<Layout className='Unsupported'>
|
||||||
<Paper className='Unsupported-paper'>
|
<Paper className='Unsupported-paper'>
|
||||||
<div className='Unsupported-paper__header'>
|
<div className='Unsupported-paper__header'>
|
||||||
<Typography variant="h1">{ t('UnsupportedContainer.title') }</Typography>
|
<Typography variant="h1">{ t('UnsupportedContainer.title') }</Typography>
|
||||||
|
@ -18,7 +19,7 @@ const Unsupported = () => {
|
||||||
|
|
||||||
<Typography variant="subtitle2">{ t('UnsupportedContainer.subtitle2') }</Typography>
|
<Typography variant="subtitle2">{ t('UnsupportedContainer.subtitle2') }</Typography>
|
||||||
</Paper>
|
</Paper>
|
||||||
</div>
|
</Layout>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue