prettify code

This commit is contained in:
michioxd 2024-04-14 10:04:54 +07:00 committed by Scott Lamb
parent a787703a31
commit 8036aa40b7
14 changed files with 4539 additions and 2313 deletions

File diff suppressed because it is too large Load Diff

View File

@ -76,12 +76,14 @@ function MoonfireMenu(props: Props) {
</Box> </Box>
)} )}
<Tooltip title="Toggle theme"> <Tooltip title="Toggle theme">
<IconButton <IconButton onClick={changeTheme} color="inherit" size="small">
onClick={changeTheme} {choosenTheme === CurrentMode.Light ? (
color="inherit" <Brightness7 />
size="small" ) : choosenTheme === CurrentMode.Dark ? (
> <Brightness2 />
{choosenTheme === CurrentMode.Light ? <Brightness7 /> : choosenTheme === CurrentMode.Dark ? <Brightness2 /> : <BrightnessAuto />} ) : (
<BrightnessAuto />
)}
</IconButton> </IconButton>
</Tooltip> </Tooltip>
{props.loginState !== "unknown" && props.loginState !== "logged-in" && ( {props.loginState !== "unknown" && props.loginState !== "logged-in" && (

View File

@ -76,7 +76,9 @@ const DisplaySelector = (props: Props) => {
<Checkbox <Checkbox
checked={props.trimStartAndEnd} checked={props.trimStartAndEnd}
size="small" size="small"
onChange={(event) => props.setTrimStartAndEnd(event.target.checked)} onChange={(event) =>
props.setTrimStartAndEnd(event.target.checked)
}
name="trim-start-and-end" name="trim-start-and-end"
color="secondary" color="secondary"
/> />
@ -90,7 +92,9 @@ const DisplaySelector = (props: Props) => {
<Checkbox <Checkbox
checked={props.timestampTrack} checked={props.timestampTrack}
size="small" size="small"
onChange={(event) => props.setTimestampTrack(event.target.checked)} onChange={(event) =>
props.setTimestampTrack(event.target.checked)
}
name="timestamp-track" name="timestamp-track"
color="secondary" color="secondary"
/> />

View File

@ -90,8 +90,7 @@ const StreamMultiSelector = ({ toplevel, selected, setSelected }: Props) => {
); );
}); });
return ( return (
<Card <Card>
>
<CardContent> <CardContent>
<Box <Box
component="table" component="table"

View File

@ -400,7 +400,9 @@ const TimerangeSelector = ({
/> />
</Box> </Box>
<Box> <Box>
<FormLabel sx={{ mt: 1 }} component="legend">To</FormLabel> <FormLabel sx={{ mt: 1 }} component="legend">
To
</FormLabel>
<RadioGroup <RadioGroup
row row
value={days.endType} value={days.endType}

View File

@ -15,7 +15,7 @@ import Fullscreen from "@mui/icons-material/Fullscreen";
export interface Layout { export interface Layout {
className: string; className: string;
cameras: number; cameras: number;
name: string name: string;
} }
// These class names must match useStyles rules (below). // These class names must match useStyles rules (below).
@ -24,7 +24,7 @@ const LAYOUTS: Layout[] = [
{ className: "dual", cameras: 2, name: "2" }, { className: "dual", cameras: 2, name: "2" },
{ className: "main-plus-five", cameras: 6, name: "Main + 5" }, { className: "main-plus-five", cameras: 6, name: "Main + 5" },
{ className: "two-by-two", cameras: 4, name: "2x2" }, { className: "two-by-two", cameras: 4, name: "2x2" },
{ className: "three-by-three", cameras: 9, name: "3x3" } { className: "three-by-three", cameras: 9, name: "3x3" },
]; ];
const MAX_CAMERAS = 9; const MAX_CAMERAS = 9;
@ -114,9 +114,9 @@ const Multiview = (props: MultiviewProps) => {
const [selected, updateSelected] = useReducer( const [selected, updateSelected] = useReducer(
selectedReducer, selectedReducer,
searchParams.has("cams") searchParams.has("cams")
? JSON.parse(searchParams.get("cams") || "") : ? JSON.parse(searchParams.get("cams") || "")
localStorage.getItem("camsSelected") !== null ? : localStorage.getItem("camsSelected") !== null
JSON.parse(localStorage.getItem("camsSelected") || "") ? JSON.parse(localStorage.getItem("camsSelected") || "")
: Array(MAX_CAMERAS).fill(null) : Array(MAX_CAMERAS).fill(null)
); );
@ -124,7 +124,8 @@ const Multiview = (props: MultiviewProps) => {
* Save previously selected cameras to local storage. * Save previously selected cameras to local storage.
*/ */
useEffect(() => { useEffect(() => {
if (searchParams.has("cams")) localStorage.setItem("camsSelected", (searchParams.get("cams") || "")); if (searchParams.has("cams"))
localStorage.setItem("camsSelected", searchParams.get("cams") || "");
}, [searchParams]); }, [searchParams]);
const outerRef = React.useRef<HTMLDivElement>(null); const outerRef = React.useRef<HTMLDivElement>(null);
@ -148,7 +149,6 @@ const Multiview = (props: MultiviewProps) => {
} }
}, [outerRef]); }, [outerRef]);
const monoviews = selected.slice(0, layout.cameras).map((e, i) => { const monoviews = selected.slice(0, layout.cameras).map((e, i) => {
// When a camera is selected, use the camera's index as the key. // When a camera is selected, use the camera's index as the key.
// This allows swapping cameras' positions without tearing down their // This allows swapping cameras' positions without tearing down their
@ -196,11 +196,23 @@ const Multiview = (props: MultiviewProps) => {
}} }}
> >
<Tooltip title="Toggle full screen"> <Tooltip title="Toggle full screen">
<IconButton size="small" sx={{ <IconButton
position: 'fixed', background: 'rgba(50,50,50,0.4) !important', transition: '0.2s', opacity: '0.4', bottom: 10, right: 10, zIndex: 9, color: "#fff", ":hover": { size="small"
opacity: '1' sx={{
} position: "fixed",
}} onClick={handleFullScreen}> background: "rgba(50,50,50,0.4) !important",
transition: "0.2s",
opacity: "0.4",
bottom: 10,
right: 10,
zIndex: 9,
color: "#fff",
":hover": {
opacity: "1",
},
}}
onClick={handleFullScreen}
>
<Fullscreen /> <Fullscreen />
</IconButton> </IconButton>
</Tooltip> </Tooltip>
@ -227,12 +239,12 @@ const Multiview = (props: MultiviewProps) => {
gridTemplateColumns: { gridTemplateColumns: {
xs: "100%", xs: "100%",
sm: "100%", sm: "100%",
md: "repeat(2, calc(100% / 2))" md: "repeat(2, calc(100% / 2))",
}, },
gridTemplateRows: { gridTemplateRows: {
xs: "50%", xs: "50%",
sm: "50%", sm: "50%",
md: "repeat(1, calc(100% / 1))" md: "repeat(1, calc(100% / 1))",
}, },
}, },
"&.two-by-two": { "&.two-by-two": {

View File

@ -19,15 +19,21 @@ export interface LiveProps {
const Live = ({ cameras, Frame }: LiveProps) => { const Live = ({ cameras, Frame }: LiveProps) => {
const [searchParams, setSearchParams] = useSearchParams(); const [searchParams, setSearchParams] = useSearchParams();
const [multiviewLayoutIndex, setMultiviewLayoutIndex] = useState( const [multiviewLayoutIndex, setMultiviewLayoutIndex] = useState(
Number.parseInt(searchParams.get("layout") || localStorage.getItem("multiviewLayoutIndex") || "0", 10) Number.parseInt(
searchParams.get("layout") ||
localStorage.getItem("multiviewLayoutIndex") ||
"0",
10
)
); );
useEffect(() => { useEffect(() => {
if (searchParams.has("layout")) if (searchParams.has("layout"))
localStorage.setItem("multiviewLayoutIndex", (searchParams.get("layout") || "0")); localStorage.setItem(
"multiviewLayoutIndex",
searchParams.get("layout") || "0"
);
}, [searchParams]); }, [searchParams]);
if ("MediaSource" in window === false) { if ("MediaSource" in window === false) {

View File

@ -118,7 +118,7 @@ const Login = ({ open, onSuccess, handleClose }: Props) => {
</DialogTitle> </DialogTitle>
<form onSubmit={onSubmit}> <form onSubmit={onSubmit}>
<DialogContent> <DialogContent>
<Box sx={{ display: 'flex', flexDirection: 'column', gap: 2 }}> <Box sx={{ display: "flex", flexDirection: "column", gap: 2 }}>
<TextField <TextField
id="username" id="username"
label="Username" label="Username"

View File

@ -18,14 +18,20 @@ import { useReducer } from "react";
import { LoginState } from "../App"; import { LoginState } from "../App";
import { Link } from "react-router-dom"; import { Link } from "react-router-dom";
export default function Header({ loginState, logout, setChangePasswordOpen, activityMenuPart, setLoginState, toplevel }: export default function Header({
{ loginState,
loginState: LoginState, logout,
logout: () => void, setChangePasswordOpen,
setChangePasswordOpen: React.Dispatch<React.SetStateAction<boolean>>, activityMenuPart,
activityMenuPart?: JSX.Element, setLoginState,
setLoginState: React.Dispatch<React.SetStateAction<LoginState>>, toplevel,
toplevel: api.ToplevelResponse | null }: {
loginState: LoginState;
logout: () => void;
setChangePasswordOpen: React.Dispatch<React.SetStateAction<boolean>>;
activityMenuPart?: JSX.Element;
setLoginState: React.Dispatch<React.SetStateAction<LoginState>>;
toplevel: api.ToplevelResponse | null;
}) { }) {
const [showMenu, toggleShowMenu] = useReducer((m: boolean) => !m, false); const [showMenu, toggleShowMenu] = useReducer((m: boolean) => !m, false);
@ -90,5 +96,5 @@ export default function Header({ loginState, logout, setChangePasswordOpen, acti
</List> </List>
</Drawer> </Drawer>
</> </>
) );
} }

View File

@ -9,19 +9,21 @@ import React, { createContext } from "react";
export enum CurrentMode { export enum CurrentMode {
Auto = 0, Auto = 0,
Light = 1, Light = 1,
Dark = 2 Dark = 2,
} }
interface ThemeProps { interface ThemeProps {
changeTheme: () => void, changeTheme: () => void;
currentTheme: 'dark' | 'light', currentTheme: "dark" | "light";
choosenTheme: CurrentMode choosenTheme: CurrentMode;
} }
export const ThemeContext = createContext<ThemeProps>({ export const ThemeContext = createContext<ThemeProps>({
currentTheme: window.matchMedia("(prefers-color-scheme: dark)").matches ? 'dark' : 'light', currentTheme: window.matchMedia("(prefers-color-scheme: dark)").matches
? "dark"
: "light",
changeTheme: () => {}, changeTheme: () => {},
choosenTheme: CurrentMode.Auto choosenTheme: CurrentMode.Auto,
}); });
const ThemeMode = ({ children }: { children: JSX.Element }): JSX.Element => { const ThemeMode = ({ children }: { children: JSX.Element }): JSX.Element => {
@ -40,21 +42,33 @@ const ThemeMode = ({ children }: { children: JSX.Element }): JSX.Element => {
return matches; return matches;
}; };
const detectedSystemColorScheme = useMediaQuery("(prefers-color-scheme: dark)") ? "dark" : "light"; const detectedSystemColorScheme = useMediaQuery(
"(prefers-color-scheme: dark)"
)
? "dark"
: "light";
const changeTheme = React.useCallback(() => { const changeTheme = React.useCallback(() => {
setMode(mode === 'dark' ? 'light' : mode === 'light' ? 'system' : 'dark') setMode(mode === "dark" ? "light" : mode === "light" ? "system" : "dark");
}, [mode, setMode]); }, [mode, setMode]);
const currentTheme = mode === 'system' ? detectedSystemColorScheme : (mode ?? detectedSystemColorScheme); const currentTheme =
const choosenTheme = mode === 'dark' ? CurrentMode.Dark : mode === 'light' ? CurrentMode.Light : CurrentMode.Auto; mode === "system"
? detectedSystemColorScheme
: mode ?? detectedSystemColorScheme;
const choosenTheme =
mode === "dark"
? CurrentMode.Dark
: mode === "light"
? CurrentMode.Light
: CurrentMode.Auto;
return ( return (
<ThemeContext.Provider value={{ changeTheme, currentTheme, choosenTheme }}> <ThemeContext.Provider value={{ changeTheme, currentTheme, choosenTheme }}>
{children} {children}
</ThemeContext.Provider> </ThemeContext.Provider>
) );
} };
export default ThemeMode; export default ThemeMode;

View File

@ -3,7 +3,10 @@
// 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 CssBaseline from "@mui/material/CssBaseline"; import CssBaseline from "@mui/material/CssBaseline";
import { Experimental_CssVarsProvider, experimental_extendTheme } from "@mui/material/styles"; import {
Experimental_CssVarsProvider,
experimental_extendTheme,
} from "@mui/material/styles";
import StyledEngineProvider from "@mui/material/StyledEngineProvider"; import StyledEngineProvider from "@mui/material/StyledEngineProvider";
import { LocalizationProvider } from "@mui/x-date-pickers/LocalizationProvider"; import { LocalizationProvider } from "@mui/x-date-pickers/LocalizationProvider";
import "@fontsource/roboto"; import "@fontsource/roboto";
@ -22,15 +25,15 @@ const themeExtended = experimental_extendTheme({
dark: { dark: {
palette: { palette: {
primary: { primary: {
main: "#000000" main: "#000000",
}, },
secondary: { secondary: {
main: "#e65100" main: "#e65100",
}
}
}, },
} },
}) },
},
});
const container = document.getElementById("root"); const container = document.getElementById("root");
const root = createRoot(container!); const root = createRoot(container!);
root.render( root.render(

View File

@ -7,11 +7,11 @@
// expect(element).toHaveTextContent(/react/i) // expect(element).toHaveTextContent(/react/i)
// learn more: https://github.com/testing-library/jest-dom // learn more: https://github.com/testing-library/jest-dom
import "@testing-library/jest-dom"; import "@testing-library/jest-dom";
import { vi } from 'vitest' import { vi } from "vitest";
Object.defineProperty(window, 'matchMedia', { Object.defineProperty(window, "matchMedia", {
writable: true, writable: true,
value: vi.fn().mockImplementation(query => ({ value: vi.fn().mockImplementation((query) => ({
matches: false, matches: false,
media: query, media: query,
onchange: null, onchange: null,
@ -21,4 +21,4 @@ Object.defineProperty(window, 'matchMedia', {
removeEventListener: vi.fn(), removeEventListener: vi.fn(),
dispatchEvent: vi.fn(), dispatchEvent: vi.fn(),
})), })),
}) });

View File

@ -11,9 +11,13 @@ const target = process.env.PROXY_TARGET ?? "http://localhost:8080/";
// https://vitejs.dev/config/ // https://vitejs.dev/config/
export default defineConfig({ export default defineConfig({
plugins: [react(), viteCompression(), viteLegacyPlugin({ plugins: [
targets: ['defaults', 'fully supports es6-module'], react(),
})], viteCompression(),
viteLegacyPlugin({
targets: ["defaults", "fully supports es6-module"],
}),
],
server: { server: {
proxy: { proxy: {
"/api": { "/api": {