initial commit
This commit is contained in:
1 parent
f8bb01190e
commit
363d89e4f4
14 files changed
+901
-2
No files matched your search
@@ -0,0 +1,159 @@
|
||||
import Stack from "@mui/material/Stack";
|
||||
import {
|
||||
ErrorFallback,
|
||||
EmptyFallback,
|
||||
EmptyMonitorFallback,
|
||||
} from "@/Components/v2/design-elements/Fallback";
|
||||
import { Breadcrumb } from "@/Components/v2/design-elements/Breadcrumb";
|
||||
import CircularProgress from "@mui/material/CircularProgress";
|
||||
|
||||
import type { StackProps } from "@mui/material/Stack";
|
||||
import { useTheme } from "@mui/material/styles";
|
||||
import { useTranslation } from "react-i18next";
|
||||
interface BasePageProps extends StackProps {
|
||||
loading?: boolean;
|
||||
error?: boolean;
|
||||
children: React.ReactNode;
|
||||
breadcrumbOverride?: string[];
|
||||
}
|
||||
|
||||
export const BasePage = ({
|
||||
loading,
|
||||
error,
|
||||
children,
|
||||
breadcrumbOverride,
|
||||
...props
|
||||
}: BasePageProps) => {
|
||||
const theme = useTheme();
|
||||
|
||||
if (loading) {
|
||||
return (
|
||||
<Stack
|
||||
alignItems="center"
|
||||
justifyContent="center"
|
||||
sx={{ height: "100%" }}
|
||||
>
|
||||
<CircularProgress
|
||||
color="primary"
|
||||
size={28}
|
||||
/>
|
||||
</Stack>
|
||||
);
|
||||
}
|
||||
|
||||
if (error) {
|
||||
return (
|
||||
<ErrorFallback
|
||||
title="Something went wrong..."
|
||||
subtitle="Please try again later"
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<Stack
|
||||
spacing={theme.spacing(10)}
|
||||
{...props}
|
||||
>
|
||||
<Breadcrumb breadcrumbOverride={breadcrumbOverride} />
|
||||
{children}
|
||||
</Stack>
|
||||
);
|
||||
};
|
||||
|
||||
interface BasePageWithStatesProps extends StackProps {
|
||||
loading: boolean;
|
||||
error: any;
|
||||
items: any[];
|
||||
bullets: string[] | unknown;
|
||||
page: string;
|
||||
actionButtonText: string;
|
||||
actionLink: string;
|
||||
children: React.ReactNode;
|
||||
}
|
||||
|
||||
export const BasePageWithStates = ({
|
||||
loading,
|
||||
error,
|
||||
items,
|
||||
page,
|
||||
bullets,
|
||||
actionButtonText,
|
||||
actionLink,
|
||||
children,
|
||||
...props
|
||||
}: BasePageWithStatesProps) => {
|
||||
const showLoading = loading && (!items || items.length === 0);
|
||||
|
||||
if (isEmpty(items)) {
|
||||
return (
|
||||
<EmptyFallback
|
||||
bullets={bullets}
|
||||
title={page}
|
||||
actionButtonText={actionButtonText}
|
||||
actionLink={actionLink}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<BasePage
|
||||
loading={showLoading}
|
||||
error={error}
|
||||
{...props}
|
||||
>
|
||||
{children}
|
||||
</BasePage>
|
||||
);
|
||||
};
|
||||
|
||||
interface MonitorBasePageWithStatesProps extends StackProps {
|
||||
loading: boolean;
|
||||
error: any;
|
||||
items: any[];
|
||||
page: string;
|
||||
actionLink?: string;
|
||||
children: React.ReactNode;
|
||||
}
|
||||
|
||||
const isEmpty = (items: any[]) => {
|
||||
if (!items) return true;
|
||||
if (Array.isArray(items) && items.length === 0) return true;
|
||||
return false;
|
||||
};
|
||||
|
||||
export const MonitorBasePageWithStates = ({
|
||||
loading,
|
||||
error,
|
||||
items,
|
||||
page,
|
||||
actionLink,
|
||||
children,
|
||||
...props
|
||||
}: MonitorBasePageWithStatesProps) => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
const showLoading = loading && (!items || items.length === 0);
|
||||
|
||||
if (!loading && isEmpty(items)) {
|
||||
return (
|
||||
<EmptyMonitorFallback
|
||||
page={page}
|
||||
title={t(`pages.${page}.fallback.title`)}
|
||||
bullets={t(`monitors.${page}.fallback.checks`, { returnObjects: true })}
|
||||
actionButtonText={t(`monitors.${page}.fallback.actionButton`)}
|
||||
actionLink={actionLink || ""}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<BasePage
|
||||
loading={showLoading}
|
||||
error={error}
|
||||
{...props}
|
||||
>
|
||||
{children}
|
||||
</BasePage>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,117 @@
|
||||
import MuiBreadcrumbs from "@mui/material/Breadcrumbs";
|
||||
import Typography from "@mui/material/Typography";
|
||||
import { Link, useLocation } from "react-router-dom";
|
||||
import { useTheme } from "@mui/material/styles";
|
||||
import { ChevronRight, Home } from "lucide-react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
export const Breadcrumb = ({ breadcrumbOverride }: { breadcrumbOverride?: string[] }) => {
|
||||
const { t } = useTranslation();
|
||||
const theme = useTheme();
|
||||
const location = useLocation();
|
||||
|
||||
// Don't show breadcrumb on dashboard
|
||||
if (location.pathname === "/" || location.pathname === "/uptime") {
|
||||
return null;
|
||||
}
|
||||
|
||||
const pathnames = breadcrumbOverride || location.pathname.split("/").filter((x) => x);
|
||||
|
||||
// Don't show if only one level (e.g., /uptime)
|
||||
if (pathnames.length === 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<MuiBreadcrumbs
|
||||
separator={
|
||||
<ChevronRight
|
||||
size={16}
|
||||
strokeWidth={1.5}
|
||||
/>
|
||||
}
|
||||
sx={{
|
||||
fontSize: "14px",
|
||||
marginBottom: theme.spacing(6),
|
||||
"& .MuiBreadcrumbs-separator": {
|
||||
color: theme.palette.text.secondary,
|
||||
},
|
||||
}}
|
||||
>
|
||||
<Link
|
||||
to="/uptime"
|
||||
style={{
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
gap: theme.spacing(2),
|
||||
textDecoration: "none",
|
||||
color: theme.palette.text.secondary,
|
||||
}}
|
||||
>
|
||||
<Home
|
||||
size={16}
|
||||
strokeWidth={1.5}
|
||||
/>
|
||||
<Typography
|
||||
sx={{
|
||||
fontSize: "14px",
|
||||
color: theme.palette.text.secondary,
|
||||
"&:hover": {
|
||||
color: theme.palette.primary.main,
|
||||
},
|
||||
}}
|
||||
>
|
||||
Home
|
||||
</Typography>
|
||||
</Link>
|
||||
{pathnames.map((value, index) => {
|
||||
const last = index === pathnames.length - 1;
|
||||
const to = `/${pathnames.slice(0, index + 1).join("/")}`;
|
||||
|
||||
let displayName = "";
|
||||
|
||||
// Paths that are IDs should be detail pages
|
||||
if (value.length === 24 || value.match(/^[a-f0-9-]{36}$/)) {
|
||||
displayName = "Details";
|
||||
} else {
|
||||
displayName =
|
||||
t(`common.breadcrumbs.${value}`) ||
|
||||
value.charAt(0).toUpperCase() + value.slice(1);
|
||||
}
|
||||
|
||||
return last ? (
|
||||
<Typography
|
||||
key={to}
|
||||
sx={{
|
||||
fontSize: "14px",
|
||||
fontWeight: 600,
|
||||
color: theme.palette.primary.main,
|
||||
}}
|
||||
>
|
||||
{displayName}
|
||||
</Typography>
|
||||
) : (
|
||||
<Link
|
||||
key={to}
|
||||
to={to}
|
||||
style={{
|
||||
textDecoration: "none",
|
||||
}}
|
||||
>
|
||||
<Typography
|
||||
sx={{
|
||||
fontSize: "14px",
|
||||
color: theme.palette.text.secondary,
|
||||
"&:hover": {
|
||||
color: theme.palette.primary.main,
|
||||
},
|
||||
}}
|
||||
>
|
||||
{displayName}
|
||||
</Typography>
|
||||
</Link>
|
||||
);
|
||||
})}
|
||||
</MuiBreadcrumbs>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,46 @@
|
||||
import Stack from "@mui/material/Stack";
|
||||
import Typography from "@mui/material/Typography";
|
||||
import { Check } from "lucide-react";
|
||||
import { useTheme } from "@mui/material/styles";
|
||||
|
||||
export const BulletPointCheck = ({
|
||||
text,
|
||||
variant = "info",
|
||||
}: {
|
||||
text: string;
|
||||
noHighlightText?: string;
|
||||
variant?: "success" | "error" | "info";
|
||||
}) => {
|
||||
const theme = useTheme();
|
||||
const colors: Record<string, string | undefined> = {
|
||||
success: theme.palette.success.main,
|
||||
error: theme.palette.error.main,
|
||||
info: theme.palette.text.secondary,
|
||||
};
|
||||
|
||||
return (
|
||||
<Stack
|
||||
direction="row"
|
||||
gap={theme.spacing(6)}
|
||||
alignItems="center"
|
||||
>
|
||||
<Check
|
||||
size={16}
|
||||
strokeWidth={1.5}
|
||||
style={{
|
||||
flexShrink: 0,
|
||||
}}
|
||||
/>
|
||||
<Typography
|
||||
component="span"
|
||||
color={variant === "info" ? theme.palette.text.secondary : colors[variant]}
|
||||
fontWeight={450}
|
||||
sx={{
|
||||
opacity: 0.9,
|
||||
}}
|
||||
>
|
||||
{text}
|
||||
</Typography>
|
||||
</Stack>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,171 @@
|
||||
import Stack from "@mui/material/Stack";
|
||||
import Typography from "@mui/material/Typography";
|
||||
import { BulletPointCheck, SkeletonCard } from "@/Components/v2/design-elements";
|
||||
import { Button } from "@/Components/v2/inputs";
|
||||
|
||||
import { useNavigate } from "react-router";
|
||||
import useMediaQuery from "@mui/material/useMediaQuery";
|
||||
import { useTheme } from "@mui/material/styles";
|
||||
import type { StackProps } from "@mui/material/Stack";
|
||||
|
||||
interface BaseFallbackProps extends StackProps {
|
||||
children: React.ReactNode;
|
||||
}
|
||||
|
||||
export const BaseFallback = ({ children, ...props }: BaseFallbackProps) => {
|
||||
const theme = useTheme();
|
||||
const isSmall = useMediaQuery(theme.breakpoints.down("md"));
|
||||
|
||||
return (
|
||||
<Stack
|
||||
alignItems={"center"}
|
||||
margin={isSmall ? "inherit" : "auto"}
|
||||
marginTop={isSmall ? "33%" : "10%"}
|
||||
width={{
|
||||
sm: "90%",
|
||||
md: "70%",
|
||||
lg: "50%",
|
||||
xl: "40%",
|
||||
}}
|
||||
padding={{ xs: theme.spacing(8), md: theme.spacing(16) }}
|
||||
bgcolor={theme.palette.background.paper}
|
||||
border={1}
|
||||
borderColor={theme.palette.divider}
|
||||
borderRadius={theme.shape.borderRadius}
|
||||
sx={{
|
||||
borderStyle: "dashed",
|
||||
}}
|
||||
{...props}
|
||||
>
|
||||
<SkeletonCard showHalo={true} />
|
||||
{children}
|
||||
</Stack>
|
||||
);
|
||||
};
|
||||
|
||||
export const ErrorFallback = ({
|
||||
title,
|
||||
subtitle,
|
||||
}: {
|
||||
title: string;
|
||||
subtitle: string;
|
||||
}) => {
|
||||
const theme = useTheme();
|
||||
return (
|
||||
<BaseFallback>
|
||||
<Typography
|
||||
variant="h1"
|
||||
marginY={theme.spacing(4)}
|
||||
color={theme.palette.text.secondary}
|
||||
>
|
||||
{title}
|
||||
</Typography>
|
||||
<Typography>{subtitle}</Typography>
|
||||
</BaseFallback>
|
||||
);
|
||||
};
|
||||
|
||||
export const EmptyFallback = ({
|
||||
title,
|
||||
bullets,
|
||||
actionButtonText,
|
||||
actionLink,
|
||||
}: {
|
||||
title: string;
|
||||
bullets: any;
|
||||
actionButtonText: string;
|
||||
actionLink: string;
|
||||
}) => {
|
||||
const theme = useTheme();
|
||||
const navigate = useNavigate();
|
||||
return (
|
||||
<BaseFallback>
|
||||
<Stack
|
||||
gap={theme.spacing(10)}
|
||||
zIndex={1}
|
||||
alignItems="center"
|
||||
>
|
||||
<Typography
|
||||
component="h1"
|
||||
color={theme.palette.primary.contrastText}
|
||||
>
|
||||
{title}
|
||||
</Typography>
|
||||
<Stack
|
||||
sx={{
|
||||
flexWrap: "wrap",
|
||||
gap: theme.spacing(2),
|
||||
maxWidth: "1100px",
|
||||
width: "100%",
|
||||
}}
|
||||
>
|
||||
{Array.isArray(bullets) &&
|
||||
bullets?.map((bullet: string) => (
|
||||
<BulletPointCheck
|
||||
text={bullet}
|
||||
key={`${bullet}-${Math.random()}`}
|
||||
/>
|
||||
))}
|
||||
</Stack>
|
||||
<Stack>
|
||||
<Button
|
||||
variant="contained"
|
||||
color="primary"
|
||||
onClick={() => navigate(actionLink)}
|
||||
>
|
||||
{actionButtonText}
|
||||
</Button>
|
||||
</Stack>
|
||||
</Stack>
|
||||
</BaseFallback>
|
||||
);
|
||||
};
|
||||
|
||||
export const EmptyMonitorFallback = ({
|
||||
page,
|
||||
title,
|
||||
bullets,
|
||||
actionButtonText,
|
||||
actionLink,
|
||||
}: {
|
||||
page: string;
|
||||
title: string;
|
||||
bullets: any;
|
||||
actionButtonText: string;
|
||||
actionLink: string;
|
||||
}) => {
|
||||
const theme = useTheme();
|
||||
const navigate = useNavigate();
|
||||
return (
|
||||
<BaseFallback>
|
||||
<Stack
|
||||
gap={theme.spacing(10)}
|
||||
zIndex={1}
|
||||
alignItems="center"
|
||||
>
|
||||
<Typography
|
||||
component="h1"
|
||||
color={theme.palette.primary.contrastText}
|
||||
>
|
||||
{title}
|
||||
</Typography>
|
||||
<Stack
|
||||
sx={{
|
||||
flexWrap: "wrap",
|
||||
gap: theme.spacing(2),
|
||||
maxWidth: "1100px",
|
||||
width: "100%",
|
||||
}}
|
||||
>
|
||||
{Array.isArray(bullets) &&
|
||||
bullets?.map((bullet: string, index: number) => (
|
||||
<BulletPointCheck
|
||||
text={bullet}
|
||||
key={`${(page + "Monitors").trim().split(" ")[0]}-${index}`}
|
||||
/>
|
||||
))}
|
||||
</Stack>
|
||||
</Stack>
|
||||
</BaseFallback>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,147 @@
|
||||
import { Box, Stack, useTheme } from "@mui/material";
|
||||
|
||||
interface SkeletonCardProps {
|
||||
width?: number | string | { xs?: number | string; md?: number | string };
|
||||
showHalo?: boolean;
|
||||
}
|
||||
|
||||
export const SkeletonCard = ({
|
||||
width = { xs: 130, md: 216 },
|
||||
showHalo = true,
|
||||
}: SkeletonCardProps) => {
|
||||
const theme = useTheme();
|
||||
const pulseAnimation = {
|
||||
"@keyframes pulse": {
|
||||
"0%, 100%": { opacity: 1 },
|
||||
"50%": { opacity: 0.72 },
|
||||
},
|
||||
};
|
||||
|
||||
const floatAnimation = {
|
||||
"@keyframes float": {
|
||||
"0%, 100%": { transform: "rotate(5deg) translate(12px, -20px)" },
|
||||
"50%": { transform: "rotate(5deg) translate(12px, -24px)" },
|
||||
},
|
||||
};
|
||||
|
||||
const cardStyle = {
|
||||
width: width,
|
||||
height: 57,
|
||||
borderRadius: theme.shape.borderRadius,
|
||||
background:
|
||||
theme.palette.mode === "dark"
|
||||
? theme.palette.secondary.dark
|
||||
: theme.palette.background.paper,
|
||||
boxShadow:
|
||||
theme.palette.mode === "dark"
|
||||
? "0 8px 30px rgba(0,0,0,.3), 0 0 0 1px rgba(255,255,255,.05) inset"
|
||||
: "0 8px 30px rgba(0,0,0,.08), 0 0 0 1px rgba(0,0,0,.05) inset",
|
||||
display: "flex",
|
||||
gap: theme.spacing(5),
|
||||
alignItems: "center",
|
||||
padding: theme.spacing(5),
|
||||
};
|
||||
|
||||
const blockStyle = {
|
||||
width: 55,
|
||||
height: 34,
|
||||
borderRadius: theme.shape.borderRadius,
|
||||
background: theme.palette.secondary.main,
|
||||
border: `1px solid ${theme.palette.divider}`,
|
||||
animation: "pulse 1.6s ease-in-out infinite",
|
||||
...pulseAnimation,
|
||||
};
|
||||
|
||||
const lineStyle = {
|
||||
height: 7,
|
||||
borderRadius: theme.shape.borderRadius,
|
||||
background: theme.palette.secondary.main,
|
||||
border: `1px solid ${theme.palette.divider}`,
|
||||
animation: "pulse 1.6s ease-in-out infinite",
|
||||
...pulseAnimation,
|
||||
};
|
||||
|
||||
return (
|
||||
<Box
|
||||
position={"relative"}
|
||||
mt={20}
|
||||
mb={20}
|
||||
>
|
||||
{showHalo && (
|
||||
<Box
|
||||
sx={{
|
||||
position: "absolute",
|
||||
inset: 0,
|
||||
display: "grid",
|
||||
placeItems: "center",
|
||||
pointerEvents: "none",
|
||||
"&::before": {
|
||||
content: '""',
|
||||
width: "260px",
|
||||
height: "260px",
|
||||
borderRadius: "999px",
|
||||
background:
|
||||
theme.palette.mode === "dark" ? "rgba(255, 255, 255, 0.05)" : "#fff",
|
||||
filter: "blur(60px)",
|
||||
opacity: 0.9,
|
||||
},
|
||||
}}
|
||||
aria-hidden="true"
|
||||
/>
|
||||
)}
|
||||
|
||||
{/* Card stack */}
|
||||
<Box sx={{ position: "relative", zIndex: 1 }}>
|
||||
{/* Front card (now at bottom) */}
|
||||
<Box sx={cardStyle}>
|
||||
<Box sx={blockStyle} />
|
||||
<Stack sx={{ flex: 1, gap: "12px" }}>
|
||||
{/* Empty space to maintain card height */}
|
||||
</Stack>
|
||||
</Box>
|
||||
|
||||
{/* Back card A */}
|
||||
<Box
|
||||
sx={{
|
||||
...cardStyle,
|
||||
transform: "rotate(-4deg) translate(-12px, -12px)",
|
||||
filter: "blur(.2px)",
|
||||
position: "absolute",
|
||||
left: 0,
|
||||
top: 0,
|
||||
}}
|
||||
aria-hidden="true"
|
||||
>
|
||||
<Box sx={blockStyle} />
|
||||
<Stack sx={{ flex: 1, gap: "12px" }}>
|
||||
<Box sx={{ ...lineStyle, width: "60%" }} />
|
||||
<Box sx={{ ...lineStyle, width: "80%" }} />
|
||||
<Box sx={{ ...lineStyle, width: "40%" }} />
|
||||
</Stack>
|
||||
</Box>
|
||||
|
||||
{/* Back card B */}
|
||||
<Box
|
||||
sx={{
|
||||
...cardStyle,
|
||||
transform: "rotate(5deg) translate(12px, -20px)",
|
||||
filter: "blur(.3px)",
|
||||
position: "absolute",
|
||||
left: 0,
|
||||
top: 0,
|
||||
animation: "float 3s ease-in-out 5",
|
||||
...floatAnimation,
|
||||
}}
|
||||
aria-hidden="true"
|
||||
>
|
||||
<Box sx={blockStyle} />
|
||||
<Stack sx={{ flex: 1, gap: "12px" }}>
|
||||
<Box sx={{ ...lineStyle, width: "60%" }} />
|
||||
<Box sx={{ ...lineStyle, width: "80%" }} />
|
||||
<Box sx={{ ...lineStyle, width: "40%" }} />
|
||||
</Stack>
|
||||
</Box>
|
||||
</Box>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,5 @@
|
||||
export * from "./Breadcrumb";
|
||||
export * from "./BasePage";
|
||||
export * from "./Fallback";
|
||||
export * from "./SkeletonCard";
|
||||
export * from "./BulletPointCheck";
|
||||
@@ -0,0 +1,37 @@
|
||||
import Button from "@mui/material/Button";
|
||||
import type { ButtonProps } from "@mui/material/Button";
|
||||
import { useTheme } from "@mui/material/styles";
|
||||
|
||||
export const ButtonInput = ({ sx, ...props }: ButtonProps) => {
|
||||
const theme = useTheme();
|
||||
const outlinedSx =
|
||||
props.variant === "outlined"
|
||||
? {
|
||||
color: theme.palette.text.primary,
|
||||
borderColor: theme.palette.divider,
|
||||
"&:hover": {
|
||||
borderColor: theme.palette.text.secondary,
|
||||
},
|
||||
}
|
||||
: {};
|
||||
return (
|
||||
<Button
|
||||
{...props}
|
||||
sx={{
|
||||
textTransform: "none",
|
||||
height: 34,
|
||||
fontWeight: 400,
|
||||
borderRadius: 2,
|
||||
whiteSpace: "nowrap",
|
||||
textOverflow: "ellipsis",
|
||||
overflow: "hidden",
|
||||
boxShadow: "none",
|
||||
"&:hover": {
|
||||
boxShadow: "none",
|
||||
},
|
||||
...outlinedSx,
|
||||
...sx,
|
||||
}}
|
||||
/>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1 @@
|
||||
export { ButtonInput as Button } from "./Button";
|
||||
@@ -0,0 +1,17 @@
|
||||
import { MonitorBasePageWithStates } from "@/Components/v2/design-elements";
|
||||
|
||||
const UptimeMonitorsPage = () => {
|
||||
return (
|
||||
<MonitorBasePageWithStates
|
||||
loading={false}
|
||||
error={false}
|
||||
items={[]}
|
||||
page="uptime"
|
||||
actionLink="/uptime/create"
|
||||
>
|
||||
Test
|
||||
</MonitorBasePageWithStates>
|
||||
);
|
||||
};
|
||||
|
||||
export default UptimeMonitorsPage;
|
||||
File renamed without changes.
@@ -1,3 +1,7 @@
|
||||
// Temp v2 theme
|
||||
import { ThemeProvider } from "@mui/material";
|
||||
import { lightTheme, darkTheme } from "@/Utils/Theme/v2Theme";
|
||||
|
||||
import { useSelector } from "react-redux";
|
||||
import { Navigate, Route, Routes as LibRoutes } from "react-router";
|
||||
import HomeLayout from "@/Components/v1/Layouts/HomeLayout";
|
||||
@@ -11,7 +15,7 @@ import AuthSetNewPassword from "../Pages/Auth/SetNewPassword.jsx";
|
||||
import AuthNewPasswordConfirmed from "../Pages/Auth/NewPasswordConfirmed.jsx";
|
||||
|
||||
// Uptime
|
||||
import Uptime from "../Pages/Uptime/Monitors/index.jsx";
|
||||
import Uptime from "../Pages/Uptime/Monitors";
|
||||
import UptimeDetails from "../Pages/Uptime/Details/index.jsx";
|
||||
import UptimeCreate from "../Pages/Uptime/Create/index.jsx";
|
||||
|
||||
@@ -75,7 +79,13 @@ const Routes = () => {
|
||||
/>
|
||||
<Route
|
||||
path="/uptime"
|
||||
element={<Uptime />}
|
||||
element={
|
||||
<>
|
||||
<ThemeProvider theme={mode === "light" ? lightTheme : darkTheme}>
|
||||
<Uptime />
|
||||
</ThemeProvider>
|
||||
</>
|
||||
}
|
||||
/>
|
||||
|
||||
<Route
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
const typographyBase = 13;
|
||||
|
||||
export const typographyLevels = {
|
||||
base: typographyBase,
|
||||
xs: `${(typographyBase - 4) / 16}rem`,
|
||||
s: `${(typographyBase - 2) / 16}rem`,
|
||||
m: `${typographyBase / 16}rem`,
|
||||
l: `${(typographyBase + 2) / 16}rem`,
|
||||
xl: `${(typographyBase + 10) / 16}rem`,
|
||||
};
|
||||
|
||||
export const colors = {
|
||||
gray200: "#EFEFEF",
|
||||
gray700: "#313131",
|
||||
blueBlueWave: "#1570EF",
|
||||
};
|
||||
|
||||
export const lightPalette = {
|
||||
primary: {
|
||||
main: colors.blueBlueWave,
|
||||
},
|
||||
secondary: {
|
||||
main: colors.gray200,
|
||||
},
|
||||
};
|
||||
|
||||
export const darkPalette = {
|
||||
primary: {
|
||||
main: colors.blueBlueWave,
|
||||
},
|
||||
secondary: {
|
||||
main: colors.gray700,
|
||||
},
|
||||
};
|
||||
@@ -0,0 +1,148 @@
|
||||
import { createTheme } from "@mui/material";
|
||||
import { lightPalette, darkPalette, typographyLevels } from "@/Utils/Theme/v2Palette";
|
||||
|
||||
import type { Theme } from "@mui/material/styles";
|
||||
|
||||
export type PaletteKey = {
|
||||
[K in keyof Theme["palette"]]: Theme["palette"][K] extends { main: any } ? K : never;
|
||||
}[keyof Theme["palette"]];
|
||||
|
||||
const fontFamilyPrimary = "system-ui, sans-serif";
|
||||
const shadow =
|
||||
"0px 4px 24px -4px rgba(16, 24, 40, 0.08), 0px 3px 3px -3px rgba(16, 24, 40, 0.03)";
|
||||
|
||||
export const theme = (mode: string, palette: any) =>
|
||||
createTheme({
|
||||
breakpoints: {
|
||||
values: {
|
||||
xs: 300,
|
||||
sm: 600,
|
||||
md: 900,
|
||||
lg: 1200,
|
||||
xl: 1536,
|
||||
},
|
||||
},
|
||||
spacing: 2,
|
||||
palette: {
|
||||
mode: mode,
|
||||
...palette,
|
||||
},
|
||||
typography: {
|
||||
fontFamily: fontFamilyPrimary,
|
||||
fontSize: typographyLevels.base,
|
||||
h1: {
|
||||
fontSize: typographyLevels.xl,
|
||||
fontWeight: 500,
|
||||
},
|
||||
h2: {
|
||||
fontSize: typographyLevels.l,
|
||||
fontWeight: 400,
|
||||
},
|
||||
body1: {
|
||||
fontSize: typographyLevels.m,
|
||||
fontWeight: 400,
|
||||
},
|
||||
body2: {
|
||||
fontSize: typographyLevels.s,
|
||||
fontWeight: 400,
|
||||
},
|
||||
},
|
||||
|
||||
components: {
|
||||
MuiButtonBase: {
|
||||
defaultProps: {
|
||||
disableRipple: true,
|
||||
disableTouchRipple: true,
|
||||
},
|
||||
},
|
||||
MuiButton: {
|
||||
defaultProps: {
|
||||
disableRipple: true,
|
||||
disableTouchRipple: true,
|
||||
disableFocusRipple: true,
|
||||
},
|
||||
},
|
||||
MuiIconButton: {
|
||||
defaultProps: {
|
||||
disableRipple: true,
|
||||
disableTouchRipple: true,
|
||||
disableFocusRipple: true,
|
||||
},
|
||||
},
|
||||
MuiListItemButton: {
|
||||
defaultProps: {
|
||||
disableRipple: true,
|
||||
disableTouchRipple: true,
|
||||
},
|
||||
},
|
||||
MuiTab: {
|
||||
defaultProps: {
|
||||
disableRipple: true,
|
||||
disableTouchRipple: true,
|
||||
disableFocusRipple: true,
|
||||
},
|
||||
},
|
||||
MuiToggleButton: {
|
||||
defaultProps: {
|
||||
disableRipple: true,
|
||||
disableTouchRipple: true,
|
||||
disableFocusRipple: true,
|
||||
},
|
||||
},
|
||||
|
||||
MuiFormLabel: {
|
||||
styleOverrides: {
|
||||
root: ({ theme }) => ({
|
||||
fontSize: typographyLevels.base,
|
||||
"&.Mui-focused": {
|
||||
color: theme.palette.secondary.contrastText,
|
||||
},
|
||||
}),
|
||||
},
|
||||
},
|
||||
MuiInputLabel: {
|
||||
styleOverrides: {
|
||||
root: ({ theme }) => ({
|
||||
top: `-${theme.spacing(4)}`,
|
||||
"&.MuiInputLabel-shrink": {
|
||||
top: 0,
|
||||
},
|
||||
}),
|
||||
},
|
||||
},
|
||||
|
||||
MuiOutlinedInput: {
|
||||
styleOverrides: {
|
||||
root: {
|
||||
"&.Mui-focused .MuiOutlinedInput-notchedOutline": {
|
||||
borderColor: palette.primary.main,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
MuiPaper: {
|
||||
styleOverrides: {
|
||||
root: ({ theme }) => {
|
||||
return {
|
||||
marginTop: 4,
|
||||
padding: 0,
|
||||
border: 1,
|
||||
borderStyle: "solid",
|
||||
borderColor: theme.palette.divider,
|
||||
borderRadius: 4,
|
||||
boxShadow: shadow,
|
||||
backgroundColor: theme.palette.background.paper,
|
||||
backgroundImage: "none",
|
||||
};
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
shape: {
|
||||
borderRadius: 2,
|
||||
},
|
||||
});
|
||||
|
||||
export const lightTheme = createTheme(theme("light", lightPalette));
|
||||
export const darkTheme = createTheme(theme("dark", darkPalette));
|
||||
@@ -125,6 +125,13 @@
|
||||
"testLocale": "testLocale",
|
||||
"add": "Add",
|
||||
"monitors": "monitors",
|
||||
"pages": {
|
||||
"uptime": {
|
||||
"fallback": {
|
||||
"title": "An uptime monitor is used to:"
|
||||
}
|
||||
}
|
||||
},
|
||||
"distributedUptimeStatusCreateStatusPage": "status page",
|
||||
"distributedUptimeStatusCreateStatusPageAccess": "Access",
|
||||
"distributedUptimeStatusCreateStatusPageReady": "If your status page is ready, you can mark it as published.",
|
||||
|
||||
Reference in new issue
Block a user