mirror of
https://bitbucket.org/wisemapping/wisemapping-frontend.git
synced 2024-11-11 01:43:23 +01:00
Refactor styles
This commit is contained in:
parent
1dda8b6c9f
commit
cd18df3811
@ -2,7 +2,7 @@ import React, { useEffect, useState } from 'react';
|
|||||||
import { IntlProvider } from 'react-intl';
|
import { IntlProvider } from 'react-intl';
|
||||||
import { Route, Switch, Redirect, BrowserRouter as Router } from 'react-router-dom';
|
import { Route, Switch, Redirect, BrowserRouter as Router } from 'react-router-dom';
|
||||||
|
|
||||||
import { GlobalStyle } from './theme/global-style';
|
import { GlobalStyle } from './theme';
|
||||||
import RegistrationSuccessPage from './components/registration-success-page';
|
import RegistrationSuccessPage from './components/registration-success-page';
|
||||||
import ForgotPasswordSuccessPage from './components/forgot-password-success-page';
|
import ForgotPasswordSuccessPage from './components/forgot-password-success-page';
|
||||||
import RegistationPage from './components/registration-page';
|
import RegistationPage from './components/registration-page';
|
||||||
@ -13,6 +13,9 @@ import store from "./store";
|
|||||||
import { ForgotPasswordPage } from './components/forgot-password-page';
|
import { ForgotPasswordPage } from './components/forgot-password-page';
|
||||||
import { Provider } from 'react-redux';
|
import { Provider } from 'react-redux';
|
||||||
import { QueryClient, QueryClientProvider } from 'react-query';
|
import { QueryClient, QueryClientProvider } from 'react-query';
|
||||||
|
import { CssBaseline, ThemeProvider } from '@material-ui/core';
|
||||||
|
import { theme } from './theme'
|
||||||
|
|
||||||
|
|
||||||
function loadLocaleData(language: string) {
|
function loadLocaleData(language: string) {
|
||||||
switch (language) {
|
switch (language) {
|
||||||
@ -43,9 +46,11 @@ const App = () => {
|
|||||||
|
|
||||||
return messages ? (
|
return messages ? (
|
||||||
<Provider store={store}>
|
<Provider store={store}>
|
||||||
|
<GlobalStyle />
|
||||||
<QueryClientProvider client={queryClient}>
|
<QueryClientProvider client={queryClient}>
|
||||||
<IntlProvider locale={locale} defaultLocale='en' messages={messages}>
|
<IntlProvider locale={locale} defaultLocale='en' messages={messages}>
|
||||||
<GlobalStyle />
|
<ThemeProvider theme={theme}>
|
||||||
|
<CssBaseline />
|
||||||
<Router>
|
<Router>
|
||||||
<Switch>
|
<Switch>
|
||||||
<Route exact path="/">
|
<Route exact path="/">
|
||||||
@ -65,6 +70,7 @@ const App = () => {
|
|||||||
</Route>
|
</Route>
|
||||||
</Switch>
|
</Switch>
|
||||||
</Router>
|
</Router>
|
||||||
|
</ThemeProvider>
|
||||||
</IntlProvider>
|
</IntlProvider>
|
||||||
</QueryClientProvider>
|
</QueryClientProvider>
|
||||||
</Provider>
|
</Provider>
|
||||||
|
@ -5,12 +5,14 @@ import { Service, ErrorInfo } from '../../services/Service'
|
|||||||
|
|
||||||
import Header from '../layout/header'
|
import Header from '../layout/header'
|
||||||
import Footer from '../layout/footer'
|
import Footer from '../layout/footer'
|
||||||
import { PageContent } from '../../theme/global-style'
|
import { PageContent } from '../../theme'
|
||||||
import { useSelector } from 'react-redux'
|
import { useSelector } from 'react-redux'
|
||||||
import { useMutation } from 'react-query'
|
import { useMutation } from 'react-query'
|
||||||
import { activeInstance } from '../../reducers/serviceSlice'
|
import { activeInstance } from '../../reducers/serviceSlice'
|
||||||
import Input from '../form/input'
|
import Input from '../form/input'
|
||||||
import GlobalError from '../form/global-error'
|
import GlobalError from '../form/global-error'
|
||||||
|
import SubmitButton from '../form/submit-button'
|
||||||
|
import { Typography } from '@material-ui/core'
|
||||||
|
|
||||||
const ForgotPassword = () => {
|
const ForgotPassword = () => {
|
||||||
const [email, setEmail] = useState<string>('');
|
const [email, setEmail] = useState<string>('');
|
||||||
@ -36,8 +38,13 @@ const ForgotPassword = () => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<PageContent>
|
<PageContent>
|
||||||
<h1><FormattedMessage id="forgot.title" defaultMessage="Reset your password" /></h1>
|
<Typography variant="h4" component="h1">
|
||||||
<p><FormattedMessage id="forgot.desc" defaultMessage="We will send you an email to reset your password" /></p>
|
<FormattedMessage id="forgot.title" defaultMessage="Reset your password" />
|
||||||
|
</Typography>
|
||||||
|
|
||||||
|
<Typography>
|
||||||
|
<FormattedMessage id="forgot.desc" defaultMessage="We will send you an email to reset your password" />
|
||||||
|
</Typography>
|
||||||
|
|
||||||
<GlobalError error={error} />
|
<GlobalError error={error} />
|
||||||
|
|
||||||
@ -45,7 +52,7 @@ const ForgotPassword = () => {
|
|||||||
<Input type="email" name="email" label={{ id: "forgot.email", defaultMessage: "Email" }}
|
<Input type="email" name="email" label={{ id: "forgot.email", defaultMessage: "Email" }}
|
||||||
autoComplete="email" onChange={e => setEmail(e.target.value)} />
|
autoComplete="email" onChange={e => setEmail(e.target.value)} />
|
||||||
|
|
||||||
<input type="submit" value={intl.formatMessage({ id: "forgot.register", defaultMessage: "Send recovery link" })} />
|
<SubmitButton value={intl.formatMessage({ id: "forgot.register", defaultMessage: "Send recovery link" })} />
|
||||||
</form>
|
</form>
|
||||||
</PageContent>
|
</PageContent>
|
||||||
);
|
);
|
||||||
|
@ -1,10 +1,11 @@
|
|||||||
import React, { useEffect } from 'react'
|
import React, { useEffect } from 'react'
|
||||||
import { FormattedMessage } from 'react-intl'
|
import { FormattedMessage } from 'react-intl'
|
||||||
|
import { PageContent } from '../../theme';
|
||||||
import { PageContent } from '../../theme/global-style';
|
|
||||||
|
|
||||||
import Header, { SignInButton } from '../layout/header'
|
import Header, { SignInButton } from '../layout/header'
|
||||||
import Footer from '../layout/footer'
|
import Footer from '../layout/footer'
|
||||||
|
import { Button, Typography } from '@material-ui/core';
|
||||||
|
import { Link as RouterLink} from 'react-router-dom'
|
||||||
|
|
||||||
|
|
||||||
const ForgotPasswordSuccessPage = () => {
|
const ForgotPasswordSuccessPage = () => {
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@ -15,14 +16,18 @@ const ForgotPasswordSuccessPage = () => {
|
|||||||
<div>
|
<div>
|
||||||
<Header type='none' />
|
<Header type='none' />
|
||||||
<PageContent>
|
<PageContent>
|
||||||
<h1>
|
<Typography variant="h4" component="h1">
|
||||||
<FormattedMessage id="forgot.success.title" defaultMessage="Your temporal password has been sent" />
|
<FormattedMessage id="forgot.success.title" defaultMessage="Your temporal password has been sent" />
|
||||||
</h1>
|
</Typography>
|
||||||
<p>
|
|
||||||
<FormattedMessage id="forgot.success.desc" defaultMessage="We've sent you an email that will allow you to reset your password. Please check your email now." />
|
<Typography paragraph>
|
||||||
</p>
|
<FormattedMessage id="forgot.success.desc" defaultMessage="We've sent you an email that will allow you to reset your password. Please check your email now." />
|
||||||
|
</Typography>
|
||||||
|
|
||||||
|
<Button color="primary" size="medium" variant="contained" component={RouterLink} to="/c/login" disableElevation={true}>
|
||||||
|
<FormattedMessage id="login.signin" defaultMessage="Sign In" />
|
||||||
|
</Button>
|
||||||
|
|
||||||
<SignInButton style='style1' />
|
|
||||||
</PageContent>
|
</PageContent>
|
||||||
<Footer />
|
<Footer />
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,8 +1,7 @@
|
|||||||
import { FormControl, TextField } from "@material-ui/core";
|
import { TextField } from "@material-ui/core";
|
||||||
import React, { ChangeEvent } from "react";
|
import React, { ChangeEvent } from "react";
|
||||||
import { MessageDescriptor, useIntl } from "react-intl";
|
import { MessageDescriptor, useIntl } from "react-intl";
|
||||||
import { ErrorInfo } from "../../../services/Service";
|
import { ErrorInfo } from "../../../services/Service";
|
||||||
import { StyledTextField } from "./styles";
|
|
||||||
|
|
||||||
type InputProps = {
|
type InputProps = {
|
||||||
name: string;
|
name: string;
|
||||||
@ -28,7 +27,7 @@ const Input = (props: InputProps) => {
|
|||||||
const fullWidth = props.fullWidth != undefined ? props.required : true;
|
const fullWidth = props.fullWidth != undefined ? props.required : true;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<StyledTextField name={name} type={props.type} label={intl.formatMessage(props.label)}
|
<TextField name={name} type={props.type} label={intl.formatMessage(props.label)}
|
||||||
value={value} onChange={onChange}
|
value={value} onChange={onChange}
|
||||||
error={fieldError} helperText={fieldError}
|
error={fieldError} helperText={fieldError}
|
||||||
variant="outlined" required={required} fullWidth={fullWidth} margin="dense"/>
|
variant="outlined" required={required} fullWidth={fullWidth} margin="dense"/>
|
||||||
|
@ -1,24 +0,0 @@
|
|||||||
import { TextField, withStyles } from "@material-ui/core";
|
|
||||||
|
|
||||||
export const StyledTextField = withStyles({
|
|
||||||
root:
|
|
||||||
{
|
|
||||||
'& label.Mui-focused': {
|
|
||||||
color: '#f9a826',
|
|
||||||
},
|
|
||||||
'& .MuiOutlinedInput-root': {
|
|
||||||
height: '53px',
|
|
||||||
borderRadius: '9px',
|
|
||||||
fontSize: '16px',
|
|
||||||
'& fieldset': {
|
|
||||||
border: 'solid 1px #ffcb66',
|
|
||||||
},
|
|
||||||
'&:hover fieldset': {
|
|
||||||
borderColor: '#f9a826',
|
|
||||||
},
|
|
||||||
'&.Mui-focused fieldset': {
|
|
||||||
borderColor: '#f9a826'
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
})(TextField);
|
|
@ -1,3 +1,4 @@
|
|||||||
|
import { Button } from '@material-ui/core';
|
||||||
import React, { useState, useEffect } from 'react'
|
import React, { useState, useEffect } from 'react'
|
||||||
import { useIntl } from 'react-intl'
|
import { useIntl } from 'react-intl'
|
||||||
|
|
||||||
@ -15,7 +16,11 @@ const SubmitButton = (props: SubmitButton) => {
|
|||||||
}
|
}
|
||||||
const [value, setValue] = useState(valueTxt);
|
const [value, setValue] = useState(valueTxt);
|
||||||
return (
|
return (
|
||||||
<input type="submit" disabled={disabled} value={value} />
|
<Button color="primary" size="medium" variant="contained" type="submit"
|
||||||
|
disableElevation={true} disabled={disabled}
|
||||||
|
style={{width: '330px', height: '53px', padding: '0px 20px', margin: '7px 0px',fontSize: '18px' }} >
|
||||||
|
{value}
|
||||||
|
</Button>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3,6 +3,7 @@ import { StyledNav, StyledDiv,Logo } from './styled';
|
|||||||
import React from 'react'
|
import React from 'react'
|
||||||
import { FormattedMessage } from 'react-intl'
|
import { FormattedMessage } from 'react-intl'
|
||||||
import { Link } from 'react-router-dom'
|
import { Link } from 'react-router-dom'
|
||||||
|
import { Button } from '@material-ui/core';
|
||||||
|
|
||||||
const logo = require('../../../images/header-logo.png')
|
const logo = require('../../../images/header-logo.png')
|
||||||
|
|
||||||
@ -49,23 +50,20 @@ class Header extends React.Component<HeaderProps, HeaderProps> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
interface ButtonProps {
|
interface ButtonProps {
|
||||||
style?: 'style1' | 'style2' | 'style3';
|
|
||||||
className?: string;
|
className?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
const SignInButton = (props: ButtonProps) => {
|
const SignInButton = (props: ButtonProps) => {
|
||||||
const style = props.style ? props.style : 'style1';
|
|
||||||
return (
|
return (
|
||||||
<span className={`button-${style} ${props.className}`}>
|
<span className={`${props.className}`}>
|
||||||
<Link to="/c/login"><FormattedMessage id="login.signin" defaultMessage="Sign In" /></Link>
|
<Button color="primary" size="medium" variant="outlined" component={Link} to="/c/login"><FormattedMessage id="login.signin" defaultMessage="Sign In" /></Button>
|
||||||
</span>);
|
</span>);
|
||||||
}
|
}
|
||||||
|
|
||||||
const SignUpButton = (props: ButtonProps) => {
|
const SignUpButton = (props: ButtonProps) => {
|
||||||
const style = props.style ? props.style : 'style1';
|
|
||||||
return (
|
return (
|
||||||
<span className={`button-${style} ${props.className}`}>
|
<span className={`${props.className}`}>
|
||||||
<Link to="/c/registration"><FormattedMessage id="login.signup" defaultMessage="Sign Up" /></Link>
|
<Button color="primary" size="medium" variant="outlined" component={Link} to="/c/registration"><FormattedMessage id="login.signup" defaultMessage="Sign Up" /></Button>
|
||||||
</span>);
|
</span>);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,14 +1,14 @@
|
|||||||
import React, { useEffect } from 'react'
|
import React, { useEffect } from 'react';
|
||||||
import { FormattedMessage, useIntl } from 'react-intl'
|
import { FormattedMessage, useIntl } from 'react-intl';
|
||||||
import { Link } from 'react-router-dom'
|
import { Link as RouterLink} from 'react-router-dom'
|
||||||
|
|
||||||
import { PageContent } from '../../theme/global-style';
|
import { PageContent } from '../../theme';
|
||||||
import Header from '../layout/header'
|
import Header from '../layout/header'
|
||||||
import Footer from '../layout/footer'
|
import Footer from '../layout/footer'
|
||||||
import SubmitButton from '../form/submit-button'
|
import SubmitButton from '../form/submit-button'
|
||||||
import Input from '../form/input';
|
import Input from '../form/input';
|
||||||
import GlobalError from '../form/global-error';
|
import GlobalError from '../form/global-error';
|
||||||
import { FormControl } from '@material-ui/core';
|
import { FormControl, Link, Typography } from '@material-ui/core';
|
||||||
|
|
||||||
|
|
||||||
const ConfigStatusMessage = (props: any) => {
|
const ConfigStatusMessage = (props: any) => {
|
||||||
@ -56,8 +56,13 @@ const LoginPage = () => {
|
|||||||
<Header type='only-signup' />
|
<Header type='only-signup' />
|
||||||
|
|
||||||
<PageContent>
|
<PageContent>
|
||||||
<h1><FormattedMessage id="login.title" defaultMessage="Welcome" /></h1>
|
<Typography variant="h4" component="h1">
|
||||||
<p><FormattedMessage id="login.desc" defaultMessage="Log into your account" /></p>
|
<FormattedMessage id="login.title" defaultMessage="Welcome" />
|
||||||
|
</Typography>
|
||||||
|
|
||||||
|
<Typography paragraph>
|
||||||
|
<FormattedMessage id="login.desc" defaultMessage="Log into your account" />
|
||||||
|
</Typography>
|
||||||
|
|
||||||
<LoginError />
|
<LoginError />
|
||||||
|
|
||||||
@ -73,7 +78,7 @@ const LoginPage = () => {
|
|||||||
</form>
|
</form>
|
||||||
</FormControl>
|
</FormControl>
|
||||||
|
|
||||||
<Link to="/c/forgot-password"><FormattedMessage id="login.forgotpwd" defaultMessage="Forgot Password ?" /></Link>
|
<Link component={RouterLink} to="/c/forgot-password"><FormattedMessage id="login.forgotpwd" defaultMessage="Forgot Password ?" /></Link>
|
||||||
<ConfigStatusMessage />
|
<ConfigStatusMessage />
|
||||||
|
|
||||||
</PageContent>
|
</PageContent>
|
||||||
|
@ -1,19 +0,0 @@
|
|||||||
import styled from 'styled-components';
|
|
||||||
|
|
||||||
|
|
||||||
export const StyledNav = styled.div`
|
|
||||||
.db-warn-msg {
|
|
||||||
margin-top: 30px;
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.db-warn-msg p {
|
|
||||||
margin: 0 auto;
|
|
||||||
width: 500px;
|
|
||||||
background-color: #e97450;
|
|
||||||
font-size: 15px;
|
|
||||||
color: white;
|
|
||||||
padding: 15px 30px;
|
|
||||||
border-radius: 10px;
|
|
||||||
}`
|
|
||||||
|
|
@ -9,7 +9,7 @@ import EditOutlinedIcon from '@material-ui/icons/EditOutlined';
|
|||||||
import PublicOutlinedIcon from '@material-ui/icons/PublicOutlined';
|
import PublicOutlinedIcon from '@material-ui/icons/PublicOutlined';
|
||||||
import PrintOutlinedIcon from '@material-ui/icons/PrintOutlined';
|
import PrintOutlinedIcon from '@material-ui/icons/PrintOutlined';
|
||||||
import ShareOutlinedIcon from '@material-ui/icons/ShareOutlined';
|
import ShareOutlinedIcon from '@material-ui/icons/ShareOutlined';
|
||||||
import { StyledMenuItem } from '../styled';
|
import { StyledMenuItem } from '../maps-list/styled';
|
||||||
import { FormattedMessage } from 'react-intl';
|
import { FormattedMessage } from 'react-intl';
|
||||||
|
|
||||||
export type ActionType = 'open' | 'share' | 'delete' | 'info' | 'duplicate' | 'export' | 'rename' | 'print' | 'info' | 'publish' | undefined;
|
export type ActionType = 'open' | 'share' | 'delete' | 'info' | 'duplicate' | 'export' | 'rename' | 'print' | 'info' | 'publish' | undefined;
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import { DialogActions, DialogContentText, DialogTitle } from "@material-ui/core";
|
import { Button, DialogContentText, DialogTitle } from "@material-ui/core";
|
||||||
import { FormattedMessage, MessageDescriptor, useIntl } from "react-intl";
|
import { FormattedMessage, MessageDescriptor, useIntl } from "react-intl";
|
||||||
import { ErrorInfo } from "../../../../services/Service";
|
import { ErrorInfo } from "../../../../services/Service";
|
||||||
import { ButtonStyled, StyledDialog, StyledDialogActions, StyledDialogContent, StyledDialogTitle } from "./style";
|
import { StyledDialog, StyledDialogActions, StyledDialogContent, StyledDialogTitle } from "./style";
|
||||||
import GlobalError from "../../../form/global-error";
|
import GlobalError from "../../../form/global-error";
|
||||||
|
|
||||||
export type DialogProps = {
|
export type DialogProps = {
|
||||||
@ -44,14 +44,14 @@ const BaseDialog = (props: DialogProps) => {
|
|||||||
</StyledDialogContent>
|
</StyledDialogContent>
|
||||||
|
|
||||||
<StyledDialogActions>
|
<StyledDialogActions>
|
||||||
|
<Button color="primary" size="medium" onClick={handleOnClose} >
|
||||||
|
{handleOnSubmit ? (<FormattedMessage id="action.cancel-button" defaultMessage="Cancel" />) : (<FormattedMessage id="action.close-button" defaultMessage="Close" />)}
|
||||||
|
</Button>
|
||||||
{handleOnSubmit ? (
|
{handleOnSubmit ? (
|
||||||
<ButtonStyled color="primary" size="medium" variant="outlined" type="submit">
|
<Button color="primary" size="medium" variant="contained" type="submit" disableElevation={true}>
|
||||||
{intl.formatMessage(props.title)}
|
{intl.formatMessage(props.title)}
|
||||||
</ButtonStyled>) : null
|
</Button>) : null
|
||||||
}
|
}
|
||||||
<ButtonStyled color="secondary" size="medium" variant="outlined" autoFocus onClick={handleOnClose}>
|
|
||||||
{handleOnSubmit ? (<FormattedMessage id="action.cancel-button" defaultMessage="Cancel" />) : (<FormattedMessage id="action.close-button" defaultMessage="Close" />)};
|
|
||||||
</ButtonStyled>
|
|
||||||
</StyledDialogActions>
|
</StyledDialogActions>
|
||||||
</form>
|
</form>
|
||||||
</StyledDialog>
|
</StyledDialog>
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { Button, Dialog, DialogActions, DialogContent, DialogTitle, TableCell, withStyles } from "@material-ui/core";
|
import { Dialog, DialogActions, DialogContent, DialogTitle, withStyles } from "@material-ui/core";
|
||||||
|
|
||||||
export const StyledDialogContent = withStyles({
|
export const StyledDialogContent = withStyles({
|
||||||
root: {
|
root: {
|
||||||
@ -18,39 +18,6 @@ export const StyledDialogActions = withStyles({
|
|||||||
}
|
}
|
||||||
})(DialogActions);
|
})(DialogActions);
|
||||||
|
|
||||||
export const ButtonStyled = withStyles({
|
|
||||||
root: {
|
|
||||||
textTransform: 'none',
|
|
||||||
fontSize: '15px',
|
|
||||||
fontWeight: 600,
|
|
||||||
width: '196px',
|
|
||||||
padding: '7px 64px 8px 64px',
|
|
||||||
'&:hover': {
|
|
||||||
border: '0'
|
|
||||||
},
|
|
||||||
borderRadius: '9px'
|
|
||||||
},
|
|
||||||
outlinedPrimary: {
|
|
||||||
border: '0',
|
|
||||||
background: '#ffa800',
|
|
||||||
color: 'white',
|
|
||||||
'&:hover': {
|
|
||||||
border: '0',
|
|
||||||
background: 'rgba(249, 168, 38, 0.91)'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
outlinedSecondary: {
|
|
||||||
background: '#white',
|
|
||||||
color: '#ffa800',
|
|
||||||
border: '1px solid #ffa800',
|
|
||||||
'&:hover': {
|
|
||||||
border: '1px solid rgba(249, 168, 38, 0.91)',
|
|
||||||
background: 'white'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})(Button)
|
|
||||||
|
|
||||||
|
|
||||||
export const StyledDialog = withStyles({
|
export const StyledDialog = withStyles({
|
||||||
root: {
|
root: {
|
||||||
borderRadius: '9px'
|
borderRadius: '9px'
|
||||||
|
@ -1,439 +1,150 @@
|
|||||||
import React, { useEffect } from 'react'
|
import React, { useEffect } from 'react';
|
||||||
import { PageContainer, MapsListArea, HeaderArea, StyledTableCell } from './styled';
|
import clsx from 'clsx';
|
||||||
|
import Drawer from '@material-ui/core/Drawer';
|
||||||
import { createStyles, makeStyles, Theme, ThemeProvider } from '@material-ui/core/styles';
|
import AppBar from '@material-ui/core/AppBar';
|
||||||
import Table from '@material-ui/core/Table';
|
|
||||||
import TableBody from '@material-ui/core/TableBody';
|
|
||||||
import TableCell from '@material-ui/core/TableCell';
|
|
||||||
import TableContainer from '@material-ui/core/TableContainer';
|
|
||||||
import TableHead from '@material-ui/core/TableHead';
|
|
||||||
import TablePagination from '@material-ui/core/TablePagination';
|
|
||||||
import TableRow from '@material-ui/core/TableRow';
|
|
||||||
import TableSortLabel from '@material-ui/core/TableSortLabel';
|
|
||||||
import Toolbar from '@material-ui/core/Toolbar';
|
import Toolbar from '@material-ui/core/Toolbar';
|
||||||
import Typography from '@material-ui/core/Typography';
|
import List from '@material-ui/core/List';
|
||||||
import Paper from '@material-ui/core/Paper';
|
import Divider from '@material-ui/core/Divider';
|
||||||
import Checkbox from '@material-ui/core/Checkbox';
|
|
||||||
import IconButton from '@material-ui/core/IconButton';
|
import IconButton from '@material-ui/core/IconButton';
|
||||||
import Tooltip from '@material-ui/core/Tooltip';
|
import MenuIcon from '@material-ui/icons/Menu';
|
||||||
import DeleteIcon from '@material-ui/icons/Delete';
|
import ChevronLeftIcon from '@material-ui/icons/ChevronLeft';
|
||||||
import FilterListIcon from '@material-ui/icons/FilterList';
|
import ListItem from '@material-ui/core/ListItem';
|
||||||
import StarRateRoundedIcon from '@material-ui/icons/StarRateRounded';
|
import ListItemIcon from '@material-ui/core/ListItemIcon';
|
||||||
import MoreHorizIcon from '@material-ui/icons/MoreHoriz';
|
import { MapsList } from './maps-list';
|
||||||
import { CSSProperties } from 'react';
|
import { ListItemTextStyled, useStyles } from './style';
|
||||||
import { useSelector } from 'react-redux';
|
import { AddTwoTone, BlurCircular, DeleteOutlineTwoTone, LabelTwoTone, PublicTwoTone, ShareTwoTone, StarRateTwoTone } from '@material-ui/icons';
|
||||||
import { activeInstance } from '../../reducers/serviceSlice';
|
import InboxTwoToneIcon from '@material-ui/icons/InboxTwoTone';
|
||||||
import { useQuery } from 'react-query';
|
import { Button, ListItemSecondaryAction } from '@material-ui/core';
|
||||||
import { ErrorInfo, MapInfo, Service } from '../../services/Service';
|
|
||||||
import { theme } from '../../theme/global-style';
|
|
||||||
import { CssBaseline } from '@material-ui/core';
|
|
||||||
import ActionChooser, { ActionType } from './action-chooser';
|
|
||||||
import ActionDispatcher from './action-dispatcher';
|
|
||||||
import NavPanel from './nav-panel';
|
|
||||||
|
|
||||||
|
type FilterType = 'public' | 'all' | 'starred' | 'shared' | 'label' | 'owned'
|
||||||
|
|
||||||
|
interface Filter {
|
||||||
function descendingComparator<T>(a: T, b: T, orderBy: keyof T) {
|
type: FilterType
|
||||||
if (b[orderBy] < a[orderBy]) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
if (b[orderBy] > a[orderBy]) {
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type Order = 'asc' | 'desc';
|
interface LabelFinter extends Filter {
|
||||||
|
label: string
|
||||||
function getComparator<Key extends keyof any>(
|
|
||||||
order: Order,
|
|
||||||
orderBy: Key,
|
|
||||||
): (a: { [key in Key]: number | string | boolean | string[] | undefined }, b: { [key in Key]: number | string | string[] | boolean }) => number {
|
|
||||||
return order === 'desc'
|
|
||||||
? (a, b) => descendingComparator(a, b, orderBy)
|
|
||||||
: (a, b) => -descendingComparator(a, b, orderBy);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function stableSort<T>(array: T[], comparator: (a: T, b: T) => number) {
|
const MapsPage = (props: any) => {
|
||||||
const stabilizedThis = array.map((el, index) => [el, index] as [T, number]);
|
|
||||||
stabilizedThis.sort((a, b) => {
|
|
||||||
const order = comparator(a[0], b[0]);
|
|
||||||
if (order !== 0) return order;
|
|
||||||
return a[1] - b[1];
|
|
||||||
});
|
|
||||||
return stabilizedThis.map((el) => el[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
interface HeadCell {
|
|
||||||
disablePadding: boolean;
|
|
||||||
id: keyof MapInfo;
|
|
||||||
label: string;
|
|
||||||
numeric: boolean;
|
|
||||||
style: CSSProperties;
|
|
||||||
}
|
|
||||||
|
|
||||||
const headCells: HeadCell[] = [
|
|
||||||
{ id: 'starred', numeric: false, disablePadding: false, label: '', style: { width: '20px', padding: '0px' } },
|
|
||||||
{ id: 'name', numeric: false, disablePadding: true, label: 'Name', style: {} },
|
|
||||||
{ id: 'labels', numeric: false, disablePadding: true, label: 'Labels', style: {} },
|
|
||||||
{ id: 'creator', numeric: false, disablePadding: false, label: 'Creator', style: {} },
|
|
||||||
{ id: 'modified', numeric: true, disablePadding: false, label: 'Modified', style: { width: '50px' } }
|
|
||||||
];
|
|
||||||
|
|
||||||
interface EnhancedTableProps {
|
|
||||||
classes: ReturnType<typeof useStyles>;
|
|
||||||
numSelected: number;
|
|
||||||
onRequestSort: (event: React.MouseEvent<unknown>, property: keyof MapInfo) => void;
|
|
||||||
onSelectAllClick: (event: React.ChangeEvent<HTMLInputElement>) => void;
|
|
||||||
order: Order;
|
|
||||||
orderBy: string;
|
|
||||||
rowCount: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
function EnhancedTableHead(props: EnhancedTableProps) {
|
|
||||||
const { classes, onSelectAllClick, order, orderBy, numSelected, rowCount, onRequestSort } = props;
|
|
||||||
|
|
||||||
const createSortHandler = (property: keyof MapInfo) => (event: React.MouseEvent<unknown>) => {
|
|
||||||
onRequestSort(event, property);
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<TableHead>
|
|
||||||
|
|
||||||
<TableRow>
|
|
||||||
<TableCell padding='checkbox' key='select' style={{ width: '20px' }}>
|
|
||||||
<Checkbox
|
|
||||||
indeterminate={numSelected > 0 && numSelected < rowCount}
|
|
||||||
checked={rowCount > 0 && numSelected === rowCount}
|
|
||||||
onChange={onSelectAllClick}
|
|
||||||
size='small'
|
|
||||||
inputProps={{ 'aria-label': 'select all desserts' }}
|
|
||||||
/>
|
|
||||||
</TableCell>
|
|
||||||
|
|
||||||
{headCells.map((headCell) => (
|
|
||||||
<TableCell
|
|
||||||
key={headCell.id}
|
|
||||||
sortDirection={orderBy === headCell.id ? order : false}
|
|
||||||
style={headCell.style}
|
|
||||||
>
|
|
||||||
<TableSortLabel
|
|
||||||
active={orderBy === headCell.id}
|
|
||||||
direction={orderBy === headCell.id ? order : 'asc'}
|
|
||||||
onClick={createSortHandler(headCell.id)}>
|
|
||||||
{headCell.label}
|
|
||||||
{orderBy === headCell.id ? (
|
|
||||||
<span className={classes.visuallyHidden}>
|
|
||||||
{order === 'desc' ? 'sorted descending' : 'sorted ascending'}
|
|
||||||
</span>
|
|
||||||
) : null}
|
|
||||||
</TableSortLabel>
|
|
||||||
</TableCell>
|
|
||||||
))}
|
|
||||||
<TableCell style={{ width: '20px', padding: '0px' }} key='actions'>
|
|
||||||
<TableSortLabel>""</TableSortLabel>
|
|
||||||
</TableCell>
|
|
||||||
</TableRow>
|
|
||||||
</TableHead>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
const useToolbarStyles = makeStyles((theme: Theme) =>
|
|
||||||
createStyles({
|
|
||||||
root: {
|
|
||||||
paddingLeft: theme.spacing(2),
|
|
||||||
paddingRight: theme.spacing(1),
|
|
||||||
},
|
|
||||||
title: {
|
|
||||||
flex: '1 1 100%',
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
|
|
||||||
interface EnhancedTableToolbarProps {
|
|
||||||
numSelected: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
const EnhancedTableToolbar = (props: EnhancedTableToolbarProps) => {
|
|
||||||
const classes = useToolbarStyles();
|
|
||||||
const { numSelected } = props;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Toolbar>
|
|
||||||
{numSelected > 0 ? (
|
|
||||||
<Typography className={classes.title} color="inherit" variant="subtitle1" component="div">
|
|
||||||
{numSelected} selected
|
|
||||||
</Typography>
|
|
||||||
) : (
|
|
||||||
<Typography className={classes.title} variant="h6" id="tableTitle" component="div">
|
|
||||||
Nutrition
|
|
||||||
</Typography>
|
|
||||||
)}
|
|
||||||
{numSelected > 0 ? (
|
|
||||||
<Tooltip title="Delete">
|
|
||||||
<IconButton aria-label="delete">
|
|
||||||
<DeleteIcon />
|
|
||||||
</IconButton>
|
|
||||||
</Tooltip>
|
|
||||||
) : (
|
|
||||||
<Tooltip title="Filter list">
|
|
||||||
<IconButton aria-label="filter list">
|
|
||||||
<FilterListIcon />
|
|
||||||
</IconButton>
|
|
||||||
</Tooltip>
|
|
||||||
)}
|
|
||||||
</Toolbar>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
const useStyles = makeStyles((theme: Theme) =>
|
|
||||||
createStyles({
|
|
||||||
root: {
|
|
||||||
width: '100%',
|
|
||||||
},
|
|
||||||
paper: {
|
|
||||||
width: '100%',
|
|
||||||
marginBottom: theme.spacing(2),
|
|
||||||
},
|
|
||||||
table: {
|
|
||||||
minWidth: 750,
|
|
||||||
border: 0,
|
|
||||||
},
|
|
||||||
visuallyHidden: {
|
|
||||||
border: 0,
|
|
||||||
clip: 'rect(0 0 0 0)',
|
|
||||||
height: 1,
|
|
||||||
margin: -1,
|
|
||||||
overflow: 'hidden',
|
|
||||||
padding: 0,
|
|
||||||
position: 'absolute',
|
|
||||||
top: 20,
|
|
||||||
width: 1,
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
|
|
||||||
type ActionPanelState = {
|
|
||||||
el: HTMLElement | undefined,
|
|
||||||
mapId: number
|
|
||||||
}
|
|
||||||
|
|
||||||
const EnhancedTable = () => {
|
|
||||||
const classes = useStyles();
|
const classes = useStyles();
|
||||||
const [order, setOrder] = React.useState<Order>('asc');
|
const [open, setOpen] = React.useState(true);
|
||||||
const [orderBy, setOrderBy] = React.useState<keyof MapInfo>('modified');
|
|
||||||
const [selected, setSelected] = React.useState<number[]>([]);
|
|
||||||
const [page, setPage] = React.useState(0);
|
|
||||||
const [rowsPerPage, setRowsPerPage] = React.useState(5);
|
|
||||||
const service: Service = useSelector(activeInstance);
|
|
||||||
|
|
||||||
const { isLoading, error, data } = useQuery<unknown, ErrorInfo, MapInfo[]>('maps', async () => {
|
const handleDrawerOpen = () => {
|
||||||
|
setOpen(true);
|
||||||
const result = await service.fetchAllMaps();
|
|
||||||
return result;
|
|
||||||
});
|
|
||||||
const mapsInfo: MapInfo[] = data ? data : [];
|
|
||||||
|
|
||||||
|
|
||||||
const [activeRowAction, setActiveRowAction] = React.useState<ActionPanelState | undefined>(undefined);
|
|
||||||
type ActiveDialog = {
|
|
||||||
actionType: ActionType;
|
|
||||||
mapId: number
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const [activeDialog, setActiveDialog] = React.useState<ActiveDialog | undefined>(undefined);
|
const handleDrawerClose = () => {
|
||||||
const handleRequestSort = (event: React.MouseEvent<unknown>, property: keyof MapInfo) => {
|
setOpen(false);
|
||||||
const isAsc = orderBy === property && order === 'asc';
|
|
||||||
setOrder(isAsc ? 'desc' : 'asc');
|
|
||||||
setOrderBy(property);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleSelectAllClick = (event: React.ChangeEvent<HTMLInputElement>): void => {
|
|
||||||
if (event.target.checked) {
|
|
||||||
const newSelecteds = mapsInfo.map((n) => n.id);
|
|
||||||
setSelected(newSelecteds);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
setSelected([]);
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleRowClick = (event: React.MouseEvent<unknown>, id: number): void => {
|
|
||||||
const selectedIndex = selected.indexOf(id);
|
|
||||||
let newSelected: number[] = [];
|
|
||||||
|
|
||||||
if (selectedIndex === -1) {
|
|
||||||
newSelected = newSelected.concat(selected, id);
|
|
||||||
} else if (selectedIndex === 0) {
|
|
||||||
newSelected = newSelected.concat(selected.slice(1));
|
|
||||||
} else if (selectedIndex === selected.length - 1) {
|
|
||||||
newSelected = newSelected.concat(selected.slice(0, -1));
|
|
||||||
} else if (selectedIndex > 0) {
|
|
||||||
newSelected = newSelected.concat(
|
|
||||||
selected.slice(0, selectedIndex),
|
|
||||||
selected.slice(selectedIndex + 1),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
setSelected(newSelected);
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleChangePage = (event: unknown, newPage: number) => {
|
|
||||||
setPage(newPage);
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleChangeRowsPerPage = (event: React.ChangeEvent<HTMLInputElement>) => {
|
|
||||||
setRowsPerPage(parseInt(event.target.value, 10));
|
|
||||||
setPage(0);
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleActionClick = (mapId: number): ((event: any) => void) => {
|
|
||||||
return (event: any): void => {
|
|
||||||
setActiveRowAction(
|
|
||||||
{
|
|
||||||
mapId: mapId,
|
|
||||||
el: event.currentTarget
|
|
||||||
}
|
|
||||||
);
|
|
||||||
event.stopPropagation();
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleActionMenuClose = (action: ActionType): void => {
|
|
||||||
if (action) {
|
|
||||||
const mapId = activeRowAction?.mapId;
|
|
||||||
|
|
||||||
setActiveRowAction(undefined);
|
|
||||||
setActiveDialog({
|
|
||||||
actionType: action as ActionType,
|
|
||||||
mapId: mapId as number
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const isSelected = (id: number) => selected.indexOf(id) !== -1;
|
|
||||||
|
|
||||||
const emptyRows = rowsPerPage - Math.min(rowsPerPage, mapsInfo.length - page * rowsPerPage);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className={classes.root}>
|
|
||||||
<Paper className={classes.paper}>
|
|
||||||
<EnhancedTableToolbar numSelected={selected.length} />
|
|
||||||
<TableContainer>
|
|
||||||
<Table
|
|
||||||
className={classes.table}
|
|
||||||
aria-labelledby="tableTitle"
|
|
||||||
size={'small'}
|
|
||||||
aria-label="sticky table"
|
|
||||||
stickyHeader
|
|
||||||
>
|
|
||||||
<EnhancedTableHead
|
|
||||||
classes={classes}
|
|
||||||
numSelected={selected.length}
|
|
||||||
order={order}
|
|
||||||
orderBy={orderBy}
|
|
||||||
onSelectAllClick={handleSelectAllClick}
|
|
||||||
onRequestSort={handleRequestSort}
|
|
||||||
rowCount={mapsInfo.length}
|
|
||||||
/>
|
|
||||||
<TableBody>
|
|
||||||
{isLoading ? (<TableRow></TableRow>) : stableSort(mapsInfo, getComparator(order, orderBy))
|
|
||||||
.slice(page * rowsPerPage, page * rowsPerPage + rowsPerPage)
|
|
||||||
.map((row: MapInfo) => {
|
|
||||||
const isItemSelected = isSelected(row.id);
|
|
||||||
const labelId = row.id;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<TableRow
|
|
||||||
hover
|
|
||||||
onClick={(event: any) => handleRowClick(event, row.id)}
|
|
||||||
role="checkbox"
|
|
||||||
aria-checked={isItemSelected}
|
|
||||||
tabIndex={-1}
|
|
||||||
key={row.id}
|
|
||||||
selected={isItemSelected}
|
|
||||||
>
|
|
||||||
|
|
||||||
<StyledTableCell padding="checkbox">
|
|
||||||
<Checkbox
|
|
||||||
checked={isItemSelected}
|
|
||||||
inputProps={{ 'aria-labelledby': String(labelId) }}
|
|
||||||
size="small"
|
|
||||||
/>
|
|
||||||
</StyledTableCell>
|
|
||||||
|
|
||||||
<StyledTableCell>
|
|
||||||
<Tooltip title="Starred">
|
|
||||||
<IconButton aria-label="Starred" size="small" onClick={(e) => { alert("") }}>
|
|
||||||
<StarRateRoundedIcon color="action" style={{ color: row.starred ? 'yellow' : 'gray' }} />
|
|
||||||
</IconButton>
|
|
||||||
</Tooltip>
|
|
||||||
</StyledTableCell>
|
|
||||||
|
|
||||||
<StyledTableCell>{row.name}</StyledTableCell>
|
|
||||||
<StyledTableCell>{row.labels}</StyledTableCell>
|
|
||||||
<StyledTableCell>{row.creator}</StyledTableCell>
|
|
||||||
<StyledTableCell>{row.modified}</StyledTableCell>
|
|
||||||
|
|
||||||
<StyledTableCell>
|
|
||||||
<Tooltip title="Others">
|
|
||||||
<IconButton aria-label="Others" size="small" onClick={handleActionClick(row.id)}>
|
|
||||||
<MoreHorizIcon color="action" />
|
|
||||||
</IconButton>
|
|
||||||
</Tooltip>
|
|
||||||
<ActionChooser anchor={activeRowAction?.el} onClose={handleActionMenuClose} />
|
|
||||||
</StyledTableCell>
|
|
||||||
</TableRow>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
{emptyRows > 0 && (
|
|
||||||
<TableRow style={{ height: 33 * emptyRows }}>
|
|
||||||
<TableCell colSpan={6} />
|
|
||||||
</TableRow>
|
|
||||||
)}
|
|
||||||
</TableBody>
|
|
||||||
</Table>
|
|
||||||
</TableContainer>
|
|
||||||
<TablePagination
|
|
||||||
rowsPerPageOptions={[5, 10, 25]}
|
|
||||||
component="div"
|
|
||||||
count={mapsInfo.length}
|
|
||||||
rowsPerPage={rowsPerPage}
|
|
||||||
page={page}
|
|
||||||
onChangePage={handleChangePage}
|
|
||||||
onChangeRowsPerPage={handleChangeRowsPerPage}
|
|
||||||
/>
|
|
||||||
</Paper>
|
|
||||||
|
|
||||||
{/* Action Dialog */}
|
|
||||||
<ActionDispatcher action={activeDialog?.actionType} onClose={() => setActiveDialog(undefined)} mapId={activeDialog ? activeDialog.mapId : -1} />
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const MapsPage = () => {
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
document.title = 'Maps | WiseMapping';
|
document.title = 'Maps | WiseMapping';
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
return (
|
|
||||||
<ThemeProvider theme={theme}>
|
|
||||||
<CssBaseline />
|
|
||||||
|
|
||||||
<PageContainer>
|
return (
|
||||||
<HeaderArea>
|
<div className={classes.root}>
|
||||||
<h2>Header</h2>
|
<AppBar
|
||||||
</HeaderArea>
|
position="fixed"
|
||||||
<NavPanel/>
|
className={clsx(classes.appBar, {
|
||||||
<MapsListArea>
|
[classes.appBarShift]: open,
|
||||||
<EnhancedTable />
|
})}>
|
||||||
</MapsListArea>
|
<Toolbar>
|
||||||
</PageContainer>
|
<IconButton
|
||||||
</ThemeProvider>
|
color="inherit"
|
||||||
|
aria-label="open drawer"
|
||||||
|
onClick={handleDrawerOpen}
|
||||||
|
edge="start"
|
||||||
|
className={clsx(classes.menuButton, {
|
||||||
|
[classes.hide]: open,
|
||||||
|
})}>
|
||||||
|
<MenuIcon />
|
||||||
|
</IconButton>
|
||||||
|
|
||||||
|
<Button color="primary" size="medium" variant="contained" type="button"
|
||||||
|
disableElevation={true} startIcon={<AddTwoTone />}>
|
||||||
|
New Map
|
||||||
|
</Button>
|
||||||
|
</Toolbar>
|
||||||
|
</AppBar>
|
||||||
|
|
||||||
|
<Drawer
|
||||||
|
variant="permanent"
|
||||||
|
className={clsx(classes.drawer, {
|
||||||
|
[classes.drawerOpen]: open,
|
||||||
|
[classes.drawerClose]: !open,
|
||||||
|
})}
|
||||||
|
classes={{
|
||||||
|
paper: clsx({
|
||||||
|
[classes.drawerOpen]: open,
|
||||||
|
[classes.drawerClose]: !open,
|
||||||
|
}),
|
||||||
|
}}>
|
||||||
|
<div className={classes.toolbar}>
|
||||||
|
<IconButton onClick={handleDrawerClose}>
|
||||||
|
{<ChevronLeftIcon />}
|
||||||
|
</IconButton>
|
||||||
|
</div>
|
||||||
|
<Divider />
|
||||||
|
|
||||||
|
<List component="nav">
|
||||||
|
|
||||||
|
<ListItem button >
|
||||||
|
<ListItemIcon>
|
||||||
|
<InboxTwoToneIcon color="secondary" />
|
||||||
|
</ListItemIcon>
|
||||||
|
<ListItemTextStyled primary="All" />
|
||||||
|
</ListItem>
|
||||||
|
|
||||||
|
<ListItem button >
|
||||||
|
<ListItemIcon>
|
||||||
|
<BlurCircular color="secondary" />
|
||||||
|
</ListItemIcon>
|
||||||
|
<ListItemTextStyled primary="Owned" />
|
||||||
|
</ListItem>
|
||||||
|
|
||||||
|
<ListItem button >
|
||||||
|
<ListItemIcon>
|
||||||
|
<StarRateTwoTone color="secondary" />
|
||||||
|
</ListItemIcon>
|
||||||
|
<ListItemTextStyled primary="Starred" />
|
||||||
|
</ListItem>
|
||||||
|
|
||||||
|
<ListItem button >
|
||||||
|
<ListItemIcon>
|
||||||
|
<ShareTwoTone color="secondary" />
|
||||||
|
</ListItemIcon>
|
||||||
|
<ListItemTextStyled primary="Shared With Me" />
|
||||||
|
</ListItem>
|
||||||
|
|
||||||
|
<ListItem button >
|
||||||
|
<ListItemIcon>
|
||||||
|
<PublicTwoTone color="secondary" />
|
||||||
|
</ListItemIcon>
|
||||||
|
<ListItemTextStyled primary="Public" />
|
||||||
|
</ListItem>
|
||||||
|
|
||||||
|
<ListItem button >
|
||||||
|
<ListItemIcon>
|
||||||
|
<LabelTwoTone color="secondary" />
|
||||||
|
</ListItemIcon>
|
||||||
|
<ListItemTextStyled primary="Some label>" />
|
||||||
|
<ListItemSecondaryAction>
|
||||||
|
<IconButton edge="end" aria-label="delete">
|
||||||
|
<DeleteOutlineTwoTone color="secondary" />
|
||||||
|
</IconButton>
|
||||||
|
</ListItemSecondaryAction>
|
||||||
|
</ListItem>
|
||||||
|
|
||||||
|
</List>
|
||||||
|
</Drawer>
|
||||||
|
<main className={classes.content}>
|
||||||
|
<div className={classes.toolbar} />
|
||||||
|
<MapsList />
|
||||||
|
</main>
|
||||||
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default MapsPage;
|
export default MapsPage;
|
||||||
|
|
||||||
|
|
||||||
|
408
packages/webapp/src/components/maps-page/maps-list/index.tsx
Normal file
408
packages/webapp/src/components/maps-page/maps-list/index.tsx
Normal file
@ -0,0 +1,408 @@
|
|||||||
|
import React, { useEffect } from 'react'
|
||||||
|
import { StyledTableCell } from './styled';
|
||||||
|
|
||||||
|
import { createStyles, makeStyles, Theme, ThemeProvider } from '@material-ui/core/styles';
|
||||||
|
import Table from '@material-ui/core/Table';
|
||||||
|
import TableBody from '@material-ui/core/TableBody';
|
||||||
|
import TableCell from '@material-ui/core/TableCell';
|
||||||
|
import TableContainer from '@material-ui/core/TableContainer';
|
||||||
|
import TableHead from '@material-ui/core/TableHead';
|
||||||
|
import TablePagination from '@material-ui/core/TablePagination';
|
||||||
|
import TableRow from '@material-ui/core/TableRow';
|
||||||
|
import TableSortLabel from '@material-ui/core/TableSortLabel';
|
||||||
|
import Toolbar from '@material-ui/core/Toolbar';
|
||||||
|
import Typography from '@material-ui/core/Typography';
|
||||||
|
import Paper from '@material-ui/core/Paper';
|
||||||
|
import Checkbox from '@material-ui/core/Checkbox';
|
||||||
|
import IconButton from '@material-ui/core/IconButton';
|
||||||
|
import Tooltip from '@material-ui/core/Tooltip';
|
||||||
|
import DeleteIcon from '@material-ui/icons/Delete';
|
||||||
|
import FilterListIcon from '@material-ui/icons/FilterList';
|
||||||
|
import StarRateRoundedIcon from '@material-ui/icons/StarRateRounded';
|
||||||
|
import MoreHorizIcon from '@material-ui/icons/MoreHoriz';
|
||||||
|
import { CSSProperties } from 'react';
|
||||||
|
import { useSelector } from 'react-redux';
|
||||||
|
import { activeInstance } from '../../../reducers/serviceSlice';
|
||||||
|
import { useQuery } from 'react-query';
|
||||||
|
import { ErrorInfo, MapInfo, Service } from '../../../services/Service';
|
||||||
|
import ActionChooser, { ActionType } from '../action-chooser';
|
||||||
|
import ActionDispatcher from '../action-dispatcher';
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
function descendingComparator<T>(a: T, b: T, orderBy: keyof T) {
|
||||||
|
if (b[orderBy] < a[orderBy]) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (b[orderBy] > a[orderBy]) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
type Order = 'asc' | 'desc';
|
||||||
|
|
||||||
|
function getComparator<Key extends keyof any>(
|
||||||
|
order: Order,
|
||||||
|
orderBy: Key,
|
||||||
|
): (a: { [key in Key]: number | string | boolean | string[] | undefined }, b: { [key in Key]: number | string | string[] | boolean }) => number {
|
||||||
|
return order === 'desc'
|
||||||
|
? (a, b) => descendingComparator(a, b, orderBy)
|
||||||
|
: (a, b) => -descendingComparator(a, b, orderBy);
|
||||||
|
}
|
||||||
|
|
||||||
|
function stableSort<T>(array: T[], comparator: (a: T, b: T) => number) {
|
||||||
|
const stabilizedThis = array.map((el, index) => [el, index] as [T, number]);
|
||||||
|
stabilizedThis.sort((a, b) => {
|
||||||
|
const order = comparator(a[0], b[0]);
|
||||||
|
if (order !== 0) return order;
|
||||||
|
return a[1] - b[1];
|
||||||
|
});
|
||||||
|
return stabilizedThis.map((el) => el[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
interface HeadCell {
|
||||||
|
disablePadding: boolean;
|
||||||
|
id: keyof MapInfo;
|
||||||
|
label: string;
|
||||||
|
numeric: boolean;
|
||||||
|
style: CSSProperties;
|
||||||
|
}
|
||||||
|
|
||||||
|
const headCells: HeadCell[] = [
|
||||||
|
{ id: 'starred', numeric: false, disablePadding: false, label: '', style: { width: '20px', padding: '0px' } },
|
||||||
|
{ id: 'name', numeric: false, disablePadding: true, label: 'Name', style: {} },
|
||||||
|
{ id: 'labels', numeric: false, disablePadding: true, label: 'Labels', style: {} },
|
||||||
|
{ id: 'creator', numeric: false, disablePadding: false, label: 'Creator', style: {} },
|
||||||
|
{ id: 'modified', numeric: true, disablePadding: false, label: 'Modified', style: { width: '50px' } }
|
||||||
|
];
|
||||||
|
|
||||||
|
interface EnhancedTableProps {
|
||||||
|
classes: ReturnType<typeof useStyles>;
|
||||||
|
numSelected: number;
|
||||||
|
onRequestSort: (event: React.MouseEvent<unknown>, property: keyof MapInfo) => void;
|
||||||
|
onSelectAllClick: (event: React.ChangeEvent<HTMLInputElement>) => void;
|
||||||
|
order: Order;
|
||||||
|
orderBy: string;
|
||||||
|
rowCount: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
function EnhancedTableHead(props: EnhancedTableProps) {
|
||||||
|
const { classes, onSelectAllClick, order, orderBy, numSelected, rowCount, onRequestSort } = props;
|
||||||
|
|
||||||
|
const createSortHandler = (property: keyof MapInfo) => (event: React.MouseEvent<unknown>) => {
|
||||||
|
onRequestSort(event, property);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<TableHead>
|
||||||
|
|
||||||
|
<TableRow>
|
||||||
|
<TableCell padding='checkbox' key='select' style={{ width: '20px' }}>
|
||||||
|
<Checkbox
|
||||||
|
indeterminate={numSelected > 0 && numSelected < rowCount}
|
||||||
|
checked={rowCount > 0 && numSelected === rowCount}
|
||||||
|
onChange={onSelectAllClick}
|
||||||
|
size='small'
|
||||||
|
inputProps={{ 'aria-label': 'select all desserts' }}
|
||||||
|
/>
|
||||||
|
</TableCell>
|
||||||
|
|
||||||
|
{headCells.map((headCell) => (
|
||||||
|
<TableCell
|
||||||
|
key={headCell.id}
|
||||||
|
sortDirection={orderBy === headCell.id ? order : false}
|
||||||
|
style={headCell.style}
|
||||||
|
>
|
||||||
|
<TableSortLabel
|
||||||
|
active={orderBy === headCell.id}
|
||||||
|
direction={orderBy === headCell.id ? order : 'asc'}
|
||||||
|
onClick={createSortHandler(headCell.id)}>
|
||||||
|
{headCell.label}
|
||||||
|
{orderBy === headCell.id ? (
|
||||||
|
<span className={classes.visuallyHidden}>
|
||||||
|
{order === 'desc' ? 'sorted descending' : 'sorted ascending'}
|
||||||
|
</span>
|
||||||
|
) : null}
|
||||||
|
</TableSortLabel>
|
||||||
|
</TableCell>
|
||||||
|
))}
|
||||||
|
<TableCell style={{ width: '20px', padding: '0px' }} key='actions'>
|
||||||
|
<TableSortLabel>""</TableSortLabel>
|
||||||
|
</TableCell>
|
||||||
|
</TableRow>
|
||||||
|
</TableHead>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const useToolbarStyles = makeStyles((theme: Theme) =>
|
||||||
|
createStyles({
|
||||||
|
root: {
|
||||||
|
paddingLeft: theme.spacing(2),
|
||||||
|
paddingRight: theme.spacing(1),
|
||||||
|
},
|
||||||
|
title: {
|
||||||
|
flex: '1 1 100%',
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
|
interface EnhancedTableToolbarProps {
|
||||||
|
numSelected: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
const EnhancedTableToolbar = (props: EnhancedTableToolbarProps) => {
|
||||||
|
const classes = useToolbarStyles();
|
||||||
|
const { numSelected } = props;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Toolbar>
|
||||||
|
{numSelected > 0 ? (
|
||||||
|
<Typography className={classes.title} color="inherit" variant="subtitle1" component="div">
|
||||||
|
{numSelected} selected
|
||||||
|
</Typography>
|
||||||
|
) : (
|
||||||
|
<Typography className={classes.title} variant="h6" id="tableTitle" component="div">
|
||||||
|
Nutrition
|
||||||
|
</Typography>
|
||||||
|
)}
|
||||||
|
{numSelected > 0 ? (
|
||||||
|
<Tooltip title="Delete">
|
||||||
|
<IconButton aria-label="delete">
|
||||||
|
<DeleteIcon />
|
||||||
|
</IconButton>
|
||||||
|
</Tooltip>
|
||||||
|
) : (
|
||||||
|
<Tooltip title="Filter list">
|
||||||
|
<IconButton aria-label="filter list">
|
||||||
|
<FilterListIcon />
|
||||||
|
</IconButton>
|
||||||
|
</Tooltip>
|
||||||
|
)}
|
||||||
|
</Toolbar>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const useStyles = makeStyles((theme: Theme) =>
|
||||||
|
createStyles({
|
||||||
|
root: {
|
||||||
|
width: '100%',
|
||||||
|
},
|
||||||
|
paper: {
|
||||||
|
width: '100%',
|
||||||
|
marginBottom: theme.spacing(2),
|
||||||
|
},
|
||||||
|
table: {
|
||||||
|
minWidth: 750,
|
||||||
|
border: 0,
|
||||||
|
},
|
||||||
|
visuallyHidden: {
|
||||||
|
border: 0,
|
||||||
|
clip: 'rect(0 0 0 0)',
|
||||||
|
height: 1,
|
||||||
|
margin: -1,
|
||||||
|
overflow: 'hidden',
|
||||||
|
padding: 0,
|
||||||
|
position: 'absolute',
|
||||||
|
top: 20,
|
||||||
|
width: 1,
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
|
type ActionPanelState = {
|
||||||
|
el: HTMLElement | undefined,
|
||||||
|
mapId: number
|
||||||
|
}
|
||||||
|
|
||||||
|
export const MapsList = () => {
|
||||||
|
const classes = useStyles();
|
||||||
|
const [order, setOrder] = React.useState<Order>('asc');
|
||||||
|
const [orderBy, setOrderBy] = React.useState<keyof MapInfo>('modified');
|
||||||
|
const [selected, setSelected] = React.useState<number[]>([]);
|
||||||
|
const [page, setPage] = React.useState(0);
|
||||||
|
const [rowsPerPage, setRowsPerPage] = React.useState(5);
|
||||||
|
const service: Service = useSelector(activeInstance);
|
||||||
|
|
||||||
|
const { isLoading, error, data } = useQuery<unknown, ErrorInfo, MapInfo[]>('maps', async () => {
|
||||||
|
|
||||||
|
const result = await service.fetchAllMaps();
|
||||||
|
return result;
|
||||||
|
});
|
||||||
|
const mapsInfo: MapInfo[] = data ? data : [];
|
||||||
|
|
||||||
|
|
||||||
|
const [activeRowAction, setActiveRowAction] = React.useState<ActionPanelState | undefined>(undefined);
|
||||||
|
type ActiveDialog = {
|
||||||
|
actionType: ActionType;
|
||||||
|
mapId: number
|
||||||
|
};
|
||||||
|
|
||||||
|
const [activeDialog, setActiveDialog] = React.useState<ActiveDialog | undefined>(undefined);
|
||||||
|
const handleRequestSort = (event: React.MouseEvent<unknown>, property: keyof MapInfo) => {
|
||||||
|
const isAsc = orderBy === property && order === 'asc';
|
||||||
|
setOrder(isAsc ? 'desc' : 'asc');
|
||||||
|
setOrderBy(property);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleSelectAllClick = (event: React.ChangeEvent<HTMLInputElement>): void => {
|
||||||
|
if (event.target.checked) {
|
||||||
|
const newSelecteds = mapsInfo.map((n) => n.id);
|
||||||
|
setSelected(newSelecteds);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
setSelected([]);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleRowClick = (event: React.MouseEvent<unknown>, id: number): void => {
|
||||||
|
const selectedIndex = selected.indexOf(id);
|
||||||
|
let newSelected: number[] = [];
|
||||||
|
|
||||||
|
if (selectedIndex === -1) {
|
||||||
|
newSelected = newSelected.concat(selected, id);
|
||||||
|
} else if (selectedIndex === 0) {
|
||||||
|
newSelected = newSelected.concat(selected.slice(1));
|
||||||
|
} else if (selectedIndex === selected.length - 1) {
|
||||||
|
newSelected = newSelected.concat(selected.slice(0, -1));
|
||||||
|
} else if (selectedIndex > 0) {
|
||||||
|
newSelected = newSelected.concat(
|
||||||
|
selected.slice(0, selectedIndex),
|
||||||
|
selected.slice(selectedIndex + 1),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
setSelected(newSelected);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleChangePage = (event: unknown, newPage: number) => {
|
||||||
|
setPage(newPage);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleChangeRowsPerPage = (event: React.ChangeEvent<HTMLInputElement>) => {
|
||||||
|
setRowsPerPage(parseInt(event.target.value, 10));
|
||||||
|
setPage(0);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleActionClick = (mapId: number): ((event: any) => void) => {
|
||||||
|
return (event: any): void => {
|
||||||
|
setActiveRowAction(
|
||||||
|
{
|
||||||
|
mapId: mapId,
|
||||||
|
el: event.currentTarget
|
||||||
|
}
|
||||||
|
);
|
||||||
|
event.stopPropagation();
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleActionMenuClose = (action: ActionType): void => {
|
||||||
|
if (action) {
|
||||||
|
const mapId = activeRowAction?.mapId;
|
||||||
|
|
||||||
|
setActiveRowAction(undefined);
|
||||||
|
setActiveDialog({
|
||||||
|
actionType: action as ActionType,
|
||||||
|
mapId: mapId as number
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const isSelected = (id: number) => selected.indexOf(id) !== -1;
|
||||||
|
|
||||||
|
const emptyRows = rowsPerPage - Math.min(rowsPerPage, mapsInfo.length - page * rowsPerPage);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={classes.root}>
|
||||||
|
<Paper className={classes.paper}>
|
||||||
|
<EnhancedTableToolbar numSelected={selected.length} />
|
||||||
|
<TableContainer>
|
||||||
|
<Table
|
||||||
|
className={classes.table}
|
||||||
|
aria-labelledby="tableTitle"
|
||||||
|
size={'small'}
|
||||||
|
aria-label="sticky table"
|
||||||
|
stickyHeader
|
||||||
|
>
|
||||||
|
<EnhancedTableHead
|
||||||
|
classes={classes}
|
||||||
|
numSelected={selected.length}
|
||||||
|
order={order}
|
||||||
|
orderBy={orderBy}
|
||||||
|
onSelectAllClick={handleSelectAllClick}
|
||||||
|
onRequestSort={handleRequestSort}
|
||||||
|
rowCount={mapsInfo.length}
|
||||||
|
/>
|
||||||
|
<TableBody>
|
||||||
|
{isLoading ? (<TableRow></TableRow>) : stableSort(mapsInfo, getComparator(order, orderBy))
|
||||||
|
.slice(page * rowsPerPage, page * rowsPerPage + rowsPerPage)
|
||||||
|
.map((row: MapInfo) => {
|
||||||
|
const isItemSelected = isSelected(row.id);
|
||||||
|
const labelId = row.id;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<TableRow
|
||||||
|
hover
|
||||||
|
onClick={(event: any) => handleRowClick(event, row.id)}
|
||||||
|
role="checkbox"
|
||||||
|
aria-checked={isItemSelected}
|
||||||
|
tabIndex={-1}
|
||||||
|
key={row.id}
|
||||||
|
selected={isItemSelected}
|
||||||
|
>
|
||||||
|
|
||||||
|
<StyledTableCell padding="checkbox">
|
||||||
|
<Checkbox
|
||||||
|
checked={isItemSelected}
|
||||||
|
inputProps={{ 'aria-labelledby': String(labelId) }}
|
||||||
|
size="small"
|
||||||
|
/>
|
||||||
|
</StyledTableCell>
|
||||||
|
|
||||||
|
<StyledTableCell>
|
||||||
|
<Tooltip title="Starred">
|
||||||
|
<IconButton aria-label="Starred" size="small" onClick={(e) => { alert("") }}>
|
||||||
|
<StarRateRoundedIcon color="action" style={{ color: row.starred ? 'yellow' : 'gray' }} />
|
||||||
|
</IconButton>
|
||||||
|
</Tooltip>
|
||||||
|
</StyledTableCell>
|
||||||
|
|
||||||
|
<StyledTableCell>{row.name}</StyledTableCell>
|
||||||
|
<StyledTableCell>{row.labels}</StyledTableCell>
|
||||||
|
<StyledTableCell>{row.creator}</StyledTableCell>
|
||||||
|
<StyledTableCell>{row.modified}</StyledTableCell>
|
||||||
|
|
||||||
|
<StyledTableCell>
|
||||||
|
<Tooltip title="Others">
|
||||||
|
<IconButton aria-label="Others" size="small" onClick={handleActionClick(row.id)}>
|
||||||
|
<MoreHorizIcon color="action" />
|
||||||
|
</IconButton>
|
||||||
|
</Tooltip>
|
||||||
|
<ActionChooser anchor={activeRowAction?.el} onClose={handleActionMenuClose} />
|
||||||
|
</StyledTableCell>
|
||||||
|
</TableRow>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
{emptyRows > 0 && (
|
||||||
|
<TableRow style={{ height: 33 * emptyRows }}>
|
||||||
|
<TableCell colSpan={6} />
|
||||||
|
</TableRow>
|
||||||
|
)}
|
||||||
|
</TableBody>
|
||||||
|
</Table>
|
||||||
|
</TableContainer>
|
||||||
|
<TablePagination
|
||||||
|
rowsPerPageOptions={[5, 10, 25]}
|
||||||
|
component="div"
|
||||||
|
count={mapsInfo.length}
|
||||||
|
rowsPerPage={rowsPerPage}
|
||||||
|
page={page}
|
||||||
|
onChangePage={handleChangePage}
|
||||||
|
onChangeRowsPerPage={handleChangeRowsPerPage}
|
||||||
|
/>
|
||||||
|
</Paper>
|
||||||
|
|
||||||
|
{/* Action Dialog */}
|
||||||
|
<ActionDispatcher action={activeDialog?.actionType} onClose={() => setActiveDialog(undefined)} mapId={activeDialog ? activeDialog.mapId : -1} />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
18
packages/webapp/src/components/maps-page/maps-list/styled.ts
Normal file
18
packages/webapp/src/components/maps-page/maps-list/styled.ts
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
import { MenuItem, TableCell } from '@material-ui/core';
|
||||||
|
import { withStyles } from '@material-ui/core/styles';
|
||||||
|
|
||||||
|
export const StyledTableCell = withStyles({
|
||||||
|
root: {
|
||||||
|
color: 'black',
|
||||||
|
padding: '0px',
|
||||||
|
cursor: 'pointer'
|
||||||
|
}
|
||||||
|
})(TableCell);
|
||||||
|
|
||||||
|
export const StyledMenuItem = withStyles({
|
||||||
|
root: {
|
||||||
|
width: '300px',
|
||||||
|
padding: '10px 20px',
|
||||||
|
marging: '0px 20px'
|
||||||
|
}
|
||||||
|
})(MenuItem)
|
@ -1,8 +0,0 @@
|
|||||||
import React from "react";
|
|
||||||
|
|
||||||
const NavPanel = (props: any) => {
|
|
||||||
|
|
||||||
return (<p>nav</p>);
|
|
||||||
|
|
||||||
}
|
|
||||||
export default NavPanel;
|
|
@ -1,7 +0,0 @@
|
|||||||
import styled from "styled-components";
|
|
||||||
|
|
||||||
|
|
||||||
export const NavArea = styled.div`
|
|
||||||
grid-area: nav;
|
|
||||||
background-color: red;
|
|
||||||
`
|
|
80
packages/webapp/src/components/maps-page/style.ts
Normal file
80
packages/webapp/src/components/maps-page/style.ts
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
import { createStyles, ListItemText, Theme, withStyles } from "@material-ui/core";
|
||||||
|
import { makeStyles } from "@material-ui/core";
|
||||||
|
|
||||||
|
const drawerWidth = 300;
|
||||||
|
|
||||||
|
export const useStyles = makeStyles((theme: Theme) =>
|
||||||
|
createStyles({
|
||||||
|
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,
|
||||||
|
}),
|
||||||
|
background: '#ffffff',
|
||||||
|
|
||||||
|
},
|
||||||
|
appBarShift: {
|
||||||
|
marginLeft: drawerWidth,
|
||||||
|
width: `calc(100% - ${drawerWidth}px)`,
|
||||||
|
transition: theme.transitions.create(['width', 'margin'], {
|
||||||
|
easing: theme.transitions.easing.sharp,
|
||||||
|
duration: theme.transitions.duration.enteringScreen,
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
menuButton: {
|
||||||
|
marginRight: 36,
|
||||||
|
},
|
||||||
|
hide: {
|
||||||
|
display: 'none',
|
||||||
|
},
|
||||||
|
drawer: {
|
||||||
|
width: drawerWidth,
|
||||||
|
flexShrink: 0,
|
||||||
|
whiteSpace: 'nowrap',
|
||||||
|
},
|
||||||
|
drawerOpen: {
|
||||||
|
background: '#ffa800',
|
||||||
|
width: drawerWidth,
|
||||||
|
transition: theme.transitions.create('width', {
|
||||||
|
easing: theme.transitions.easing.sharp,
|
||||||
|
duration: theme.transitions.duration.enteringScreen,
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
drawerClose: {
|
||||||
|
transition: theme.transitions.create('width', {
|
||||||
|
easing: theme.transitions.easing.sharp,
|
||||||
|
duration: theme.transitions.duration.leavingScreen,
|
||||||
|
}),
|
||||||
|
overflowX: 'hidden',
|
||||||
|
width: theme.spacing(7) + 1,
|
||||||
|
[theme.breakpoints.up('sm')]: {
|
||||||
|
width: theme.spacing(9) + 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
toolbar: {
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'flex-end',
|
||||||
|
padding: theme.spacing(0, 1),
|
||||||
|
// necessary for content to be below app bar
|
||||||
|
...theme.mixins.toolbar,
|
||||||
|
},
|
||||||
|
content: {
|
||||||
|
flexGrow: 1,
|
||||||
|
padding: theme.spacing(3),
|
||||||
|
},
|
||||||
|
listItemText: {
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
|
export const ListItemTextStyled = withStyles({
|
||||||
|
root:
|
||||||
|
{
|
||||||
|
color: 'white',
|
||||||
|
}
|
||||||
|
})(ListItemText);
|
@ -1,40 +0,0 @@
|
|||||||
import { Button, Dialog, MenuItem, TableCell } from '@material-ui/core';
|
|
||||||
import { withStyles } from '@material-ui/core/styles';
|
|
||||||
import styled from 'styled-components';
|
|
||||||
|
|
||||||
export const PageContainer = styled.div`
|
|
||||||
display: grid;
|
|
||||||
height: 100vh;
|
|
||||||
width: 100vw;
|
|
||||||
grid-template-areas: "nav header header"
|
|
||||||
"nav main ads"
|
|
||||||
"nav main ads";
|
|
||||||
grid-template-columns: 240px 1fr 240px;
|
|
||||||
grid-template-rows: 60px 1fr 30px;
|
|
||||||
`
|
|
||||||
|
|
||||||
export const MapsListArea = styled.div`
|
|
||||||
grid-area: main;
|
|
||||||
background-color: #ffff64;
|
|
||||||
`
|
|
||||||
|
|
||||||
export const HeaderArea = styled.div`
|
|
||||||
grid-area: header;
|
|
||||||
background-color: blue;
|
|
||||||
`
|
|
||||||
|
|
||||||
export const StyledTableCell = withStyles({
|
|
||||||
root: {
|
|
||||||
color: 'black',
|
|
||||||
padding: '0px',
|
|
||||||
cursor: 'pointer'
|
|
||||||
}
|
|
||||||
})(TableCell);
|
|
||||||
|
|
||||||
export const StyledMenuItem = withStyles({
|
|
||||||
root: {
|
|
||||||
width: '300px',
|
|
||||||
padding: '10px 20px',
|
|
||||||
marging: '0px 20px'
|
|
||||||
}
|
|
||||||
})(MenuItem)
|
|
@ -7,14 +7,14 @@ import { ErrorInfo, Service } from '../../services/Service';
|
|||||||
import Header from '../layout/header';
|
import Header from '../layout/header';
|
||||||
import Footer from '../layout/footer';
|
import Footer from '../layout/footer';
|
||||||
|
|
||||||
import { StyledReCAPTCHA } from './styled';
|
import { PageContent } from '../../theme';
|
||||||
import { PageContent, theme } from '../../theme/global-style';
|
import { FormControl, Typography } from '@material-ui/core';
|
||||||
import { CssBaseline, FormControl, ThemeProvider } from '@material-ui/core';
|
|
||||||
import { useSelector } from 'react-redux';
|
import { useSelector } from 'react-redux';
|
||||||
import { useMutation } from 'react-query';
|
import { useMutation } from 'react-query';
|
||||||
import { activeInstance } from '../../reducers/serviceSlice';
|
import { activeInstance } from '../../reducers/serviceSlice';
|
||||||
import Input from '../form/input';
|
import Input from '../form/input';
|
||||||
import GlobalError from '../form/global-error';
|
import GlobalError from '../form/global-error';
|
||||||
|
import SubmitButton from '../form/submit-button';
|
||||||
|
|
||||||
export type Model = {
|
export type Model = {
|
||||||
email: string;
|
email: string;
|
||||||
@ -58,8 +58,13 @@ const RegistrationForm = () => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<PageContent>
|
<PageContent>
|
||||||
<h1><FormattedMessage id="registration.title" defaultMessage="Become a member" /></h1>
|
<Typography variant="h4" component="h1">
|
||||||
<p><FormattedMessage id="registration.desc" defaultMessage="Signing up is free and just take a moment " /></p>
|
<FormattedMessage id="registration.title" defaultMessage="Become a member" />
|
||||||
|
</Typography>
|
||||||
|
|
||||||
|
<Typography paragraph>
|
||||||
|
<FormattedMessage id="registration.desc" defaultMessage="Signing up is free and just take a moment " />
|
||||||
|
</Typography>
|
||||||
|
|
||||||
<FormControl>
|
<FormControl>
|
||||||
|
|
||||||
@ -78,17 +83,17 @@ const RegistrationForm = () => {
|
|||||||
<Input name="password" type="password" onChange={handleOnChange} label={{ id: "registration.password", defaultMessage: "Password" }}
|
<Input name="password" type="password" onChange={handleOnChange} label={{ id: "registration.password", defaultMessage: "Password" }}
|
||||||
autoComplete="new-password" />
|
autoComplete="new-password" />
|
||||||
|
|
||||||
<StyledReCAPTCHA>
|
<div style={{ width: '330px', padding: '5px 10px' }}>
|
||||||
<ReCAPTCHA
|
<ReCAPTCHA
|
||||||
sitekey="6LeIxAcTAAAAAJcZVRqyHh71UMIEGNQ_MXjiZKhI"
|
sitekey="6LeIxAcTAAAAAJcZVRqyHh71UMIEGNQ_MXjiZKhI"
|
||||||
onChange={(value: string) => { model.recaptcha = value; setModel(model) }} />
|
onChange={(value: string) => { model.recaptcha = value; setModel(model) }} />
|
||||||
</StyledReCAPTCHA>
|
</div>
|
||||||
|
|
||||||
<div style={{ fontSize: "12px", padding: "5px 0px" }}>
|
<div style={{ fontSize: "12px", padding: "5px 0px" }}>
|
||||||
<FormattedMessage id="registration.termandconditions" defaultMessage="Terms of Service: Please check the WiseMapping Account information you've entered above, and review the Terms of Service here. By clicking on 'Register' below you are agreeing to the Terms of Service above and the Privacy Policy" />
|
<FormattedMessage id="registration.termandconditions" defaultMessage="Terms of Service: Please check the WiseMapping Account information you've entered above, and review the Terms of Service here. By clicking on 'Register' below you are agreeing to the Terms of Service above and the Privacy Policy" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<input type="submit" value={intl.formatMessage({ id: "registration.register", defaultMessage: "Register" })} />
|
<SubmitButton value={intl.formatMessage({ id: "registration.register", defaultMessage: "Register" })} />
|
||||||
</form>
|
</form>
|
||||||
</FormControl>
|
</FormControl>
|
||||||
|
|
||||||
|
@ -1,23 +0,0 @@
|
|||||||
import styled from 'styled-components';
|
|
||||||
|
|
||||||
export const StyledReCAPTCHA = styled.div`
|
|
||||||
font-size: 13px;
|
|
||||||
width: 300px;
|
|
||||||
margin: auto;
|
|
||||||
}`;
|
|
||||||
|
|
||||||
export const StyledNav = styled.div`
|
|
||||||
.db-warn-msg {
|
|
||||||
margin-top: 30px;
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.db-warn-msg p {
|
|
||||||
margin: 0 auto;
|
|
||||||
width: 500px;
|
|
||||||
background-color: #e97450;
|
|
||||||
font-size: 15px;
|
|
||||||
color: white;
|
|
||||||
padding: 15px 30px;
|
|
||||||
border-radius: 10px;
|
|
||||||
}`;
|
|
@ -1,11 +1,10 @@
|
|||||||
import React, { useEffect } from 'react'
|
import React, { useEffect } from 'react'
|
||||||
import { FormattedMessage } from 'react-intl'
|
import { FormattedMessage } from 'react-intl'
|
||||||
|
import { PageContent } from '../../theme';
|
||||||
import {PageContent} from '../../theme/global-style';
|
|
||||||
|
|
||||||
import Header, { SignInButton } from '../layout/header'
|
import Header, { SignInButton } from '../layout/header'
|
||||||
import Footer from '../layout/footer'
|
import Footer from '../layout/footer'
|
||||||
|
import { Button, Typography } from '@material-ui/core';
|
||||||
|
import { Link as RouterLink } from 'react-router-dom'
|
||||||
|
|
||||||
|
|
||||||
const RegistrationSuccessPage = () => {
|
const RegistrationSuccessPage = () => {
|
||||||
@ -17,13 +16,19 @@ const RegistrationSuccessPage = () => {
|
|||||||
<div>
|
<div>
|
||||||
<Header type='none' />
|
<Header type='none' />
|
||||||
<PageContent>
|
<PageContent>
|
||||||
<h1>
|
<Typography variant="h4" component="h1">
|
||||||
<FormattedMessage id="resetpassword.success.title" defaultMessage="Your account has been created successfully" />
|
<FormattedMessage id="resetpassword.success.title" defaultMessage="Your account has been created successfully" />
|
||||||
</h1>
|
</Typography>
|
||||||
<p>
|
|
||||||
|
<Typography paragraph>
|
||||||
<FormattedMessage id="registration.success.desc" defaultMessage="Click 'Sign In' button below and start creating mind maps." />
|
<FormattedMessage id="registration.success.desc" defaultMessage="Click 'Sign In' button below and start creating mind maps." />
|
||||||
</p>
|
</Typography>
|
||||||
<SignInButton style='style1' />
|
|
||||||
|
|
||||||
|
<Button color="primary" size="medium" variant="contained" component={RouterLink} to="/c/login" disableElevation={true}>
|
||||||
|
<FormattedMessage id="login.signin" defaultMessage="Sign In" />
|
||||||
|
</Button>
|
||||||
|
|
||||||
</PageContent>
|
</PageContent>
|
||||||
<Footer />
|
<Footer />
|
||||||
</div>
|
</div>
|
||||||
|
14
packages/webapp/src/images/logo-icon.svg
Normal file
14
packages/webapp/src/images/logo-icon.svg
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="38" height="27" fill="none" viewBox="0 0 38 27">
|
||||||
|
<path fill="#FFCB00" stroke="#000" stroke-linejoin="round" stroke-width="1.5" d="M19 26c-1.5-4-3.5-3.5-9-7h17.5c-4.786 3.127-7.5 3-8.5 7z"/>
|
||||||
|
<path fill="#FFCB00" stroke="#000" stroke-width="1.5" d="M32.34 11.956c0 2.447-1.45 4.745-3.97 6.465-2.514 1.718-6.03 2.804-9.95 2.804-3.92 0-7.436-1.086-9.951-2.804-2.519-1.72-3.97-4.018-3.97-6.465 0-2.446 1.451-4.745 3.97-6.465 2.515-1.717 6.03-2.804 9.95-2.804 3.921 0 7.437 1.087 9.952 2.804 2.518 1.72 3.97 4.019 3.97 6.465z"/>
|
||||||
|
<mask id="i08j30ef6a" fill="#fff">
|
||||||
|
<path d="M17 8c0 2.122-.895 4.157-2.49 5.657C12.916 15.157 10.754 16 8.5 16s-4.416-.843-6.01-2.343C.896 12.157 0 10.122 0 8h17z"/>
|
||||||
|
</mask>
|
||||||
|
<path fill="#B3D4FF" stroke="#000" stroke-width="3" d="M17 8c0 2.122-.895 4.157-2.49 5.657C12.916 15.157 10.754 16 8.5 16s-4.416-.843-6.01-2.343C.896 12.157 0 10.122 0 8h17z" mask="url(#i08j30ef6a)"/>
|
||||||
|
<mask id="1f1ltfoetb" fill="#fff">
|
||||||
|
<path d="M38 8c0 2.122-.895 4.157-2.49 5.657C33.916 15.157 31.754 16 29.5 16s-4.416-.843-6.01-2.343C21.895 12.157 21 10.122 21 8h17z"/>
|
||||||
|
</mask>
|
||||||
|
<path fill="#B3D4FF" stroke="#000" stroke-width="3" d="M38 8c0 2.122-.895 4.157-2.49 5.657C33.916 15.157 31.754 16 29.5 16s-4.416-.843-6.01-2.343C21.895 12.157 21 10.122 21 8h17z" mask="url(#1f1ltfoetb)"/>
|
||||||
|
<path stroke="#000" stroke-width="1.5" d="M16 9.125c2-1.5 4-1.5 6 0"/>
|
||||||
|
<path fill="#FFCB00" d="M19.186 24.75C17.686 20.75 9 19 10.5 18s16-1.5 17-.5-6.857 2.826-8.314 7.25z"/>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 1.5 KiB |
3
packages/webapp/src/images/logo-text-black.svg
Normal file
3
packages/webapp/src/images/logo-text-black.svg
Normal file
File diff suppressed because one or more lines are too long
After Width: | Height: | Size: 7.0 KiB |
@ -1,176 +0,0 @@
|
|||||||
import { createMuiTheme, TextField, withStyles } from '@material-ui/core';
|
|
||||||
import { Alert } from '@material-ui/lab';
|
|
||||||
import styled, { createGlobalStyle } from 'styled-components';
|
|
||||||
|
|
||||||
|
|
||||||
const GlobalStyle = createGlobalStyle`
|
|
||||||
|
|
||||||
@import url('https://fonts.googleapis.com/css?family=Montserrat:100,300,400,700,900');
|
|
||||||
* {
|
|
||||||
box-sizing: border-box;
|
|
||||||
}
|
|
||||||
|
|
||||||
body {
|
|
||||||
font: 1.2em Montserrat, arial, sans-serif;
|
|
||||||
margin: 0px;
|
|
||||||
}
|
|
||||||
|
|
||||||
a {
|
|
||||||
text-decoration: none;
|
|
||||||
transition: background-color 0.3s ease;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Buttons */
|
|
||||||
|
|
||||||
.button-style1,
|
|
||||||
.button-style2,
|
|
||||||
.button-style3 {
|
|
||||||
font-size: 16px;
|
|
||||||
font-weight: 500;
|
|
||||||
font-stretch: normal;
|
|
||||||
font-style: normal;
|
|
||||||
letter-spacing: normal;
|
|
||||||
white-space: nowrap;
|
|
||||||
padding-top: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.button-style1 a,
|
|
||||||
.button-style2 a,
|
|
||||||
.button-style3 a {
|
|
||||||
padding: 10px 30px 10px 30px;
|
|
||||||
transition: background-color 0.3s ease;
|
|
||||||
border-radius: 9px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.button-style1 a {
|
|
||||||
color: #f9a826;
|
|
||||||
background-color: white;
|
|
||||||
border: solid 1px #f9a826;
|
|
||||||
}
|
|
||||||
|
|
||||||
.button-style1 a:hover {
|
|
||||||
color: white;
|
|
||||||
background-color: rgba(255, 168, 0, 0.6);
|
|
||||||
border: 0px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.button-style2 a {
|
|
||||||
color: #ffa800;
|
|
||||||
background-color: white;
|
|
||||||
border: solid 1px rgba(255, 168, 0, 0.6);
|
|
||||||
}
|
|
||||||
|
|
||||||
.button-style2 a:hover {
|
|
||||||
color: white;
|
|
||||||
border: solid 1px white;
|
|
||||||
background-color: rgba(243, 220, 174, 0.6);
|
|
||||||
}
|
|
||||||
|
|
||||||
.button-style3 a {
|
|
||||||
color: white;
|
|
||||||
background-color: #ffa800;
|
|
||||||
font-weight: 600;
|
|
||||||
}
|
|
||||||
|
|
||||||
.button-style3 a:hover {
|
|
||||||
color: #ffa800;
|
|
||||||
background-color: white;
|
|
||||||
border: solid 1px #ffa800;
|
|
||||||
font-weight: 600;
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
|
|
||||||
const PageContent = styled.div`
|
|
||||||
max-width: 350px;
|
|
||||||
min-height: 350px;
|
|
||||||
margin: 10px auto;
|
|
||||||
text-align:center;
|
|
||||||
padding: 20px 10px 20px 10px;
|
|
||||||
|
|
||||||
/* Form Styles Section */
|
|
||||||
|
|
||||||
& input[type=checkbox] {
|
|
||||||
border: solid 1px #f9a826;
|
|
||||||
background-color: #f9a826;
|
|
||||||
}
|
|
||||||
|
|
||||||
& input[type=submit],
|
|
||||||
& input[type=button] {
|
|
||||||
width: 330px;
|
|
||||||
height: 53px;
|
|
||||||
padding: 0px 20px;
|
|
||||||
margin: 7px 0px;
|
|
||||||
font-size: 20px;
|
|
||||||
font-weight: 600;
|
|
||||||
border-radius: 9px;
|
|
||||||
border: 0px;
|
|
||||||
background-color: #ffa800;
|
|
||||||
color: white;
|
|
||||||
}
|
|
||||||
|
|
||||||
& input[type=submit]:hover {
|
|
||||||
background-color: rgba(249, 168, 38, 0.91);
|
|
||||||
cursor: pointer
|
|
||||||
}
|
|
||||||
|
|
||||||
& label {
|
|
||||||
font-size:15px;
|
|
||||||
}
|
|
||||||
|
|
||||||
& input:placeholder {
|
|
||||||
color: grey;
|
|
||||||
}
|
|
||||||
|
|
||||||
& h1,
|
|
||||||
& h2 {
|
|
||||||
font-stretch: normal;
|
|
||||||
font-style: normal;
|
|
||||||
line-height: 1.2;
|
|
||||||
letter-spacing: normal;
|
|
||||||
}
|
|
||||||
|
|
||||||
& h1 {
|
|
||||||
font-size: 36px;
|
|
||||||
font-weight: bold;
|
|
||||||
font-stretch: normal;
|
|
||||||
font-style: normal;
|
|
||||||
line-height: normal;
|
|
||||||
letter-spacing: normal;
|
|
||||||
color: #f9a826;
|
|
||||||
}
|
|
||||||
|
|
||||||
& a {
|
|
||||||
font-size: 15px;
|
|
||||||
color: #f9a826;
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
|
|
||||||
const theme = createMuiTheme({
|
|
||||||
typography: {
|
|
||||||
fontFamily: [
|
|
||||||
'Montserrat'
|
|
||||||
].join(','),
|
|
||||||
h6: {
|
|
||||||
fontSize: '25px',
|
|
||||||
fontWeight: 'bold'
|
|
||||||
},
|
|
||||||
},
|
|
||||||
palette: {
|
|
||||||
primary: {
|
|
||||||
main: '#ffffff',
|
|
||||||
light: '#ffffff',
|
|
||||||
dark: '#ffffff',
|
|
||||||
contrastText: '#ffffff'
|
|
||||||
},
|
|
||||||
secondary: {
|
|
||||||
main: '#ffffff',
|
|
||||||
light: '#ffffff',
|
|
||||||
dark: '#ffffff',
|
|
||||||
contrastText: '#ffffff'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
theme.palette.secondary
|
|
||||||
export { GlobalStyle, PageContent, theme };
|
|
||||||
|
|
92
packages/webapp/src/theme/index.ts
Normal file
92
packages/webapp/src/theme/index.ts
Normal file
@ -0,0 +1,92 @@
|
|||||||
|
import { createMuiTheme } from '@material-ui/core';
|
||||||
|
import styled, { createGlobalStyle } from 'styled-components';
|
||||||
|
|
||||||
|
|
||||||
|
const GlobalStyle = createGlobalStyle`
|
||||||
|
|
||||||
|
@import url('https://fonts.googleapis.com/css2?family=Montserrat:wght@100;200;300;400;600&display=swap');
|
||||||
|
* {
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
const PageContent = styled.div`
|
||||||
|
max-width: 350px;
|
||||||
|
min-height: 350px;
|
||||||
|
margin: 10px auto;
|
||||||
|
text-align:center;
|
||||||
|
padding: 20px 10px 20px 10px;
|
||||||
|
`;
|
||||||
|
|
||||||
|
const theme = createMuiTheme({
|
||||||
|
overrides: {
|
||||||
|
MuiOutlinedInput: {
|
||||||
|
root: {
|
||||||
|
height: '53px',
|
||||||
|
borderRadius: '9px',
|
||||||
|
fontSize: '14px',
|
||||||
|
'& fieldset': {
|
||||||
|
border: 'solid 1px #ffcb66',
|
||||||
|
},
|
||||||
|
'&:hover:not($disabled):not($focused):not($error) $notchedOutline': {
|
||||||
|
borderColor: '#f9a826',
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
MuiInputLabel: {
|
||||||
|
root: {
|
||||||
|
color: '#f9a826'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
MuiButton: {
|
||||||
|
root: {
|
||||||
|
fontSize: '15px',
|
||||||
|
fontWeight: 600,
|
||||||
|
whiteSpace: 'nowrap',
|
||||||
|
textTransform: 'none',
|
||||||
|
borderRadius: '9px',
|
||||||
|
padding: '6px 54px 6px 54px',
|
||||||
|
width: '136px'
|
||||||
|
},
|
||||||
|
containedPrimary: {
|
||||||
|
color: 'white',
|
||||||
|
'&:hover': {
|
||||||
|
backgroundColor: 'rgba(249, 168, 38, 0.91)'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
textPrimary: {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
typography: {
|
||||||
|
fontFamily: [
|
||||||
|
'Montserrat'
|
||||||
|
].join(','),
|
||||||
|
h4: {
|
||||||
|
color: '#ffa800',
|
||||||
|
fontWeight: 600
|
||||||
|
},
|
||||||
|
h6: {
|
||||||
|
fontSize: '25px',
|
||||||
|
fontWeight: 'bold'
|
||||||
|
},
|
||||||
|
},
|
||||||
|
palette: {
|
||||||
|
primary: {
|
||||||
|
light: '#ffa800',
|
||||||
|
main: '#ffa800',
|
||||||
|
dark: '#ffa800',
|
||||||
|
contrastText: '#FFFFFF',
|
||||||
|
},
|
||||||
|
secondary: {
|
||||||
|
light: '#FFFFFF',
|
||||||
|
main: '#FFFFFF',
|
||||||
|
dark: '#FFFFFF',
|
||||||
|
contrastText: '#FFFFFF',
|
||||||
|
},
|
||||||
|
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
export { GlobalStyle, PageContent, theme };
|
||||||
|
|
Loading…
Reference in New Issue
Block a user