модалка - на ревью

This commit is contained in:
Nikolai 2022-09-14 13:24:02 +03:00
parent 27c1a782ed
commit 072fe6f848
9 changed files with 202 additions and 425 deletions

@ -1,185 +0,0 @@
import React from "react";
import {
BrowserRouter as Router,
Switch,
Route,
Link,
useHistory,
useLocation,
useParams
} from "react-router-dom";
// This example shows how to render two different screens
// (or the same screen in a different context) at the same URL,
// depending on how you got there.
//
// Click the "featured images" and see them full screen. Then
// "visit the gallery" and click on the colors. Note the URL and
// the component are the same as before but now we see them
// inside a modal on top of the gallery screen.
export default function ModalGalleryExample() {
return (
<Router>
<ModalSwitch />
</Router>
);
}
function ModalSwitch() {
let location = useLocation();
// This piece of state is set when one of the
// gallery links is clicked. The `background` state
// is the location that we were at when one of
// the gallery links was clicked. If it's there,
// use it as the location for the <Switch> so
// we show the gallery in the background, behind
// the modal.
let background = location.state && location.state.background;
return (
<div>
<Switch location={background || location}>
<Route exact path="/" children={<Home />} />
<Route path="/gallery" children={<Gallery />} />
<Route path="/img/:id" children={<ImageView />} />
</Switch>
{/* Show the modal when a background page is set */}
{background && <Route path="/img/:id" children={<Modal />} />}
</div>
);
}
const IMAGES = [
{ id: 0, title: "Dark Orchid", color: "DarkOrchid" },
{ id: 1, title: "Lime Green", color: "LimeGreen" },
{ id: 2, title: "Tomato", color: "Tomato" },
{ id: 3, title: "Seven Ate Nine", color: "#789" },
{ id: 4, title: "Crimson", color: "Crimson" }
];
function Thumbnail({ color }) {
return (
<div
style={{
width: 50,
height: 50,
background: color
}}
/>
);
}
function Image({ color }) {
return (
<div
style={{
width: "100%",
height: 400,
background: color
}}
/>
);
}
function Home() {
return (
<div>
<Link to="/gallery">Visit the Gallery</Link>
<h2>Featured Images</h2>
<ul>
<li>
<Link to="/img/2">Tomato</Link>
</li>
<li>
<Link to="/img/4">Crimson</Link>
</li>
</ul>
</div>
);
}
function Gallery() {
let location = useLocation();
return (
<div>
{IMAGES.map(i => (
<Link
key={i.id}
to={{
pathname: `/img/${i.id}`,
// This is the trick! This link sets
// the `background` in location state.
state: { background: location }
}}
>
<Thumbnail color={i.color} />
<p>{i.title}</p>
</Link>
))}
</div>
);
}
function ImageView() {
let { id } = useParams();
let image = IMAGES[parseInt(id, 10)];
if (!image) return <div>Image not found</div>;
return (
<div>
<h1>{image.title}</h1>
<Image color={image.color} />
</div>
);
}
function Modal() {
let history = useHistory();
let { id } = useParams();
let image = IMAGES[parseInt(id, 10)];
if (!image) return null;
let back = e => {
e.stopPropagation();
history.goBack();
};
return (
<div
onClick={back}
style={{
position: "absolute",
top: 0,
left: 0,
bottom: 0,
right: 0,
background: "rgba(0, 0, 0, 0.15)"
}}
>
<div
className="modal"
style={{
position: "absolute",
background: "#fff",
top: 25,
left: "10%",
right: "10%",
padding: 15,
border: "2px solid #444"
}}
>
<h1>{image.title}</h1>
<Image color={image.color} />
<button type="button" onClick={back}>
Close
</button>
</div>
</div>
);
}

48
package-lock.json generated

@ -26,7 +26,8 @@
"react-scripts": "5.0.1",
"styled-components": "^5.3.5",
"typescript": "^4.8.2",
"web-vitals": "^2.1.4"
"web-vitals": "^2.1.4",
"zustand": "^4.1.1"
}
},
"node_modules/@adobe/css-tools": {
@ -16240,6 +16241,14 @@
"requires-port": "^1.0.0"
}
},
"node_modules/use-sync-external-store": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz",
"integrity": "sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==",
"peerDependencies": {
"react": "^16.8.0 || ^17.0.0 || ^18.0.0"
}
},
"node_modules/util-deprecate": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
@ -17219,6 +17228,29 @@
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/zustand": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/zustand/-/zustand-4.1.1.tgz",
"integrity": "sha512-h4F3WMqsZgvvaE0n3lThx4MM81Ls9xebjvrABNzf5+jb3/03YjNTSgZXeyrvXDArMeV9untvWXRw1tY+ntPYbA==",
"dependencies": {
"use-sync-external-store": "1.2.0"
},
"engines": {
"node": ">=12.7.0"
},
"peerDependencies": {
"immer": ">=9.0",
"react": ">=16.8"
},
"peerDependenciesMeta": {
"immer": {
"optional": true
},
"react": {
"optional": true
}
}
}
},
"dependencies": {
@ -28616,6 +28648,12 @@
"requires-port": "^1.0.0"
}
},
"use-sync-external-store": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz",
"integrity": "sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==",
"requires": {}
},
"util-deprecate": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
@ -29379,6 +29417,14 @@
"version": "0.1.0",
"resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz",
"integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q=="
},
"zustand": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/zustand/-/zustand-4.1.1.tgz",
"integrity": "sha512-h4F3WMqsZgvvaE0n3lThx4MM81Ls9xebjvrABNzf5+jb3/03YjNTSgZXeyrvXDArMeV9untvWXRw1tY+ntPYbA==",
"requires": {
"use-sync-external-store": "1.2.0"
}
}
}
}

@ -21,7 +21,8 @@
"react-scripts": "5.0.1",
"styled-components": "^5.3.5",
"typescript": "^4.8.2",
"web-vitals": "^2.1.4"
"web-vitals": "^2.1.4",
"zustand": "^4.1.1"
},
"scripts": {
"start": "react-scripts start",

@ -1,14 +1,25 @@
import * as React from "react";
import { Box } from "@mui/material";
import { ThemeProvider } from "@mui/material";
import theme from "../../theme";
import CssBaseline from '@mui/material/CssBaseline';
import Menu from "../Menu";
import Header from "../Header";
import Content from "../Content";
import ModalWindow from "../ModalWindow";
import theme from "../../theme";
import { useMatch } from "react-router-dom";
import useStore from "../../store";
const CenterBox: React.FC = () => {
const LoggedIn: React.FC = () => {
const handleOpen = useStore((state) => state.handleOpen);
const handleClose = useStore((state) => state.handleClose);
const match = useMatch('/modal');
match ? handleOpen() : handleClose()
return (
<React.Fragment>
<ThemeProvider theme={theme}>
@ -37,12 +48,14 @@ const CenterBox: React.FC = () => {
<Content />
</Box>
</Box>
</Box>
<ModalWindow />
</ThemeProvider>
</React.Fragment>
);
}
export default CenterBox;
export default LoggedIn;

@ -1,132 +0,0 @@
import * as React from "react";
import { Box, Modal, Fade, Backdrop, Typography, Button } from "@mui/material";
import { BrowserRouter, Routes, Route } from "react-router-dom";
import theme from "../../theme";
const ModalWindow: React.FC = () => {
const [open, setOpen] = React.useState(false);
const handleOpen = () => setOpen(true);
const handleClose = () => setOpen(false);
return (
<React.Fragment>
<Button onClick={handleOpen}>Open modal</Button>
<Modal
aria-labelledby="transition-modal-title"
aria-describedby="transition-modal-description"
open={open}
onClose={handleClose}
closeAfterTransition
BackdropComponent={Backdrop}
BackdropProps={{
timeout: 500,
}}
>
<Fade in={open}>
<Box sx={{
position: "absolute" as "absolute",
top: "50%",
left: "50%",
transform: "translate(-50%, -50%)",
width: "90%",
height: "90%",
bgcolor: theme.palette.menu.main,
border: "2px solid #000",
boxShadow: 24,
color: theme.palette.secondary.main,
display: "flex",
flexDirection: "column",
alignItems: "center",
}}>
<Typography id="transition-modal-title" variant="caption">
Проект
</Typography>
<Box sx={{
width: "100%",
marginTop: "15px",
display: "flex"
}}>
<Box sx={{
backgroundColor: theme.palette.grayMedium.main,
width: "155px"
}}>
<Typography variant="h4" sx={{
backgroundColor: theme.palette.grayMedium.main,
width: "100%",
height: "55px", //205px
display: "flex",
flexDirection: "column",
justifyContent: "center",
alignItems: "center",
cursor: "pointer",
}}>
СТАТИСТИКА
</Typography>
<Typography variant="h4" sx={{
backgroundColor: theme.palette.grayMedium.main,
color: theme.palette.grayDisabled.main,
width: "100%",
height: "55px", //205px
display: "flex",
flexDirection: "column",
justifyContent: "center",
alignItems: "center",
cursor: "pointer",
textAlign: "center"
}}>
ТРЕКЕРЫ УСТРОЙСТВ
</Typography>
<Typography variant="h4" sx={{
backgroundColor: theme.palette.grayMedium.main,
color: theme.palette.grayDisabled.main,
width: "100%",
height: "55px", //205px
display: "flex",
flexDirection: "column",
justifyContent: "center",
alignItems: "center",
cursor: "pointer",
textAlign: "center"
}}>
ВВОДЫ
</Typography>
<Typography variant="h4" sx={{
backgroundColor: theme.palette.grayMedium.main,
color: theme.palette.grayDisabled.main,
width: "100%",
height: "55px", //205px
display: "flex",
flexDirection: "column",
justifyContent: "center",
alignItems: "center",
cursor: "pointer",
textAlign: "center"
}}>
ВЫВОДЫ
</Typography>
</Box>
<Box sx={{
backgroundColor: theme.palette.grayMedium.main,
width: "calc(100% - 155px)",
height: "55px",
display: "flex",
flexDirection: "column",
justifyContent: "center",
alignItems: "center"
}}>
Long text Long text Long text Long text Long text
Long text Long text Long text Long text Long text
Long text Long text Long text
</Box>
</Box>
</Box>
</Fade>
</Modal>
</React.Fragment>
);
}
export default ModalWindow;

@ -1,112 +1,128 @@
import * as React from "react";
import { Box, Typography } from "@mui/material";
import { ThemeProvider } from "@mui/material";
import { useNavigate } from "react-router-dom";
import { Box, Modal, Fade, Backdrop, Typography } from "@mui/material";
import theme from "../../theme";
import useStore from "../../store";
const ModalWindow: React.FC = () => {
const open = useStore((state) => state.open);
// const handleClose = useStore((state) => state.handleClose);
const navigate = useNavigate();
return (
<React.Fragment>
<ThemeProvider theme={theme}>
<Box sx={{
position: "absolute" as "absolute",
top: "50%",
left: "50%",
transform: "translate(-50%, -50%)",
width: "90%",
height: "90%",
bgcolor: theme.palette.menu.main,
border: "2px solid #000",
boxShadow: 24,
color: theme.palette.secondary.main,
display: "flex",
flexDirection: "column",
alignItems: "center",
}}>
<Typography id="transition-modal-title" variant="caption">
Проект
</Typography>
<Modal
aria-labelledby="transition-modal-title"
aria-describedby="transition-modal-description"
open={ open }
onClose={ () => navigate(-1) }
closeAfterTransition
BackdropComponent={Backdrop}
BackdropProps={{
timeout: 500,
}}
>
<Fade in={open}>
<Box sx={{
width: "100%",
marginTop: "15px",
display: "flex"
position: "absolute" as "absolute",
top: "50%",
left: "50%",
transform: "translate(-50%, -50%)",
width: "90%",
height: "90%",
bgcolor: theme.palette.menu.main,
boxShadow: 24,
color: theme.palette.secondary.main,
display: "flex",
flexDirection: "column",
alignItems: "center",
}}>
<Typography id="transition-modal-title" variant="caption">
Проект
</Typography>
<Box sx={{
backgroundColor: theme.palette.grayMedium.main,
width: "155px"
width: "100%",
marginTop: "15px",
display: "flex"
}}>
<Typography variant="h4" sx={{
<Box sx={{
backgroundColor: theme.palette.grayMedium.main,
width: "100%",
height: "55px", //205px
width: "155px"
}}>
<Typography variant="h4" sx={{
backgroundColor: theme.palette.grayMedium.main,
width: "100%",
height: "55px", //205px
display: "flex",
flexDirection: "column",
justifyContent: "center",
alignItems: "center",
cursor: "pointer",
}}>
СТАТИСТИКА
</Typography>
<Typography variant="h4" sx={{
backgroundColor: theme.palette.grayMedium.main,
color: theme.palette.grayDisabled.main,
width: "100%",
height: "55px", //205px
display: "flex",
flexDirection: "column",
justifyContent: "center",
alignItems: "center",
cursor: "pointer",
textAlign: "center"
}}>
ТРЕКЕРЫ УСТРОЙСТВ
</Typography>
<Typography variant="h4" sx={{
backgroundColor: theme.palette.grayMedium.main,
color: theme.palette.grayDisabled.main,
width: "100%",
height: "55px", //205px
display: "flex",
flexDirection: "column",
justifyContent: "center",
alignItems: "center",
cursor: "pointer",
textAlign: "center"
}}>
ВВОДЫ
</Typography>
<Typography variant="h4" sx={{
backgroundColor: theme.palette.grayMedium.main,
color: theme.palette.grayDisabled.main,
width: "100%",
height: "55px", //205px
display: "flex",
flexDirection: "column",
justifyContent: "center",
alignItems: "center",
cursor: "pointer",
textAlign: "center"
}}>
ВЫВОДЫ
</Typography>
</Box>
<Box sx={{
backgroundColor: theme.palette.grayMedium.main,
width: "calc(100% - 155px)",
height: "55px",
display: "flex",
flexDirection: "column",
justifyContent: "center",
alignItems: "center",
cursor: "pointer",
alignItems: "center"
}}>
СТАТИСТИКА
</Typography>
<Typography variant="h4" sx={{
backgroundColor: theme.palette.grayMedium.main,
color: theme.palette.grayDisabled.main,
width: "100%",
height: "55px", //205px
display: "flex",
flexDirection: "column",
justifyContent: "center",
alignItems: "center",
cursor: "pointer",
textAlign: "center"
}}>
ТРЕКЕРЫ УСТРОЙСТВ
</Typography>
<Typography variant="h4" sx={{
backgroundColor: theme.palette.grayMedium.main,
color: theme.palette.grayDisabled.main,
width: "100%",
height: "55px", //205px
display: "flex",
flexDirection: "column",
justifyContent: "center",
alignItems: "center",
cursor: "pointer",
textAlign: "center"
}}>
ВВОДЫ
</Typography>
<Typography variant="h4" sx={{
backgroundColor: theme.palette.grayMedium.main,
color: theme.palette.grayDisabled.main,
width: "100%",
height: "55px", //205px
display: "flex",
flexDirection: "column",
justifyContent: "center",
alignItems: "center",
cursor: "pointer",
textAlign: "center"
}}>
ВЫВОДЫ
</Typography>
</Box>
<Box sx={{
backgroundColor: theme.palette.grayMedium.main,
width: "calc(100% - 155px)",
height: "55px",
display: "flex",
flexDirection: "column",
justifyContent: "center",
alignItems: "center"
}}>
Long text Long text Long text Long text Long text
Long text Long text Long text Long text Long text
Long text Long text Long text
Long text Long text Long text Long text Long text
Long text Long text Long text Long text Long text
Long text Long text Long text
</Box>
</Box>
</Box>
</Box>
</ThemeProvider>
</Fade>
</Modal>
</React.Fragment>
);
}

@ -1,6 +1,6 @@
import * as React from "react";
import { useNavigate } from "react-router-dom";
import { Box, Typography, TextField, Button } from "@mui/material";
import { Link } from "react-router-dom";
import Table from '@mui/material/Table';
import TableHead from '@mui/material/TableHead';
import TableBody from '@mui/material/TableBody';
@ -12,19 +12,17 @@ import theme from "../../theme";
const Users: React.FC = () => {
const [selectedValue, setSelectedValue] = React.useState('a');
const handleChange = (event: React.ChangeEvent<HTMLInputElement>) => {
setSelectedValue(event.target.value);
};
const navigate = useNavigate();
return (
<React.Fragment>
<Link to={{
pathname: "/modal",
state: { modal: true }
}}>
<Button
variant="text"
onClick={ () => navigate("/modal") }
sx={{
width: "90%",
height: "60px",
@ -35,11 +33,13 @@ const Users: React.FC = () => {
border: "2px solid",
fontWeight: "normal",
borderColor: theme.palette.golden.main,
color: theme.palette.secondary.main
}} >
color: theme.palette.secondary.main,
"&:hover": {
backgroundColor: theme.palette.menu.main
}
}}>
ИНФОРМАЦИЯ О ПРОЕКТЕ
</Button>
</Link>
<Table sx={{

@ -4,7 +4,6 @@ import { BrowserRouter, Routes, Route } from "react-router-dom";
import Authorization from "./Components/Authorization";
import Sections from "./Components/Sections";
import LoggedIn from "./Components/LoggedIn";
import ModalWindow from "./Components/ModalWindow";
import Error404 from "./Components/Error404";
@ -17,7 +16,7 @@ root.render(
<Route path="/" element={ <Authorization /> } />
<Route path="/dispatch" element={ <Sections /> } />
<Route path="/users" element={ <LoggedIn /> } />
<Route path="/modal" element={ <ModalWindow /> } />
<Route path="/modal" element={ <LoggedIn /> } />
<Route
path="*"
element={ <Error404 /> }

19
src/store.ts Normal file

@ -0,0 +1,19 @@
import create from "zustand";
const useStore = create<StoreState>((set) => ({
open: false,
handleOpen: () => set({ open: true }),
handleClose: () => set({ open: false }),
openModal: () => { }
}))
interface StoreState {
open: boolean
handleOpen: () => void
handleClose: () => void
}
export default useStore;