mirror of
https://github.com/scottlamb/moonfire-nvr.git
synced 2025-04-14 00:09:58 -04:00
Stop using deprecated @mui/styles
I was struggling to upgrade the version of mui stuff (material and date picker). I'm hoping getting rid of the deprecated stuff eases this a bit. I don't love that I can't just use sx on plain HTML stuff and have to wrap it in Box, but oh well. Looks like I'm not alone, fwiw. https://github.com/mui/material-ui/issues/23220
This commit is contained in:
parent
ae502200c0
commit
8d716bf4dd
21045
ui/package-lock.json
generated
21045
ui/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -9,7 +9,6 @@
|
|||||||
"@mui/icons-material": "^5.5.1",
|
"@mui/icons-material": "^5.5.1",
|
||||||
"@mui/lab": "^5.0.0-alpha.73",
|
"@mui/lab": "^5.0.0-alpha.73",
|
||||||
"@mui/material": "^5.5.1",
|
"@mui/material": "^5.5.1",
|
||||||
"@mui/styles": "^5.5.1",
|
|
||||||
"@react-hook/resize-observer": "^1.2.5",
|
"@react-hook/resize-observer": "^1.2.5",
|
||||||
"@types/jest": "^27.4.1",
|
"@types/jest": "^27.4.1",
|
||||||
"@types/node": "^17.0.21",
|
"@types/node": "^17.0.21",
|
||||||
|
@ -6,25 +6,14 @@ import Button from "@mui/material/Button";
|
|||||||
import IconButton from "@mui/material/IconButton";
|
import IconButton from "@mui/material/IconButton";
|
||||||
import Menu from "@mui/material/Menu";
|
import Menu from "@mui/material/Menu";
|
||||||
import MenuItem from "@mui/material/MenuItem";
|
import MenuItem from "@mui/material/MenuItem";
|
||||||
import { Theme } from "@mui/material/styles";
|
import { useTheme } from "@mui/material/styles";
|
||||||
import { createStyles, makeStyles } from "@mui/styles";
|
|
||||||
import Toolbar from "@mui/material/Toolbar";
|
import Toolbar from "@mui/material/Toolbar";
|
||||||
import Typography from "@mui/material/Typography";
|
import Typography from "@mui/material/Typography";
|
||||||
import AccountCircle from "@mui/icons-material/AccountCircle";
|
import AccountCircle from "@mui/icons-material/AccountCircle";
|
||||||
import MenuIcon from "@mui/icons-material/Menu";
|
import MenuIcon from "@mui/icons-material/Menu";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { LoginState } from "./App";
|
import { LoginState } from "./App";
|
||||||
|
import Box from "@mui/material/Box";
|
||||||
const useStyles = makeStyles((theme: Theme) =>
|
|
||||||
createStyles({
|
|
||||||
title: {
|
|
||||||
flexGrow: 1,
|
|
||||||
},
|
|
||||||
activity: {
|
|
||||||
marginRight: theme.spacing(2),
|
|
||||||
},
|
|
||||||
})
|
|
||||||
);
|
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
loginState: LoginState;
|
loginState: LoginState;
|
||||||
@ -36,7 +25,7 @@ interface Props {
|
|||||||
|
|
||||||
// https://material-ui.com/components/app-bar/
|
// https://material-ui.com/components/app-bar/
|
||||||
function MoonfireMenu(props: Props) {
|
function MoonfireMenu(props: Props) {
|
||||||
const classes = useStyles();
|
const theme = useTheme();
|
||||||
const [accountMenuAnchor, setAccountMenuAnchor] =
|
const [accountMenuAnchor, setAccountMenuAnchor] =
|
||||||
React.useState<null | HTMLElement>(null);
|
React.useState<null | HTMLElement>(null);
|
||||||
|
|
||||||
@ -66,11 +55,13 @@ function MoonfireMenu(props: Props) {
|
|||||||
>
|
>
|
||||||
<MenuIcon />
|
<MenuIcon />
|
||||||
</IconButton>
|
</IconButton>
|
||||||
<Typography variant="h6" className={classes.title}>
|
<Typography variant="h6" sx={{ flexGrow: 1 }}>
|
||||||
Moonfire NVR
|
Moonfire NVR
|
||||||
</Typography>
|
</Typography>
|
||||||
{props.activityMenuPart !== null && (
|
{props.activityMenuPart !== null && (
|
||||||
<div className={classes.activity}>{props.activityMenuPart}</div>
|
<Box sx={{ marginRight: theme.spacing(2) }}>
|
||||||
|
{props.activityMenuPart}
|
||||||
|
</Box>
|
||||||
)}
|
)}
|
||||||
{props.loginState !== "unknown" && props.loginState !== "logged-in" && (
|
{props.loginState !== "unknown" && props.loginState !== "logged-in" && (
|
||||||
<Button color="inherit" onClick={props.requestLogin}>
|
<Button color="inherit" onClick={props.requestLogin}>
|
||||||
|
@ -2,11 +2,11 @@
|
|||||||
// Copyright (C) 2021 The Moonfire NVR Authors; see AUTHORS and LICENSE.txt.
|
// Copyright (C) 2021 The Moonfire NVR Authors; see AUTHORS and LICENSE.txt.
|
||||||
// SPDX-License-Identifier: GPL-v3.0-or-later WITH GPL-3.0-linking-exception
|
// SPDX-License-Identifier: GPL-v3.0-or-later WITH GPL-3.0-linking-exception
|
||||||
|
|
||||||
|
import Box from "@mui/material/Box";
|
||||||
import Card from "@mui/material/Card";
|
import Card from "@mui/material/Card";
|
||||||
import { Camera, Stream, StreamType } from "../types";
|
import { Camera, Stream, StreamType } from "../types";
|
||||||
import Checkbox from "@mui/material/Checkbox";
|
import Checkbox from "@mui/material/Checkbox";
|
||||||
import { useTheme } from "@mui/material/styles";
|
import { useTheme } from "@mui/material/styles";
|
||||||
import { makeStyles } from "@mui/styles";
|
|
||||||
import { ToplevelResponse } from "../api";
|
import { ToplevelResponse } from "../api";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
@ -15,30 +15,9 @@ interface Props {
|
|||||||
setSelected: (selected: Set<number>) => void;
|
setSelected: (selected: Set<number>) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
const useStyles = makeStyles({
|
|
||||||
streamSelectorTable: {
|
|
||||||
fontSize: "0.9rem",
|
|
||||||
"& td:first-child": {
|
|
||||||
paddingRight: "3px",
|
|
||||||
},
|
|
||||||
"& td:not(:first-child)": {
|
|
||||||
textAlign: "center",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
check: {
|
|
||||||
padding: "3px",
|
|
||||||
},
|
|
||||||
"@media (pointer: fine)": {
|
|
||||||
check: {
|
|
||||||
padding: "0px",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
/** Returns a table which allows selecting zero or more streams. */
|
/** Returns a table which allows selecting zero or more streams. */
|
||||||
const StreamMultiSelector = ({ toplevel, selected, setSelected }: Props) => {
|
const StreamMultiSelector = ({ toplevel, selected, setSelected }: Props) => {
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
const classes = useStyles();
|
|
||||||
const setStream = (s: Stream, checked: boolean) => {
|
const setStream = (s: Stream, checked: boolean) => {
|
||||||
const updated = new Set(selected);
|
const updated = new Set(selected);
|
||||||
if (checked) {
|
if (checked) {
|
||||||
@ -92,13 +71,10 @@ const StreamMultiSelector = ({ toplevel, selected, setSelected }: Props) => {
|
|||||||
function checkbox(st: StreamType) {
|
function checkbox(st: StreamType) {
|
||||||
const s = c.streams[st];
|
const s = c.streams[st];
|
||||||
if (s === undefined) {
|
if (s === undefined) {
|
||||||
return (
|
return <Checkbox color="secondary" disabled />;
|
||||||
<Checkbox className={classes.check} color="secondary" disabled />
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
<Checkbox
|
<Checkbox
|
||||||
className={classes.check}
|
|
||||||
size="small"
|
size="small"
|
||||||
checked={selected.has(s.id)}
|
checked={selected.has(s.id)}
|
||||||
color="secondary"
|
color="secondary"
|
||||||
@ -120,7 +96,26 @@ const StreamMultiSelector = ({ toplevel, selected, setSelected }: Props) => {
|
|||||||
padding: theme.spacing(1),
|
padding: theme.spacing(1),
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<table className={classes.streamSelectorTable}>
|
<Box
|
||||||
|
component="table"
|
||||||
|
sx={{
|
||||||
|
fontSize: "0.9rem",
|
||||||
|
"& td:first-child": {
|
||||||
|
paddingRight: "3px",
|
||||||
|
},
|
||||||
|
"& td:not(:first-child)": {
|
||||||
|
textAlign: "center",
|
||||||
|
},
|
||||||
|
"& .MuiCheckbox-root": {
|
||||||
|
padding: "3px",
|
||||||
|
},
|
||||||
|
"@media (pointer: fine)": {
|
||||||
|
"& .MuiCheckbox-root": {
|
||||||
|
padding: "0px",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
>
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<td />
|
<td />
|
||||||
@ -129,7 +124,7 @@ const StreamMultiSelector = ({ toplevel, selected, setSelected }: Props) => {
|
|||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>{cameraRows}</tbody>
|
<tbody>{cameraRows}</tbody>
|
||||||
</table>
|
</Box>
|
||||||
</Card>
|
</Card>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -5,8 +5,7 @@
|
|||||||
import Box from "@mui/material/Box";
|
import Box from "@mui/material/Box";
|
||||||
import Modal from "@mui/material/Modal";
|
import Modal from "@mui/material/Modal";
|
||||||
import Paper from "@mui/material/Paper";
|
import Paper from "@mui/material/Paper";
|
||||||
import { Theme } from "@mui/material/styles";
|
import { useTheme } from "@mui/material/styles";
|
||||||
import { makeStyles } from "@mui/styles";
|
|
||||||
import Table from "@mui/material/Table";
|
import Table from "@mui/material/Table";
|
||||||
import TableContainer from "@mui/material/TableContainer";
|
import TableContainer from "@mui/material/TableContainer";
|
||||||
import utcToZonedTime from "date-fns-tz/utcToZonedTime";
|
import utcToZonedTime from "date-fns-tz/utcToZonedTime";
|
||||||
@ -26,56 +25,6 @@ import { FrameProps } from "../App";
|
|||||||
import IconButton from "@mui/material/IconButton";
|
import IconButton from "@mui/material/IconButton";
|
||||||
import FilterList from "@mui/icons-material/FilterList";
|
import FilterList from "@mui/icons-material/FilterList";
|
||||||
|
|
||||||
const useStyles = makeStyles((theme: Theme) => ({
|
|
||||||
root: {
|
|
||||||
display: "flex",
|
|
||||||
flexWrap: "wrap",
|
|
||||||
margin: theme.spacing(2),
|
|
||||||
},
|
|
||||||
selectors: {
|
|
||||||
width: "max-content",
|
|
||||||
"& .MuiCard-root": {
|
|
||||||
marginRight: theme.spacing(2),
|
|
||||||
marginBottom: theme.spacing(2),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
videoTable: {
|
|
||||||
flexGrow: 1,
|
|
||||||
width: "max-content",
|
|
||||||
height: "max-content",
|
|
||||||
"& .streamHeader": {
|
|
||||||
background: theme.palette.primary.light,
|
|
||||||
color: theme.palette.primary.contrastText,
|
|
||||||
},
|
|
||||||
"& .MuiTableBody-root:not(:last-child):after": {
|
|
||||||
content: "''",
|
|
||||||
display: "block",
|
|
||||||
height: theme.spacing(2),
|
|
||||||
},
|
|
||||||
"& tbody .recording": {
|
|
||||||
cursor: "pointer",
|
|
||||||
},
|
|
||||||
"& .opt": {
|
|
||||||
[theme.breakpoints.down("lg")]: {
|
|
||||||
display: "none",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
// When there's a video modal up, make the content as large as possible
|
|
||||||
// without distorting it. Center it in the screen and ensure that the video
|
|
||||||
// element only takes up the space actually used by the content, so that
|
|
||||||
// clicking outside it will dismiss the modal.
|
|
||||||
videoModal: {
|
|
||||||
display: "flex",
|
|
||||||
alignItems: "center",
|
|
||||||
justifyContent: "center",
|
|
||||||
"& video": {
|
|
||||||
objectFit: "fill",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}));
|
|
||||||
|
|
||||||
interface FullScreenVideoProps {
|
interface FullScreenVideoProps {
|
||||||
src: string;
|
src: string;
|
||||||
aspect: [number, number];
|
aspect: [number, number];
|
||||||
@ -225,7 +174,7 @@ const calcSelectedStreams = (
|
|||||||
};
|
};
|
||||||
|
|
||||||
const Main = ({ toplevel, timeZoneName, Frame }: Props) => {
|
const Main = ({ toplevel, timeZoneName, Frame }: Props) => {
|
||||||
const classes = useStyles();
|
const theme = useTheme();
|
||||||
|
|
||||||
const {
|
const {
|
||||||
selectedStreamIds,
|
selectedStreamIds,
|
||||||
@ -288,7 +237,31 @@ const Main = ({ toplevel, timeZoneName, Frame }: Props) => {
|
|||||||
setActiveRecording(null);
|
setActiveRecording(null);
|
||||||
};
|
};
|
||||||
const recordingsTable = (
|
const recordingsTable = (
|
||||||
<TableContainer component={Paper} className={classes.videoTable}>
|
<TableContainer
|
||||||
|
component={Paper}
|
||||||
|
sx={{
|
||||||
|
flexGrow: 1,
|
||||||
|
width: "max-content",
|
||||||
|
height: "max-content",
|
||||||
|
"& .streamHeader": {
|
||||||
|
background: theme.palette.primary.light,
|
||||||
|
color: theme.palette.primary.contrastText,
|
||||||
|
},
|
||||||
|
"& .MuiTableBody-root:not(:last-child):after": {
|
||||||
|
content: "''",
|
||||||
|
display: "block",
|
||||||
|
height: theme.spacing(2),
|
||||||
|
},
|
||||||
|
"& tbody .recording": {
|
||||||
|
cursor: "pointer",
|
||||||
|
},
|
||||||
|
"& .opt": {
|
||||||
|
[theme.breakpoints.down("lg")]: {
|
||||||
|
display: "none",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
>
|
||||||
<Table size="small">{videoLists}</Table>
|
<Table size="small">{videoLists}</Table>
|
||||||
</TableContainer>
|
</TableContainer>
|
||||||
);
|
);
|
||||||
@ -305,10 +278,22 @@ const Main = ({ toplevel, timeZoneName, Frame }: Props) => {
|
|||||||
</IconButton>
|
</IconButton>
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<div className={classes.root}>
|
<Box
|
||||||
|
sx={{
|
||||||
|
display: "flex",
|
||||||
|
flexWrap: "wrap",
|
||||||
|
margin: theme.spacing(2),
|
||||||
|
}}
|
||||||
|
>
|
||||||
<Box
|
<Box
|
||||||
className={classes.selectors}
|
sx={{
|
||||||
sx={{ display: showSelectors ? "block" : "none" }}
|
display: showSelectors ? "block" : "none",
|
||||||
|
width: "max-content",
|
||||||
|
"& .MuiCard-root": {
|
||||||
|
marginRight: theme.spacing(2),
|
||||||
|
marginBottom: theme.spacing(2),
|
||||||
|
},
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
<StreamMultiSelector
|
<StreamMultiSelector
|
||||||
toplevel={toplevel}
|
toplevel={toplevel}
|
||||||
@ -331,7 +316,22 @@ const Main = ({ toplevel, timeZoneName, Frame }: Props) => {
|
|||||||
</Box>
|
</Box>
|
||||||
{videoLists.length > 0 && recordingsTable}
|
{videoLists.length > 0 && recordingsTable}
|
||||||
{activeRecording != null && (
|
{activeRecording != null && (
|
||||||
<Modal open onClose={closeModal} className={classes.videoModal}>
|
<Modal
|
||||||
|
open
|
||||||
|
onClose={closeModal}
|
||||||
|
sx={{
|
||||||
|
// Make the content as large as possible without distorting it.
|
||||||
|
// Center it in the screen and ensure that the video element only
|
||||||
|
// takes up the space actually used by the content, so that clicking
|
||||||
|
// outside it will dismiss the modal.
|
||||||
|
display: "flex",
|
||||||
|
alignItems: "center",
|
||||||
|
justifyContent: "center",
|
||||||
|
"& video": {
|
||||||
|
objectFit: "fill",
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
>
|
||||||
<FullScreenVideo
|
<FullScreenVideo
|
||||||
src={api.recordingUrl(
|
src={api.recordingUrl(
|
||||||
activeRecording[0].camera.uuid,
|
activeRecording[0].camera.uuid,
|
||||||
@ -347,7 +347,7 @@ const Main = ({ toplevel, timeZoneName, Frame }: Props) => {
|
|||||||
/>
|
/>
|
||||||
</Modal>
|
</Modal>
|
||||||
)}
|
)}
|
||||||
</div>
|
</Box>
|
||||||
</Frame>
|
</Frame>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -2,12 +2,12 @@
|
|||||||
// Copyright (C) 2021 The Moonfire NVR Authors; see AUTHORS and LICENSE.txt.
|
// Copyright (C) 2021 The Moonfire NVR Authors; see AUTHORS and LICENSE.txt.
|
||||||
// SPDX-License-Identifier: GPL-v3.0-or-later WITH GPL-3.0-linking-exception
|
// SPDX-License-Identifier: GPL-v3.0-or-later WITH GPL-3.0-linking-exception
|
||||||
|
|
||||||
|
import Box from "@mui/material/Box";
|
||||||
import Select, { SelectChangeEvent } from "@mui/material/Select";
|
import Select, { SelectChangeEvent } from "@mui/material/Select";
|
||||||
import MenuItem from "@mui/material/MenuItem";
|
import MenuItem from "@mui/material/MenuItem";
|
||||||
import React, { useReducer } from "react";
|
import React, { useReducer } from "react";
|
||||||
import { Camera } from "../types";
|
import { Camera } from "../types";
|
||||||
import { makeStyles } from "@mui/styles";
|
import { useTheme } from "@mui/material/styles";
|
||||||
import { Theme } from "@mui/material/styles";
|
|
||||||
import { useSearchParams } from "react-router-dom";
|
import { useSearchParams } from "react-router-dom";
|
||||||
|
|
||||||
export interface Layout {
|
export interface Layout {
|
||||||
@ -24,52 +24,6 @@ const LAYOUTS: Layout[] = [
|
|||||||
];
|
];
|
||||||
const MAX_CAMERAS = 9;
|
const MAX_CAMERAS = 9;
|
||||||
|
|
||||||
const useStyles = makeStyles((theme: Theme) => ({
|
|
||||||
root: {
|
|
||||||
flex: "1 0 0",
|
|
||||||
color: "white",
|
|
||||||
marginTop: theme.spacing(2),
|
|
||||||
overflow: "hidden",
|
|
||||||
|
|
||||||
// TODO: this mid-level div can probably be removed.
|
|
||||||
"& .mid": {
|
|
||||||
width: "100%",
|
|
||||||
height: "100%",
|
|
||||||
position: "relative",
|
|
||||||
display: "inline-block",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
inner: {
|
|
||||||
// match parent's size without influencing it.
|
|
||||||
position: "absolute",
|
|
||||||
width: "100%",
|
|
||||||
height: "100%",
|
|
||||||
|
|
||||||
backgroundColor: "#000",
|
|
||||||
overflow: "hidden",
|
|
||||||
display: "grid",
|
|
||||||
gridGap: "0px",
|
|
||||||
|
|
||||||
// These class names must match LAYOUTS (above).
|
|
||||||
"&.solo": {
|
|
||||||
gridTemplateColumns: "100%",
|
|
||||||
gridTemplateRows: "100%",
|
|
||||||
},
|
|
||||||
"&.two-by-two": {
|
|
||||||
gridTemplateColumns: "repeat(2, calc(100% / 2))",
|
|
||||||
gridTemplateRows: "repeat(2, calc(100% / 2))",
|
|
||||||
},
|
|
||||||
"&.main-plus-five, &.three-by-three": {
|
|
||||||
gridTemplateColumns: "repeat(3, calc(100% / 3))",
|
|
||||||
gridTemplateRows: "repeat(3, calc(100% / 3))",
|
|
||||||
},
|
|
||||||
"&.main-plus-five > div:nth-child(1)": {
|
|
||||||
gridColumn: "span 2",
|
|
||||||
gridRow: "span 2",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}));
|
|
||||||
|
|
||||||
export interface MultiviewProps {
|
export interface MultiviewProps {
|
||||||
cameras: Camera[];
|
cameras: Camera[];
|
||||||
layoutIndex: number;
|
layoutIndex: number;
|
||||||
@ -152,6 +106,7 @@ function selectedReducer(old: SelectedCameras, op: SelectOp): SelectedCameras {
|
|||||||
*/
|
*/
|
||||||
const Multiview = (props: MultiviewProps) => {
|
const Multiview = (props: MultiviewProps) => {
|
||||||
const [searchParams, setSearchParams] = useSearchParams();
|
const [searchParams, setSearchParams] = useSearchParams();
|
||||||
|
const theme = useTheme();
|
||||||
|
|
||||||
const [selected, updateSelected] = useReducer(
|
const [selected, updateSelected] = useReducer(
|
||||||
selectedReducer,
|
selectedReducer,
|
||||||
@ -161,7 +116,6 @@ const Multiview = (props: MultiviewProps) => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
const outerRef = React.useRef<HTMLDivElement>(null);
|
const outerRef = React.useRef<HTMLDivElement>(null);
|
||||||
const classes = useStyles();
|
|
||||||
const layout = LAYOUTS[props.layoutIndex];
|
const layout = LAYOUTS[props.layoutIndex];
|
||||||
|
|
||||||
const monoviews = selected.slice(0, layout.cameras).map((e, i) => {
|
const monoviews = selected.slice(0, layout.cameras).map((e, i) => {
|
||||||
@ -194,13 +148,60 @@ const Multiview = (props: MultiviewProps) => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={classes.root} ref={outerRef}>
|
<Box
|
||||||
|
ref={outerRef}
|
||||||
|
sx={{
|
||||||
|
flex: "1 0 0",
|
||||||
|
color: "white",
|
||||||
|
marginTop: theme.spacing(2),
|
||||||
|
overflow: "hidden",
|
||||||
|
|
||||||
|
// TODO: this mid-level div can probably be removed.
|
||||||
|
"& > .mid": {
|
||||||
|
width: "100%",
|
||||||
|
height: "100%",
|
||||||
|
position: "relative",
|
||||||
|
display: "inline-block",
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
>
|
||||||
<div className="mid">
|
<div className="mid">
|
||||||
<div className={`${classes.inner} ${layout.className}`}>
|
<Box
|
||||||
|
className={layout.className}
|
||||||
|
sx={{
|
||||||
|
// match parent's size without influencing it.
|
||||||
|
position: "absolute",
|
||||||
|
width: "100%",
|
||||||
|
height: "100%",
|
||||||
|
|
||||||
|
backgroundColor: "#000",
|
||||||
|
overflow: "hidden",
|
||||||
|
display: "grid",
|
||||||
|
gridGap: "0px",
|
||||||
|
|
||||||
|
// These class names must match LAYOUTS (above).
|
||||||
|
"&.solo": {
|
||||||
|
gridTemplateColumns: "100%",
|
||||||
|
gridTemplateRows: "100%",
|
||||||
|
},
|
||||||
|
"&.two-by-two": {
|
||||||
|
gridTemplateColumns: "repeat(2, calc(100% / 2))",
|
||||||
|
gridTemplateRows: "repeat(2, calc(100% / 2))",
|
||||||
|
},
|
||||||
|
"&.main-plus-five, &.three-by-three": {
|
||||||
|
gridTemplateColumns: "repeat(3, calc(100% / 3))",
|
||||||
|
gridTemplateRows: "repeat(3, calc(100% / 3))",
|
||||||
|
},
|
||||||
|
"&.main-plus-five > div:nth-child(1)": {
|
||||||
|
gridColumn: "span 2",
|
||||||
|
gridRow: "span 2",
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
>
|
||||||
{monoviews}
|
{monoviews}
|
||||||
</div>
|
</Box>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</Box>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -8,8 +8,7 @@ import DialogActions from "@mui/material/DialogActions";
|
|||||||
import DialogTitle from "@mui/material/DialogTitle";
|
import DialogTitle from "@mui/material/DialogTitle";
|
||||||
import FormControl from "@mui/material/FormControl";
|
import FormControl from "@mui/material/FormControl";
|
||||||
import FormHelperText from "@mui/material/FormHelperText";
|
import FormHelperText from "@mui/material/FormHelperText";
|
||||||
import { Theme } from "@mui/material/styles";
|
import { useTheme } from "@mui/material/styles";
|
||||||
import { makeStyles } from "@mui/styles";
|
|
||||||
import TextField from "@mui/material/TextField";
|
import TextField from "@mui/material/TextField";
|
||||||
import LockOutlinedIcon from "@mui/icons-material/LockOutlined";
|
import LockOutlinedIcon from "@mui/icons-material/LockOutlined";
|
||||||
import LoadingButton from "@mui/lab/LoadingButton";
|
import LoadingButton from "@mui/lab/LoadingButton";
|
||||||
@ -17,12 +16,6 @@ import React, { useEffect } from "react";
|
|||||||
import * as api from "./api";
|
import * as api from "./api";
|
||||||
import { useSnackbars } from "./snackbars";
|
import { useSnackbars } from "./snackbars";
|
||||||
|
|
||||||
const useStyles = makeStyles((theme: Theme) => ({
|
|
||||||
avatar: {
|
|
||||||
backgroundColor: theme.palette.secondary.main,
|
|
||||||
},
|
|
||||||
}));
|
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
open: boolean;
|
open: boolean;
|
||||||
onSuccess: () => void;
|
onSuccess: () => void;
|
||||||
@ -55,7 +48,7 @@ interface Props {
|
|||||||
* <tt>--allow-unauthenticated-permissions</tt>), the caller may ignore this.
|
* <tt>--allow-unauthenticated-permissions</tt>), the caller may ignore this.
|
||||||
*/
|
*/
|
||||||
const Login = ({ open, onSuccess, handleClose }: Props) => {
|
const Login = ({ open, onSuccess, handleClose }: Props) => {
|
||||||
const classes = useStyles();
|
const theme = useTheme();
|
||||||
const snackbars = useSnackbars();
|
const snackbars = useSnackbars();
|
||||||
|
|
||||||
// This is a simple uncontrolled form; use refs.
|
// This is a simple uncontrolled form; use refs.
|
||||||
@ -119,7 +112,7 @@ const Login = ({ open, onSuccess, handleClose }: Props) => {
|
|||||||
fullWidth={true}
|
fullWidth={true}
|
||||||
>
|
>
|
||||||
<DialogTitle id="login-title">
|
<DialogTitle id="login-title">
|
||||||
<Avatar className={classes.avatar}>
|
<Avatar sx={{ backgroundColor: theme.palette.secondary.main }}>
|
||||||
<LockOutlinedIcon />
|
<LockOutlinedIcon />
|
||||||
</Avatar>
|
</Avatar>
|
||||||
Log in
|
Log in
|
||||||
|
Loading…
x
Reference in New Issue
Block a user