Migrate to MUI v5

This commit is contained in:
Maksim Karasev 2022-06-11 00:36:20 +03:00
parent f2e7cdbfd2
commit e1e2d7d715
26 changed files with 912 additions and 543 deletions

11
.vscode/settings.json vendored
View File

@ -1,8 +1,7 @@
{
"prettier.enable": false,
"editor.defaultFormatter": "dbaeumer.vscode-eslint",
"eslint.workingDirectories": [
"./packages/web",
"./packages/server"
]
}
"eslint.workingDirectories": ["./packages/web", "./packages/server"],
"editor.codeActionsOnSave": {
"source.fixAll": true
}
}

View File

@ -1,7 +1,7 @@
{
"$schema": "https://json.schemastore.org/package.json",
"name": "personal-gallery",
"version": "1.0.0",
"version": "1.1.0",
"description": "",
"scripts": {
"server-dev": "yarn workspace server dev",

View File

@ -1,6 +1,6 @@
{
"name": "server",
"version": "1.0.0",
"version": "1.1.0",
"description": "",
"main": "index.js",
"scripts": {
@ -43,8 +43,8 @@
"jest": "^26.6.3",
"supertest": "^6.0.1",
"ts-jest": "^26.4.4",
"ts-node": "^9.1.1",
"ts-node-dev": "^1.1.1",
"ts-node": "^10.8.1",
"ts-node-dev": "^2.0.0",
"typescript": "^4.1.3"
},
"dependencies": {

View File

@ -1,10 +1,13 @@
{
"name": "web",
"version": "0.1.0",
"version": "1.1.0",
"private": true,
"dependencies": {
"@emotion/react": "^11.9.0",
"@emotion/styled": "^11.8.1",
"@fontsource/roboto": "^4.2.1",
"@material-ui/core": "^4.11.3",
"@mui/material": "^5.8.2",
"@mui/styles": "^5.8.0",
"@testing-library/jest-dom": "^5.11.4",
"@testing-library/react": "^11.1.0",
"@testing-library/user-event": "^12.1.10",
@ -35,7 +38,7 @@
"test": "react-scripts test",
"eject": "react-scripts eject"
},
"proxy": "http://localhost:3002",
"proxy": "http://localhost:3001",
"eslintConfig": {
"extends": [
"react-app",
@ -67,7 +70,19 @@
"location": "anywhere"
}
],
"linebreak-style": 0
"linebreak-style": 0,
"no-void": [
"error",
{
"allowAsStatement": true
}
],
"@typescript-eslint/no-misused-promises": [
"error",
{
"checksVoidReturn": false
}
]
}
},
"browserslist": {
@ -94,4 +109,4 @@
"eslint-plugin-react-hooks": "^4.0.8",
"react-scripts": "^5.0.1"
}
}
}

View File

@ -1,9 +0,0 @@
import React from 'react';
import { render, screen } from '@testing-library/react';
import App from './App';
test('renders learn react link', () => {
render(<App />);
const linkElement = screen.getByText(/learn react/i);
expect(linkElement).toBeInTheDocument();
});

View File

@ -1,21 +1,22 @@
/** @jsxImportSource @emotion/react */
import React, { useEffect, useRef, useState } from 'react';
import {
Container,
makeStyles,
Theme,
createStyles,
withWidth,
WithWidth,
Dialog,
CircularProgress,
IconButton,
Snackbar,
Grid,
Typography,
} from '@material-ui/core';
Breakpoint,
useMediaQuery,
} from '@mui/material';
import { css } from '@emotion/react';
import InfiniteScroll from 'react-infinite-scroller';
import { AxiosError } from 'axios';
import axios from 'axios';
import { useTranslation } from 'react-i18next';
import { useTheme } from '@mui/styles';
import * as imageService from './services/images';
import * as settingsService from './services/settings';
import * as loginService from './services/login';
@ -32,62 +33,22 @@ import LoginView from './components/LoginView';
import ConfirmationDialog from './components/ConfirmationDialog';
import CredentialChangeDialog from './components/CredentialChangeDialog';
const useStyles = makeStyles((theme: Theme) => createStyles({
root: {
height: '100vh',
},
titleBar: {
background:
'linear-gradient(to bottom, rgba(0,0,0,0) 0%, '
+ 'rgba(0,0,0,0) 70%, rgba(0,0,0,0) 100%)',
transition: 'background 2s ease-out',
'&:hover': {
background:
'linear-gradient(to bottom, rgba(0,0,0,0) 0%, '
+ 'rgba(0,0,0,0) 70%, rgba(0,0,0,0) 100%)',
},
},
icon: {
color: 'white',
filter: 'drop-shadow(2px 4px 3px #222222)',
},
listItem: {
cursor: 'pointer',
'&:hover': {
opacity: '0.9',
},
},
dialogImage: {
maxHeight: '80vh',
},
loader: {
margin: '1rem',
},
toolbarTitle: {
flexGrow: 1,
},
toolbarButton: {
flexGrow: 1,
},
placeholderText: {
textAlign: 'center',
margin: theme.spacing(1),
color: '#696969',
},
placeholderIconContainer: {
textAlign: 'center',
color: '#696969',
},
placeholderIcon: {
fontSize: '96px',
verticalAlign: '-25%',
},
}));
function useWidth() {
const theme: Theme = useTheme();
const keys: readonly Breakpoint[] = [...theme.breakpoints.keys].reverse();
return (
keys.reduce((output: Breakpoint | null, key: Breakpoint) => {
// eslint-disable-next-line react-hooks/rules-of-hooks
const matches = useMediaQuery(theme.breakpoints.up(key));
return !output && matches ? key : output;
}, null) || 'xs'
);
}
function App(props: WithWidth) {
function App() {
const [modalImage, setModalImage] = useState('');
const [modalVideo, setModalVideo] = useState('');
const [imagesData, setImagesData] = useState<any>(undefined);
const [imagesData, setImagesData] = useState<{ [key: number]: Image[]; }>({});
const imagesPage = useRef(0);
const [hasMore, setHasMore] = useState(true);
const [userSettings, setUserSettings] = useState<Config | undefined>(
@ -114,14 +75,65 @@ function App(props: WithWidth) {
const [setupFinished, setSetupFinished] = useState(true);
const [apiKey, setApiKey] = useState<string | undefined>();
const { width } = props;
const theme: Theme = useTheme();
const styles = {
root: css({
height: '100vh',
}),
titleBar: css({
background:
'linear-gradient(to bottom, rgba(0,0,0,0) 0%, '
+ 'rgba(0,0,0,0) 70%, rgba(0,0,0,0) 100%)',
transition: 'background 2s ease-out',
'&:hover': {
background:
'linear-gradient(to bottom, rgba(0,0,0,0) 0%, '
+ 'rgba(0,0,0,0) 70%, rgba(0,0,0,0) 100%)',
},
}),
icon: css({
color: 'white',
filter: 'drop-shadow(2px 4px 3px #222222)',
}),
listItem: css({
cursor: 'pointer',
'&:hover': {
opacity: '0.9',
},
}),
dialogImage: css({
maxHeight: '80vh',
}),
loader: css({
margin: '1rem',
}),
toolbarTitle: css({
flexGrow: 1,
}),
toolbarButton: css({
flexGrow: 1,
}),
placeholderText: css({
textAlign: 'center',
margin: theme.spacing(1),
color: '#696969',
}),
placeholderIconContainer: css({
textAlign: 'center',
color: '#696969',
}),
placeholderIcon: css({
fontSize: '96px',
verticalAlign: '-25%',
}),
};
const width = useWidth();
const { t } = useTranslation();
const widthMap = {
xs: 3, sm: 4, md: 5, lg: 6, xl: 6,
};
const cols = widthMap[width];
const classes = useStyles();
useEffect(() => {
// imageService.getAll().then(result => setImagesData(result));
@ -130,7 +142,7 @@ function App(props: WithWidth) {
setSetupFinished(result.setupFinished);
setUserSettings(settingsService.getSettings());
setUserLoggedIn(settingsService.getUserState());
});
}).catch((e) => console.error(e));
}, []);
const imageTileClickHandler = (url: string) => {
if (/\.(mp4|webm)$/.test(url)) {
@ -140,9 +152,9 @@ function App(props: WithWidth) {
}
};
const handleLogout = async (clientOnly: boolean = false) => {
const handleLogout = async (clientOnly = false) => {
if (!clientOnly) {
loginService.doLogout();
await loginService.doLogout();
}
setUserLoggedIn(false);
setDragOpen(false);
@ -166,17 +178,19 @@ function App(props: WithWidth) {
if (result.length === 0) {
setHasMore(false);
} else {
setImagesData((data: any) => ({ ...data, [page]: result }));
setImagesData((data) => ({ ...data, [page]: result }));
}
})
.catch((e: AxiosError) => {
if (e.response?.status === 401) {
handleLogout(true);
setNotification(t('Authorization error, please login'));
} else {
setNotification(t('Error getting image list from server'));
.catch((e) => {
if (axios.isAxiosError(e)) {
if (e.response?.status === 401) {
void handleLogout(true);
setNotification(t('Authorization error, please login'));
} else {
setNotification(t('Error getting image list from server'));
}
imagesPage.current -= 1;
}
imagesPage.current -= 1;
});
imagesPage.current += 1;
};
@ -193,7 +207,7 @@ function App(props: WithWidth) {
try {
const combinedResult = await Promise.all(promises);
if (combinedResult.length > 0) {
setImagesData((data: { [key:number]: Image[] }) => {
setImagesData((data) => {
if (data === undefined || Object.keys(data).length === 0) {
return { [-1]: combinedResult };
}
@ -215,7 +229,7 @@ function App(props: WithWidth) {
if (acceptedUploadFiletypes.includes(item.type)) {
const pasteAsFile = item.getAsFile();
if (pasteAsFile !== null) {
handleUpload([pasteAsFile]);
void handleUpload([pasteAsFile]);
}
}
});
@ -272,10 +286,10 @@ function App(props: WithWidth) {
) => {
try {
await userService.updateCredentials(oldPassword, username, password);
handleLogout();
void handleLogout();
setNotification(t('Please login with your new credentials'));
} catch (e: any) {
if (e.response.status === 401) {
} catch (e) {
if (axios.isAxiosError(e) && e?.response?.status === 401) {
setNotification(t('Check your old password and try again'));
}
}
@ -284,13 +298,13 @@ function App(props: WithWidth) {
if (userSettings === undefined || userLoggedIn === undefined) {
return (
<Grid container justifyContent="center">
<CircularProgress className={classes.loader} />
<CircularProgress css={styles.loader} />
</Grid>
);
}
return (
<div
className={classes.root}
css={styles.root}
onDragEnter={() => setDragOpen(true)}
onPaste={handlePaste}
>
@ -308,28 +322,34 @@ function App(props: WithWidth) {
hasMore={hasMore}
loader={(
<Grid key="asdf" container justifyContent="center">
<CircularProgress className={classes.loader} />
<CircularProgress css={styles.loader} />
</Grid>
)}
>
{typeof imagesData === 'object' && Object.keys(imagesData).length !== 0 ? (
<ImageGridListTile
images={[...new Set(Object.keys(imagesData).sort((a:any, b:any) => a - b).reduce(
(r, k) => (r.concat(imagesData[k])),
[],
))]}
images={
[
...new Set(Object.keys(imagesData)
.map(Number)
.sort((a:number, b:number) => a - b)
.reduce(
(r: Image[], k) => (r.concat(imagesData[k])),
[],
))]
}
cols={cols}
onTileClick={imageTileClickHandler}
onNotification={setNotification}
/>
) : (
<Grid key="qwerty">
<div className={classes.placeholderIconContainer}>
<span className={`material-icons-outlined ${classes.placeholderIcon}`}>
<div css={styles.placeholderIconContainer}>
<span css={styles.placeholderIcon} className="material-icons-outlined">
insert_photo
</span>
</div>
<Typography className={classes.placeholderText}>
<Typography css={styles.placeholderText}>
{t('Upload your first image')}
</Typography>
</Grid>
@ -352,12 +372,12 @@ function App(props: WithWidth) {
maxWidth="lg"
>
{modalImage !== '' ? (
<img className={classes.dialogImage} src={modalImage} alt="" />
<img css={styles.dialogImage} src={modalImage} alt="" />
) : null}
{modalVideo !== '' ? (
// eslint-disable-next-line jsx-a11y/media-has-caption
<video
className={classes.dialogImage}
css={styles.dialogImage}
autoPlay
controls
src={modalVideo}
@ -384,7 +404,7 @@ function App(props: WithWidth) {
content={t('This will invalidate your previous API key, continue?')}
open={confirmDialogOpen}
onConfirm={() => {
handleApiKeyChange();
void handleApiKeyChange();
setConfirmDialogOpen(false);
}}
onCancel={() => setConfirmDialogOpen(false)}
@ -405,20 +425,18 @@ function App(props: WithWidth) {
onClose={() => setNotification('')}
message={notification}
action={(
<>
<IconButton
size="small"
aria-label="close"
color="inherit"
onClick={() => setNotification('')}
>
<span className="material-icons">close</span>
</IconButton>
</>
<IconButton
size="small"
aria-label="close"
color="inherit"
onClick={() => setNotification('')}
>
<span className="material-icons">close</span>
</IconButton>
)}
/>
</div>
);
}
export default withWidth()(App);
export default App;

View File

@ -1,6 +1,6 @@
/** @jsxImportSource @emotion/react */
import {
Button,
createStyles,
Dialog,
DialogActions,
DialogContent,
@ -9,43 +9,22 @@ import {
FormControlLabel,
FormLabel,
InputLabel,
makeStyles,
MenuItem,
Radio,
RadioGroup,
Select,
Theme,
Tooltip,
} from '@material-ui/core';
} from '@mui/material';
import { css } from '@emotion/react';
import React, { useState } from 'react';
import { useTranslation } from 'react-i18next';
import { useTheme } from '@mui/styles';
import generateConfig from '../utils/ShareX';
import { availableLanguages } from '../i18n';
import { Config, SortBy, SortOrder } from '../types';
const useStyles = makeStyles((theme: Theme) => createStyles({
form: {
display: 'flex',
flexDirection: 'column',
margin: 'auto',
width: 'fit-content',
},
formControl: {
margin: theme.spacing(1),
},
wide: {
width: '100%',
},
buttonSpan: {
display: 'inline-flex',
flexGrow: 1,
},
button: {
flexGrow: 1,
},
}));
const ConfigurationDialog = ({
function ConfigurationDialog({
open,
onDialogClose,
currentSettings,
@ -61,11 +40,33 @@ const ConfigurationDialog = ({
onApiKeyChange: () => void;
onCredentialsChange: () => void;
apiKey?: string;
}) => {
}) {
const [sortBy, setSortBy] = useState(currentSettings.sortBy);
const [sortOrder, setSortOrder] = useState(currentSettings.sortOrder);
const classes = useStyles();
const { t, i18n } = useTranslation();
const theme: Theme = useTheme();
const styles = {
form: css({
display: 'flex',
flexDirection: 'column',
margin: 'auto',
width: 'fit-content',
}),
formControl: css({
margin: theme.spacing(1),
}),
wide: css({
width: '100%',
}),
buttonSpan: css({
display: 'inline-flex',
flexGrow: 1,
}),
button: css({
flexGrow: 1,
}),
};
const handleSave = () => {
onSave(sortBy, sortOrder);
};
@ -98,8 +99,11 @@ const ConfigurationDialog = ({
{/* <DialogContentText>
Configure how you want your list to be displayed.
</DialogContentText> */}
<form className={classes.form} noValidate>
<FormControl className={classes.formControl}>
<form
css={styles.form}
noValidate
>
<FormControl css={styles.formControl}>
<FormLabel component="legend">{t('Sort By')}</FormLabel>
<RadioGroup
row
@ -122,7 +126,7 @@ const ConfigurationDialog = ({
/>
</RadioGroup>
</FormControl>
<FormControl className={classes.formControl}>
<FormControl css={styles.formControl}>
<FormLabel component="legend">{t('Sort Direction')}</FormLabel>
<RadioGroup
row
@ -146,14 +150,15 @@ const ConfigurationDialog = ({
</RadioGroup>
</FormControl>
</form>
<div className={classes.form}>
<FormControl className={classes.formControl}>
<div css={styles.form}>
<FormControl css={styles.formControl}>
<InputLabel id="demo-simple-select-label">Language</InputLabel>
<Select
labelId="demo-simple-select-label"
label="Language"
id="demo-simple-select"
value={i18n.language.slice(0, 2)}
onChange={(e) => i18n.changeLanguage(e.target.value as string)}
value={i18n.language && i18n.language.slice(0, 2)}
onChange={(e) => i18n.changeLanguage(e.target.value)}
>
{availableLanguages.map((lang) => (
<MenuItem value={lang.short} key={lang.short}>
@ -163,7 +168,8 @@ const ConfigurationDialog = ({
</Select>
</FormControl>
<Button
className={classes.formControl}
css={styles.formControl}
style={{}}
variant="contained"
color="primary"
onClick={onCredentialsChange}
@ -171,7 +177,7 @@ const ConfigurationDialog = ({
{t('Change username/password')}
</Button>
<Button
className={classes.formControl}
css={styles.formControl}
variant="contained"
color="primary"
onClick={onApiKeyChange}
@ -188,10 +194,10 @@ const ConfigurationDialog = ({
disableHoverListener={typeof apiKey !== 'undefined'}
disableTouchListener={typeof apiKey !== 'undefined'}
>
<span className={classes.buttonSpan}>
<span css={styles.buttonSpan}>
<Button
disabled={typeof apiKey === 'undefined'}
className={`${classes.formControl} ${classes.button}`}
css={[styles.formControl, styles.button]}
variant="contained"
color="primary"
onClick={downloadSharexConfig}
@ -212,6 +218,6 @@ const ConfigurationDialog = ({
</DialogActions>
</Dialog>
);
};
}
export default ConfigurationDialog;

View File

@ -5,12 +5,12 @@ import {
DialogContent,
DialogContentText,
DialogTitle,
} from '@material-ui/core';
} from '@mui/material';
import React from 'react';
import { useTranslation } from 'react-i18next';
const ConfirmationDialog = ({
function ConfirmationDialog({
open, header, content, onConfirm, onCancel,
}:{
open: boolean;
@ -18,7 +18,7 @@ const ConfirmationDialog = ({
content?: string;
onConfirm: () => void;
onCancel: () => void;
}) => {
}) {
const { t } = useTranslation();
return (
<Dialog onClose={onCancel} open={open} aria-labelledby="dialog-title">
@ -36,6 +36,6 @@ const ConfirmationDialog = ({
</DialogActions>
</Dialog>
);
};
}
export default ConfirmationDialog;

View File

@ -1,30 +1,20 @@
/** @jsxImportSource @emotion/react */
import {
Button,
createStyles,
Dialog,
DialogActions,
DialogContent,
DialogContentText,
DialogTitle,
makeStyles,
TextField,
Theme,
} from '@material-ui/core';
} from '@mui/material';
import { useTheme } from '@mui/styles';
import { css } from '@emotion/react';
import React, { useState } from 'react';
import { useTranslation } from 'react-i18next';
const useStyles = makeStyles((theme: Theme) => createStyles({
form: {
display: 'flex',
flexDirection: 'column',
},
margin: {
marginTop: theme.spacing(1),
marginBottom: theme.spacing(1),
},
}));
const CredentialChangeDialog = ({
function CredentialChangeDialog({
open, onDialogClose, onCredentialsUpdate, onNotification,
}: {
open: boolean;
@ -35,14 +25,25 @@ const CredentialChangeDialog = ({
password: string
) => void;
onNotification: (text: string) => void;
}) => {
const classes = useStyles();
}) {
const { t } = useTranslation();
const [username, setUsername] = useState('');
const [password, setPassword] = useState('');
const [oldPassword, setOldPassword] = useState('');
const handleSubmit = async () => {
const theme: Theme = useTheme();
const styles = {
form: css({
display: 'flex',
flexDirection: 'column',
}),
margin: css({
marginTop: theme.spacing(1),
marginBottom: theme.spacing(1),
}),
};
const handleSubmit = () => {
if (username === '' && password === '') {
onNotification(t('At least one field must be filled'));
return;
@ -55,7 +56,7 @@ const CredentialChangeDialog = ({
<DialogContent>
<DialogContentText>{t('enter_new_username')}</DialogContentText>
<form
className={classes.form}
css={styles.form}
onSubmit={(e: React.FormEvent) => {
e.preventDefault();
handleSubmit();
@ -70,7 +71,7 @@ const CredentialChangeDialog = ({
variant="outlined"
value={username}
onChange={(e) => setUsername(e.target.value)}
className={classes.margin}
css={styles.margin}
/>
<TextField
label={t('Password')}
@ -80,7 +81,7 @@ const CredentialChangeDialog = ({
variant="outlined"
value={password}
onChange={(e) => setPassword(e.target.value)}
className={classes.margin}
css={styles.margin}
/>
<TextField
label={t('Old password')}
@ -90,7 +91,7 @@ const CredentialChangeDialog = ({
variant="outlined"
value={oldPassword}
onChange={(e) => setOldPassword(e.target.value)}
className={classes.margin}
css={styles.margin}
/>
</form>
</DialogContent>
@ -104,6 +105,6 @@ const CredentialChangeDialog = ({
</DialogActions>
</Dialog>
);
};
}
export default CredentialChangeDialog;

View File

@ -1,9 +1,11 @@
/** @jsxImportSource @emotion/react */
import React from 'react';
import { ImageList, ImageListItem } from '@material-ui/core';
import { css } from '@emotion/react';
import { ImageList, ImageListItem } from '@mui/material';
import { Image } from '../types';
import ImageThumbnail from './ImageThumbnail';
const ImageGridListTile = ({
function ImageGridListTile({
images,
cols,
onTileClick,
@ -13,19 +15,21 @@ const ImageGridListTile = ({
cols: number;
onTileClick: (url: string) => void;
onNotification: (text: string) => void;
}) => (
<ImageList rowHeight={160} cols={cols}>
{images.map((image) => (
<ImageListItem key={image.filename}>
<ImageThumbnail
image={image}
onTileClick={onTileClick}
onNotification={onNotification}
/>
</ImageListItem>
))}
</ImageList>
);
}) {
return (
<ImageList css={css({ margin: 0, overflowY: 'hidden' })} rowHeight={160} cols={cols}>
{images.map((image) => (
<ImageListItem key={image.filename}>
<ImageThumbnail
image={image}
onTileClick={onTileClick}
onNotification={onNotification}
/>
</ImageListItem>
))}
</ImageList>
);
}
export default React.memo(ImageGridListTile, (prevProps, nextProps) => {
if (

View File

@ -1,17 +1,18 @@
import { ButtonBase, ImageListItemBar, IconButton } from '@material-ui/core';
import { makeStyles, createStyles } from '@material-ui/core/styles';
/** @jsxImportSource @emotion/react */
import { ButtonBase, ImageListItemBar, IconButton } from '@mui/material';
import { css } from '@emotion/react';
import React, { useState } from 'react';
import { useTranslation } from 'react-i18next';
import { Image } from '../types';
const useStyles = makeStyles(() => createStyles({
image: {
const styles = {
image: css({
cursor: 'pointer',
width: '100%',
height: '100%',
objectFit: 'cover',
},
link: {
}),
link: css({
width: '100%',
height: '100%',
'&:hover': {
@ -20,51 +21,50 @@ const useStyles = makeStyles(() => createStyles({
'&:focus': {
opacity: '0.9',
},
},
item: {
}),
item: css({
opacity: '0',
transition: 'opacity 0.3s cubic-bezier(0.22, 1, 0.36, 1)',
width: '100%',
height: '100%',
},
fadeIn: {
}),
fadeIn: css({
opacity: '100',
backgroundColor: '#fff',
},
titleBar: {
}),
titleBar: css({
background: 'rgba(0, 0, 0, 0)',
width: '48px',
},
icon: {
}),
icon: css({
color: 'white',
filter: 'drop-shadow(2px 4px 3px #222222)',
},
container: {
}),
container: css({
width: '100%',
height: '100%',
backgroundColor: '#ebebeb',
},
}));
}),
};
const ImageThumbnail = ({ image, onTileClick, onNotification }:{
function ImageThumbnail({ image, onTileClick, onNotification }:{
image: Image;
onTileClick: (url: string) => void;
onNotification: (text: string) => void;
}) => {
}) {
const [loaded, setLoaded] = useState(false);
const classes = useStyles();
const { t } = useTranslation();
const copyToClipboard = async (stringToCopy: string) => {
await navigator.clipboard.writeText(stringToCopy);
onNotification(t('Copied link to clipboard'));
};
return (
<div className={classes.container}>
<div className={`${classes.item} ${loaded ? classes.fadeIn : null}`}>
<ButtonBase disableTouchRipple className={classes.link} tabIndex="-1">
<div css={styles.container}>
<div css={[styles.item, loaded ? styles.fadeIn : null]}>
<ButtonBase disableTouchRipple css={styles.link}>
<a
href={image.url}
className={classes.link}
css={styles.link}
onClick={(e: React.MouseEvent) => {
e.preventDefault();
onTileClick(image.url);
@ -80,7 +80,7 @@ const ImageThumbnail = ({ image, onTileClick, onNotification }:{
))}
<img
loading="lazy"
className={classes.image}
css={styles.image}
src={
image.thumbnails.filter(
(thumb) => thumb.filetype === 'image/jpeg',
@ -96,23 +96,24 @@ const ImageThumbnail = ({ image, onTileClick, onNotification }:{
position="top"
actionIcon={(
<IconButton
className={classes.icon}
css={styles.icon}
onClick={() => {
copyToClipboard(
void copyToClipboard(
`${window.location.href.replace(/\/$/, '')}${image.url}`,
);
}}
size="large"
>
{/* <FileCopyOutlinedIcon /> */}
<span className="material-icons">content_copy</span>
</IconButton>
)}
actionPosition="left"
className={classes.titleBar}
css={styles.titleBar}
/>
</div>
</div>
);
};
}
export default ImageThumbnail;

View File

@ -1,36 +1,27 @@
import {
AppBar,
Button,
createStyles,
Grid,
makeStyles,
TextField,
Theme,
Toolbar,
Typography,
} from '@material-ui/core';
/** @jsxImportSource @emotion/react */
import { css } from '@emotion/react'; import {
AppBar, Button, Grid, TextField, Theme, Toolbar, Typography,
} from '@mui/material';
import React, { useState } from 'react';
import { useTranslation } from 'react-i18next';
import { useTheme } from '@mui/styles';
const useStyles = makeStyles((theme: Theme) => createStyles({
margin: {
margin: theme.spacing(1),
},
header: {
textAlign: 'center',
fontWeight: 300,
},
}));
const LoginView = (
{ onLogin, setupFinished }:
{
onLogin: (username: string, password: string) => void;
setupFinished: boolean;
},
) => {
const classes = useStyles();
function LoginView({ onLogin, setupFinished }:
{
onLogin: (username: string, password: string) => void;
setupFinished: boolean;
}) {
const { t } = useTranslation();
const theme: Theme = useTheme();
const styles = {
margin: css({
margin: theme.spacing(1),
}),
header: css({
textAlign: 'center',
fontWeight: 300,
}),
};
const [username, setUsername] = useState('');
const [password, setPassword] = useState('');
@ -44,13 +35,12 @@ const LoginView = (
<Grid
container
spacing={0}
direction="column"
alignItems="center"
justifyContent="center"
style={{ minHeight: '80vh' }}
>
<Grid item xs={10} md={4}>
<Typography variant="h3" className={classes.header}>
<Grid item xs={8} md={6}>
<Typography variant="h3" css={styles.header}>
{setupFinished ? t('Login') : t('Register')}
</Typography>
<form
@ -68,7 +58,7 @@ const LoginView = (
variant="outlined"
value={username}
onChange={(e) => setUsername(e.target.value)}
className={classes.margin}
css={styles.margin}
/>
<TextField
id="outlined-password-input"
@ -79,13 +69,13 @@ const LoginView = (
variant="outlined"
value={password}
onChange={(e) => setPassword(e.target.value)}
className={classes.margin}
css={styles.margin}
/>
<Button
variant="contained"
color="primary"
type="submit"
className={classes.margin}
css={styles.margin}
fullWidth
>
{setupFinished ? t('Login') : t('Register')}
@ -95,6 +85,6 @@ const LoginView = (
</Grid>
</div>
);
};
}
export default LoginView;

View File

@ -1,4 +1,5 @@
import { createStyles, makeStyles, Theme } from '@material-ui/core/styles';
/** @jsxImportSource @emotion/react */
import { css } from '@emotion/react';
import React from 'react';
import {
AppBar,
@ -8,63 +9,25 @@ import {
Toolbar,
Typography,
useScrollTrigger,
} from '@material-ui/core';
} from '@mui/material';
import { useTranslation } from 'react-i18next';
const useStyles = makeStyles((theme: Theme) => createStyles({
root: {
display: 'flex',
flexWrap: 'wrap',
justifyContent: 'space-around',
overflow: 'hidden',
backgroundColor: theme.palette.background.paper,
},
titleBar: {
background:
'linear-gradient(to bottom, rgba(0,0,0,0) 0%, '
+ 'rgba(0,0,0,0) 70%, rgba(0,0,0,0) 100%)',
transition: 'background 2s ease-out',
'&:hover': {
background:
'linear-gradient(to bottom, rgba(0,0,0,0) 0%, '
+ 'rgba(0,0,0,0) 70%, rgba(0,0,0,0) 100%)',
},
},
icon: {
color: 'white',
filter: 'drop-shadow(2px 4px 3px #222222)',
},
listItem: {
cursor: 'pointer',
'&:hover': {
opacity: '0.9',
},
},
dialogImage: {
maxHeight: '80vh',
},
loader: {
margin: '1rem',
},
toolbarTitle: {
flexGrow: 1,
textAlign: 'left',
},
toolbarButton: {
flexGrow: 1,
},
}));
const PicturesAppBar = (
{ onUploadClick, onSettingsClick, onLogoutClick }:
{
onUploadClick: () => void;
onSettingsClick: () => void;
onLogoutClick: () => void;
},
) => {
const classes = useStyles();
function PicturesAppBar({ onUploadClick, onSettingsClick, onLogoutClick }:
{
onUploadClick: () => void;
onSettingsClick: () => void;
onLogoutClick: () => void;
}) {
const trigger = useScrollTrigger();
const styles = {
toolbarTitle: css({
flexGrow: 1,
textAlign: 'left',
}),
toolbarButton: css({
flexGrow: 1,
}),
};
const { t } = useTranslation();
return (
<>
@ -72,27 +35,24 @@ const PicturesAppBar = (
<AppBar>
<Toolbar>
{/* <IconButton
edge="start"
color="inherit"
aria-label="menu"
onClick={onDrawer}
>
<MenuIcon />
</IconButton> */}
<Typography variant="h6" className={classes.toolbarTitle}>
edge="start"
color="inherit"
aria-label="menu"
onClick={onDrawer}
>
<MenuIcon />
</IconButton> */}
<Typography variant="h6" css={styles.toolbarTitle}>
{t('Pictures')}
</Typography>
<IconButton
color="inherit"
aria-label="upload"
onClick={onUploadClick}
>
<IconButton color="inherit" aria-label="upload" onClick={onUploadClick} size="large">
<span className="material-icons">cloud_upload</span>
</IconButton>
<IconButton
color="inherit"
aria-label="settings"
onClick={onSettingsClick}
size="large"
>
<span className="material-icons">settings</span>
</IconButton>
@ -105,6 +65,6 @@ const PicturesAppBar = (
<Toolbar />
</>
);
};
}
export default PicturesAppBar;

View File

@ -1,56 +1,55 @@
/* eslint-disable react/jsx-props-no-spreading */
/** @jsxImportSource @emotion/react */
import React from 'react';
import {
createStyles,
Dialog,
DialogTitle,
IconButton,
makeStyles,
Theme,
} from '@material-ui/core';
Dialog, DialogTitle, IconButton, Theme,
} from '@mui/material';
import { css } from '@emotion/react';
import { useDropzone } from 'react-dropzone';
import { useTranslation } from 'react-i18next';
import { useTheme } from '@mui/styles';
const useStyles = makeStyles((theme: Theme) => createStyles({
dropzone: {
textAlign: 'center',
padding: '20px',
border: '3px dashed #eeeeee',
backgroundColor: '#fafafa',
color: '#bdbdbd',
marginBottom: '20px',
marginLeft: '20px',
marginRight: '20px',
height: '20vh',
minWidth: '40vw',
transition: 'border-color 0.4s cubic-bezier(0.22, 1, 0.36, 1)',
},
icon: {
fontSize: '2rem',
},
accept: {
borderColor: 'green !important',
},
reject: {
borderColor: 'red !important',
},
closeButton: {
position: 'absolute',
right: theme.spacing(1),
top: theme.spacing(1),
color: theme.palette.grey[500],
},
}));
const UploadDialog = ({
function UploadDialog({
isOpen, onClose, onDrop, accept,
}:{
isOpen: boolean;
onClose: () => void;
onDrop: (files: File[]) => void;
accept: string[];
}) => {
const classes = useStyles();
}) {
const theme: Theme = useTheme();
const styles = {
dropzone: css({
textAlign: 'center',
padding: '20px',
border: '3px dashed #eeeeee',
backgroundColor: '#fafafa',
color: '#bdbdbd',
marginBottom: '20px',
marginLeft: '20px',
marginRight: '20px',
height: '20vh',
minWidth: '40vw',
transition: 'border-color 0.4s cubic-bezier(0.22, 1, 0.36, 1)',
}),
icon: css({
fontSize: '2rem',
}),
accept: css({
borderColor: 'green !important',
}),
reject: css({
borderColor: 'red !important',
}),
closeButton: css({
position: 'absolute',
right: theme.spacing(1),
top: theme.spacing(1),
color: theme.palette.grey[500],
}),
};
const { t } = useTranslation();
const {
getRootProps,
getInputProps,
@ -74,8 +73,9 @@ const UploadDialog = ({
{t('Upload')}
<IconButton
aria-label="close"
className={classes.closeButton}
css={styles.closeButton}
onClick={onClose}
size="large"
>
<span className="material-icons">close</span>
</IconButton>
@ -83,13 +83,15 @@ const UploadDialog = ({
<section>
<div
{...getRootProps({
className: `dropzone ${classes.dropzone} ${
isDragAccept ? classes.accept : null
} ${isDragReject ? classes.reject : null}`,
css: [
styles.dropzone,
isDragAccept ? styles.accept : null,
isDragReject ? styles.reject : null],
className: 'dropzone ',
})}
>
<input {...getInputProps()} />
<span className={classes.icon}>
<span css={styles.icon}>
{isDragActive ? null : '📁'}
{isDragAccept ? '📂' : null}
{isDragReject ? '❌' : null}
@ -99,6 +101,6 @@ const UploadDialog = ({
</section>
</Dialog>
);
};
}
export default UploadDialog;

View File

@ -19,7 +19,8 @@ i18n
react: {
useSuspense: false,
},
});
})
.catch((e) => { console.error(e); });
export const availableLanguages = [
{

View File

@ -1,6 +1,8 @@
import React from 'react';
import ReactDOM from 'react-dom';
import CssBaseline from '@material-ui/core/CssBaseline';
import CssBaseline from '@mui/material/CssBaseline';
import { ThemeProvider, createTheme, Theme } from '@mui/material/styles';
import App from './App';
import reportWebVitals from './reportWebVitals';
import '@fontsource/roboto/300.css';
@ -16,11 +18,26 @@ import './icons/icons.css';
import * as serviceWorkerRegistration from './serviceWorkerRegistration';
import './i18n';
declare module '@mui/styles/defaultTheme' {
type DefaultTheme = Theme;
}
serviceWorkerRegistration.register();
const theme = createTheme({
palette: {
primary: {
light: '#757ce8',
main: '#3f50b5',
dark: '#002884',
contrastText: '#fff',
},
},
});
ReactDOM.render(
<React.StrictMode>
<CssBaseline>
<App />
<ThemeProvider theme={theme}>
<App />
</ThemeProvider>
</CssBaseline>
</React.StrictMode>,
document.getElementById('root'),

View File

@ -1,3 +1,4 @@
/* eslint-disable @typescript-eslint/no-floating-promises */
import { ReportHandler } from 'web-vitals';
const reportWebVitals = (onPerfEntry?: ReportHandler) => {

View File

@ -1,6 +1,9 @@
/* eslint-disable @typescript-eslint/no-unsafe-return */
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
/* eslint-disable @typescript-eslint/no-floating-promises */
/* eslint-disable no-underscore-dangle */
/// <reference lib="webworker" />
/* eslint-disable no-restricted-globals */
/// <reference lib="webworker" />
// This service worker can be customized!
// See https://developers.google.com/web/tools/workbox/modules
@ -27,7 +30,7 @@ precacheAndRoute(self.__WB_MANIFEST);
// Set up App Shell-style routing, so that all navigation requests
// are fulfilled with your index.html shell. Learn more at
// https://developers.google.com/web/fundamentals/architecture/app-shell
const fileExtensionRegexp = new RegExp('/[^/?]+\\.[^/]+$');
const fileExtensionRegexp = /\/[^/?]+\.[^/]+$/;
registerRoute(
// Return false to exempt requests from being fulfilled by index.html.
({ request, url }: { request: Request; url: URL }) => {
@ -64,7 +67,7 @@ registerRoute(
);
registerRoute(
new RegExp('https?:\\/\\/localhost:3002\\/\\w+\\.\\w+$'),
({ url }) => /^\/\w+\.(mp4|webm|png|webp|gif|avif|jpeg|jpg)/gm.test(url.pathname),
new CacheFirst({
cacheName: 'fulls',
plugins: [

View File

@ -1,3 +1,4 @@
/* eslint-disable @typescript-eslint/no-floating-promises */
/* eslint-disable @typescript-eslint/no-use-before-define */
// This optional code is used to register a service worker.
// register() is not called by default.
@ -138,7 +139,7 @@ export function unregister() {
registration.unregister();
})
.catch((error) => {
console.error(error.message);
console.error(error);
});
}
}

View File

@ -0,0 +1,4 @@
// eslint-disable-next-line import/prefer-default-export
export const hasKey = <K extends string, T extends object>(
k: K, o: T,
): o is T & Record<K, unknown> => k in o;

View File

@ -3,13 +3,16 @@ import {
Image, SortBy, SortOrder, Thumbnail,
} from '../types';
import { API_BASE_URL } from '../consts';
import { hasKey } from './common';
// Type guards
const isThumbnail = (thumb: any): thumb is Thumbnail => {
const isThumbnail = (thumb: unknown): thumb is Thumbnail => {
if (
'url' in thumb
typeof thumb === 'object'
&& thumb !== null
&& hasKey('url', thumb)
&& typeof thumb.url === 'string'
&& 'filetype' in thumb
&& hasKey('filetype', thumb)
&& typeof thumb.filetype === 'string'
) {
return true;
@ -17,17 +20,19 @@ const isThumbnail = (thumb: any): thumb is Thumbnail => {
return false;
};
const isThumbnailArray = (thumbnails: any): thumbnails is Thumbnail[] => (
const isThumbnailArray = (thumbnails: unknown): thumbnails is Thumbnail[] => (
Array.isArray(thumbnails) && thumbnails.every(isThumbnail)
);
const isImage = (image: any): image is Image => {
const isImage = (image: unknown): image is Image => {
if (
'url' in image
typeof image === 'object'
&& image !== null
&& hasKey('url', image)
&& typeof image.url === 'string'
&& 'filename' in image
&& hasKey('filename', image)
&& typeof image.url === 'string'
&& 'thumbnails' in image
&& hasKey('thumbnails', image)
&& isThumbnailArray(image.thumbnails)
) {
return true;
@ -35,7 +40,7 @@ const isImage = (image: any): image is Image => {
return false;
};
const isImageArray = (images: any): images is Image[] => (
const isImageArray = (images: unknown): images is Image[] => (
Array.isArray(images) && images.every(isImage)
);
@ -47,16 +52,16 @@ const isImageArray = (images: any): images is Image[] => (
* @return List of images
*/
export const getPage = async (
page: number = 0,
page = 0,
sortBy: SortBy = SortBy.Date,
sortOrder: SortOrder = SortOrder.Descending,
): Promise<Image[]> => {
const { data } = await axios.get(`${API_BASE_URL}/images`, {
const response = await axios.get(`${API_BASE_URL}/images`, {
params: { page, sortBy, sortOrder },
timeout: 5000,
});
if (isImageArray(data)) {
return data;
if (isImageArray(response?.data)) {
return response.data;
}
throw new Error('Malformed response from server');
};
@ -70,14 +75,14 @@ export const getPage = async (
export const uploadImage = async (image: File): Promise<Image> => {
const formData = new FormData();
formData.append('file', image);
const { data } = await axios.post(`${API_BASE_URL}/images`, formData, {
const response = await axios.post(`${API_BASE_URL}/images`, formData, {
headers: {
'Content-Type': 'multipart/form-data',
},
timeout: 10000,
});
if (isImage(data)) {
return data;
if (isImage(response?.data)) {
return response.data;
}
throw new Error('Malformed response from server');
};

View File

@ -23,9 +23,12 @@ export const doLogin = async (
},
);
return status;
} catch (e: any) {
console.error(e);
return e.response.status || 500;
} catch (e) {
if (axios.isAxiosError(e)) {
console.error(e);
return e?.response?.status || 500;
}
return 500;
}
};
@ -45,9 +48,12 @@ export const doRegister = async (
},
);
return status;
} catch (e: any) {
console.error(e);
return e.response.status || 500;
} catch (e) {
if (axios.isAxiosError(e)) {
console.error(e);
return e?.response?.status || 500;
}
return 500;
}
};

View File

@ -1,16 +1,23 @@
import axios from 'axios';
import { API_BASE_URL } from '../consts';
import { Meta } from '../types';
import { hasKey } from './common';
const isMeta = (data: unknown): data is Meta => typeof data === 'object'
&& data != null
&& hasKey('accepted', data)
&& Array.isArray(data.accepted)
&& data.accepted.every((x: unknown): x is string => typeof x === 'string')
&& hasKey('setupFinished', data)
&& typeof data.setupFinished === 'boolean';
// eslint-disable-next-line import/prefer-default-export
export const getMeta = async (): Promise<Meta> => {
const { data } = await axios.get(`${API_BASE_URL}/meta`);
const response = await axios.get(`${API_BASE_URL}/meta`);
if (
Array.isArray(data.accepted)
&& data.accepted.every((x: any): x is string => typeof x === 'string')
&& typeof data.setupFinished === 'boolean'
isMeta(response.data)
) {
return { accepted: data.accepted, setupFinished: data.setupFinished };
return response.data;
}
throw new Error('Malformed server response');
};

View File

@ -17,6 +17,7 @@ export const getUserState = (): boolean => {
if (serializedUserState === null) {
return false;
}
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
const userState = JSON.parse(serializedUserState);
if (typeof userState !== 'boolean') {
return false;

View File

@ -1,20 +1,35 @@
import axios from 'axios';
import { API_BASE_URL } from '../consts';
import { hasKey } from './common';
const isApiToken = (data: unknown): data is {
token: string
} => typeof data === 'object'
&& data != null
&& hasKey('token', data)
&& typeof data.token === 'string';
export const getApiKey = async (): Promise<string> => {
const { data } = await axios.post(`${API_BASE_URL}/user/getApiKey`);
if (typeof data?.token === 'string') {
return data.token;
const response = await axios.post(`${API_BASE_URL}/user/getApiKey`);
if (isApiToken(response.data)) {
return response.data.token;
}
throw new Error('Malformed server response');
};
const isStatus = (data: unknown): data is {
status: string
} => typeof data === 'object'
&& data != null
&& hasKey('status', data)
&& typeof data.status === 'string';
export const updateCredentials = async (
oldPassword: string,
username: string,
password: string,
) => {
const { data } = await axios.post(
const response = await axios.post(
`${API_BASE_URL}/user/updateCredentials`,
{
...(username !== '' ? { username } : {}),
@ -23,7 +38,7 @@ export const updateCredentials = async (
},
{},
);
if (data.status !== 'success') {
if (!isStatus(response.data) || response.data.status !== 'success') {
throw new Error('Malformed server response');
}
};

553
yarn.lock
View File

@ -723,7 +723,7 @@ __metadata:
languageName: node
linkType: hard
"@babel/plugin-syntax-jsx@npm:^7.17.12":
"@babel/plugin-syntax-jsx@npm:^7.12.13, @babel/plugin-syntax-jsx@npm:^7.17.12":
version: 7.17.12
resolution: "@babel/plugin-syntax-jsx@npm:7.17.12"
dependencies:
@ -1453,7 +1453,7 @@ __metadata:
languageName: node
linkType: hard
"@babel/runtime@npm:^7.10.2, @babel/runtime@npm:^7.11.2, @babel/runtime@npm:^7.12.0, @babel/runtime@npm:^7.12.5, @babel/runtime@npm:^7.14.5, @babel/runtime@npm:^7.14.6, @babel/runtime@npm:^7.16.3, @babel/runtime@npm:^7.3.1, @babel/runtime@npm:^7.4.4, @babel/runtime@npm:^7.5.5, @babel/runtime@npm:^7.8.3, @babel/runtime@npm:^7.8.4, @babel/runtime@npm:^7.8.7, @babel/runtime@npm:^7.9.2":
"@babel/runtime@npm:^7.10.2, @babel/runtime@npm:^7.11.2, @babel/runtime@npm:^7.12.0, @babel/runtime@npm:^7.12.5, @babel/runtime@npm:^7.13.10, @babel/runtime@npm:^7.14.5, @babel/runtime@npm:^7.14.6, @babel/runtime@npm:^7.16.3, @babel/runtime@npm:^7.17.2, @babel/runtime@npm:^7.3.1, @babel/runtime@npm:^7.5.5, @babel/runtime@npm:^7.7.2, @babel/runtime@npm:^7.8.3, @babel/runtime@npm:^7.8.4, @babel/runtime@npm:^7.8.7, @babel/runtime@npm:^7.9.2":
version: 7.18.3
resolution: "@babel/runtime@npm:7.18.3"
dependencies:
@ -1527,6 +1527,15 @@ __metadata:
languageName: node
linkType: hard
"@cspotcode/source-map-support@npm:^0.8.0":
version: 0.8.1
resolution: "@cspotcode/source-map-support@npm:0.8.1"
dependencies:
"@jridgewell/trace-mapping": 0.3.9
checksum: 5718f267085ed8edb3e7ef210137241775e607ee18b77d95aa5bd7514f47f5019aa2d82d96b3bf342ef7aa890a346fa1044532ff7cc3009e7d24fce3ce6200fa
languageName: node
linkType: hard
"@csstools/normalize.css@npm:*":
version: 12.0.0
resolution: "@csstools/normalize.css@npm:12.0.0"
@ -1690,6 +1699,41 @@ __metadata:
languageName: node
linkType: hard
"@emotion/babel-plugin@npm:^11.7.1":
version: 11.9.2
resolution: "@emotion/babel-plugin@npm:11.9.2"
dependencies:
"@babel/helper-module-imports": ^7.12.13
"@babel/plugin-syntax-jsx": ^7.12.13
"@babel/runtime": ^7.13.10
"@emotion/hash": ^0.8.0
"@emotion/memoize": ^0.7.5
"@emotion/serialize": ^1.0.2
babel-plugin-macros: ^2.6.1
convert-source-map: ^1.5.0
escape-string-regexp: ^4.0.0
find-root: ^1.1.0
source-map: ^0.5.7
stylis: 4.0.13
peerDependencies:
"@babel/core": ^7.0.0
checksum: 2d2c4fadd389862896bcbc5f42c9b9c1a199810173fcf14e5520506c7179c2ddb991b8832fd273f42104cf0dae98886ad8e767b5e38ad235b652d903c3b8a328
languageName: node
linkType: hard
"@emotion/cache@npm:^11.7.1":
version: 11.7.1
resolution: "@emotion/cache@npm:11.7.1"
dependencies:
"@emotion/memoize": ^0.7.4
"@emotion/sheet": ^1.1.0
"@emotion/utils": ^1.0.0
"@emotion/weak-memoize": ^0.2.5
stylis: 4.0.13
checksum: cf7aa8fe3bacfdedcda94b53e76a7635e122043439715fcfbf7f1a81340cfe6099a59134481a03ec3e0437466566d18528577d1e6ea92f5b98c372b8b38a8f35
languageName: node
linkType: hard
"@emotion/hash@npm:^0.8.0":
version: 0.8.0
resolution: "@emotion/hash@npm:0.8.0"
@ -1697,6 +1741,108 @@ __metadata:
languageName: node
linkType: hard
"@emotion/is-prop-valid@npm:^1.1.2":
version: 1.1.2
resolution: "@emotion/is-prop-valid@npm:1.1.2"
dependencies:
"@emotion/memoize": ^0.7.4
checksum: 58b1f2d429a589f8f5bc2c33a8732cbb7bbcb17131a103511ef9a94ac754d7eeb53d627f947da480cd977f9d419fd92e244991680292f3287204159652745707
languageName: node
linkType: hard
"@emotion/memoize@npm:^0.7.4, @emotion/memoize@npm:^0.7.5":
version: 0.7.5
resolution: "@emotion/memoize@npm:0.7.5"
checksum: 83da8d4a7649a92c72f960817692bc6be13cc13e107b9f7e878d63766525ed4402881bfeb3cda61145c050281e7e260f114a0a2870515527346f2ef896b915b3
languageName: node
linkType: hard
"@emotion/react@npm:^11.9.0":
version: 11.9.0
resolution: "@emotion/react@npm:11.9.0"
dependencies:
"@babel/runtime": ^7.13.10
"@emotion/babel-plugin": ^11.7.1
"@emotion/cache": ^11.7.1
"@emotion/serialize": ^1.0.3
"@emotion/utils": ^1.1.0
"@emotion/weak-memoize": ^0.2.5
hoist-non-react-statics: ^3.3.1
peerDependencies:
"@babel/core": ^7.0.0
react: ">=16.8.0"
peerDependenciesMeta:
"@babel/core":
optional: true
"@types/react":
optional: true
checksum: 4ceb004f942fb7557a55ea17aad2c48c4cd48ed5a780ccdc2993e4bded2f94d7c1764bd2f4fbe53f5b26059263599cec64ff66d29447e281a58c60b39c72e5cc
languageName: node
linkType: hard
"@emotion/serialize@npm:^1.0.2, @emotion/serialize@npm:^1.0.3":
version: 1.0.3
resolution: "@emotion/serialize@npm:1.0.3"
dependencies:
"@emotion/hash": ^0.8.0
"@emotion/memoize": ^0.7.4
"@emotion/unitless": ^0.7.5
"@emotion/utils": ^1.0.0
csstype: ^3.0.2
checksum: 99a9053bd98c99d63af542ebee029281eeaf653e3a12e97ee79bad7330c68408104c30be6fc07a528e38bb69aba680655181744b76ec6c6f459c121cb805fac2
languageName: node
linkType: hard
"@emotion/sheet@npm:^1.1.0":
version: 1.1.0
resolution: "@emotion/sheet@npm:1.1.0"
checksum: a4b74e16a8fea1157413efe4904f5f679d724323cb605d66d20a0b98744422f5d411fca927ceb52e4de454a0a819c5273ca9496db9f011b4ecd17b9f1b212007
languageName: node
linkType: hard
"@emotion/styled@npm:^11.8.1":
version: 11.8.1
resolution: "@emotion/styled@npm:11.8.1"
dependencies:
"@babel/runtime": ^7.13.10
"@emotion/babel-plugin": ^11.7.1
"@emotion/is-prop-valid": ^1.1.2
"@emotion/serialize": ^1.0.2
"@emotion/utils": ^1.1.0
peerDependencies:
"@babel/core": ^7.0.0
"@emotion/react": ^11.0.0-rc.0
react: ">=16.8.0"
peerDependenciesMeta:
"@babel/core":
optional: true
"@types/react":
optional: true
checksum: 67150fa788785c34e285b90acecc91fe7a63babceaefbeffd053bed0fa31f72a05bfeeb9d15620766e543e007b9ccac2e836812eec2e791f962ec4e52731ae4c
languageName: node
linkType: hard
"@emotion/unitless@npm:^0.7.5":
version: 0.7.5
resolution: "@emotion/unitless@npm:0.7.5"
checksum: f976e5345b53fae9414a7b2e7a949aa6b52f8bdbcc84458b1ddc0729e77ba1d1dfdff9960e0da60183877873d3a631fa24d9695dd714ed94bcd3ba5196586a6b
languageName: node
linkType: hard
"@emotion/utils@npm:^1.0.0, @emotion/utils@npm:^1.1.0":
version: 1.1.0
resolution: "@emotion/utils@npm:1.1.0"
checksum: d3b681ca3a23b07033ac6c6937e71010a5549ac8ccec325eb6c91a7e48d9a73db83fa5dadc58be981bb125d7c00fedca868ea4362b1da9e02866615f96be4df1
languageName: node
linkType: hard
"@emotion/weak-memoize@npm:^0.2.5":
version: 0.2.5
resolution: "@emotion/weak-memoize@npm:0.2.5"
checksum: 27d402b0c683b94658220b6d47840346ee582329ca2a15ec9c233492e0f1a27687ccb233b76eedc922f2e185e444cc89f7b97a81a1d3e5ae9f075bab08e965ea
languageName: node
linkType: hard
"@eslint/eslintrc@npm:^0.4.3":
version: 0.4.3
resolution: "@eslint/eslintrc@npm:0.4.3"
@ -2291,6 +2437,16 @@ __metadata:
languageName: node
linkType: hard
"@jridgewell/trace-mapping@npm:0.3.9":
version: 0.3.9
resolution: "@jridgewell/trace-mapping@npm:0.3.9"
dependencies:
"@jridgewell/resolve-uri": ^3.0.3
"@jridgewell/sourcemap-codec": ^1.4.10
checksum: d89597752fd88d3f3480845691a05a44bd21faac18e2185b6f436c3b0fd0c5a859fbbd9aaa92050c4052caf325ad3e10e2e1d1b64327517471b7d51babc0ddef
languageName: node
linkType: hard
"@jridgewell/trace-mapping@npm:^0.3.7, @jridgewell/trace-mapping@npm:^0.3.9":
version: 0.3.13
resolution: "@jridgewell/trace-mapping@npm:0.3.13"
@ -2308,106 +2464,182 @@ __metadata:
languageName: node
linkType: hard
"@material-ui/core@npm:^4.11.3":
version: 4.12.4
resolution: "@material-ui/core@npm:4.12.4"
"@mui/base@npm:5.0.0-alpha.83":
version: 5.0.0-alpha.83
resolution: "@mui/base@npm:5.0.0-alpha.83"
dependencies:
"@babel/runtime": ^7.4.4
"@material-ui/styles": ^4.11.5
"@material-ui/system": ^4.12.2
"@material-ui/types": 5.1.0
"@material-ui/utils": ^4.11.3
"@types/react-transition-group": ^4.2.0
clsx: ^1.0.4
hoist-non-react-statics: ^3.3.2
popper.js: 1.16.1-lts
prop-types: ^15.7.2
react-is: ^16.8.0 || ^17.0.0
react-transition-group: ^4.4.0
"@babel/runtime": ^7.17.2
"@emotion/is-prop-valid": ^1.1.2
"@mui/types": ^7.1.3
"@mui/utils": ^5.8.0
"@popperjs/core": ^2.11.5
clsx: ^1.1.1
prop-types: ^15.8.1
react-is: ^17.0.2
peerDependencies:
"@types/react": ^16.8.6 || ^17.0.0
react: ^16.8.0 || ^17.0.0
react-dom: ^16.8.0 || ^17.0.0
"@types/react": ^17.0.0 || ^18.0.0
react: ^17.0.0 || ^18.0.0
react-dom: ^17.0.0 || ^18.0.0
peerDependenciesMeta:
"@types/react":
optional: true
checksum: 96b48deccda87ced841b1db45bed2be6d2b6d1b4eae72cd5c9b931201cb72026330688e0fead54e715bcead40b267ea88bde781c9f1563b1a71a5c51bf187289
checksum: 0ad413a8da41dd09b018bb4c7961c5937f68e2656b56d4d9ecadc49c3c43a3d7974a52be9fe015df1f8381864fa8eefb98c8599deed991a4741c6287145a1da9
languageName: node
linkType: hard
"@material-ui/styles@npm:^4.11.5":
version: 4.11.5
resolution: "@material-ui/styles@npm:4.11.5"
"@mui/material@npm:^5.8.2":
version: 5.8.2
resolution: "@mui/material@npm:5.8.2"
dependencies:
"@babel/runtime": ^7.4.4
"@babel/runtime": ^7.17.2
"@mui/base": 5.0.0-alpha.83
"@mui/system": ^5.8.2
"@mui/types": ^7.1.3
"@mui/utils": ^5.8.0
"@types/react-transition-group": ^4.4.4
clsx: ^1.1.1
csstype: ^3.1.0
hoist-non-react-statics: ^3.3.2
prop-types: ^15.8.1
react-is: ^17.0.2
react-transition-group: ^4.4.2
peerDependencies:
"@emotion/react": ^11.5.0
"@emotion/styled": ^11.3.0
"@types/react": ^17.0.0 || ^18.0.0
react: ^17.0.0 || ^18.0.0
react-dom: ^17.0.0 || ^18.0.0
peerDependenciesMeta:
"@emotion/react":
optional: true
"@emotion/styled":
optional: true
"@types/react":
optional: true
checksum: 2957cb50478099579f83b187df6faaaf4dc794b7948bdb5263bee68ce005f1037b6a6b78420e60dbacf6911c616601337ca884e118804753d15fbea6364c5626
languageName: node
linkType: hard
"@mui/private-theming@npm:^5.8.0":
version: 5.8.0
resolution: "@mui/private-theming@npm:5.8.0"
dependencies:
"@babel/runtime": ^7.17.2
"@mui/utils": ^5.8.0
prop-types: ^15.8.1
peerDependencies:
"@types/react": ^17.0.0 || ^18.0.0
react: ^17.0.0 || ^18.0.0
peerDependenciesMeta:
"@types/react":
optional: true
checksum: 6107b579409913a5e0d6d79fbe074ae4ad55e57f7a485da4542a5772be86b835994311609e84e4e881ea187c5b8892e432bcce9ac98d4e69dd7ace55da675f8a
languageName: node
linkType: hard
"@mui/styled-engine@npm:^5.8.0":
version: 5.8.0
resolution: "@mui/styled-engine@npm:5.8.0"
dependencies:
"@babel/runtime": ^7.17.2
"@emotion/cache": ^11.7.1
prop-types: ^15.8.1
peerDependencies:
"@emotion/react": ^11.4.1
"@emotion/styled": ^11.3.0
react: ^17.0.0 || ^18.0.0
peerDependenciesMeta:
"@emotion/react":
optional: true
"@emotion/styled":
optional: true
checksum: f1140151cb06b72af774e6c14f537879bee0e699fff05cac5f9b1e4483d5202e161dc6d8e23ff7e31e3f660867056689b2225ab1d7ad69f45dc489d9ed058a92
languageName: node
linkType: hard
"@mui/styles@npm:^5.8.0":
version: 5.8.0
resolution: "@mui/styles@npm:5.8.0"
dependencies:
"@babel/runtime": ^7.17.2
"@emotion/hash": ^0.8.0
"@material-ui/types": 5.1.0
"@material-ui/utils": ^4.11.3
clsx: ^1.0.4
csstype: ^2.5.2
"@mui/private-theming": ^5.8.0
"@mui/types": ^7.1.3
"@mui/utils": ^5.8.0
clsx: ^1.1.1
csstype: ^3.0.11
hoist-non-react-statics: ^3.3.2
jss: ^10.5.1
jss-plugin-camel-case: ^10.5.1
jss-plugin-default-unit: ^10.5.1
jss-plugin-global: ^10.5.1
jss-plugin-nested: ^10.5.1
jss-plugin-props-sort: ^10.5.1
jss-plugin-rule-value-function: ^10.5.1
jss-plugin-vendor-prefixer: ^10.5.1
prop-types: ^15.7.2
jss: ^10.8.2
jss-plugin-camel-case: ^10.8.2
jss-plugin-default-unit: ^10.8.2
jss-plugin-global: ^10.8.2
jss-plugin-nested: ^10.8.2
jss-plugin-props-sort: ^10.8.2
jss-plugin-rule-value-function: ^10.8.2
jss-plugin-vendor-prefixer: ^10.8.2
prop-types: ^15.8.1
peerDependencies:
"@types/react": ^16.8.6 || ^17.0.0
react: ^16.8.0 || ^17.0.0
react-dom: ^16.8.0 || ^17.0.0
"@types/react": ^17.0.0
react: ^17.0.0
peerDependenciesMeta:
"@types/react":
optional: true
checksum: dbf3985ef57c1b7dae3fd916d5bfd61f2097afb93c9e1f64832cfcb8fc9bbf38a504c9632ed7b76eb5d235670083d9e66d35942bc976b7cd148c71d75b808e82
checksum: 5c14a9ef6319f008ac6fc20bc5f7a50e20258e29bcce15f4c6224e3248b9bfe4dae52798390b3c8aae98c4ddbec9814df87f942c5e1a8dd1809b0eaf55ab5e37
languageName: node
linkType: hard
"@material-ui/system@npm:^4.12.2":
version: 4.12.2
resolution: "@material-ui/system@npm:4.12.2"
"@mui/system@npm:^5.8.2":
version: 5.8.2
resolution: "@mui/system@npm:5.8.2"
dependencies:
"@babel/runtime": ^7.4.4
"@material-ui/utils": ^4.11.3
csstype: ^2.5.2
prop-types: ^15.7.2
"@babel/runtime": ^7.17.2
"@mui/private-theming": ^5.8.0
"@mui/styled-engine": ^5.8.0
"@mui/types": ^7.1.3
"@mui/utils": ^5.8.0
clsx: ^1.1.1
csstype: ^3.1.0
prop-types: ^15.8.1
peerDependencies:
"@types/react": ^16.8.6 || ^17.0.0
react: ^16.8.0 || ^17.0.0
react-dom: ^16.8.0 || ^17.0.0
"@emotion/react": ^11.5.0
"@emotion/styled": ^11.3.0
"@types/react": ^17.0.0 || ^18.0.0
react: ^17.0.0 || ^18.0.0
peerDependenciesMeta:
"@emotion/react":
optional: true
"@emotion/styled":
optional: true
"@types/react":
optional: true
checksum: ebe6b3cc5f111034eacd763014f3260f7647b5e0cd132870f2ee18855cf3d51a996b4633035fe6f5f8965489944db4ac0cb3b71b84a765faa35a6861532ac9f6
checksum: 1d968620bbca0663308b6940252311dcb1c591a0f94a8ad112252d404e2ff52c9eb343a475e32b2bf5ac1ae3b56f349c1ef2a165b60158b8ea752a177acefea6
languageName: node
linkType: hard
"@material-ui/types@npm:5.1.0":
version: 5.1.0
resolution: "@material-ui/types@npm:5.1.0"
"@mui/types@npm:^7.1.3":
version: 7.1.3
resolution: "@mui/types@npm:7.1.3"
peerDependencies:
"@types/react": "*"
peerDependenciesMeta:
"@types/react":
optional: true
checksum: 64ac0938ee6f48011ba596f7422ab0660d9a8d9b4f5f183b39bd63185b1ce724209f65580f0af686d59b524603ffa57418ca2d443b69bec894303f80779c61f8
checksum: 4990f505f1058bdd4c01ea21a6a6f788e5d3ff73b50962879d33bbf9c98ef1f18d8b6664025ce1dbd42544a79d7697d0011834f8fd83d12c9705f2c702829bb4
languageName: node
linkType: hard
"@material-ui/utils@npm:^4.11.3":
version: 4.11.3
resolution: "@material-ui/utils@npm:4.11.3"
"@mui/utils@npm:^5.8.0":
version: 5.8.0
resolution: "@mui/utils@npm:5.8.0"
dependencies:
"@babel/runtime": ^7.4.4
prop-types: ^15.7.2
react-is: ^16.8.0 || ^17.0.0
"@babel/runtime": ^7.17.2
"@types/prop-types": ^15.7.5
"@types/react-is": ^16.7.1 || ^17.0.0
prop-types: ^15.8.1
react-is: ^17.0.2
peerDependencies:
react: ^16.8.0 || ^17.0.0
react-dom: ^16.8.0 || ^17.0.0
checksum: 05ff67c982b33d3b4260cfaeaf566f3ccaecaebb231907ed626bcc30322d89d705bfe79b8805c0dda2f1dc2cfa98ca9d731ec8ae12868da7a98568a41c7dc231
react: ^17.0.0 || ^18.0.0
checksum: 488b4e709e3f86e7a627f2e61b4c8b3d6fcb606922666b829f5a24c77383ee5776446a30e7b5c10007d03e4e764c3190d608485113d5108e54f79308bddafefc
languageName: node
linkType: hard
@ -2497,6 +2729,13 @@ __metadata:
languageName: node
linkType: hard
"@popperjs/core@npm:^2.11.5":
version: 2.11.5
resolution: "@popperjs/core@npm:2.11.5"
checksum: fd7f9dca3fb716d7426332b6ee283f88d2724c0ab342fb678865a640bad403dfb9eeebd8204a406986162f7e2b33394f104320008b74d0e9066d7322f70ea35d
languageName: node
linkType: hard
"@rollup/plugin-babel@npm:^5.2.0":
version: 5.3.1
resolution: "@rollup/plugin-babel@npm:5.3.1"
@ -2824,6 +3063,34 @@ __metadata:
languageName: node
linkType: hard
"@tsconfig/node10@npm:^1.0.7":
version: 1.0.8
resolution: "@tsconfig/node10@npm:1.0.8"
checksum: b8d5fffbc6b17ef64ef74f7fdbccee02a809a063ade785c3648dae59406bc207f70ea2c4296f92749b33019fa36a5ae716e42e49cc7f1bbf0fd147be0d6b970a
languageName: node
linkType: hard
"@tsconfig/node12@npm:^1.0.7":
version: 1.0.9
resolution: "@tsconfig/node12@npm:1.0.9"
checksum: a01b2400ab3582b86b589c6d31dcd0c0656f333adecde85d6d7d4086adb059808b82692380bb169546d189bf771ae21d02544a75b57bd6da4a5dd95f8567bec9
languageName: node
linkType: hard
"@tsconfig/node14@npm:^1.0.0":
version: 1.0.1
resolution: "@tsconfig/node14@npm:1.0.1"
checksum: 976345e896c0f059867f94f8d0f6ddb8b1844fb62bf36b727de8a9a68f024857e5db97ed51d3325e23e0616a5e48c034ff51a8d595b3fe7e955f3587540489be
languageName: node
linkType: hard
"@tsconfig/node16@npm:^1.0.2":
version: 1.0.2
resolution: "@tsconfig/node16@npm:1.0.2"
checksum: ca94d3639714672bbfd55f03521d3f56bb6a25479bd425da81faf21f13e1e9d15f40f97377dedbbf477a5841c5b0c8f4cd1b391f33553d750b9202c54c2c07aa
languageName: node
linkType: hard
"@types/aria-query@npm:^4.2.0":
version: 4.2.2
resolution: "@types/aria-query@npm:4.2.2"
@ -3252,7 +3519,7 @@ __metadata:
languageName: node
linkType: hard
"@types/prop-types@npm:*":
"@types/prop-types@npm:*, @types/prop-types@npm:^15.7.5":
version: 15.7.5
resolution: "@types/prop-types@npm:15.7.5"
checksum: 5b43b8b15415e1f298243165f1d44390403bb2bd42e662bca3b5b5633fdd39c938e91b7fce3a9483699db0f7a715d08cef220c121f723a634972fdf596aec980
@ -3298,7 +3565,16 @@ __metadata:
languageName: node
linkType: hard
"@types/react-transition-group@npm:^4.2.0":
"@types/react-is@npm:^16.7.1 || ^17.0.0":
version: 17.0.3
resolution: "@types/react-is@npm:17.0.3"
dependencies:
"@types/react": "*"
checksum: 6abb7c47d54f012272650df8a962a28bd82f219291e5ef8b4dfa7fe0bb98ae243b060bf9fbe8ceff6213141794855a006db194b490b00ffd15842ae19d0ce1f0
languageName: node
linkType: hard
"@types/react-transition-group@npm:^4.4.4":
version: 4.4.4
resolution: "@types/react-transition-group@npm:4.4.4"
dependencies:
@ -3858,6 +4134,13 @@ __metadata:
languageName: node
linkType: hard
"acorn-walk@npm:^8.1.1":
version: 8.2.0
resolution: "acorn-walk@npm:8.2.0"
checksum: 1715e76c01dd7b2d4ca472f9c58968516a4899378a63ad5b6c2d668bba8da21a71976c14ec5f5b75f887b6317c4ae0b897ab141c831d741dc76024d8745f1ad1
languageName: node
linkType: hard
"acorn@npm:^7.0.0, acorn@npm:^7.1.1, acorn@npm:^7.4.0":
version: 7.4.1
resolution: "acorn@npm:7.4.1"
@ -4455,6 +4738,17 @@ __metadata:
languageName: node
linkType: hard
"babel-plugin-macros@npm:^2.6.1":
version: 2.8.0
resolution: "babel-plugin-macros@npm:2.8.0"
dependencies:
"@babel/runtime": ^7.7.2
cosmiconfig: ^6.0.0
resolve: ^1.12.0
checksum: 59b09a21cf3ae1e14186c1b021917d004b49b953824b24953a54c6502da79e8051d4ac31cfd4a0ae7f6ea5ddf1f7edd93df4895dd3c3982a5b2431859c2889ac
languageName: node
linkType: hard
"babel-plugin-macros@npm:^3.1.0":
version: 3.1.0
resolution: "babel-plugin-macros@npm:3.1.0"
@ -5215,7 +5509,7 @@ __metadata:
languageName: node
linkType: hard
"clsx@npm:^1.0.4":
"clsx@npm:^1.1.1":
version: 1.1.1
resolution: "clsx@npm:1.1.1"
checksum: ff052650329773b9b245177305fc4c4dc3129f7b2be84af4f58dc5defa99538c61d4207be7419405a5f8f3d92007c954f4daba5a7b74e563d5de71c28c830063
@ -5499,7 +5793,7 @@ __metadata:
languageName: node
linkType: hard
"convert-source-map@npm:^1.4.0, convert-source-map@npm:^1.6.0, convert-source-map@npm:^1.7.0":
"convert-source-map@npm:^1.4.0, convert-source-map@npm:^1.5.0, convert-source-map@npm:^1.6.0, convert-source-map@npm:^1.7.0":
version: 1.8.0
resolution: "convert-source-map@npm:1.8.0"
dependencies:
@ -5977,14 +6271,7 @@ __metadata:
languageName: node
linkType: hard
"csstype@npm:^2.5.2":
version: 2.6.20
resolution: "csstype@npm:2.6.20"
checksum: cb5d5ded49c3390909e93b20b285d4a63d0ba5b10294bdfbc4cf911f80e91d6cf367ea671f99f09570762535c14ea7074a2c7fa73f02008203f01328dea8968b
languageName: node
linkType: hard
"csstype@npm:^3.0.2":
"csstype@npm:^3.0.11, csstype@npm:^3.0.2, csstype@npm:^3.1.0":
version: 3.1.0
resolution: "csstype@npm:3.1.0"
checksum: 644e986cefab86525f0b674a06889cfdbb1f117e5b7d1ce0fc55b0423ecc58807a1ea42ecc75c4f18999d14fc42d1d255f84662a45003a52bb5840e977eb2ffd
@ -7666,6 +7953,13 @@ __metadata:
languageName: node
linkType: hard
"find-root@npm:^1.1.0":
version: 1.1.0
resolution: "find-root@npm:1.1.0"
checksum: b2a59fe4b6c932eef36c45a048ae8f93c85640212ebe8363164814990ee20f154197505965f3f4f102efc33bfb1cbc26fd17c4a2fc739ebc51b886b137cbefaf
languageName: node
linkType: hard
"find-up@npm:^2.1.0":
version: 2.1.0
resolution: "find-up@npm:2.1.0"
@ -8331,7 +8625,7 @@ __metadata:
languageName: node
linkType: hard
"hoist-non-react-statics@npm:^3.3.2":
"hoist-non-react-statics@npm:^3.3.1, hoist-non-react-statics@npm:^3.3.2":
version: 3.3.2
resolution: "hoist-non-react-statics@npm:3.3.2"
dependencies:
@ -10469,7 +10763,7 @@ __metadata:
languageName: node
linkType: hard
"jss-plugin-camel-case@npm:^10.5.1":
"jss-plugin-camel-case@npm:^10.8.2":
version: 10.9.0
resolution: "jss-plugin-camel-case@npm:10.9.0"
dependencies:
@ -10480,7 +10774,7 @@ __metadata:
languageName: node
linkType: hard
"jss-plugin-default-unit@npm:^10.5.1":
"jss-plugin-default-unit@npm:^10.8.2":
version: 10.9.0
resolution: "jss-plugin-default-unit@npm:10.9.0"
dependencies:
@ -10490,7 +10784,7 @@ __metadata:
languageName: node
linkType: hard
"jss-plugin-global@npm:^10.5.1":
"jss-plugin-global@npm:^10.8.2":
version: 10.9.0
resolution: "jss-plugin-global@npm:10.9.0"
dependencies:
@ -10500,7 +10794,7 @@ __metadata:
languageName: node
linkType: hard
"jss-plugin-nested@npm:^10.5.1":
"jss-plugin-nested@npm:^10.8.2":
version: 10.9.0
resolution: "jss-plugin-nested@npm:10.9.0"
dependencies:
@ -10511,7 +10805,7 @@ __metadata:
languageName: node
linkType: hard
"jss-plugin-props-sort@npm:^10.5.1":
"jss-plugin-props-sort@npm:^10.8.2":
version: 10.9.0
resolution: "jss-plugin-props-sort@npm:10.9.0"
dependencies:
@ -10521,7 +10815,7 @@ __metadata:
languageName: node
linkType: hard
"jss-plugin-rule-value-function@npm:^10.5.1":
"jss-plugin-rule-value-function@npm:^10.8.2":
version: 10.9.0
resolution: "jss-plugin-rule-value-function@npm:10.9.0"
dependencies:
@ -10532,7 +10826,7 @@ __metadata:
languageName: node
linkType: hard
"jss-plugin-vendor-prefixer@npm:^10.5.1":
"jss-plugin-vendor-prefixer@npm:^10.8.2":
version: 10.9.0
resolution: "jss-plugin-vendor-prefixer@npm:10.9.0"
dependencies:
@ -10543,7 +10837,7 @@ __metadata:
languageName: node
linkType: hard
"jss@npm:10.9.0, jss@npm:^10.5.1":
"jss@npm:10.9.0, jss@npm:^10.8.2":
version: 10.9.0
resolution: "jss@npm:10.9.0"
dependencies:
@ -11164,7 +11458,7 @@ __metadata:
languageName: node
linkType: hard
"minimist@npm:^1.1.1, minimist@npm:^1.2.0, minimist@npm:^1.2.3, minimist@npm:^1.2.5, minimist@npm:^1.2.6":
"minimist@npm:^1.1.1, minimist@npm:^1.2.0, minimist@npm:^1.2.3, minimist@npm:^1.2.6":
version: 1.2.6
resolution: "minimist@npm:1.2.6"
checksum: d15428cd1e11eb14e1233bcfb88ae07ed7a147de251441d61158619dfb32c4d7e9061d09cab4825fdee18ecd6fce323228c8c47b5ba7cd20af378ca4048fb3fb
@ -12210,13 +12504,6 @@ __metadata:
languageName: node
linkType: hard
"popper.js@npm:1.16.1-lts":
version: 1.16.1-lts
resolution: "popper.js@npm:1.16.1-lts"
checksum: 27c00b5b07afa91a5e9f9db78a9a61b50f44ca156d09c851cd29d79cd359e54cfde4288ae555b88801438227e452e56cb4b56bd79fd45ab17dac780a70a7e9ac
languageName: node
linkType: hard
"posix-character-classes@npm:^0.1.0":
version: 0.1.1
resolution: "posix-character-classes@npm:0.1.1"
@ -13185,7 +13472,7 @@ __metadata:
languageName: node
linkType: hard
"prop-types@npm:^15.5.8, prop-types@npm:^15.6.2, prop-types@npm:^15.7.2, prop-types@npm:^15.8.1":
"prop-types@npm:^15.5.8, prop-types@npm:^15.6.2, prop-types@npm:^15.8.1":
version: 15.8.1
resolution: "prop-types@npm:15.8.1"
dependencies:
@ -13434,7 +13721,7 @@ __metadata:
languageName: node
linkType: hard
"react-is@npm:^16.8.0 || ^17.0.0, react-is@npm:^17.0.1":
"react-is@npm:^17.0.1, react-is@npm:^17.0.2":
version: 17.0.2
resolution: "react-is@npm:17.0.2"
checksum: 9d6d111d8990dc98bc5402c1266a808b0459b5d54830bbea24c12d908b536df7883f268a7868cfaedde3dd9d4e0d574db456f84d2e6df9c4526f99bb4b5344d8
@ -13522,7 +13809,7 @@ __metadata:
languageName: node
linkType: hard
"react-transition-group@npm:^4.4.0":
"react-transition-group@npm:^4.4.2":
version: 4.4.2
resolution: "react-transition-group@npm:4.4.2"
dependencies:
@ -13905,7 +14192,7 @@ __metadata:
languageName: node
linkType: hard
"resolve@npm:^1.0.0, resolve@npm:^1.10.0, resolve@npm:^1.14.2, resolve@npm:^1.18.1, resolve@npm:^1.19.0, resolve@npm:^1.20.0, resolve@npm:^1.22.0":
"resolve@npm:^1.0.0, resolve@npm:^1.10.0, resolve@npm:^1.12.0, resolve@npm:^1.14.2, resolve@npm:^1.18.1, resolve@npm:^1.19.0, resolve@npm:^1.20.0, resolve@npm:^1.22.0":
version: 1.22.0
resolution: "resolve@npm:1.22.0"
dependencies:
@ -13928,7 +14215,7 @@ __metadata:
languageName: node
linkType: hard
"resolve@patch:resolve@^1.0.0#~builtin<compat/resolve>, resolve@patch:resolve@^1.10.0#~builtin<compat/resolve>, resolve@patch:resolve@^1.14.2#~builtin<compat/resolve>, resolve@patch:resolve@^1.18.1#~builtin<compat/resolve>, resolve@patch:resolve@^1.19.0#~builtin<compat/resolve>, resolve@patch:resolve@^1.20.0#~builtin<compat/resolve>, resolve@patch:resolve@^1.22.0#~builtin<compat/resolve>":
"resolve@patch:resolve@^1.0.0#~builtin<compat/resolve>, resolve@patch:resolve@^1.10.0#~builtin<compat/resolve>, resolve@patch:resolve@^1.12.0#~builtin<compat/resolve>, resolve@patch:resolve@^1.14.2#~builtin<compat/resolve>, resolve@patch:resolve@^1.18.1#~builtin<compat/resolve>, resolve@patch:resolve@^1.19.0#~builtin<compat/resolve>, resolve@patch:resolve@^1.20.0#~builtin<compat/resolve>, resolve@patch:resolve@^1.22.0#~builtin<compat/resolve>":
version: 1.22.0
resolution: "resolve@patch:resolve@npm%3A1.22.0#~builtin<compat/resolve>::version=1.22.0&hash=07638b"
dependencies:
@ -14376,8 +14663,8 @@ __metadata:
supertest: ^6.0.1
tmp: ^0.2.1
ts-jest: ^26.4.4
ts-node: ^9.1.1
ts-node-dev: ^1.1.1
ts-node: ^10.8.1
ts-node-dev: ^2.0.0
typescript: ^4.1.3
winston: ^3.3.3
languageName: unknown
@ -14681,7 +14968,7 @@ __metadata:
languageName: node
linkType: hard
"source-map-support@npm:^0.5.12, source-map-support@npm:^0.5.17, source-map-support@npm:^0.5.6, source-map-support@npm:~0.5.20":
"source-map-support@npm:^0.5.12, source-map-support@npm:^0.5.6, source-map-support@npm:~0.5.20":
version: 0.5.21
resolution: "source-map-support@npm:0.5.21"
dependencies:
@ -14705,7 +14992,7 @@ __metadata:
languageName: node
linkType: hard
"source-map@npm:^0.5.6":
"source-map@npm:^0.5.6, source-map@npm:^0.5.7":
version: 0.5.7
resolution: "source-map@npm:0.5.7"
checksum: 5dc2043b93d2f194142c7f38f74a24670cd7a0063acdaf4bf01d2964b402257ae843c2a8fa822ad5b71013b5fcafa55af7421383da919752f22ff488bc553f4d
@ -15149,6 +15436,13 @@ __metadata:
languageName: node
linkType: hard
"stylis@npm:4.0.13":
version: 4.0.13
resolution: "stylis@npm:4.0.13"
checksum: 8ea7a87028b6383c6a982231c4b5b6150031ce028e0fdaf7b2ace82253d28a8af50cc5a9da8a421d3c7c4441592f393086e332795add672aa4a825f0fe3713a3
languageName: node
linkType: hard
"superagent@npm:^7.1.3":
version: 7.1.6
resolution: "superagent@npm:7.1.6"
@ -15676,19 +15970,19 @@ __metadata:
languageName: node
linkType: hard
"ts-node-dev@npm:^1.1.1":
version: 1.1.8
resolution: "ts-node-dev@npm:1.1.8"
"ts-node-dev@npm:^2.0.0":
version: 2.0.0
resolution: "ts-node-dev@npm:2.0.0"
dependencies:
chokidar: ^3.5.1
dynamic-dedupe: ^0.3.0
minimist: ^1.2.5
minimist: ^1.2.6
mkdirp: ^1.0.4
resolve: ^1.0.0
rimraf: ^2.6.1
source-map-support: ^0.5.12
tree-kill: ^1.2.2
ts-node: ^9.0.0
ts-node: ^10.4.0
tsconfig: ^7.0.0
peerDependencies:
node-notifier: "*"
@ -15699,28 +15993,45 @@ __metadata:
bin:
ts-node-dev: lib/bin.js
tsnd: lib/bin.js
checksum: 768a5806215ca78694d39b85ec6877ba41d33b5affcbedc8208f0e4befd5ba1cffbcc505d5d8eca82ea23a4517a79be5f5de6350cb6e249425c832f4ddf10a0f
checksum: d654b401de3d13c167981481be2a375229f6bfd2aeedf43bc0b6816e57676fcbfba3afdcf209c7a06fb6bd8768ca548c2eb0a0c9d38fa42246be3f50df1b28fb
languageName: node
linkType: hard
"ts-node@npm:^9.0.0, ts-node@npm:^9.1.1":
version: 9.1.1
resolution: "ts-node@npm:9.1.1"
"ts-node@npm:^10.4.0, ts-node@npm:^10.8.1":
version: 10.8.1
resolution: "ts-node@npm:10.8.1"
dependencies:
"@cspotcode/source-map-support": ^0.8.0
"@tsconfig/node10": ^1.0.7
"@tsconfig/node12": ^1.0.7
"@tsconfig/node14": ^1.0.0
"@tsconfig/node16": ^1.0.2
acorn: ^8.4.1
acorn-walk: ^8.1.1
arg: ^4.1.0
create-require: ^1.1.0
diff: ^4.0.1
make-error: ^1.1.1
source-map-support: ^0.5.17
v8-compile-cache-lib: ^3.0.1
yn: 3.1.1
peerDependencies:
"@swc/core": ">=1.2.50"
"@swc/wasm": ">=1.2.50"
"@types/node": "*"
typescript: ">=2.7"
peerDependenciesMeta:
"@swc/core":
optional: true
"@swc/wasm":
optional: true
bin:
ts-node: dist/bin.js
ts-node-cwd: dist/bin-cwd.js
ts-node-esm: dist/bin-esm.js
ts-node-script: dist/bin-script.js
ts-node-transpile-only: dist/bin-transpile.js
ts-script: dist/bin-script-deprecated.js
checksum: 356e2647b8b1e6ab00380c0537fa569b63bd9b6f006cc40fd650f81fae1817bd8fecc075300036950d8f45c1d85b95be33cd1e48a1a424a7d86c3dbb42bf60e5
checksum: 7d1aa7aa3ae1c0459c4922ed0dbfbade442cfe0c25aebaf620cdf1774f112c8d7a9b14934cb6719274917f35b2c503ba87bcaf5e16a0d39ba0f68ce3e7728363
languageName: node
linkType: hard
@ -16080,6 +16391,13 @@ __metadata:
languageName: node
linkType: hard
"v8-compile-cache-lib@npm:^3.0.1":
version: 3.0.1
resolution: "v8-compile-cache-lib@npm:3.0.1"
checksum: 78089ad549e21bcdbfca10c08850022b22024cdcc2da9b168bcf5a73a6ed7bf01a9cebb9eac28e03cd23a684d81e0502797e88f3ccd27a32aeab1cfc44c39da0
languageName: node
linkType: hard
"v8-compile-cache@npm:^2.0.3":
version: 2.3.0
resolution: "v8-compile-cache@npm:2.3.0"
@ -16190,8 +16508,11 @@ __metadata:
version: 0.0.0-use.local
resolution: "web@workspace:packages/web"
dependencies:
"@emotion/react": ^11.9.0
"@emotion/styled": ^11.8.1
"@fontsource/roboto": ^4.2.1
"@material-ui/core": ^4.11.3
"@mui/material": ^5.8.2
"@mui/styles": ^5.8.0
"@testing-library/jest-dom": ^5.11.4
"@testing-library/react": ^11.1.0
"@testing-library/user-event": ^12.1.10