Merge pull request #748 from bluewave-labs/fix/colorful-revamp-extravaganza

Theme file revamp
This commit is contained in:
Alexander Holliday
2024-08-30 08:03:25 -07:00
committed by GitHub
101 changed files with 2515 additions and 2206 deletions

View File

@@ -1,31 +1,3 @@
.logo {
height: 6em;
padding: 1.5em;
will-change: filter;
transition: filter 300ms;
}
.logo:hover {
filter: drop-shadow(0 0 2em #646cffaa);
}
.logo.react:hover {
filter: drop-shadow(0 0 2em #61dafbaa);
}
@keyframes logo-spin {
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
}
@media (prefers-reduced-motion: no-preference) {
a:nth-of-type(2) .logo {
animation: logo-spin infinite 20s linear;
}
}
.card {
padding: 2em;
}

View File

@@ -28,14 +28,22 @@ import CreatePageSpeed from "./Pages/PageSpeed/CreatePageSpeed";
import CreateNewMaintenanceWindow from "./Pages/Maintenance/CreateMaintenanceWindow";
import PageSpeedDetails from "./Pages/PageSpeed/Details";
import PageSpeedConfigure from "./Pages/PageSpeed/Configure";
import { ThemeProvider } from "@emotion/react";
import lightTheme from "./Utils/Theme/lightTheme";
import darkTheme from "./Utils/Theme/darkTheme";
import { useSelector } from "react-redux";
function App() {
const AdminCheckedRegister = withAdminCheck(Register);
const MonitorsWithAdminProp = withAdminProp(Monitors);
const DetailsWithAdminProp = withAdminProp(Details);
const PageSpeedWithAdminProp = withAdminProp(PageSpeed);
const MaintenanceWithAdminProp = withAdminProp(Maintenance);
const mode = useSelector((state) => state.ui.mode);
return (
<>
<ThemeProvider theme={mode === "light" ? lightTheme : darkTheme}>
<Routes>
<Route exact path="/" element={<HomeLayout />}>
<Route
@@ -74,7 +82,7 @@ function App() {
/>
<Route
path="maintenance"
element={<ProtectedRoute Component={Maintenance} />}
element={<ProtectedRoute Component={MaintenanceWithAdminProp} />}
/>
<Route
path="/maintenance/create"
@@ -129,7 +137,7 @@ function App() {
/>
</Routes>
<ToastContainer />
</>
</ThemeProvider>
);
}

View File

@@ -32,7 +32,7 @@ const icons = {
const Alert = ({ variant, title, body, isToast, hasIcon = true, onClick }) => {
const theme = useTheme();
const { bg, border, color } = theme.alert[variant];
const { text, light, border } = theme.palette[variant];
const icon = icons[variant];
return (
@@ -41,23 +41,25 @@ const Alert = ({ variant, title, body, isToast, hasIcon = true, onClick }) => {
justifyContent="flex-start"
alignItems={hasIcon ? "" : "center"}
className="alert row-stack"
gap={theme.gap.ml}
gap={theme.spacing(8)}
sx={{
padding: hasIcon ? theme.gap.ml : `${theme.gap.small} ${theme.gap.ml}`,
backgroundColor: bg,
padding: hasIcon
? theme.spacing(8)
: `${theme.spacing(4)} ${theme.spacing(8)}`,
backgroundColor: light,
border: `solid 1px ${border}`,
borderRadius: `${theme.shape.borderRadius}px`,
borderRadius: theme.shape.borderRadius,
}}
>
{hasIcon && <Box sx={{ color: color }}>{icon}</Box>}
{hasIcon && <Box sx={{ color: text }}>{icon}</Box>}
<Stack direction="column" gap="2px" sx={{ flex: 1 }}>
{title && (
<Typography sx={{ fontWeight: "700", color: `${color} !important` }}>
<Typography sx={{ fontWeight: "700", color: `${text}` }}>
{title}
</Typography>
)}
{body && (
<Typography sx={{ fontWeight: "400", color: `${color} !important` }}>
<Typography sx={{ fontWeight: "400", color: `${text}` }}>
{body}
</Typography>
)}
@@ -69,7 +71,7 @@ const Alert = ({ variant, title, body, isToast, hasIcon = true, onClick }) => {
sx={{
fontWeight: "600",
width: "fit-content",
mt: theme.gap.small,
mt: theme.spacing(4),
padding: 0,
minWidth: 0,
"&:hover": {
@@ -95,10 +97,6 @@ const Alert = ({ variant, title, body, isToast, hasIcon = true, onClick }) => {
"&:focus": {
outline: "none",
},
"& .MuiTouchRipple-root": {
pointerEvents: "none",
display: "none",
},
}}
>
<CloseIcon

View File

@@ -57,6 +57,7 @@ const Avatar = ({ src, small, sx }) => {
}
sx={{
fontSize: small ? "16px" : "22px",
color: "white",
fontWeight: 400,
backgroundColor: stringToColor(`${user?.firstName} ${user?.lastName}`),
display: "inline-flex",

View File

@@ -17,8 +17,6 @@
.MuiPaper-root:has(table.MuiTable-root) {
box-shadow: none;
border: solid 1px var(--env-var-color-16);
border-radius: var(--env-var-radius-1);
}
.MuiTable-root
.MuiTableBody-root
@@ -26,10 +24,7 @@
.MuiTableCell-root {
border: none;
}
.MuiTable-root .MuiTableHead-root,
.MuiTable-root .MuiTableRow-root:hover {
background-color: var(--env-var-color-13);
}
.MuiTable-root .MuiTableHead-root .MuiTableCell-root,
.MuiTable-root .MuiTableBody-root .MuiTableCell-root {
font-size: var(--env-var-font-size-medium);
@@ -37,7 +32,6 @@
.MuiTable-root .MuiTableHead-root .MuiTableCell-root {
padding: var(--env-var-spacing-1) var(--env-var-spacing-2);
font-weight: 500;
color: var(--env-var-color-2);
}
.MuiTable-root .MuiTableHead-root span {
display: inline-block;
@@ -52,7 +46,6 @@
height: 20px;
}
.MuiTable-root .MuiTableBody-root .MuiTableCell-root {
color: var(--env-var-color-5);
padding: 6px var(--env-var-spacing-2);
}
.MuiTable-root .MuiTableBody-root .MuiTableRow-root {
@@ -60,21 +53,14 @@
}
.MuiPaper-root + .MuiPagination-root {
margin-top: 24px;
border: solid 1px var(--env-var-color-16);
border-radius: var(--env-var-radius-1);
padding: var(--env-var-spacing-1-plus) var(--env-var-spacing-2);
}
.MuiPaper-root + .MuiPagination-root ul {
justify-content: center;
}
.MuiPaper-root
+ .MuiPagination-root
ul
li:not(:first-child):not(:last-child)
button {
.MuiPaper-root + .MuiPagination-root button {
font-size: var(--env-var-font-size-medium);
color: var(--env-var-color-5);
font-weight: 500;
}
.MuiPaper-root + .MuiPagination-root ul li:first-child {
@@ -83,11 +69,6 @@
.MuiPaper-root + .MuiPagination-root ul li:last-child {
margin-left: auto;
}
.MuiPaper-root + .MuiPagination-root ul li:first-child button,
.MuiPaper-root + .MuiPagination-root ul li:last-child button {
border: solid 1px var(--env-var-color-16);
border-radius: var(--env-var-radius-1);
}
.MuiPaper-root + .MuiPagination-root ul li:first-child button {
padding: 0 var(--env-var-spacing-1) 0 var(--env-var-spacing-1-plus);
}
@@ -107,23 +88,14 @@
content: "Next";
margin-right: 15px;
}
.MuiPaper-root + .MuiPagination-root .MuiPaginationItem-root.Mui-selected {
background-color: var(--env-var-color-15);
}
.MuiPaper-root + .MuiPagination-root div.MuiPaginationItem-root {
user-select: none;
}
.MuiTablePagination-root p {
color: var(--env-var-color-2);
font-weight: 500;
font-size: var(--env-var-font-size-small-plus);
}
.MuiTablePagination-root button,
.MuiTablePagination-root .MuiSelect-select {
border: solid 1px #ebebeb;
border-radius: var(--env-var-radius-1);
}
.MuiTablePagination-root .MuiTablePagination-select.MuiSelect-select {
text-align: left;
text-align-last: left;
@@ -137,10 +109,6 @@
width: 22px;
height: 22px;
}
.MuiTablePagination-root svg path {
stroke: var(--env-var-color-2);
stroke-width: 1.3;
}
.MuiTablePagination-root .MuiSelect-icon {
width: 16px;
height: 16px;
@@ -151,38 +119,9 @@
.MuiTablePagination-root button.Mui-disabled {
opacity: 0.4;
}
.MuiTablePagination-root button:not(.Mui-disabled):hover {
background-color: #f4f4f4;
border-color: #f4f4f4;
}
.pagination-dropdown.MuiPaper-root {
box-shadow: var(--env-var-shadow-1);
border: solid 1px var(--env-var-color-6);
border-radius: var(--env-var-radius-1);
}
.pagination-dropdown ul {
padding: 4px;
min-width: 100px;
}
.pagination-dropdown li,
body:has(.pagination-dropdown) p:has(+ .MuiTablePagination-root) {
font-size: var(--env-var-font-size-medium);
color: var(--env-var-color-2);
padding: 4px;
}
.pagination-dropdown li.Mui-selected,
.pagination-dropdown li.Mui-selected.Mui-focusVisible,
.pagination-dropdown li.Mui-selected:hover {
background-color: #f4f4f4;
}
body:has(.pagination-dropdown) p:has(+ .MuiTablePagination-root) {
font-size: var(--env-var-font-size-small-plus);
}
.monitors .MuiTable-root .MuiTableHead-root .MuiTableCell-root {
text-transform: uppercase;
color: var(--env-var-color-5);
opacity: 0.8;
font-size: var(--env-var-font-size-small-plus);
font-weight: 400;

View File

@@ -200,12 +200,31 @@ const BasicTable = ({ data, paginated, reversed, table }) => {
return (
<>
<TableContainer component={Paper}>
<TableContainer
component={Paper}
sx={{
backgroundColor: theme.palette.background.main,
border: `solid 1px ${theme.palette.border.light}`,
borderRadius: theme.shape.borderRadius,
}}
>
<Table>
<TableHead>
<TableHead
sx={{
backgroundColor: theme.palette.background.accent,
}}
>
<TableRow>
{data.cols.map((col) => (
<TableCell key={col.id}>{col.name}</TableCell>
<TableCell
key={col.id}
sx={{
color: theme.palette.text.secondary,
borderBottomColor: theme.palette.border.light,
}}
>
{col.name}
</TableCell>
))}
</TableRow>
</TableHead>
@@ -215,12 +234,25 @@ const BasicTable = ({ data, paginated, reversed, table }) => {
<TableRow
sx={{
cursor: row.handleClick ? "pointer" : "default",
"&:hover": {
backgroundColor: theme.palette.background.accent,
},
}}
key={row.id}
onClick={row.handleClick ? row.handleClick : null}
>
{row.data.map((cell) => {
return <TableCell key={cell.id}>{cell.data}</TableCell>;
return (
<TableCell
key={cell.id}
sx={{
color: theme.palette.text.secondary,
borderBottomColor: theme.palette.border.light,
}}
>
{cell.data}
</TableCell>
);
})}
</TableRow>
);
@@ -233,9 +265,14 @@ const BasicTable = ({ data, paginated, reversed, table }) => {
direction="row"
alignItems="center"
justifyContent="space-between"
px={theme.gap.small}
px={theme.spacing(4)}
sx={{
"& p": {
color: theme.palette.text.tertiary,
},
}}
>
<Typography sx={{ opacity: 0.7 }}>
<Typography px={theme.spacing(2)} fontSize={12} sx={{ opacity: 0.7 }}>
Showing {getRange()} of {data.rows.length} monitor(s)
</Typography>
<TablePagination
@@ -260,27 +297,44 @@ const BasicTable = ({ data, paginated, reversed, table }) => {
keepMounted: true,
PaperProps: {
className: "pagination-dropdown",
sx: {
mt: 0,
mb: theme.spacing(2),
},
},
transformOrigin: { vertical: "bottom", horizontal: "left" },
anchorOrigin: { vertical: "top", horizontal: "left" },
sx: { mt: "-4px" },
sx: { mt: theme.spacing(-2) },
},
inputProps: { id: "pagination-dropdown" },
IconComponent: SelectorVertical,
sx: {
ml: theme.gap.small,
mr: theme.gap.large,
minWidth: theme.gap.xl,
ml: theme.spacing(4),
mr: theme.spacing(12),
minWidth: theme.spacing(20),
textAlign: "left",
"&.Mui-focused > div": {
backgroundColor: theme.palette.otherColors.white,
backgroundColor: theme.palette.background.main,
},
},
},
}}
sx={{
mt: theme.gap.medium,
color: theme.palette.otherColors.bluishGray,
mt: theme.spacing(6),
color: theme.palette.text.secondary,
"& button.MuiButtonBase-root, & .MuiSelect-select": {
border: 1,
borderColor: theme.palette.border.light,
borderRadius: theme.shape.borderRadius,
},
"& svg path": {
stroke: theme.palette.text.tertiary,
strokeWidth: 1.3,
},
"& button:not(.Mui-disabled):hover": {
backgroundColor: theme.palette.background.fill,
borderColor: theme.palette.background.fill,
},
}}
/>
</Stack>

View File

@@ -1,5 +1,5 @@
.MuiBreadcrumbs-root {
height: 36px;
height: 34px;
}
.MuiBreadcrumbs-root svg {
width: 16px;
@@ -7,17 +7,8 @@
}
.MuiBreadcrumbs-root .MuiBreadcrumbs-li a {
font-size: var(--env-var-font-size-medium);
color: var(--env-var-color-2);
opacity: 0.8;
font-weight: 400;
}
.MuiBreadcrumbs-root .MuiBreadcrumbs-li:hover a {
color: var(--env-var-color-2);
}
.MuiBreadcrumbs-root .MuiBreadcrumbs-li:not(:last-child):hover a {
opacity: 1;
background-color: #e3e3e3;
}
.MuiBreadcrumbs-root .MuiBreadcrumbs-li:not(:last-child) {
cursor: pointer;
}

View File

@@ -25,23 +25,36 @@ const Breadcrumbs = ({ list }) => {
<MUIBreadcrumbs
separator={<ArrowRight />}
aria-label="breadcrumb"
p={theme.gap.small}
px={theme.spacing(2)}
py={theme.spacing(3.5)}
width="fit-content"
backgroundColor={theme.palette.otherColors.fillGray}
borderRadius={`${theme.shape.borderRadius}px`}
backgroundColor={theme.palette.background.fill}
borderRadius={theme.shape.borderRadius}
lineHeight="18px"
sx={{
"& .MuiBreadcrumbs-li:not(:last-of-type):hover a": {
backgroundColor: theme.palette.other.fill,
opacity: 1,
},
}}
>
{list.map((item, index) => {
return (
<Box
component="a"
key={`${item.name}-${index}`}
px={theme.gap.small}
pt={theme.gap.xs}
pb="6px"
sx={{ textTransform: "capitalize" }}
borderRadius={`${theme.shape.borderRadius}px`}
px={theme.spacing(4)}
pt={theme.spacing(2)}
pb={theme.spacing(3)}
borderRadius={theme.shape.borderRadius}
onClick={() => navigate(item.path)}
sx={{
opacity: 0.8,
textTransform: "capitalize",
"&, &:hover": {
color: theme.palette.text.tertiary,
},
}}
>
{item.name}
</Box>

View File

@@ -77,6 +77,7 @@ const Button = ({
fontWeight: 400,
boxShadow: "none",
textTransform: "none",
borderRadius: "4px",
"&:focus": {
outline: "none",
},

View File

@@ -74,12 +74,13 @@ const ButtonSpinner = ({
sx={{
boxShadow: "none",
textTransform: "none",
borderRadius: "4px",
"&:focus": {
outline: "none",
},
"&:hover": {
boxShadow: "none",
transition: "none"
transition: "none",
},
...sx,
}}

View File

@@ -1,19 +0,0 @@
.bar-tooltip .MuiTooltip-tooltip {
background-color: white;
border: solid 1px black;
box-shadow: var(--env-var-shadow-1);
border: solid 1px var(--env-var-color-6);
border-radius: var(--env-var-radius-1);
padding: 4px 8px;
}
.bar-tooltip .MuiTooltip-tooltip p {
font-size: var(--env-var-font-size-small-plus);
color: var(--env-var-color-2);
font-weight: 500;
}
.bar-tooltip .MuiTooltip-tooltip span {
font-size: var(--env-var-font-size-small);
color: var(--env-var-color-2);
font-weight: 600;
}

View File

@@ -26,7 +26,7 @@ const BarChart = ({ checks = [] }) => {
<Stack
direction="row"
flexWrap="nowrap"
gap="3px"
gap={theme.spacing(1.5)}
height="50px"
width="fit-content"
onClick={(event) => event.stopPropagation()}
@@ -39,11 +39,11 @@ const BarChart = ({ checks = [] }) => {
<Box
key={`${check}-${index}`}
position="relative"
width="9px"
width={theme.spacing(4.5)}
height="100%"
backgroundColor={theme.palette.otherColors.fillGray}
backgroundColor={theme.palette.background.fill}
sx={{
borderRadius: "3px",
borderRadius: theme.spacing(1.5),
}}
/>
) : (
@@ -53,15 +53,15 @@ const BarChart = ({ checks = [] }) => {
<Typography>
{formatDate(new Date(check.createdAt), { year: undefined })}
</Typography>
<Box mt={theme.gap.xs}>
<Box mt={theme.spacing(2)}>
<Box
display="inline-block"
width={theme.gap.small}
height={theme.gap.small}
width={theme.spacing(4)}
height={theme.spacing(4)}
backgroundColor={
check.status
? theme.label.up.dotColor
: theme.label.down.dotColor
? theme.palette.success.main
: theme.palette.error.text
}
sx={{ borderRadius: "50%" }}
/>
@@ -69,8 +69,8 @@ const BarChart = ({ checks = [] }) => {
display="inline-flex"
direction="row"
justifyContent="space-between"
ml={theme.gap.xs}
gap={theme.gap.large}
ml={theme.spacing(2)}
gap={theme.spacing(12)}
>
<Typography component="span" sx={{ opacity: 0.8 }}>
Response Time
@@ -99,6 +99,27 @@ const BarChart = ({ checks = [] }) => {
},
},
],
sx: {
"& .MuiTooltip-tooltip": {
backgroundColor: theme.palette.background.main,
border: 1,
borderColor: theme.palette.border.dark,
borderRadius: theme.shape.borderRadius,
boxShadow: theme.shape.boxShadow,
px: theme.spacing(4),
py: theme.spacing(2),
},
"& .MuiTooltip-tooltip p": {
fontSize: 12,
color: theme.palette.text.tertiary,
fontWeight: 500,
},
"& .MuiTooltip-tooltip span": {
fontSize: 11,
color: theme.palette.text.tertiary,
fontWeight: 600,
},
},
},
}}
>
@@ -107,10 +128,10 @@ const BarChart = ({ checks = [] }) => {
width="9px"
height="100%"
backgroundColor={
check.status ? theme.label.up.bgColor : theme.label.down.bgColor
check.status ? theme.palette.success.bg : theme.palette.error.bg
}
sx={{
borderRadius: "3px",
borderRadius: theme.spacing(1.5),
"&:hover > .MuiBox-root": {
filter: "brightness(0.8)",
},
@@ -123,11 +144,11 @@ const BarChart = ({ checks = [] }) => {
height={`${animate ? check.responseTime : 0}%`}
backgroundColor={
check.status
? theme.label.up.dotColor
: theme.label.down.dotColor
? theme.palette.success.main
: theme.palette.error.text
}
sx={{
borderRadius: "3px",
borderRadius: theme.spacing(1.5),
transition: "height 600ms cubic-bezier(0.4, 0, 0.2, 1)",
}}
/>

View File

@@ -1,17 +1,20 @@
import { BarChart, Bar, Cell, ReferenceLine, Label } from "recharts";
import PropTypes from "prop-types";
import { useTheme } from "@emotion/react";
const MonitorDetails60MinChart = ({ data }) => {
const theme = useTheme();
const labelStyle = {
fontSize: "10px",
fill: "#475467",
fill: theme.palette.text.tertiary,
};
const color = {
true: "var(--env-var-color-23)",
false: "var(--env-var-color-24)",
undefined: "var(--env-var-color-33)",
true: theme.palette.success.main,
false: theme.palette.error.text,
undefined: theme.palette.unresolved.main,
};
return (
<BarChart

View File

@@ -1,19 +0,0 @@
.area-tooltip {
background-color: white;
border: solid 1px var(--env-var-color-4);
border-radius: var(--env-var-radius-1);
padding: var(--env-var-spacing-1) var(--env-var-spacing-2);
}
.area-tooltip p {
margin: 0;
padding: 0;
}
.area-tooltip p:first-of-type {
color: var(--env-var-color-3);
font-size: var(--env-var-font-size-medium);
}
.area-tooltip p:last-of-type {
margin-top: 5px;
color: var(--env-var-color-5);
font-size: var(--env-var-font-size-small);
}

View File

@@ -1,12 +1,31 @@
import PropTypes from "prop-types";
import { AreaChart, Area, XAxis, Tooltip, ResponsiveContainer } from "recharts";
import { Box, Typography } from "@mui/material";
import { useTheme } from "@emotion/react";
import "./index.css";
const CustomToolTip = ({ active, payload, label }) => {
const theme = useTheme();
if (active && payload && payload.length) {
return (
<div className="area-tooltip">
<p>
<Box
className="area-tooltip"
sx={{
backgroundColor: theme.palette.background.main,
border: 1,
borderColor: theme.palette.border.dark,
borderRadius: theme.shape.borderRadius,
py: theme.spacing(6),
px: theme.spacing(8),
}}
>
<Typography
sx={{
color: theme.palette.common.main,
fontSize: 13,
}}
>
{new Date(label).toLocaleDateString("en-US", {
weekday: "short", // Mon
month: "long", // July
@@ -18,10 +37,18 @@ const CustomToolTip = ({ active, payload, label }) => {
minute: "2-digit", // 15
hour12: true, // AM/PM format
})}
</p>
<p>Response Time (ms): {payload[0].payload.originalResponseTime}</p>{" "}
</Typography>
<Typography
mt={theme.spacing(2.5)}
sx={{
color: theme.palette.text.secondary,
fontSize: 13,
}}
>
Response Time (ms): {payload[0].payload.originalResponseTime}
</Typography>{" "}
{/* Display original value */}
</div>
</Box>
);
}
return null;

View File

@@ -1,7 +0,0 @@
.chart-container {
display: flex;
justify-content: space-around;
align-items: flex-end;
height: 50px;
width: 300px;
}

View File

@@ -1,10 +1,17 @@
import "./index.css";
import PropTypes from "prop-types";
import { Stack } from "@mui/material";
import { BarChart, Bar, ResponsiveContainer, Cell } from "recharts";
import "./index.css";
const ResponseTimeChart = ({ checks = [] }) => {
return (
<div className="chart-container">
<Stack
flexDirection="row"
justifyContent="space-around"
alignItems="flex-end"
height="50px"
width="300px"
>
<ResponsiveContainer width="100%" height="100%">
<BarChart
width={150}
@@ -18,15 +25,15 @@ const ResponseTimeChart = ({ checks = [] }) => {
key={`cell-${index}`}
fill={
check.status === true
? "var(--env-var-color-23)"
: "var(--env-var-color-24)"
? "var(--success-color)"
: "var(--error-color)"
}
/>
))}
</Bar>
</BarChart>
</ResponsiveContainer>
</div>
</Stack>
);
};

View File

@@ -1,35 +0,0 @@
import React from "react";
import "./statistic.css";
import PropTypes from "prop-types";
import { useTheme } from "@mui/material";
/**
* @component
* @param {Object} props
* @param {string} props.title - The title text for the statistic (required)
* @param {string} props.value - The numerical or textual value for the statistic (required)
* @returns {JSX.Element} - Renders the statistic component
*/
const Statistic = ({ title, value }) => {
const theme = useTheme();
const fontLookup = {
default: theme.font.default.font,
};
const fontFamily = fontLookup["default"];
return (
<div className="statistic-tile" style={{ fontFamily: fontFamily }}>
<div className="statistic-tile-title">{title}</div>
<div className="statistic-tile-value">{value}</div>
</div>
);
};
Statistic.propTypes = {
title: PropTypes.string.isRequired,
value: PropTypes.string.isRequired,
};
export default Statistic;

View File

@@ -1,31 +0,0 @@
:root {
--stats-spacing-general-0: 5px 10px;
--color-border-0: #eaecf0;
--border-radius-0: 4px;
--font-size-0: 1rem;
--font-size-1: 13px;
--font-color-0: #344054;
--margin-bottom-0: 10px;
}
.statistic-tile {
margin: var(--stats-spacing-general-0);
padding: var(--stats-spacing-general-0);
border: 1px solid var(--color-border-0);
border-radius: var(--border-radius-0);
width: 180px;
}
.statistic-tile-title {
font-size: var(--font-size-0);
color: var(--font-color-0);
margin-bottom: var(--margin-bottom-0);
}
.statistic-tile-value {
font-size: var(--font-size-1);
color: var(--font-color-0);
font-weight: 700;
margin-bottom: var(--margin-bottom-0);
}

View File

@@ -2,7 +2,7 @@ import "./check.css";
import PropTypes from "prop-types";
import CheckGrey from "../../assets/icons/check.svg?react";
import CheckOutlined from "../../assets/icons/check-outlined.svg?react";
import { Stack, Typography } from "@mui/material";
import { Box, Stack, Typography } from "@mui/material";
import { useTheme } from "@emotion/react";
/**
@@ -22,25 +22,41 @@ import { useTheme } from "@emotion/react";
*/
const Check = ({ text, variant = "info", outlined = false }) => {
const theme = useTheme();
const colors = {
success: theme.palette.success.main,
error: theme.palette.error.text,
info: theme.palette.info.border,
};
return (
<Stack
direction="row"
gap={outlined ? theme.gap.medium : theme.gap.small}
className={`check${
variant === "error"
? " check-error"
: variant === "success"
? " check-success"
: " check-info"
}`}
className="check"
gap={outlined ? theme.spacing(6) : theme.spacing(4)}
alignItems="center"
>
{outlined ? (
<CheckOutlined alt="check" />
) : (
<CheckGrey alt="form checks" />
<Box
lineHeight={0}
sx={{
"& svg > path": { fill: colors[variant] },
}}
>
<CheckGrey alt="form checks" />
</Box>
)}
<Typography component="span">{text}</Typography>
<Typography
component="span"
sx={{
color:
variant === "info" ? theme.palette.text.tertiary : colors[variant],
opacity: 0.8,
}}
>
{text}
</Typography>
</Stack>
);
};

View File

@@ -1,17 +1 @@
.check > span.MuiTypography-root {
font-size: var(--env-var-font-size-small-plus);
color: var(--env-var-color-2);
opacity: 0.8;
}
.check-error span.MuiTypography-root {
color: var(--env-var-color-24);
}
.check-error svg > path {
fill: var(--env-var-color-19);
}
.check-success span.MuiTypography-root {
color: var(--env-var-color-17);
}
.check-success svg > path {
fill: var(--env-var-color-23);
}

View File

@@ -7,10 +7,6 @@
font-size: var(--env-var-font-size-large);
font-weight: 600;
}
[class*="fallback__"] .check span.MuiTypography-root,
[class*="fallback__"] h1.MuiTypography-root {
color: var(--env-var-color-5);
}
[class*="fallback__"] button.MuiButtonBase-root,
[class*="fallback__"] .check {
width: max-content;

View File

@@ -2,7 +2,7 @@ import PropTypes from "prop-types";
import { useTheme } from "@emotion/react";
import { Box, Stack, Typography } from "@mui/material";
import Skeleton from "../../assets/Images/create-placeholder.svg?react";
import background from "../../assets/Images/background_pattern_decorative.png";
import Background from "../../assets/Images/background-grid.svg?react";
import Button from "../Button";
import Check from "../Check/Check";
import { useNavigate } from "react-router-dom";
@@ -27,16 +27,26 @@ const Fallback = ({ title, checks, link = "/", isAdmin }) => {
<Stack
className={`fallback__${title.trim().split(" ")[0]}`}
alignItems="center"
gap={theme.gap.xl}
gap={theme.spacing(20)}
>
<Skeleton style={{ zIndex: 1 }} />
<Box
className="background-pattern-svg"
sx={{ backgroundImage: `url(${background})` }}
/>
<Stack gap={theme.gap.small} maxWidth={"275px"} zIndex={1}>
<Typography component="h1" marginY={theme.gap.medium}>
A {title} monitor is used to:
sx={{
"& svg g g:last-of-type path": {
stroke: theme.palette.border.light,
},
}}
>
<Background style={{ width: "100%" }} />
</Box>
<Stack gap={theme.spacing(4)} maxWidth={"275px"} zIndex={1}>
<Typography
component="h1"
marginY={theme.spacing(4)}
color={theme.palette.text.secondary}
>
A {title} is used to:
</Typography>
{checks.map((check, index) => (
<Check
@@ -46,6 +56,7 @@ const Fallback = ({ title, checks, link = "/", isAdmin }) => {
/>
))}
</Stack>
{/* TODO - display a different fallback if user is not an admin*/}
{isAdmin && (
<Button
level="primary"

View File

@@ -1,14 +0,0 @@
.checkbox-wrapper {
border-radius: var(--env-var-radius-1);
}
.checkbox-wrapper:not(:has(.Mui-disabled)):hover {
background-color: var(--env-var-color-15);
}
.checkbox-wrapper span.MuiTypography-root {
font-size: var(--env-var-font-size-medium);
color: var(--env-var-color-2);
}
.checkbox-wrapper .MuiButtonBase-root {
margin-right: var(--env-var-spacing-1);
padding: 0;
}

View File

@@ -1,5 +1,6 @@
import PropTypes from "prop-types";
import { FormControlLabel, Checkbox as MuiCheckbox } from "@mui/material";
import { useTheme } from "@emotion/react";
import CheckboxOutline from "../../../assets/icons/checkbox-outline.svg?react";
import CheckboxFilled from "../../../assets/icons/checkbox-filled.svg?react";
@@ -16,7 +17,7 @@ import "./index.css";
* @param {boolean} [props.isDisabled] - Whether the checkbox is disabled or not.
*
* @returns {JSX.Element}
*
*
* @example
* <Checkbox
* id="checkbox-id"
@@ -37,6 +38,7 @@ const Checkbox = ({
isDisabled,
}) => {
const sizes = { small: "14px", medium: "16px", large: "18px" };
const theme = useTheme();
return (
<FormControlLabel
@@ -61,10 +63,20 @@ const Checkbox = ({
label={label}
disabled={isDisabled}
sx={{
p: "5px",
m: "-5px",
borderRadius: theme.shape.borderRadius,
p: theme.spacing(2.5),
m: theme.spacing(-2.5),
"& .MuiButtonBase-root": {
width: "20px",
width: theme.spacing(10),
p: 0,
mr: theme.spacing(6),
},
"&:not(:has(.Mui-disabled)):hover": {
backgroundColor: theme.palette.background.accent,
},
"& span.MuiTypography-root": {
fontSize: 13,
color: theme.palette.text.tertiary,
},
}}
/>

View File

@@ -8,24 +8,6 @@
.field .input-error {
font-size: var(--env-var-font-size-medium);
}
.field h3.MuiTypography-root,
.field h5.MuiTypography-root,
.field input,
.field textarea {
color: var(--env-var-color-5);
}
.field h3.MuiTypography-root {
font-weight: 500;
}
.field h3.MuiTypography-root span.field-required {
color: var(--env-var-color-19);
margin-left: 2px;
}
.field h3.MuiTypography-root span.field-optional {
opacity: 0.6;
margin-left: 4px;
font-weight: 400;
}
.field h5.MuiTypography-root {
position: relative;
opacity: 0.8;
@@ -37,24 +19,7 @@
.field .MuiInputBase-root:has(.MuiInputAdornment-root) {
padding-right: var(--env-var-spacing-1-minus);
}
.field
.MuiInputBase-root:has(.copy.MuiInputAdornment-root > .MuiButtonBase-root) {
padding-right: 0;
}
.field .MuiInputBase-root .copy.MuiInputAdornment-root .MuiButtonBase-root {
padding: 0 var(--env-var-spacing-1-minus);
font-size: var(--env-var-font-size-medium);
border-radius: 0;
height: 34px;
}
.field .MuiInputBase-root .copy.MuiInputAdornment-root .MuiButtonBase-root svg {
width: 20px;
height: 20px;
margin-right: 5px;
}
.field .MuiInputBase-root .MuiInputAdornment-root .MuiButtonBase-root:hover {
border-color: var(--env-var-color-29);
}
.field input {
height: 100%;
padding: 0 var(--env-var-spacing-1-minus);
@@ -62,22 +27,6 @@
.field .MuiInputBase-root:has(textarea) {
padding: var(--env-var-spacing-1-minus);
}
.field .MuiOutlinedInput-root fieldset {
border-color: var(--env-var-color-29);
border-radius: var(--env-var-radius-1);
}
.field:not(:has(.Mui-disabled)):not(:has(.input-error))
.MuiOutlinedInput-root:hover:not(:has(input:focus)):not(:has(textarea:focus))
fieldset {
border-color: var(--env-var-color-29);
}
.field .input-error {
color: var(--env-var-color-24);
opacity: 0.8;
}
.field:has(.input-error) .MuiOutlinedInput-root fieldset {
border-color: var(--env-var-color-19);
}
.register-page .field .MuiOutlinedInput-root fieldset,
.register-page .field input,

View File

@@ -1,4 +1,5 @@
import PropTypes from "prop-types";
import { forwardRef, useState } from "react";
import { useTheme } from "@emotion/react";
import {
IconButton,
@@ -9,10 +10,7 @@ import {
} from "@mui/material";
import VisibilityOff from "@mui/icons-material/VisibilityOff";
import Visibility from "@mui/icons-material/Visibility";
import ContentCopyIcon from "@mui/icons-material/ContentCopy";
import Button from "../../Button";
import "./index.css";
import { forwardRef, useState } from "react";
/**
* @param {Object} props
@@ -23,7 +21,6 @@ import { forwardRef, useState } from "react";
* @param {boolean} [props.isRequired] - Indicates if the field is required, will display a red asterisk.
* @param {boolean} [props.isOptional] - Indicates if the field is optional, will display optional text.
* @param {string} [props.optionalLabel] - Optional label for the input field.
* @param {boolean} [props.hasCopy] - Indicates if the field supports copying.
* @param {string} [props.autoComplete] - Autocomplete value for the input field.
* @param {string} [props.placeholder] - Placeholder text for the input field.
* @param {string} props.value - Value of the input field.
@@ -43,7 +40,6 @@ const Field = forwardRef(
isRequired,
isOptional,
optionalLabel,
hasCopy,
autoComplete,
placeholder,
value,
@@ -56,25 +52,54 @@ const Field = forwardRef(
) => {
const theme = useTheme();
// TODO - are we using this feature anywhere ?
const [copy, setCopy] = useState(false);
const handleCopy = () => {
setCopy(true);
setTimeout(() => setCopy(false), 1000);
};
const [isVisible, setVisible] = useState(false);
return (
<Stack gap={theme.gap.xs} className={`field field-${type}`}>
<Stack
gap={theme.spacing(2)}
className={`field field-${type}`}
sx={{
"& fieldset": {
borderColor: theme.palette.border.dark,
borderRadius: theme.shape.borderRadius,
},
"&:not(:has(.Mui-disabled)):not(:has(.input-error)) .MuiOutlinedInput-root:hover:not(:has(input:focus)):not(:has(textarea:focus)) fieldset":
{
borderColor: theme.palette.border.dark,
},
"&:has(.input-error) .MuiOutlinedInput-root fieldset": {
borderColor: theme.palette.error.text,
},
}}
>
{label && (
<Typography component="h3">
<Typography
component="h3"
color={theme.palette.text.secondary}
fontWeight={500}
>
{label}
{isRequired ? <span className="field-required">*</span> : ""}
{isRequired ? (
<Typography
component="span"
ml={theme.spacing(1)}
color={theme.palette.error.text}
>
*
</Typography>
) : (
""
)}
{isOptional ? (
<span className="field-optional">
<Typography
component="span"
fontSize="inherit"
fontWeight={400}
ml={theme.spacing(2)}
sx={{ opacity: 0.6 }}
>
{optionalLabel || "(optional)"}
</span>
</Typography>
) : (
""
)}
@@ -92,13 +117,18 @@ const Field = forwardRef(
onChange={onChange}
disabled={disabled}
inputRef={ref}
inputProps={{
sx: {
color: theme.palette.text.secondary,
},
}}
sx={
type === "url"
? {
"& .MuiInputBase-root": { padding: 0 },
"& .MuiStack-root": {
borderTopLeftRadius: `${theme.shape.borderRadius}px`,
borderBottomLeftRadius: `${theme.shape.borderRadius}px`,
borderTopLeftRadius: theme.shape.borderRadius,
borderBottomLeftRadius: theme.shape.borderRadius,
},
}
: {}
@@ -110,65 +140,53 @@ const Field = forwardRef(
alignItems="center"
height="100%"
sx={{
borderRight: `solid 1px ${theme.palette.section.borderColor}`,
backgroundColor: "#f9f9fa",
pl: theme.gap.medium,
borderRight: `solid 1px ${theme.palette.border.dark}`,
backgroundColor: theme.palette.background.accent,
pl: theme.spacing(6),
}}
>
<Typography component="h5" sx={{ lineHeight: 1 }}>
<Typography
component="h5"
color={theme.palette.text.secondary}
sx={{ lineHeight: 1 }}
>
{https ? "https" : "http"}://
</Typography>
</Stack>
),
endAdornment:
type === "password" ? (
<InputAdornment position="end">
<IconButton
aria-label="toggle password visibility"
onClick={() => setVisible((show) => !show)}
tabIndex={-1}
sx={{
color: theme.palette.section.borderColor,
padding: `calc(${theme.gap.xs} / 2)`,
"&:focus": {
outline: "none",
},
"& .MuiTouchRipple-root": {
pointerEvents: "none",
display: "none",
},
}}
>
{!isVisible ? <VisibilityOff /> : <Visibility />}
</IconButton>
</InputAdornment>
) : (
hasCopy && (
<InputAdornment className="copy" position="end">
<Button
level="tertiary"
label={copy ? "Copied" : "Copy"}
img={<ContentCopyIcon />}
onClick={handleCopy}
sx={{
borderLeft: `solid 1px ${theme.palette.section.borderColor}`,
lineHeight: 0,
"& .MuiTouchRipple-root": {
pointerEvents: "none",
display: "none",
},
}}
/>
</InputAdornment>
)
),
endAdornment: type === "password" && (
<InputAdornment position="end">
<IconButton
aria-label="toggle password visibility"
onClick={() => setVisible((show) => !show)}
tabIndex={-1}
sx={{
color: theme.palette.border.dark,
padding: theme.spacing(1),
"&:focus": {
outline: "none",
},
"& .MuiTouchRipple-root": {
pointerEvents: "none",
display: "none",
},
}}
>
{!isVisible ? <VisibilityOff /> : <Visibility />}
</IconButton>
</InputAdornment>
),
}}
/>
{error && (
<Typography
component="span"
className="input-error"
mt={theme.gap.xs}
color={theme.palette.error.text}
mt={theme.spacing(2)}
sx={{
opacity: 0.8,
}}
>
{error}
</Typography>
@@ -195,7 +213,6 @@ Field.propTypes = {
isRequired: PropTypes.bool,
isOptional: PropTypes.bool,
optionalLabel: PropTypes.string,
hasCopy: PropTypes.bool,
autoComplete: PropTypes.string,
placeholder: PropTypes.string,
value: PropTypes.string.isRequired,

View File

@@ -1,9 +1,3 @@
.image-field-wrapper h2.MuiTypography-root,
.image-field-wrapper p.MuiTypography-root,
.image-field-wrapper + p.MuiTypography-root,
.MuiStack-root:has(#modal-update-picture) h1.MuiTypography-root {
color: var(--env-var-color-2);
}
.MuiStack-root:has(#modal-update-picture) h1.MuiTypography-root {
font-weight: 600;
}
@@ -20,10 +14,5 @@
}
.image-field-wrapper + p.MuiTypography-root,
.image-field-wrapper p.MuiTypography-root {
opacity: 0.6;
font-size: var(--env-var-font-size-small-plus);
}
.image-field-wrapper h2.MuiTypography-root span {
color: var(--env-var-color-3);
font-weight: 500;
}

View File

@@ -31,19 +31,19 @@ const ImageField = ({ id, src, loading, onChange }) => {
<>
<Box
className="image-field-wrapper"
mt="20px"
mt={theme.spacing(8)}
sx={{
position: "relative",
height: "fit-content",
border: "dashed",
borderRadius: `${theme.shape.borderRadius}px`,
borderRadius: theme.shape.borderRadius,
borderColor: isDragging
? theme.palette.primary.main
: theme.palette.otherColors.graishWhite,
? theme.palette.common.main
: theme.palette.border.light,
borderWidth: "2px",
transition: "0.2s",
"&:hover": {
borderColor: theme.palette.primary.main,
borderColor: theme.palette.common.main,
backgroundColor: "hsl(215, 87%, 51%, 0.05)",
},
}}
@@ -85,20 +85,40 @@ const ImageField = ({ id, src, loading, onChange }) => {
<IconButton
sx={{
pointerEvents: "none",
borderRadius: `${theme.shape.borderRadius}px`,
border: `solid ${theme.shape.borderThick}px ${theme.palette.otherColors.graishWhite}`,
borderRadius: theme.shape.borderRadius,
border: `solid ${theme.shape.borderThick}px ${theme.palette.border.light}`,
boxShadow: theme.shape.boxShadow,
}}
>
<CloudUploadIcon />
</IconButton>
<Typography component="h2">
<span>Click to upload</span> or drag and drop
<Typography component="h2" color={theme.palette.text.tertiary}>
<Typography
component="span"
fontSize="inherit"
color={theme.palette.common.main}
fontWeight={500}
>
Click to upload
</Typography>{" "}
or drag and drop
</Typography>
<Typography
component="p"
color={theme.palette.text.tertiary}
sx={{ opacity: 0.6 }}
>
(maximum size: 3MB)
</Typography>
<Typography component="p">(maximum size: 3MB)</Typography>
</Stack>
</Box>
<Typography component="p">Supported formats: JPG, PNG</Typography>
<Typography
component="p"
color={theme.palette.text.tertiary}
sx={{ opacity: 0.6 }}
>
Supported formats: JPG, PNG
</Typography>
</>
) : (
<Stack direction="row" justifyContent="center">

View File

@@ -0,0 +1 @@

View File

@@ -1,10 +1,16 @@
import PropTypes from "prop-types";
import { FormControlLabel, Radio as MUIRadio, Typography } from "@mui/material";
import { useTheme } from "@emotion/react";
import RadioChecked from "../../../assets/icons/radio-checked.svg?react";
import "./index.css";
/**
* RadioButton component.
* Radio component.
*
* @component
* @example
* // Usage:
* <RadioButton
* <Radio
* title="Radio Button Title"
* desc="Radio Button Description"
* size="small"
@@ -15,47 +21,66 @@
* @param {string} props.title - The title of the radio button.
* @param {string} [props.desc] - The description of the radio button.
* @param {string} [props.size="small"] - The size of the radio button.
* @returns {JSX.Element} - The rendered RadioButton component.
* @returns {JSX.Element} - The rendered Radio component.
*/
import PropTypes from "prop-types";
import { FormControlLabel, Radio, Typography } from "@mui/material";
import { useTheme } from "@emotion/react";
import "./index.css";
function RadioButton(props) {
const Radio = (props) => {
const theme = useTheme();
return (
<FormControlLabel
className="custom-radio-button"
checked={props.checked}
value={props.value}
control={
<Radio
<MUIRadio
id={props.id}
size={props.size}
sx={{ color: theme.palette.secondary.main }}
checkedIcon={<RadioChecked />}
sx={{
color: "transparent",
width: 16,
height: 16,
boxShadow: "inset 0 0 0 1px #656a74",
mt: theme.spacing(0.5),
}}
/>
}
onChange={props.onChange}
label={
<>
<Typography component="p">{props.title}</Typography>
<Typography component="h6" mt="2px">
<Typography
component="h6"
mt={theme.spacing(1)}
color={theme.palette.text.secondary}
>
{props.desc}
</Typography>
</>
}
labelPlacement="end"
sx={{ margin: 0, alignItems: "flex-start" }}
sx={{
alignItems: "flex-start",
p: theme.spacing(2.5),
m: theme.spacing(-2.5),
borderRadius: theme.shape.borderRadius,
"&:hover": {
backgroundColor: theme.palette.background.accent,
},
"& .MuiButtonBase-root": {
p: 0,
mr: theme.spacing(6),
},
}}
/>
);
}
};
RadioButton.propTypes = {
Radio.propTypes = {
title: PropTypes.string.isRequired,
desc: PropTypes.string,
size: PropTypes.string,
};
export default RadioButton;
export default Radio;

View File

@@ -1,46 +1,7 @@
.select-wrapper .select-component > .MuiSelect-select {
padding: 0 10px;
height: 34px !important;
display: flex !important;
height: 34px;
display: flex;
align-items: center;
text-transform: capitalize;
line-height: 1;
}
.select-wrapper .MuiInputBase-root:has(> .MuiSelect-select) {
min-width: 150px;
}
.select-wrapper .MuiInputBase-root:has(> .MuiSelect-select),
.MuiMenu-List .MuiMenuItem-root,
.select-wrapper h3.MuiTypography-root {
font-size: var(--env-var-font-size-medium);
color: var(--env-var-color-5);
}
.select-wrapper h3.MuiTypography-root {
font-weight: 500;
}
.MuiInputBase-root:has(> .MuiSelect-select) fieldset {
border-color: var(--env-var-color-29);
}
.MuiInputBase-root:not(.Mui-focused):has(> .MuiSelect-select):hover fieldset {
border-color: var(--env-var-color-29);
}
.select-dropdown.MuiPaper-root {
box-shadow: var(--env-var-shadow-1);
border: solid 1px var(--env-var-color-6);
border-radius: var(--env-var-radius-1);
}
.select-dropdown .MuiList-root {
min-width: 100px;
}
.select-dropdown li {
font-size: var(--env-var-font-size-medium);
color: var(--env-var-color-5);
padding: 5px 8px;
border-radius: var(--env-var-radius-1);
}
.select-dropdown li.Mui-selected,
.select-dropdown li.Mui-selected.Mui-focusVisible,
.select-dropdown li.Mui-selected:hover {
background-color: #f4f4f4;
}

View File

@@ -55,34 +55,44 @@ const Select = ({
const theme = useTheme();
const itemStyles = {
fontSize: "var(--env-var-font-size-medium)",
color: theme.palette.otherColors.bluishGray,
textTransform: "capitalize",
borderRadius: `${theme.shape.borderRadius}px`,
margin: theme.gap.xs,
color: theme.palette.text.tertiary,
borderRadius: theme.shape.borderRadius,
margin: theme.spacing(2),
};
return (
<Stack gap={theme.gap.xs} className="select-wrapper">
{label && <Typography component="h3">{label}</Typography>}
<Stack gap={theme.spacing(2)} className="select-wrapper">
{label && (
<Typography
component="h3"
color={theme.palette.text.secondary}
fontWeight={500}
>
{label}
</Typography>
)}
<MuiSelect
className="select-component"
value={value}
onChange={onChange}
displayEmpty
inputProps={{ id: id }}
MenuProps={{
PaperProps: {
className: "select-dropdown",
style: {
marginTop: theme.gap.xs,
},
},
MenuListProps: {
style: { padding: 0 },
},
}}
IconComponent={KeyboardArrowDownIcon}
sx={{ ...sx }}
sx={{
fontSize: 13,
minWidth: "125px",
"& fieldset": {
borderRadius: theme.shape.borderRadius,
borderColor: theme.palette.border.dark,
},
"&:not(.Mui-focused):hover fieldset": {
borderColor: theme.palette.border.dark,
},
"& svg path": {
fill: theme.palette.other.icon,
},
...sx,
}}
>
{placeholder && (
<MenuItem

View File

@@ -30,9 +30,9 @@ const BaseLabel = ({ label, styles, children }) => {
<Box
className="label"
sx={{
borderRadius: `${borderRadius}px`,
borderColor: theme.palette.tertiary.main,
color: theme.palette.tertiary.main,
borderRadius: borderRadius,
borderColor: theme.palette.text.tertiary,
color: theme.palette.text.tertiary,
padding: padding,
...styles,
}}
@@ -90,7 +90,7 @@ const ColoredLabel = ({ label, color }) => {
typeof color !== "string" ||
!/^#([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$/.test(color)
) {
color = theme.palette.labelGray.color;
color = theme.palette.border.light;
}
// Calculate lighter shades for border and bg
@@ -127,8 +127,26 @@ ColoredLabel.propTypes = {
const StatusLabel = ({ status, text, customStyles }) => {
const theme = useTheme();
const colors = {
up: {
dotColor: theme.palette.success.main,
bgColor: theme.palette.success.bg,
borderColor: theme.palette.success.light,
},
down: {
dotColor: theme.palette.error.text,
bgColor: theme.palette.error.bg,
borderColor: theme.palette.error.light,
},
"cannot resolve": {
dotColor: theme.palette.unresolved.main,
bgColor: theme.palette.unresolved.bg,
borderColor: theme.palette.unresolved.light,
},
};
// Look up the color for the status
const { borderColor, bgColor, dotColor } = theme.label[status];
const { borderColor, bgColor, dotColor } = colors[status];
return (
<BaseLabel

View File

@@ -16,24 +16,24 @@ const Link = ({ level, label, url }) => {
const levelConfig = {
primary: {},
secondary: {
color: theme.palette.otherColors.bluishGray,
color: theme.palette.text.secondary,
sx: {
":hover": {
color: theme.palette.otherColors.bluishGray,
color: theme.palette.text.secondary,
},
},
},
tertiary: {
color: theme.palette.tertiary.main,
color: theme.palette.text.tertiary,
sx: {
textDecoration: "underline",
textDecorationStyle: "dashed",
textDecorationColor: theme.palette.primary.main,
textDecorationColor: theme.palette.common.main,
textUnderlineOffset: "1px",
":hover": {
color: theme.palette.tertiary.main,
textDecorationColor: theme.palette.primary.main,
backgroundColor: theme.palette.tertiary.linkHover,
color: theme.palette.text.tertiary,
textDecorationColor: theme.palette.common.main,
backgroundColor: theme.palette.background.fill,
},
},
},

View File

@@ -1,32 +1,10 @@
.progress-bar-container {
background-color: #fafafa;
padding: var(--env-var-spacing-1-plus);
}
.progress-bar-container h2.MuiTypography-root,
.progress-bar-container p.MuiTypography-root {
color: var(--env-var-color-2);
font-size: var(--env-var-font-size-medium);
}
.progress-bar-container p.MuiTypography-root {
opacity: 0.6;
}
.progress-bar-container p.MuiTypography-root:has(span) {
font-size: 12px;
}
.progress-bar-container p.MuiTypography-root span {
padding-left: 2px;
}
.progress-bar-container:has(p.input-error){
border-color: var(--env-var-color-19);
background-color: var(--env-var-color-21);
padding: 8px var(--env-var-spacing-1-plus);
}
.progress-bar-container p.input-error{
color: var(--env-var-color-24);
opacity: 0.8;
}
.progress-bar-container:has(p.input-error)>.MuiStack-root>svg{
fill: var(--env-var-color-24);
width: 20px;
height: 20px;
}

View File

@@ -32,21 +32,36 @@ const ProgressUpload = ({
error,
}) => {
const theme = useTheme();
return (
<Box
className="progress-bar-container"
mt="20px"
mt={theme.spacing(10)}
p={theme.spacing(8)}
sx={{
minWidth: "200px",
height: "fit-content",
borderRadius: `${theme.shape.borderRadius}px`,
border: `solid 1px ${theme.palette.otherColors.graishWhite}`,
borderRadius: theme.shape.borderRadius,
border: 1,
borderColor: theme.palette.border.light,
backgroundColor: "#fafafa",
"&:has(.input-error)": {
borderColor: theme.palette.error.main,
backgroundColor: theme.palette.error.bg,
py: theme.spacing(4),
px: theme.spacing(8),
"& > .MuiStack-root > svg": {
fill: theme.palette.error.text,
width: "20px",
height: "20px",
},
},
}}
>
<Stack
direction="row"
mb={error ? "0" : "10px"}
gap="10px"
mb={error ? 0 : theme.spacing(5)}
gap={theme.spacing(5)}
alignItems={error ? "center" : "flex-end"}
>
{error ? (
@@ -54,10 +69,11 @@ const ProgressUpload = ({
) : icon ? (
<IconButton
sx={{
backgroundColor: theme.palette.otherColors.white,
backgroundColor: theme.palette.background.main,
pointerEvents: "none",
borderRadius: `${theme.shape.borderRadius}px`,
border: `solid ${theme.shape.borderThick}px ${theme.palette.otherColors.graishWhite}`,
borderRadius: theme.shape.borderRadius,
border: 2,
borderColor: theme.palette.border.light,
boxShadow: theme.shape.boxShadow,
}}
>
@@ -67,15 +83,21 @@ const ProgressUpload = ({
""
)}
{error ? (
<Typography component="p" className="input-error">
<Typography
component="p"
className="input-error"
color={theme.palette.error.text}
>
{error}
</Typography>
) : (
<Box>
<Typography component="h2" mb="5px">
<Box color={theme.palette.text.tertiary}>
<Typography component="h2" mb={theme.spacing(1.5)}>
{error ? error : label}
</Typography>
<Typography component="p">{!error && size}</Typography>
<Typography component="p" sx={{ opacity: 0.6 }}>
{!error && size}
</Typography>
</Box>
)}
<IconButton
@@ -85,9 +107,9 @@ const ProgressUpload = ({
? {
alignSelf: "flex-start",
ml: "auto",
mr: "-5px",
mt: "-5px",
padding: "5px",
mr: theme.spacing(-2.5),
mt: theme.spacing(-2.5),
padding: theme.spacing(2.5),
"&:focus": {
outline: "none",
},
@@ -109,20 +131,23 @@ const ProgressUpload = ({
</Stack>
{!error ? (
<Stack direction="row" alignItems="center">
<Box sx={{ width: "100%", mr: "10px" }}>
<Box sx={{ width: "100%", mr: theme.spacing(5) }}>
<LinearProgress
variant="determinate"
value={progress}
sx={{
width: "100%",
height: "10px",
borderRadius: `${theme.shape.borderRadius}px`,
borderRadius: theme.shape.borderRadius,
maxWidth: "500px",
backgroundColor: theme.palette.otherColors.graishWhite,
backgroundColor: theme.palette.border.light,
}}
/>
</Box>
<Typography component="p" sx={{ minWidth: "max-content" }}>
<Typography
component="p"
sx={{ minWidth: "max-content", opacity: 0.6 }}
>
{progress}
<span>%</span>
</Typography>

View File

@@ -1,15 +0,0 @@
.create-monitor-form .custom-radio-button.MuiFormControlLabel-root,
.configure-monitor .custom-radio-button.MuiFormControlLabel-root {
padding: 5px;
margin: -5px;
border-radius: var(--env-var-radius-1);
}
.create-monitor-form .custom-radio-button.MuiFormControlLabel-root:hover,
.configure-monitor .custom-radio-button.MuiFormControlLabel-root:hover {
background-color: var(--env-var-color-15);
}
.custom-radio-button.MuiFormControlLabel-root .MuiButtonBase-root {
margin-right: var(--env-var-spacing-1);
padding: 0;
}

View File

@@ -1,16 +1,8 @@
aside .selected-path,
.sidebar-popup .selected-path,
aside .MuiListItemButton-root:hover {
background-color: var(--env-var-color-13);
}
aside .MuiList-root svg {
width: 20px;
height: 20px;
opacity: 0.9;
}
aside .MuiList-root svg path {
stroke: var(--env-var-color-2);
}
aside span.MuiTypography-root {
font-size: var(--env-var-font-size-medium);
line-height: 1;
@@ -26,11 +18,6 @@ aside .MuiListSubheader-root {
margin-bottom: 2px;
opacity: 0.6;
}
aside span.MuiTypography-root,
aside p.MuiTypography-root,
aside .MuiListSubheader-root {
color: var(--env-var-color-5);
}
aside p.MuiTypography-root {
font-size: var(--env-var-font-size-small);
opacity: 0.8;
@@ -47,82 +34,15 @@ aside .selected-path span.MuiTypography-root {
aside .MuiCollapse-wrapperInner .MuiList-root > .MuiListItemButton-root {
position: relative;
}
aside .MuiDivider-root {
border-color: var(--env-var-color-6);
}
aside
.MuiCollapse-wrapperInner
.MuiList-root
> .MuiListItemButton-root::before {
content: "";
position: absolute;
left: -7px;
top: 0;
height: 100%;
width: 100%;
border-left: solid 1px var(--env-var-color-5);
opacity: 0.2;
}
aside
.MuiCollapse-wrapperInner
.MuiList-root
> .MuiListItemButton-root:last-child::before {
height: 50%;
}
aside .MuiCollapse-wrapperInner .MuiList-root svg,
aside .MuiList-root .MuiListItemText-root + svg {
width: 18px;
height: 18px;
}
aside .MuiCollapse-wrapperInner .MuiList-root > .MuiListItemButton-root::after {
content: "";
position: absolute;
left: -8px;
top: 45%;
height: 3px;
width: 3px;
border-radius: 50%;
background-color: #d6d9dd;
}
aside
.MuiCollapse-wrapperInner
.MuiList-root
> .selected-path.MuiListItemButton-root::after {
background-color: var(--env-var-color-2);
transform: scale(1.2);
}
.sidebar-popup .MuiPaper-root {
box-shadow: var(--env-var-shadow-1);
border: solid 1px var(--env-var-color-6);
border-radius: var(--env-var-radius-1);
gap: 1px;
}
.sidebar-popup .MuiList-root {
padding: 3px;
min-width: 100px;
}
.sidebar-popup li.MuiButtonBase-root {
font-size: var(--env-var-font-size-medium);
color: var(--env-var-color-5);
padding: 5px 8px;
border-radius: var(--env-var-radius-1);
}
.sidebar-popup li.MuiButtonBase-root:hover {
background-color: var(--env-var-color-13);
}
.sidebar-popup li.MuiButtonBase-root:has(.MuiBox-root):hover {
background-color: white;
}
.sidebar-popup li.MuiButtonBase-root:has(.MuiBox-root) {
padding-bottom: 0;
}
.sidebar-popup .MuiModal-root p.MuiTypography-root {
font-size: var(--env-var-font-size-medium);
color: var(--env-var-color-2);
}
.sidebar-popup svg {
width: 16px;
height: 16px;

View File

@@ -19,7 +19,7 @@ import { useLocation, useNavigate } from "react-router";
import { useTheme } from "@emotion/react";
import { useDispatch, useSelector } from "react-redux";
import { clearAuthState } from "../../Features/Auth/authSlice";
import { toggleSidebar } from "../../Features/UI/uiSlice";
import { setMode, toggleSidebar } from "../../Features/UI/uiSlice";
import { clearUptimeMonitorState } from "../../Features/UptimeMonitors/uptimeMonitorsSlice";
import Avatar from "../Avatar";
import LockSvg from "../../assets/icons/lock.svg?react";
@@ -40,6 +40,7 @@ import ArrowDown from "../../assets/icons/down-arrow.svg?react";
import ArrowUp from "../../assets/icons/up-arrow.svg?react";
import ArrowRight from "../../assets/icons/right-arrow.svg?react";
import ArrowLeft from "../../assets/icons/left-arrow.svg?react";
import DotsVertical from "../../assets/icons/dots-vertical.svg?react";
import "./index.css";
@@ -85,8 +86,7 @@ function Sidebar() {
const location = useLocation();
const dispatch = useDispatch();
const authState = useSelector((state) => state.auth);
const { sidebar } = useSelector((state) => state.ui);
let collapsed = sidebar.collapsed;
const collapsed = useSelector((state) => state.ui.sidebar.collapsed);
const [open, setOpen] = useState({ Dashboard: false, Account: false });
const [anchorEl, setAnchorEl] = useState(null);
const [popup, setPopup] = useState();
@@ -124,21 +124,38 @@ function Sidebar() {
<Stack
component="aside"
className={collapsed ? "collapsed" : "expanded"}
gap={theme.gap.medium}
py={theme.spacing(6)}
gap={theme.spacing(6)}
sx={{
border: 1,
borderColor: theme.palette.border.light,
borderRadius: theme.shape.borderRadius,
backgroundColor: theme.palette.background.main,
"& .selected-path, & .MuiListItemButton-root:hover": {
backgroundColor: theme.palette.background.accent,
},
"& .MuiList-root svg path": {
stroke: theme.palette.text.tertiary,
},
"& p, & span, & .MuiListSubheader-root": {
color: theme.palette.text.secondary,
},
}}
>
<Stack pt={theme.gap.medium} pb={theme.gap.large} pl={theme.gap.ml}>
<Stack direction="row" alignItems="center" gap={theme.gap.small}>
<Stack pt={theme.spacing(6)} pb={theme.spacing(12)} pl={theme.spacing(8)}>
<Stack direction="row" alignItems="center" gap={theme.spacing(4)}>
<Stack
justifyContent="center"
alignItems="center"
minWidth={theme.gap.lgplus}
minHeight={theme.gap.lgplus}
fontSize="18px"
minWidth={theme.spacing(16)}
minHeight={theme.spacing(16)}
pl="1px"
fontSize={18}
color="white"
sx={{
position: "relative",
backgroundColor: theme.palette.primary.main,
borderRadius: "4px",
backgroundColor: theme.palette.common.main,
borderRadius: theme.shape.borderRadius,
userSelect: "none",
}}
>
@@ -146,7 +163,7 @@ function Sidebar() {
</Stack>
<Typography
component="span"
mt={theme.gap.xs}
mt={theme.spacing(2)}
sx={{ opacity: 0.8, fontWeight: 500 }}
>
BlueWave Uptime
@@ -158,20 +175,21 @@ function Sidebar() {
top: 60,
right: 0,
transform: `translate(50%, 0)`,
backgroundColor: theme.palette.otherColors.fillGray,
border: `solid 1px ${theme.palette.otherColors.graishWhite}`,
p: "5px",
backgroundColor: theme.palette.background.fill,
border: 1,
borderColor: theme.palette.border.light,
p: theme.spacing(2.5),
"& svg": {
width: theme.gap.ml,
height: theme.gap.ml,
width: theme.spacing(8),
height: theme.spacing(8),
"& path": {
stroke: theme.palette.otherColors.bluishGray,
stroke: theme.palette.text.secondary,
},
},
"&:focus": { outline: "none" },
"&:hover": {
backgroundColor: "#e3e3e3",
borderColor: theme.palette.otherColors.graishWhite,
backgroundColor: theme.palette.border.light,
borderColor: theme.palette.border.light,
},
}}
onClick={() => {
@@ -192,15 +210,15 @@ function Sidebar() {
component="div"
id="nested-menu-subheader"
sx={{
pt: theme.gap.small,
px: collapsed ? theme.gap.xs : theme.gap.small,
backgroundColor: "transparent"
pt: theme.spacing(4),
px: collapsed ? theme.spacing(2) : theme.spacing(4),
backgroundColor: "transparent",
}}
>
Menu
</ListSubheader>
}
sx={{ px: theme.gap.medium }}
sx={{ px: theme.spacing(6) }}
>
{menu.map((item) =>
item.path ? (
@@ -229,9 +247,9 @@ function Sidebar() {
onClick={() => navigate(`/${item.path}`)}
sx={{
height: "37px",
gap: theme.gap.small,
borderRadius: `${theme.shape.borderRadius}px`,
px: theme.gap.small,
gap: theme.spacing(4),
borderRadius: theme.shape.borderRadius,
px: theme.spacing(4),
}}
>
<ListItemIcon sx={{ minWidth: 0 }}>{item.icon}</ListItemIcon>
@@ -266,9 +284,9 @@ function Sidebar() {
onClick={(event) => openPopup(event, item.name)}
sx={{
position: "relative",
gap: theme.gap.small,
borderRadius: `${theme.shape.borderRadius}px`,
px: theme.gap.small,
gap: theme.spacing(4),
borderRadius: theme.shape.borderRadius,
px: theme.spacing(4),
}}
>
<ListItemIcon sx={{ minWidth: 0 }}>{item.icon}</ListItemIcon>
@@ -284,7 +302,21 @@ function Sidebar() {
vertical: "top",
horizontal: "right",
}}
sx={{ ml: theme.gap.ml }}
slotProps={{
paper: {
sx: {
mt: theme.spacing(-2),
ml: theme.spacing(1),
},
},
}}
MenuListProps={{ sx: { px: 1, py: 2 } }}
sx={{
ml: theme.spacing(8),
"& .selected-path": {
backgroundColor: theme.palette.background.accent,
},
}}
>
{item.nested.map((child) => {
if (
@@ -308,10 +340,14 @@ function Sidebar() {
closePopup();
}}
sx={{
gap: theme.gap.small,
borderRadius: `${theme.shape.borderRadius}px`,
pl: theme.gap.small,
mb: "1px",
gap: theme.spacing(4),
opacity: 0.9,
"& svg": {
"& path": {
stroke: theme.palette.other.icon,
strokeWidth: 1.1,
},
},
}}
>
{child.icon}
@@ -331,9 +367,9 @@ function Sidebar() {
}))
}
sx={{
gap: theme.gap.small,
borderRadius: `${theme.shape.borderRadius}px`,
px: theme.gap.small,
gap: theme.spacing(4),
borderRadius: theme.shape.borderRadius,
px: theme.spacing(4),
}}
>
<ListItemIcon sx={{ minWidth: 0 }}>{item.icon}</ListItemIcon>
@@ -344,7 +380,7 @@ function Sidebar() {
<List
component="div"
disablePadding
sx={{ pl: theme.gap.large }}
sx={{ pl: theme.spacing(12) }}
>
{item.nested.map((child) => {
if (
@@ -365,9 +401,35 @@ function Sidebar() {
key={child.path}
onClick={() => navigate(`/${child.path}`)}
sx={{
gap: theme.gap.small,
borderRadius: `${theme.shape.borderRadius}px`,
pl: theme.gap.small,
gap: theme.spacing(4),
borderRadius: theme.shape.borderRadius,
pl: theme.spacing(4),
"&::before": {
content: `""`,
position: "absolute",
top: 0,
left: "-7px",
height: "100%",
borderLeft: 1,
borderLeftColor: theme.palette.other.line,
},
"&:last-child::before": {
height: "50%",
},
"&::after": {
content: `""`,
position: "absolute",
top: "45%",
left: "-8px",
height: "3px",
width: "3px",
borderRadius: "50%",
backgroundColor: theme.palette.other.line,
},
"&.selected-path::after": {
backgroundColor: theme.palette.text.tertiary,
transform: "scale(1.2)",
},
}}
>
<ListItemIcon sx={{ minWidth: 0 }}>
@@ -383,7 +445,7 @@ function Sidebar() {
)
)}
</List>
<Divider sx={{ my: theme.gap.small }} />
<Divider sx={{ my: theme.spacing(4) }} />
{/* other */}
<List
component="nav"
@@ -393,15 +455,15 @@ function Sidebar() {
component="div"
id="nested-other-subheader"
sx={{
pt: theme.gap.small,
px: collapsed ? 0 : theme.gap.small,
backgroundColor: "transparent"
pt: theme.spacing(4),
px: collapsed ? 0 : theme.spacing(4),
backgroundColor: "transparent",
}}
>
Other
</ListSubheader>
}
sx={{ px: theme.gap.medium }}
sx={{ px: theme.spacing(6) }}
>
{other.map((item) => (
<Tooltip
@@ -436,9 +498,9 @@ function Sidebar() {
: navigate(`/${item.path}`)
}
sx={{
gap: theme.gap.small,
borderRadius: `${theme.shape.borderRadius}px`,
px: theme.gap.small,
gap: theme.spacing(4),
borderRadius: theme.shape.borderRadius,
px: theme.spacing(4),
}}
>
<ListItemIcon sx={{ minWidth: 0 }}>{item.icon}</ListItemIcon>
@@ -453,10 +515,10 @@ function Sidebar() {
direction="row"
height="50px"
alignItems="center"
py={theme.gap.small}
px={theme.gap.ml}
gap={theme.gap.xs}
borderRadius={`${theme.shape.borderRadius}px`}
py={theme.spacing(4)}
px={theme.spacing(8)}
gap={theme.spacing(2)}
borderRadius={theme.shape.borderRadius}
>
{collapsed ? (
<>
@@ -483,47 +545,11 @@ function Sidebar() {
<Avatar small={true} />
</IconButton>
</Tooltip>
<Menu
className="sidebar-popup"
anchorEl={anchorEl}
open={Boolean(anchorEl) && popup === "logout"}
onClose={closePopup}
anchorOrigin={{
vertical: "top",
horizontal: "right",
}}
sx={{ ml: theme.gap.ml }}
>
<MenuItem sx={{ cursor: "default", minWidth: "150px" }}>
<Box>
<Typography component="span" fontWeight={500} fontSize="13px">
{authState.user?.firstName} {authState.user?.lastName}
</Typography>
<Typography
sx={{ textTransform: "capitalize", fontSize: "12px" }}
>
{authState.user?.role}
</Typography>
</Box>
</MenuItem>
<Divider />
<MenuItem
onClick={logout}
sx={{
gap: theme.gap.small,
borderRadius: `${theme.shape.borderRadius}px`,
pl: theme.gap.small,
}}
>
<LogoutSvg />
Log out
</MenuItem>
</Menu>
</>
) : (
<>
<Avatar small={true} />
<Box ml={theme.gap.xs}>
<Box ml={theme.spacing(2)}>
<Typography component="span" fontWeight={500}>
{authState.user?.firstName} {authState.user?.lastName}
</Typography>
@@ -531,16 +557,84 @@ function Sidebar() {
{authState.user?.role}
</Typography>
</Box>
<Tooltip title="Log Out">
<Tooltip title="Controls" disableInteractive>
<IconButton
sx={{ ml: "auto", "&:focus": { outline: "none" } }}
onClick={logout}
sx={{
ml: "auto",
mr: "-8px",
"&:focus": { outline: "none" },
"& svg": {
width: "20px",
height: "20px",
},
"& svg path": {
stroke: theme.palette.other.icon,
},
}}
onClick={(event) => openPopup(event, "logout")}
>
<LogoutSvg style={{ width: "20px", height: "20px" }} />
<DotsVertical />
</IconButton>
</Tooltip>
</>
)}
<Menu
className="sidebar-popup"
anchorEl={anchorEl}
open={Boolean(anchorEl) && popup === "logout"}
onClose={closePopup}
anchorOrigin={{
vertical: "top",
horizontal: "right",
}}
slotProps={{
paper: {
sx: {
marginTop: theme.spacing(-4),
marginLeft: collapsed ? theme.spacing(2) : 0,
},
},
}}
MenuListProps={{
sx: {
p: 2,
"& li:has(.MuiBox-root):hover": {
backgroundColor: theme.palette.background.main,
},
},
}}
sx={{
ml: theme.spacing(8),
}}
>
{collapsed && (
<MenuItem sx={{ cursor: "default", minWidth: "150px" }}>
<Box mb={theme.spacing(2)}>
<Typography component="span" fontWeight={500} fontSize={13}>
{authState.user?.firstName} {authState.user?.lastName}
</Typography>
<Typography sx={{ textTransform: "capitalize", fontSize: 12 }}>
{authState.user?.role}
</Typography>
</Box>
</MenuItem>
)}
{collapsed && <Divider />}
<MenuItem onClick={() => dispatch(setMode("light"))}>Light</MenuItem>
<MenuItem onClick={() => dispatch(setMode("dark"))}>Dark</MenuItem>
<Divider />
<MenuItem
onClick={logout}
sx={{
gap: theme.spacing(4),
borderRadius: theme.shape.borderRadius,
pl: theme.spacing(4),
}}
>
<LogoutSvg />
Log out
</MenuItem>
</Menu>
</Stack>
</Stack>
);

View File

@@ -1,7 +1,7 @@
import TabPanel from "@mui/lab/TabPanel";
import React, { useState } from "react";
import { useTheme } from "@emotion/react";
import { Box, Divider, Stack, Typography } from "@mui/material";
import { Box, Stack, Typography } from "@mui/material";
import ButtonSpinner from "../../ButtonSpinner";
import Field from "../../Inputs/Field";
import { credentials } from "../../../Validation/validation";
@@ -97,13 +97,20 @@ const PasswordPanel = () => {
};
return (
<TabPanel value="password">
<TabPanel
value="password"
sx={{
"& h1, & input": {
color: theme.palette.text.tertiary,
},
}}
>
<Stack
component="form"
onSubmit={handleSubmit}
noValidate
spellCheck="false"
gap={theme.gap.xl}
gap={theme.spacing(20)}
>
<Stack direction="row">
<Box flex={0.9}>
@@ -165,9 +172,9 @@ const PasswordPanel = () => {
loadingText="Saving..."
disabled={Object.keys(errors).length !== 0 && true}
sx={{
paddingX: theme.gap.large,
paddingX: theme.spacing(12),
width: "fit-content",
mt: theme.gap.xl,
mt: theme.spacing(20),
}}
/>
</Stack>

View File

@@ -216,13 +216,20 @@ const ProfilePanel = () => {
const isModalOpen = (name) => isOpen === name;
return (
<TabPanel value="profile">
<TabPanel
value="profile"
sx={{
"& h1, & p, & input": {
color: theme.palette.text.tertiary,
},
}}
>
<Stack
component="form"
className="edit-profile-form"
noValidate
spellCheck="false"
gap={theme.gap.xl}
gap={theme.spacing(20)}
>
<Stack direction="row">
<Box flex={0.9}>
@@ -295,7 +302,7 @@ const ProfilePanel = () => {
label="Update"
onClick={openPictureModal}
sx={{
color: theme.palette.primary.main,
color: theme.palette.common.main,
}}
/>
</Stack>
@@ -303,7 +310,9 @@ const ProfilePanel = () => {
<Divider
aria-hidden="true"
width="0"
sx={{ marginY: theme.spacing(1) }}
sx={{
marginY: theme.spacing(1),
}}
/>
<Stack direction="row" justifyContent="flex-end">
<Box width="fit-content">
@@ -317,18 +326,24 @@ const ProfilePanel = () => {
Object.keys(errors).length !== 0 && !errors?.picture && true
}
sx={{
paddingX: theme.gap.large,
paddingX: theme.spacing(12),
}}
/>
</Box>
</Stack>
</Stack>
<Divider aria-hidden="true" sx={{ marginY: theme.spacing(6) }} />
<Divider
aria-hidden="true"
sx={{
marginY: theme.spacing(20),
borderColor: theme.palette.border.light,
}}
/>
<Stack
component="form"
noValidate
spellCheck="false"
gap={theme.gap.small}
gap={theme.spacing(4)}
>
<Box>
<Typography component="h1">Delete account</Typography>
@@ -341,7 +356,7 @@ const ProfilePanel = () => {
level="error"
label="Delete account"
onClick={() => setIsOpen("delete")}
sx={{ width: "fit-content", mt: theme.gap.small }}
sx={{ width: "fit-content", mt: theme.spacing(4) }}
/>
</Stack>
{/* TODO - Update ModalPopup Component with @mui for reusability */}
@@ -353,18 +368,19 @@ const ProfilePanel = () => {
disablePortal
>
<Stack
gap="10px"
gap={theme.spacing(5)}
sx={{
position: "absolute",
top: "50%",
left: "50%",
transform: "translate(-50%, -50%)",
width: 500,
bgcolor: "white",
border: "solid 1px #f2f2f2",
borderRadius: `${theme.shape.borderRadius}px`,
bgcolor: theme.palette.background.main,
border: 1,
borderColor: theme.palette.border.light,
borderRadius: theme.shape.borderRadius,
boxShadow: 24,
p: "30px",
p: theme.spacing(15),
"&:focus": {
outline: "none",
},
@@ -378,7 +394,12 @@ const ProfilePanel = () => {
and all of your data will be deleted. Deleting your account is
permanent and non-recoverable action.
</Typography>
<Stack direction="row" gap="10px" mt="10px" justifyContent="flex-end">
<Stack
direction="row"
gap={theme.spacing(5)}
mt={theme.spacing(5)}
justifyContent="flex-end"
>
<Button
level="tertiary"
label="Cancel"
@@ -406,17 +427,22 @@ const ProfilePanel = () => {
left: "50%",
transform: "translate(-50%, -50%)",
width: 450,
bgcolor: "white",
border: "solid 1px #f2f2f2",
borderRadius: `${theme.shape.borderRadius}px`,
bgcolor: theme.palette.background.main,
border: 1,
borderColor: theme.palette.border.light,
borderRadius: theme.shape.borderRadius,
boxShadow: 24,
p: "30px",
p: theme.spacing(15),
"&:focus": {
outline: "none",
},
}}
>
<Typography id="modal-update-picture" component="h1">
<Typography
id="modal-update-picture"
component="h1"
color={theme.palette.text.secondary}
>
Upload Image
</Typography>
<ImageField
@@ -447,7 +473,12 @@ const ProfilePanel = () => {
) : (
""
)}
<Stack direction="row" mt="20px" gap="10px" justifyContent="flex-end">
<Stack
direction="row"
mt={theme.spacing(10)}
gap={theme.spacing(5)}
justifyContent="flex-end"
>
<Button
level="secondary"
label="Edit"

View File

@@ -99,12 +99,10 @@ const TeamPanel = () => {
id: idx,
data: (
<Stack>
<Typography
style={{ color: theme.palette.otherColors.blackish }}
>
<Typography style={{ color: theme.palette.text.secondary }}>
{member.firstName + " " + member.lastName}
</Typography>
<Typography sx={{ opacity: 0.6 }}>
<Typography>
Created {new Date(member.createdAt).toLocaleDateString()}
</Typography>
</Stack>
@@ -212,7 +210,18 @@ const TeamPanel = () => {
};
return (
<TabPanel value="team">
<TabPanel
value="team"
sx={{
"& h1": {
color: theme.palette.text.tertiary,
},
"& .MuiTable-root .MuiTableBody-root .MuiTableCell-root, & .MuiTable-root p + p":
{
color: theme.palette.text.accent,
},
}}
>
{/* FEATURE STILL TO BE IMPLEMENTED */}
{/* <Stack component="form">
<Box sx={{ alignSelf: "flex-start" }}>
@@ -243,7 +252,7 @@ const TeamPanel = () => {
},
}}
inputProps={{
sx: { textAlign: "end", padding: theme.gap.small },
sx: { textAlign: "end", padding: theme.spacing(4) },
}}
/>
<Button
@@ -253,8 +262,8 @@ const TeamPanel = () => {
onClick={() => toggleEdit()}
sx={{
minWidth: 0,
paddingX: theme.gap.small,
ml: orgStates.isEdit ? theme.gap.small : 0,
paddingX: theme.spacing(4),
ml: orgStates.isEdit ? theme.spacing(4) : 0,
}}
/>
</Stack>
@@ -264,24 +273,30 @@ const TeamPanel = () => {
component="form"
noValidate
spellCheck="false"
gap={theme.gap.large}
gap={theme.spacing(12)}
>
<Typography component="h1">Team members</Typography>
<Stack direction="row" justifyContent="space-between">
<Stack
direction="row"
alignItems="flex-end"
gap={theme.gap.medium}
sx={{ fontSize: "14px" }}
gap={theme.spacing(6)}
sx={{ fontSize: 14 }}
>
<ButtonGroup>
<ButtonGroup
sx={{
"& button, & button:hover": {
borderColor: theme.palette.border.light,
},
}}
>
<Button
level="secondary"
label="All"
onClick={() => setFilter("all")}
sx={{
backgroundColor:
filter === "all" && theme.palette.otherColors.fillGray,
filter === "all" && theme.palette.background.fill,
}}
/>
<Button
@@ -290,7 +305,7 @@ const TeamPanel = () => {
onClick={() => setFilter("admin")}
sx={{
backgroundColor:
filter === "admin" && theme.palette.otherColors.fillGray,
filter === "admin" && theme.palette.background.fill,
}}
/>
<Button
@@ -299,7 +314,7 @@ const TeamPanel = () => {
onClick={() => setFilter("user")}
sx={{
backgroundColor:
filter === "user" && theme.palette.otherColors.fillGray,
filter === "user" && theme.palette.background.fill,
}}
/>
</ButtonGroup>
@@ -307,7 +322,7 @@ const TeamPanel = () => {
<Button
level="primary"
label="Invite a team member"
sx={{ paddingX: "30px" }}
sx={{ paddingX: theme.spacing(15) }}
onClick={() => setIsOpen(true)}
/>
</Stack>
@@ -326,18 +341,19 @@ const TeamPanel = () => {
disablePortal
>
<Stack
gap="10px"
gap={theme.spacing(5)}
sx={{
position: "absolute",
top: "50%",
left: "50%",
transform: "translate(-50%, -50%)",
width: 400,
bgcolor: "white",
border: "solid 1px #f2f2f2",
borderRadius: `${theme.shape.borderRadius}px`,
bgcolor: theme.palette.background.main,
border: 1,
borderColor: theme.palette.border.light,
borderRadius: theme.shape.borderRadius,
boxShadow: 24,
p: "30px",
p: theme.spacing(15),
"&:focus": {
outline: "none",
},
@@ -349,7 +365,7 @@ const TeamPanel = () => {
<Typography
id="invite-member-to-team"
component="p"
sx={{ mb: theme.gap.medium }}
sx={{ mb: theme.spacing(6) }}
>
When you add a new team member, they will get access to all
monitors.
@@ -374,14 +390,14 @@ const TeamPanel = () => {
}))
}
items={[
{ _id: "admin", name: "admin" },
{ _id: "user", name: "user" },
{ _id: "admin", name: "Admin" },
{ _id: "user", name: "User" },
]}
/>
<Stack
direction="row"
gap={theme.gap.small}
mt={theme.gap.ml}
gap={theme.spacing(4)}
mt={theme.spacing(8)}
justifyContent="flex-end"
>
<Button

View File

@@ -1,45 +0,0 @@
import "./tooltipWithTail.css";
import React from "react";
import { styled } from "@mui/material/styles";
import Tooltip, { tooltipClasses } from "@mui/material/Tooltip";
import HelpOutlineIcon from "@mui/icons-material/HelpOutline";
const CustomizedTooltip = styled(
({ className, placement, arrow, ...props }) => (
<Tooltip
{...props}
placement={placement}
arrow={arrow}
classes={{ popper: className }}
/>
)
)(({ theme }) => ({
[`& .${tooltipClasses.tooltip}`]: {
backgroundColor: "black",
},
[`& .${tooltipClasses.arrow}`]: {
color: "black",
},
}));
function TooltipWithTail({ placement, arrow = false, title, text }) {
return (
<div>
<CustomizedTooltip
arrow={arrow}
placement={placement}
title={
<React.Fragment>
{title && <div className="tooltip-title">{title}</div>}
<div className="tooltip-description">{text}</div>
</React.Fragment>
}
className="tooltip-holder"
>
<HelpOutlineIcon style={{ fill: "#98A2B3" }} />
</CustomizedTooltip>
</div>
);
}
export default TooltipWithTail;

View File

@@ -1,49 +0,0 @@
:root {
--env-var-color-1: #101828;
--env-var-color-2: #475467;
--env-var-color-3: #1570ef;
--env-var-color-4: #d0d5dd;
--env-var-color-5: #344054;
--env-var-color-6: #eaecf0;
--env-var-color-7: #7f56d9;
--env-var-color-8: #fff;
--env-var-color-9: #f2f2f2;
--env-var-color-10: #175cd3;
--env-var-radius-1: 4px;
--env-var-radius-2: 8px;
--env-var-width-1: 100vw;
--env-var-width-2: 360px;
--env-var-height-1: 100vh;
--env-var-spacing-1: 12px;
--env-var-spacing-2: 24px;
--env-var-spacing-3: 32px;
--env-var-spacing-4: 40px;
--env-var-font-size-small: 11px;
--env-var-font-size-medium: 13px;
--env-var-font-size-medium-plus: 14px;
--env-var-font-size-large: 16px;
--env-var-font-size-xlarge: 30px;
--env-var-img-width-1: 20px;
--env-var-default-1: 24px;
--env-var-default-2: 40px;
}
.tooltip-title {
font-size: var(--env-var-font-size-medium);
font-weight: bold;
margin: 5px;
}
.tooltip-description {
font-size: var(--env-var-font-size-medium);
color: var(--env-var-color-4);
margin: 5px;
}

View File

@@ -12,6 +12,7 @@ const initialState = {
sidebar: {
collapsed: false,
},
mode: "light",
};
const uiSlice = createSlice({
@@ -19,13 +20,19 @@ const uiSlice = createSlice({
initialState,
reducers: {
setRowsPerPage: (state, action) => {
state[action.payload.table].rowsPerPage = action.payload.value;
const { table, value } = action.payload;
if (state[table]) {
state[table].rowsPerPage = value;
}
},
toggleSidebar: (state) => {
state.sidebar.collapsed = !state.sidebar.collapsed;
},
setMode: (state, action) => {
state.mode = action.payload;
},
},
});
export default uiSlice.reducer;
export const { setRowsPerPage, toggleSidebar } = uiSlice.actions;
export const { setRowsPerPage, toggleSidebar, setMode } = uiSlice.actions;

View File

@@ -1,5 +1,5 @@
#root:has(.home-layout) {
background-color: var(--env-var-color-30);
background-color: var(--secondary-bg);
}
.home-layout {
@@ -19,12 +19,6 @@
height: calc(100vh - var(--env-var-spacing-2) * 2);
max-width: var(--env-var-side-bar-width);
border: 1px solid var(--env-var-color-6);
border-radius: var(--env-var-radius-1);
background-color: var(--env-var-color-8);
padding: var(--env-var-spacing-1) 0;
}
.home-layout > div {
@@ -32,19 +26,11 @@
flex: 1;
}
.home-layout > div:has(> [class*="fallback__"]) {
border: solid 1px var(--env-var-color-6);
border-radius: var(--env-var-radius-1);
border-style: dashed;
background-color: var(--env-var-color-8);
overflow: hidden;
position: relative;
}
.home-layout > div:has(> [class*="fallback__"]) .background-pattern-svg {
position: absolute;
top: 0;
left: 50%;
transform: translate(-50%, -33%);
transform: translate(-50%, -50%);
z-index: 0;
width: 100%;

View File

@@ -1,14 +1,19 @@
import Sidebar from "../../Components/Sidebar";
import { Outlet } from "react-router";
import { Box } from "@mui/material";
import { useTheme } from "@emotion/react";
import "./index.css";
const HomeLayout = () => {
const theme = useTheme();
return (
<Box className="home-layout">
<Sidebar />
<Outlet />
<Box backgroundColor={theme.palette.background.alt}>
<Box className="home-layout">
<Sidebar />
<Outlet />
</Box>
</Box>
);
};

View File

@@ -6,12 +6,6 @@
.account .MuiSelect-select {
font-size: var(--env-var-font-size-medium);
}
.account h1.MuiTypography-root,
.account p.MuiTypography-root,
.account input,
.account .MuiSelect-select {
color: var(--env-var-color-2);
}
.account h1.MuiTypography-root {
font-weight: 600;
}
@@ -19,10 +13,6 @@
padding: 0;
margin-top: 50px;
}
.account .MuiDivider-root,
.account .MuiButtonGroup-root button {
border-color: var(--env-var-color-16);
}
.account button:not(.MuiIconButton-root) {
height: 34px;
}
@@ -43,9 +33,6 @@
top: 100%;
}
.account .MuiTable-root .MuiTableBody-root .MuiTableCell-root {
color: var(--env-var-color-25);
}
.account .MuiTableBody-root .MuiTableCell-root {
padding: var(--env-var-spacing-1-plus) var(--env-var-spacing-2);
}

View File

@@ -34,18 +34,18 @@ const Account = ({ open = "profile" }) => {
return (
<Box
className="account"
px={theme.gap.xl}
py={theme.gap.large}
px={theme.spacing(20)}
py={theme.spacing(12)}
border={1}
borderColor={theme.palette.otherColors.graishWhite}
borderRadius={`${theme.shape.borderRadius}px`}
backgroundColor={theme.palette.otherColors.white}
borderColor={theme.palette.border.light}
borderRadius={theme.shape.borderRadius}
backgroundColor={theme.palette.background.main}
>
<TabContext value={tab}>
<Box
sx={{
borderBottom: 1,
borderColor: "var(--env-var-color-16)",
borderColor: theme.palette.border.light,
"& .MuiTabs-root": { height: "fit-content", minHeight: "0" },
}}
>
@@ -56,15 +56,15 @@ const Account = ({ open = "profile" }) => {
key={index}
value={label.toLowerCase()}
sx={{
fontSize: "13px",
color: theme.palette.secondary.main,
fontSize: 13,
color: theme.palette.text.tertiary,
textTransform: "none",
minWidth: "fit-content",
minHeight: 0,
paddingLeft: "0",
paddingY: theme.gap.small,
paddingLeft: 0,
paddingY: theme.spacing(4),
fontWeight: 400,
marginRight: theme.gap.ml,
marginRight: theme.spacing(8),
"&:focus": {
outline: "none",
},

View File

@@ -85,7 +85,21 @@ const CheckEmail = () => {
};
return (
<Stack className="check-email-page auth" overflow="hidden">
<Stack
className="check-email-page auth"
overflow="hidden"
sx={{
"& h1": {
color: theme.palette.common.main,
fontWeight: 600,
fontSize: 26,
},
"& p": {
fontSize: 14,
color: theme.palette.text.accent,
},
}}
>
<Box
className="background-pattern-svg"
sx={{ backgroundImage: `url(${background})` }}
@@ -93,8 +107,8 @@ const CheckEmail = () => {
<Stack
direction="row"
alignItems="center"
px={theme.gap.large}
gap={theme.gap.small}
px={theme.spacing(12)}
gap={theme.spacing(4)}
>
<Logo style={{ borderRadius: theme.shape.borderRadius }} />
<Typography sx={{ userSelect: "none" }}>BlueWave Uptime</Typography>
@@ -104,31 +118,31 @@ const CheckEmail = () => {
maxWidth={600}
flex={1}
justifyContent="center"
px={{ xs: theme.gap.large, lg: theme.gap.xl }}
pb={theme.gap.xl}
px={{ xs: theme.spacing(12), lg: theme.spacing(20) }}
pb={theme.spacing(20)}
mx="auto"
sx={{
"& > .MuiStack-root": {
border: 1,
borderRadius: theme.shape.borderRadius,
borderColor: theme.palette.otherColors.graishWhite,
backgroundColor: theme.palette.otherColors.white,
borderRadius: theme.spacing(5),
borderColor: theme.palette.border.light,
backgroundColor: theme.palette.background.main,
padding: {
xs: theme.gap.large,
sm: theme.gap.xl,
xs: theme.spacing(12),
sm: theme.spacing(20),
},
},
}}
>
<Stack
gap={{ xs: theme.gap.ml, sm: theme.gap.large }}
gap={{ xs: theme.spacing(8), sm: theme.spacing(12) }}
alignItems="center"
textAlign="center"
>
<Box>
<EmailIcon alt="email icon" />
<Typography component="h1">Check your email</Typography>
<Typography mt={theme.gap.xs}>
<Typography mt={theme.spacing(2)}>
We sent a password reset link to{" "}
<Typography className="email-sent-to" component="span">
{email || "username@email.com"}
@@ -144,13 +158,13 @@ const CheckEmail = () => {
maxWidth: 400,
}}
/>
<Typography sx={{ alignSelf: "center", mb: theme.gap.medium }}>
<Typography sx={{ alignSelf: "center", mb: theme.spacing(6) }}>
Didn&apos;t receive the email?{" "}
<Typography
component="span"
onClick={resendToken}
sx={{
color: theme.palette.primary.main,
color: theme.palette.common.main,
userSelect: "none",
pointerEvents: disabled ? "none" : "auto",
cursor: disabled ? "default" : "pointer",
@@ -162,11 +176,12 @@ const CheckEmail = () => {
</Typography>
</Stack>
</Stack>
<Box textAlign="center" p={theme.gap.large}>
<Box textAlign="center" p={theme.spacing(12)}>
<Typography display="inline-block">Go back to </Typography>
<Typography
component="span"
ml={theme.gap.xs}
ml={theme.spacing(2)}
color={theme.palette.common.main}
onClick={handleNavigate}
sx={{ userSelect: "none" }}
>

View File

@@ -87,7 +87,21 @@ const ForgotPassword = () => {
};
return (
<Stack className="forgot-password-page auth" overflow="hidden">
<Stack
className="forgot-password-page auth"
overflow="hidden"
sx={{
"& h1": {
color: theme.palette.common.main,
fontWeight: 600,
fontSize: 24,
},
"& p": {
fontSize: 14,
color: theme.palette.text.accent,
},
}}
>
<Box
className="background-pattern-svg"
sx={{ backgroundImage: `url(${background})` }}
@@ -95,8 +109,8 @@ const ForgotPassword = () => {
<Stack
direction="row"
alignItems="center"
px={theme.gap.large}
gap={theme.gap.small}
px={theme.spacing(12)}
gap={theme.spacing(4)}
>
<Logo style={{ borderRadius: theme.shape.borderRadius }} />
<Typography sx={{ userSelect: "none" }}>BlueWave Uptime</Typography>
@@ -106,24 +120,24 @@ const ForgotPassword = () => {
maxWidth={600}
flex={1}
justifyContent="center"
px={{ xs: theme.gap.large, lg: theme.gap.xl }}
pb={theme.gap.xl}
px={{ xs: theme.spacing(12), lg: theme.spacing(20) }}
pb={theme.spacing(20)}
mx="auto"
sx={{
"& > .MuiStack-root": {
border: 1,
borderRadius: theme.shape.borderRadius,
borderColor: theme.palette.otherColors.graishWhite,
backgroundColor: theme.palette.otherColors.white,
borderRadius: theme.spacing(5),
borderColor: theme.palette.border.light,
backgroundColor: theme.palette.background.main,
padding: {
xs: theme.gap.large,
sm: theme.gap.xl,
xs: theme.spacing(12),
sm: theme.spacing(20),
},
},
}}
>
<Stack
gap={{ xs: theme.gap.ml, sm: theme.gap.large }}
gap={{ xs: theme.spacing(8), sm: theme.spacing(12) }}
alignItems="center"
textAlign="center"
>
@@ -134,39 +148,45 @@ const ForgotPassword = () => {
No worries, we&apos;ll send you reset instructions.
</Typography>
</Box>
<Box width="100%" textAlign="left">
<form noValidate spellCheck={false} onSubmit={handleSubmit}>
<Field
type="email"
id="forgot-password-email-input"
label="Email"
isRequired={true}
placeholder="Enter your email"
value={form.email}
onChange={handleChange}
error={errors.email}
/>
<ButtonSpinner
disabled={errors.email !== undefined}
onClick={handleSubmit}
isLoading={isLoading}
level="primary"
label="Send instructions"
sx={{
width: "100%",
fontWeight: 400,
mt: theme.gap.mlplus,
}}
/>
</form>
<Box
component="form"
width="95%"
textAlign="left"
noValidate
spellCheck={false}
onSubmit={handleSubmit}
>
<Field
type="email"
id="forgot-password-email-input"
label="Email"
isRequired={true}
placeholder="Enter your email"
value={form.email}
onChange={handleChange}
error={errors.email}
/>
<ButtonSpinner
disabled={errors.email !== undefined}
onClick={handleSubmit}
isLoading={isLoading}
level="primary"
label="Send instructions"
sx={{
width: "100%",
fontWeight: 400,
mt: theme.spacing(15),
}}
/>
</Box>
</Stack>
</Stack>
<Box textAlign="center" p={theme.gap.large}>
<Box textAlign="center" p={theme.spacing(12)}>
<Typography display="inline-block">Go back to </Typography>
<Typography
component="span"
ml={theme.gap.xs}
color={theme.palette.common.main}
ml={theme.spacing(2)}
onClick={handleNavigate}
sx={{ userSelect: "none" }}
>

View File

@@ -30,7 +30,7 @@ const LandingPage = ({ onContinue }) => {
return (
<>
<Stack
gap={{ xs: theme.gap.ml, sm: theme.gap.large }}
gap={{ xs: theme.spacing(8), sm: theme.spacing(12) }}
alignItems="center"
textAlign="center"
>
@@ -47,7 +47,7 @@ const LandingPage = ({ onContinue }) => {
sx={{
width: "100%",
"& svg": {
mr: theme.gap.small,
mr: theme.spacing(4),
},
}}
/>
@@ -64,6 +64,11 @@ const LandingPage = ({ onContinue }) => {
"noreferrer"
);
}}
sx={{
"&:hover": {
color: theme.palette.text.tertiary,
},
}}
>
Terms of Service
</Typography>{" "}
@@ -77,6 +82,11 @@ const LandingPage = ({ onContinue }) => {
"noreferrer"
);
}}
sx={{
"&:hover": {
color: theme.palette.text.tertiary,
},
}}
>
Privacy Policy.
</Typography>
@@ -114,12 +124,15 @@ const StepOne = ({ form, errors, onSubmit, onChange, onBack }) => {
return (
<>
<Stack gap={{ xs: theme.gap.ml, sm: theme.gap.large }} textAlign="center">
<Stack
gap={{ xs: theme.spacing(8), sm: theme.spacing(12) }}
textAlign="center"
>
<Box>
<Typography component="h1">Log In</Typography>
<Typography>Enter your email address</Typography>
</Box>
<Box textAlign="left">
<Box textAlign="left" mb={theme.spacing(5)}>
<form noValidate spellCheck={false} onSubmit={onSubmit}>
<Field
type="email"
@@ -144,10 +157,10 @@ const StepOne = ({ form, errors, onSubmit, onChange, onBack }) => {
img={<ArrowBackRoundedIcon />}
onClick={onBack}
sx={{
mb: theme.gap.medium,
px: theme.gap.ml,
mb: theme.spacing(6),
px: theme.spacing(8),
"& svg.MuiSvgIcon-root": {
mr: theme.gap.xs,
mr: theme.spacing(2),
},
}}
props={{ tabIndex: -1 }}
@@ -204,12 +217,15 @@ const StepTwo = ({ form, errors, onSubmit, onChange, onBack }) => {
return (
<>
<Stack gap={{ xs: theme.gap.ml, sm: theme.gap.large }} textAlign="center">
<Stack
gap={{ xs: theme.spacing(8), sm: theme.spacing(12) }}
textAlign="center"
>
<Box>
<Typography component="h1">Log In</Typography>
<Typography>Enter your password</Typography>
</Box>
<Box textAlign="left">
<Box textAlign="left" mb={theme.spacing(5)}>
<form noValidate spellCheck={false} onSubmit={onSubmit}>
<Field
type="password"
@@ -233,10 +249,10 @@ const StepTwo = ({ form, errors, onSubmit, onChange, onBack }) => {
img={<ArrowBackRoundedIcon />}
onClick={onBack}
sx={{
mb: theme.gap.medium,
px: theme.gap.ml,
mb: theme.spacing(6),
px: theme.spacing(8),
"& svg.MuiSvgIcon-root": {
mr: theme.gap.xs,
mr: theme.spacing(2),
},
}}
props={{ tabIndex: -1 }}
@@ -250,12 +266,17 @@ const StepTwo = ({ form, errors, onSubmit, onChange, onBack }) => {
/>
</Stack>
<Box textAlign="center">
<Typography className="forgot-p" display="inline-block">
<Typography
className="forgot-p"
display="inline-block"
color={theme.palette.common.main}
>
Forgot password?
</Typography>
<Typography
component="span"
ml={theme.gap.xs}
color={theme.palette.common.main}
ml={theme.spacing(2)}
sx={{ userSelect: "none" }}
onClick={handleNavigate}
>
@@ -393,7 +414,21 @@ const Login = () => {
};
return (
<Stack className="login-page auth" overflow="hidden">
<Stack
className="login-page auth"
overflow="hidden"
sx={{
"& h1": {
color: theme.palette.common.main,
fontWeight: 600,
fontSize: 30,
},
"& p": {
fontSize: 14,
color: theme.palette.text.accent,
},
}}
>
<Box
className="background-pattern-svg"
sx={{ backgroundImage: `url(${background})` }}
@@ -401,8 +436,8 @@ const Login = () => {
<Stack
direction="row"
alignItems="center"
px={theme.gap.large}
gap={theme.gap.small}
px={theme.spacing(12)}
gap={theme.spacing(4)}
>
<Logo style={{ borderRadius: theme.shape.borderRadius }} />
<Typography sx={{ userSelect: "none" }}>BlueWave Uptime</Typography>
@@ -412,18 +447,18 @@ const Login = () => {
maxWidth={600}
flex={1}
justifyContent="center"
px={{ xs: theme.gap.large, lg: theme.gap.xl }}
pb={theme.gap.xl}
px={{ xs: theme.spacing(12), lg: theme.spacing(20) }}
pb={theme.spacing(20)}
mx="auto"
sx={{
"& > .MuiStack-root": {
border: 1,
borderRadius: theme.shape.borderRadius,
borderColor: theme.palette.otherColors.graishWhite,
backgroundColor: theme.palette.otherColors.white,
borderRadius: theme.spacing(5),
borderColor: theme.palette.border.light,
backgroundColor: theme.palette.background.main,
padding: {
xs: theme.gap.large,
sm: theme.gap.xl,
xs: theme.spacing(12),
sm: theme.spacing(20),
},
},
}}
@@ -450,13 +485,14 @@ const Login = () => {
)
)}
</Stack>
<Box textAlign="center" p={theme.gap.large}>
<Box textAlign="center" p={theme.spacing(12)}>
<Typography display="inline-block">
Don&apos;t have an account?
</Typography>
<Typography
component="span"
ml={theme.gap.xs}
color={theme.palette.common.main}
ml={theme.spacing(2)}
onClick={() => {
navigate("/register");
}}

View File

@@ -22,7 +22,21 @@ const NewPasswordConfirmed = () => {
};
return (
<Stack className="password-confirmed-page auth" overflow="hidden">
<Stack
className="password-confirmed-page auth"
overflow="hidden"
sx={{
"& h1": {
color: theme.palette.common.main,
fontWeight: 600,
fontSize: 22,
},
"& p": {
fontSize: 14,
color: theme.palette.text.accent,
},
}}
>
<Box
className="background-pattern-svg"
sx={{ backgroundImage: `url(${background})` }}
@@ -30,8 +44,8 @@ const NewPasswordConfirmed = () => {
<Stack
direction="row"
alignItems="center"
px={theme.gap.large}
gap={theme.gap.small}
px={theme.spacing(12)}
gap={theme.spacing(4)}
>
<Logo style={{ borderRadius: theme.shape.borderRadius }} />
<Typography sx={{ userSelect: "none" }}>BlueWave Uptime</Typography>
@@ -41,31 +55,31 @@ const NewPasswordConfirmed = () => {
maxWidth={600}
flex={1}
justifyContent="center"
px={{ xs: theme.gap.large, lg: theme.gap.xl }}
pb={theme.gap.xl}
px={{ xs: theme.spacing(12), lg: theme.spacing(20) }}
pb={theme.spacing(20)}
mx="auto"
sx={{
"& > .MuiStack-root": {
border: 1,
borderRadius: theme.shape.borderRadius,
borderColor: theme.palette.otherColors.graishWhite,
backgroundColor: theme.palette.otherColors.white,
borderRadius: theme.spacing(5),
borderColor: theme.palette.border.light,
backgroundColor: theme.palette.background.main,
padding: {
xs: theme.gap.large,
sm: theme.gap.xl,
xs: theme.spacing(12),
sm: theme.spacing(20),
},
},
}}
>
<Stack
gap={{ xs: theme.gap.ml, sm: theme.gap.large }}
gap={{ xs: theme.spacing(8), sm: theme.spacing(12) }}
alignItems="center"
textAlign="center"
>
<Box>
<ConfirmIcon alt="password confirm icon" />
<Typography component="h1">Password reset</Typography>
<Typography mt={theme.gap.xs}>
<Typography mt={theme.spacing(2)}>
Your password has been successfully reset. Click below to log in
magically.
</Typography>
@@ -81,11 +95,12 @@ const NewPasswordConfirmed = () => {
/>
</Stack>
</Stack>
<Box textAlign="center" p={theme.gap.large}>
<Box textAlign="center" p={theme.spacing(12)}>
<Typography display="inline-block">Go back to </Typography>
<Typography
component="span"
ml={theme.gap.xs}
color={theme.palette.common.main}
ml={theme.spacing(2)}
onClick={handleNavigate}
sx={{ userSelect: "none" }}
>

View File

@@ -33,7 +33,7 @@ const LandingPage = ({ isSuperAdmin, onSignup }) => {
return (
<>
<Stack
gap={{ xs: theme.gap.ml, sm: theme.gap.large }}
gap={{ xs: theme.spacing(8), sm: theme.spacing(12) }}
alignItems="center"
textAlign="center"
>
@@ -53,7 +53,7 @@ const LandingPage = ({ isSuperAdmin, onSignup }) => {
sx={{
width: "100%",
"& svg": {
mr: theme.gap.small,
mr: theme.spacing(4),
},
}}
/>
@@ -70,6 +70,11 @@ const LandingPage = ({ isSuperAdmin, onSignup }) => {
"noreferrer"
);
}}
sx={{
"&:hover": {
color: theme.palette.text.tertiary,
},
}}
>
Terms of Service
</Typography>{" "}
@@ -83,6 +88,11 @@ const LandingPage = ({ isSuperAdmin, onSignup }) => {
"noreferrer"
);
}}
sx={{
"&:hover": {
color: theme.palette.text.tertiary,
},
}}
>
Privacy Policy.
</Typography>
@@ -121,13 +131,22 @@ const StepOne = ({ form, errors, onSubmit, onChange, onBack }) => {
return (
<>
<Stack gap={{ xs: theme.gap.ml, sm: theme.gap.large }} textAlign="center">
<Stack
gap={{ xs: theme.spacing(8), sm: theme.spacing(12) }}
textAlign="center"
>
<Box>
<Typography component="h1">Sign Up</Typography>
<Typography>Enter your personal details</Typography>
</Box>
<Box textAlign="left">
<form noValidate spellCheck={false} onSubmit={onSubmit}>
<Box
component="form"
noValidate
spellCheck={false}
onSubmit={onSubmit}
mb={theme.spacing(10)}
>
<Field
id="register-firstname-input"
label="Name"
@@ -139,8 +158,14 @@ const StepOne = ({ form, errors, onSubmit, onChange, onBack }) => {
error={errors.firstName}
ref={inputRef}
/>
</form>
<form noValidate spellCheck={false} onSubmit={onSubmit}>
</Box>
<Box
component="form"
noValidate
spellCheck={false}
onSubmit={onSubmit}
mb={theme.spacing(5)}
>
<Field
id="register-lastname-input"
label="Surname"
@@ -151,7 +176,7 @@ const StepOne = ({ form, errors, onSubmit, onChange, onBack }) => {
onChange={onChange}
error={errors.lastName}
/>
</form>
</Box>
</Box>
<Stack direction="row" justifyContent="space-between">
<Button
@@ -161,9 +186,9 @@ const StepOne = ({ form, errors, onSubmit, onChange, onBack }) => {
img={<ArrowBackRoundedIcon />}
onClick={onBack}
sx={{
px: theme.gap.ml,
px: theme.spacing(8),
"& svg.MuiSvgIcon-root": {
mr: theme.gap.xs,
mr: theme.spacing(2),
},
}}
props={{ tabIndex: -1 }}
@@ -212,13 +237,22 @@ const StepTwo = ({ form, errors, onSubmit, onChange, onBack }) => {
return (
<>
<Stack gap={{ xs: theme.gap.ml, sm: theme.gap.large }} textAlign="center">
<Stack
gap={{ xs: theme.spacing(8), sm: theme.spacing(12) }}
textAlign="center"
>
<Box>
<Typography component="h1">Sign Up</Typography>
<Typography>Enter your email address</Typography>
</Box>
<Box textAlign="left">
<form noValidate spellCheck={false} onSubmit={onSubmit}>
<Box
component="form"
noValidate
spellCheck={false}
onSubmit={onSubmit}
mb={theme.spacing(5)}
>
<Field
type="email"
id="register-email-input"
@@ -232,7 +266,7 @@ const StepTwo = ({ form, errors, onSubmit, onChange, onBack }) => {
error={errors.email}
ref={inputRef}
/>
</form>
</Box>
</Box>
<Stack direction="row" justifyContent="space-between">
<Button
@@ -242,9 +276,9 @@ const StepTwo = ({ form, errors, onSubmit, onChange, onBack }) => {
img={<ArrowBackRoundedIcon />}
onClick={onBack}
sx={{
px: theme.gap.ml,
px: theme.spacing(8),
"& svg.MuiSvgIcon-root": {
mr: theme.gap.xs,
mr: theme.spacing(2),
},
}}
props={{ tabIndex: -1 }}
@@ -293,13 +327,28 @@ const StepThree = ({ form, errors, onSubmit, onChange, onBack }) => {
return (
<>
<Stack gap={{ xs: theme.gap.ml, sm: theme.gap.large }} textAlign="center">
<Stack
gap={{ xs: theme.spacing(8), sm: theme.spacing(12) }}
textAlign="center"
>
<Box>
<Typography component="h1">Sign Up</Typography>
<Typography>Create your password</Typography>
</Box>
<Box textAlign="left">
<form noValidate spellCheck={false} onSubmit={onSubmit}>
<Box
textAlign="left"
sx={{
"& .input-error": {
display: "none",
},
}}
>
<Box
component="form"
noValidate
spellCheck={false}
onSubmit={onSubmit}
>
<Field
type="password"
id="register-password-input"
@@ -312,8 +361,13 @@ const StepThree = ({ form, errors, onSubmit, onChange, onBack }) => {
error={errors.password}
ref={inputRef}
/>
</form>
<form noValidate spellCheck={false} onSubmit={onSubmit}>
</Box>
<Box
component="form"
noValidate
spellCheck={false}
onSubmit={onSubmit}
>
<Field
type="password"
id="register-confirm-input"
@@ -325,10 +379,10 @@ const StepThree = ({ form, errors, onSubmit, onChange, onBack }) => {
onChange={onChange}
error={errors.confirm}
/>
</form>
</Box>
<Stack
gap={theme.gap.small}
mb={{ xs: theme.gap.ml, sm: theme.gap.large }}
gap={theme.spacing(4)}
mb={{ xs: theme.spacing(6), sm: theme.spacing(8) }}
>
<Check
text={
@@ -395,9 +449,9 @@ const StepThree = ({ form, errors, onSubmit, onChange, onBack }) => {
img={<ArrowBackRoundedIcon />}
onClick={onBack}
sx={{
px: theme.gap.ml,
px: theme.spacing(8),
"& svg.MuiSvgIcon-root": {
mr: theme.gap.xs,
mr: theme.spacing(2),
},
}}
props={{ tabIndex: -1 }}
@@ -585,7 +639,21 @@ const Register = ({ isSuperAdmin }) => {
};
return (
<Stack className="register-page auth" overflow="hidden">
<Stack
className="register-page auth"
overflow="hidden"
sx={{
"& h1": {
color: theme.palette.common.main,
fontWeight: 600,
fontSize: 30,
},
"& p": {
fontSize: 14,
color: theme.palette.text.accent,
},
}}
>
<Box
className="background-pattern-svg"
sx={{ backgroundImage: `url(${background})` }}
@@ -593,8 +661,8 @@ const Register = ({ isSuperAdmin }) => {
<Stack
direction="row"
alignItems="center"
px={theme.gap.large}
gap={theme.gap.small}
px={theme.spacing(12)}
gap={theme.spacing(4)}
>
<Logo style={{ borderRadius: theme.shape.borderRadius }} />
<Typography sx={{ userSelect: "none" }}>BlueWave Uptime</Typography>
@@ -604,18 +672,18 @@ const Register = ({ isSuperAdmin }) => {
maxWidth={600}
flex={1}
justifyContent="center"
px={{ xs: theme.gap.large, lg: theme.gap.xl }}
pb={theme.gap.xl}
px={{ xs: theme.spacing(12), lg: theme.spacing(20) }}
pb={theme.spacing(20)}
mx="auto"
sx={{
"& > .MuiStack-root": {
border: 1,
borderRadius: theme.shape.borderRadius,
borderColor: theme.palette.otherColors.graishWhite,
backgroundColor: theme.palette.otherColors.white,
borderRadius: theme.spacing(5),
borderColor: theme.palette.border.light,
backgroundColor: theme.palette.background.main,
padding: {
xs: theme.gap.large,
sm: theme.gap.xl,
xs: theme.spacing(12),
sm: theme.spacing(20),
},
},
}}
@@ -653,17 +721,17 @@ const Register = ({ isSuperAdmin }) => {
""
)}
</Stack>
<Box textAlign="center" p={theme.gap.large}>
<Box textAlign="center" p={theme.spacing(12)}>
<Typography display="inline-block">
Already have an account?
</Typography>
<Typography
component="span"
ml={theme.gap.xs}
ml={theme.spacing(2)}
onClick={() => {
navigate("/login");
}}
sx={{ userSelect: "none" }}
sx={{ userSelect: "none", color: theme.palette.common.main }}
>
Log In
</Typography>

View File

@@ -104,7 +104,21 @@ const SetNewPassword = () => {
};
return (
<Stack className="set-new-password-page auth" overflow="hidden">
<Stack
className="set-new-password-page auth"
overflow="hidden"
sx={{
"& h1": {
color: theme.palette.common.main,
fontWeight: 600,
fontSize: 24,
},
"& p": {
fontSize: 14,
color: theme.palette.text.accent,
},
}}
>
<Box
className="background-pattern-svg"
sx={{ backgroundImage: `url(${background})` }}
@@ -112,8 +126,8 @@ const SetNewPassword = () => {
<Stack
direction="row"
alignItems="center"
px={theme.gap.large}
gap={theme.gap.small}
px={theme.spacing(12)}
gap={theme.spacing(4)}
>
<Logo style={{ borderRadius: theme.shape.borderRadius }} />
<Typography sx={{ userSelect: "none" }}>BlueWave Uptime</Typography>
@@ -123,24 +137,24 @@ const SetNewPassword = () => {
maxWidth={600}
flex={1}
justifyContent="center"
px={{ xs: theme.gap.large, lg: theme.gap.xl }}
pb={theme.gap.large}
px={{ xs: theme.spacing(12), lg: theme.spacing(20) }}
pb={theme.spacing(12)}
mx="auto"
sx={{
"& > .MuiStack-root": {
border: 1,
borderRadius: theme.shape.borderRadius,
borderColor: theme.palette.otherColors.graishWhite,
backgroundColor: theme.palette.otherColors.white,
borderRadius: theme.spacing(5),
borderColor: theme.palette.border.light,
backgroundColor: theme.palette.background.main,
padding: {
xs: theme.gap.large,
sm: theme.gap.xl,
xs: theme.spacing(12),
sm: theme.spacing(20),
},
},
}}
>
<Stack
gap={{ xs: theme.gap.ml, sm: theme.gap.large }}
gap={{ xs: theme.spacing(8), sm: theme.spacing(12) }}
alignItems="center"
textAlign="center"
>
@@ -151,8 +165,21 @@ const SetNewPassword = () => {
Your new password must be different to previously used passwords.
</Typography>
</Box>
<Box width="100%" textAlign="left">
<form noValidate spellCheck={false} onSubmit={handleSubmit}>
<Box
width="100%"
textAlign="left"
sx={{
"& .input-error": {
display: "none",
},
}}
>
<Box
component="form"
noValidate
spellCheck={false}
onSubmit={handleSubmit}
>
<Field
type="password"
id="register-password-input"
@@ -163,8 +190,13 @@ const SetNewPassword = () => {
onChange={handleChange}
error={errors.password}
/>
</form>
<form noValidate spellCheck={false} onSubmit={handleSubmit}>
</Box>
<Box
component="form"
noValidate
spellCheck={false}
onSubmit={handleSubmit}
>
<Field
type="password"
id="confirm-password-input"
@@ -175,8 +207,8 @@ const SetNewPassword = () => {
onChange={handleChange}
error={errors.confirm}
/>
</form>
<Stack gap={theme.gap.small} mb={theme.gap.large}>
</Box>
<Stack gap={theme.spacing(4)} mb={theme.spacing(12)}>
<Check
text={
<>
@@ -244,11 +276,12 @@ const SetNewPassword = () => {
/>
</Stack>
</Stack>
<Box textAlign="center" p={theme.gap.large}>
<Box textAlign="center" p={theme.spacing(12)}>
<Typography display="inline-block">Go back to </Typography>
<Typography
component="span"
ml={theme.gap.xs}
color={theme.palette.common.main}
ml={theme.spacing(2)}
onClick={() => navigate("/login")}
sx={{ userSelect: "none" }}
>

View File

@@ -5,7 +5,6 @@
.auth h1 {
font-size: var(--env-var-font-size-xlarge);
font-weight: 600;
color: var(--env-var-color-3);
}
.auth button:not(.MuiIconButton-root),
.auth p,
@@ -13,16 +12,8 @@
.auth span {
font-size: var(--env-var-font-size-medium-plus);
}
.auth p {
color: var(--env-var-color-2-light);
}
.auth .field h3.MuiTypography-root,
.auth .field input {
color: var(--env-var-color-5);
}
.auth p + span {
color: var(--env-var-color-3);
opacity: 0.8;
cursor: pointer;
transition: opacity 300ms ease-in;
@@ -34,7 +25,6 @@
transition: all 200ms;
}
.auth p > span:not(.email-sent-to):hover {
color: var(--env-var-color-2);
text-underline-offset: 4px;
}
.auth p + span:hover {
@@ -86,11 +76,12 @@
background-repeat: no-repeat;
}
.forgot-password-page h1,
.check-email-page h1,
.password-confirmed-page h1,
.set-new-password-page h1 {
font-size: 22px;
.auth .field {
position: relative;
}
.auth .input-error {
position: absolute;
top: calc(100% - 2px);
}
@media (max-width: 800px) {

View File

@@ -21,14 +21,16 @@ import { useSelector } from "react-redux";
import { networkService } from "../../../main";
import { StatusLabel } from "../../../Components/Label";
import { logger } from "../../../Utils/Logger";
import { useTheme } from "@emotion/react";
const IncidentTable = ({ monitors, selectedMonitor, filter }) => {
const theme = useTheme();
const { authToken, user } = useSelector((state) => state.auth);
const [checks, setChecks] = useState([]);
const [checksCount, setChecksCount] = useState(0);
const [paginationController, setPaginationController] = useState({
page: 0,
rowsPerPage: 12,
rowsPerPage: 14,
});
useEffect(() => {
@@ -107,26 +109,31 @@ const IncidentTable = ({ monitors, selectedMonitor, filter }) => {
next: ArrowForwardRoundedIcon,
}}
{...item}
sx={{
"&:focus": {
outline: "none",
},
}}
/>
)}
/>
);
}
let sharedStyles = {
border: 1,
borderColor: theme.palette.border.light,
borderRadius: theme.shape.borderRadius,
backgroundColor: theme.palette.background.main,
p: theme.spacing(30),
};
return (
<>
{checks?.length === 0 && selectedMonitor === "0" ? (
<Box>
<Typography textAlign="center">No incidents recorded yet.</Typography>
<Box sx={{ ...sharedStyles }}>
<Typography textAlign="center" color={theme.palette.text.secondary}>
No incidents recorded yet.
</Typography>
</Box>
) : checks?.length === 0 ? (
<Box>
<Typography textAlign="center">
<Box sx={{ ...sharedStyles }}>
<Typography textAlign="center" color={theme.palette.text.secondary}>
The monitor you have selected has no recorded incidents yet.
</Typography>
</Box>

View File

@@ -1,7 +1,3 @@
.incidents h1.MuiTypography-root,
.incidents p.MuiTypography-root {
color: var(--env-var-color-5);
}
.incidents h1.MuiTypography-root {
font-size: var(--env-var-font-size-large);
font-weight: 600;
@@ -12,19 +8,4 @@
}
.incidents button.MuiButtonBase-root {
height: 34px;
border-color: var(--env-var-color-16);
}
.incidents .MuiPagination-root {
background-color: var(--env-var-color-8);
}
.incidents > .MuiBox-root {
background-color: var(--env-var-color-8);
border: solid 1px var(--env-var-color-6);
border-radius: var(--env-var-radius-1);
padding: 60px;
}
/* remove later */
.incidents .MuiSelect-select {
padding: 0 10px;
}

View File

@@ -18,7 +18,7 @@ const SkeletonLayout = () => {
return (
<>
<Stack direction="row" alignItems="center" gap={theme.gap.medium}>
<Stack direction="row" alignItems="center" gap={theme.spacing(6)}>
<Skeleton variant="rounded" width={150} height={34} />
<Skeleton variant="rounded" width="15%" height={34} />
<Skeleton
@@ -78,13 +78,21 @@ const Incidents = () => {
};
return (
<Stack className="incidents" pt={theme.gap.xl} gap={theme.gap.large}>
<Stack
className="incidents"
pt={theme.spacing(21)}
gap={theme.spacing(12)}
>
{loading ? (
<SkeletonLayout />
) : (
<>
<Stack direction="row" alignItems="center" gap={theme.gap.medium}>
<Typography display="inline-block" component="h1">
<Stack direction="row" alignItems="center" gap={theme.spacing(6)}>
<Typography
display="inline-block"
component="h1"
color={theme.palette.text.secondary}
>
Incidents for
</Typography>
<Select
@@ -93,15 +101,27 @@ const Incidents = () => {
value={selectedMonitor}
onChange={handleSelect}
items={Object.values(monitors)}
sx={{
backgroundColor: theme.palette.background.main,
}}
/>
<ButtonGroup sx={{ ml: "auto" }}>
<ButtonGroup
sx={{
ml: "auto",
"& .MuiButtonBase-root, & .MuiButtonBase-root:hover": {
borderColor: theme.palette.border.light,
},
}}
>
<Button
level="secondary"
label="All"
onClick={() => setFilter("all")}
sx={{
backgroundColor:
filter === "all" && theme.palette.otherColors.fillGray,
filter === "all"
? theme.palette.background.fill
: theme.palette.background.main,
}}
/>
<Button
@@ -110,7 +130,9 @@ const Incidents = () => {
onClick={() => setFilter("down")}
sx={{
backgroundColor:
filter === "down" && theme.palette.otherColors.fillGray,
filter === "down"
? theme.palette.background.fill
: theme.palette.background.main,
}}
/>
<Button
@@ -119,7 +141,9 @@ const Incidents = () => {
onClick={() => setFilter("resolve")}
sx={{
backgroundColor:
filter === "resolve" && theme.palette.otherColors.fillGray,
filter === "resolve"
? theme.palette.background.fill
: theme.palette.background.main,
}}
/>
</ButtonGroup>

View File

@@ -1,7 +1,3 @@
.integrations h1.MuiTypography-root,
.integrations p.MuiTypography-root {
color: var(--env-var-color-5);
}
.integrations h1.MuiTypography-root {
font-size: var(--env-var-font-size-large);
font-weight: 600;
@@ -12,9 +8,3 @@
.integrations button {
height: var(--env-var-height-2);
}
.integrations .MuiGrid-item > .MuiStack-root {
border: solid 1px var(--env-var-color-6);
border-radius: var(--env-var-radius-1);
background-color: var(--env-var-color-8);
}

View File

@@ -25,13 +25,17 @@ const IntegrationsComponent = ({ icon, header, info, onClick }) => {
<Stack
direction="row"
justifyContent="space-between"
gap={theme.gap.large}
p={theme.gap.ml}
pl={theme.gap.large}
gap={theme.spacing(12)}
p={theme.spacing(8)}
pl={theme.spacing(12)}
height="100%"
border={1}
borderColor={theme.palette.border.light}
borderRadius={theme.shape.borderRadius}
backgroundColor={theme.palette.background.main}
>
{icon}
<Stack gap={theme.gap.xs} flex={1}>
<Stack gap={theme.spacing(2)} flex={1}>
<Typography component="h1">{header}</Typography>
<Typography
sx={{
@@ -108,12 +112,21 @@ const Integrations = () => {
];
return (
<Stack className="integrations" pt={theme.gap.xl} gap={theme.gap.xs}>
<Stack
className="integrations"
pt={theme.spacing(20)}
gap={theme.spacing(2)}
sx={{
"& h1, & p": {
color: theme.palette.text.secondary,
},
}}
>
<Typography component="h1">Integrations</Typography>
<Typography mb={theme.gap.large}>
<Typography mb={theme.spacing(12)}>
Connect BlueWave Uptime to your favorite service.
</Typography>
<Grid container spacing={theme.gap.large}>
<Grid container spacing={theme.spacing(12)}>
{integrations.map((integration, index) => (
<IntegrationsComponent
key={index}

View File

@@ -13,6 +13,7 @@ import Field from "../../../Components/Inputs/Field";
import { maintenanceWindowValidation } from "../../../Validation/validation";
import { logger } from "../../../Utils/Logger";
import { createToast } from "../../../Utils/toastUtils";
import { useTheme } from "@emotion/react";
const directory = {
title: "Create a maintenance window",
@@ -56,6 +57,8 @@ const durationOptions = [
];
const CreateNewMaintenanceWindow = () => {
const theme = useTheme();
const [values, setValues] = useState({
repeat: 1,
date: dayjs(),
@@ -159,7 +162,11 @@ const CreateNewMaintenanceWindow = () => {
{
title: "Duration",
component: (
<Stack className="duration-config" gap={2} direction="row">
<Stack
className="duration-config"
gap={theme.spacing(5)}
direction="row"
>
<Field
id="duration-value"
placeholder="60"
@@ -195,7 +202,7 @@ const CreateNewMaintenanceWindow = () => {
<Stack
className="add-monitors-fields"
sx={{ width: "60%", maxWidth: "380px" }}
gap={2}
gap={theme.spacing(5)}
>
<Field
id="add-monitors"
@@ -208,7 +215,7 @@ const CreateNewMaintenanceWindow = () => {
sx={{
width: "fit-content",
fontSize: "var(--env-var-font-size-small)",
borderBottom: "1px dashed var(--env-var-color-3)",
borderBottom: `1px dashed ${theme.palette.common.main}`,
paddingBottom: "4px",
}}
>
@@ -221,15 +228,15 @@ const CreateNewMaintenanceWindow = () => {
return (
<div className="create-maintenance-window">
<Stack gap={3}>
<Stack gap={theme.spacing(10)}>
<Button
id="btn-back"
sx={{
width: "100px",
height: "30px",
gap: "10px",
backgroundColor: "var(--env-var-color-32)",
color: "var(--env-var-color-5)",
backgroundColor: theme.palette.background.fill,
color: theme.palette.text.secondary,
}}
label="Back"
level="tertiary"
@@ -239,8 +246,8 @@ const CreateNewMaintenanceWindow = () => {
<Typography
sx={{
fontSize: "var(--env-var-font-size-large)",
fontWeight: "600",
color: "var(--env-var-color-5)",
fontWeight: 600,
color: theme.palette.text.secondary,
}}
>
{directory.title}
@@ -252,14 +259,14 @@ const CreateNewMaintenanceWindow = () => {
</Box>
<Stack
className="maintenance-options"
gap={5}
paddingY={4}
paddingX={8}
paddingBottom={10}
gap={theme.spacing(20)}
paddingY={theme.spacing(15)}
paddingX={theme.spacing(20)}
sx={{
border: "1px solid var(--env-var-color-16)",
borderRadius: "var(--env-var-radius-1)",
backgroundColor: "var(--env-var-color-0)",
border: 1,
borderColor: theme.palette.border.light,
borderRadius: theme.shape.borderRadius,
backgroundColor: theme.palette.background.main,
}}
>
{configOptions.map((item, index) => (

View File

@@ -13,7 +13,7 @@
}
.maintenance-title {
color: var(--env-var-color-2);
color: var(--secondary-color-light);
font-size: 16px;
font-weight: bold;
margin-top: 40px;
@@ -22,7 +22,7 @@
.checklist-item {
font-size: 13px;
color: var(--env-var-color-2);
color: var(--secondary-color-light);
display: flex;
margin-bottom: 10px;
}

View File

@@ -1,9 +1,26 @@
import { Box } from "@mui/material";
import { useTheme } from "@emotion/react";
import Fallback from "../../Components/Fallback";
import "./index.css";
const Maintenance = () => {
const Maintenance = ({ isAdmin }) => {
const theme = useTheme();
return (
<div className="maintenance">
<Box
className="maintenance"
sx={{
':has(> [class*="fallback__"])': {
position: "relative",
border: 1,
borderColor: theme.palette.border.light,
borderRadius: theme.shape.borderRadius,
borderStyle: "dashed",
backgroundColor: theme.palette.background.main,
overflow: "hidden",
},
}}
>
<Fallback
title="maintenance window"
checks={[
@@ -12,8 +29,9 @@ const Maintenance = () => {
"Stop sending alerts in maintenance windows",
]}
link="/maintenance/create"
isAdmin={isAdmin}
/>
</div>
</Box>
);
};

View File

@@ -1,52 +1,17 @@
.configure-monitor h1.MuiTypography-root {
font-size: var(--env-var-font-size-large-plus);
color: var(--env-var-color-1);
font-weight: 600;
}
.configure-monitor h2.MuiTypography-root {
font-size: var(--env-var-font-size-large);
font-weight: 600;
}
.configure-monitor h2.MuiTypography-root,
.configure-monitor .config-box p.MuiTypography-root,
.configure-monitor .MuiSelect-select {
color: var(--env-var-color-5);
}
.configure-monitor .MuiModal-root h2.MuiTypography-root {
color: var(--env-var-color-1);
}
.configure-monitor p.MuiTypography-root,
.configure-monitor .MuiSelect-select {
.configure-monitor p.MuiTypography-root {
font-size: var(--env-var-font-size-medium);
}
.configure-monitor h6.MuiTypography-root {
opacity: 0.6;
}
.configure-monitor h6.MuiTypography-root,
.configure-monitor h1.MuiTypography-root + span.MuiTypography-root {
font-size: var(--env-var-font-size-small-plus);
}
.configure-monitor button.MuiButtonBase-root {
font-size: var(--env-var-font-size-medium);
}
.configure-monitor button.MuiButtonBase-root {
height: var(--env-var-height-2);
}
.configure-monitor .config-box {
border: 1px solid var(--env-var-color-16);
border-radius: var(--env-var-radius-1);
background-color: var(--env-var-color-8);
}
.configure-monitor .config-box > .MuiBox-root,
.configure-monitor .config-box > .MuiStack-root {
flex: 1;
padding: 24px 30px;
padding-bottom: 40px;
}
.configure-monitor .config-box > *:first-child {
flex: 0.7;
border-right: solid 1px var(--env-var-color-16);
}
.configure-monitor .MuiStack-root:has(span.MuiTypography-root.input-error) {
position: relative;
}
@@ -54,25 +19,3 @@
position: absolute;
top: 100%;
}
.configure-monitor .MuiInputBase-root:has(> .Mui-disabled) {
background-color: var(--env-var-color-13);
}
.MuiInputBase-root:has(#monitor-interval) {
height: 34px;
width: 100%;
}
#monitor-interval {
padding: 0 10px;
height: 100%;
display: flex;
align-items: center;
}
.MuiInputBase-root:not(.Mui-focused):has(#monitor-interval):hover fieldset {
border-color: var(--env-var-color-29);
}
body:has(.configure-monitor) .select-dropdown .MuiMenuItem-root,
.configure-monitor .select-wrapper .select-component > .MuiSelect-select {
text-transform: lowercase;
}

View File

@@ -6,6 +6,7 @@ import { Box, Modal, Stack, Typography } from "@mui/material";
import { monitorValidation } from "../../../Validation/validation";
import { createToast } from "../../../Utils/toastUtils";
import { logger } from "../../../Utils/Logger";
import { ConfigBox } from "../styled";
import {
updateUptimeMonitor,
pauseUptimeMonitor,
@@ -189,7 +190,7 @@ const Configure = () => {
const protocol = parsedUrl?.protocol?.replace(":", "") || "";
return (
<Stack className="configure-monitor" gap={theme.gap.large}>
<Stack className="configure-monitor" gap={theme.spacing(12)}>
{Object.keys(monitor).length === 0 ? (
<SkeletonLayout />
) : (
@@ -205,20 +206,25 @@ const Configure = () => {
component="form"
noValidate
spellCheck="false"
gap={theme.gap.large}
gap={theme.spacing(12)}
flex={1}
>
<Stack direction="row" gap={theme.gap.xs}>
<Stack direction="row" gap={theme.spacing(2)}>
<PulseDot
color={
monitor?.status
? theme.label.up.dotColor
: theme.label.down.dotColor
? theme.palette.success.main
: theme.palette.error.main
}
/>
<Box>
{parsedUrl?.host ? (
<Typography component="h1" mb={theme.gap.xs} lineHeight={1}>
<Typography
component="h1"
mb={theme.spacing(2)}
lineHeight={1}
color={theme.palette.text.primary}
>
{parsedUrl.host || "..."}
</Typography>
) : (
@@ -226,11 +232,11 @@ const Configure = () => {
)}
<Typography
component="span"
lineHeight={theme.gap.large}
lineHeight={theme.spacing(12)}
sx={{
color: monitor?.status
? "var(--env-var-color-17)"
: "var(--env-var-color-24)",
? theme.palette.success.main
: theme.palette.error.text,
}}
>
Your site is {monitor?.status ? "up" : "down"}.
@@ -249,12 +255,12 @@ const Configure = () => {
animate="rotate180"
img={<PauseCircleOutlineIcon />}
sx={{
backgroundColor: theme.palette.otherColors.fillGray,
pl: theme.gap.small,
pr: theme.gap.medium,
mr: theme.gap.medium,
backgroundColor: theme.palette.background.main,
pl: theme.spacing(4),
pr: theme.spacing(6),
mr: theme.spacing(6),
"& svg": {
mr: theme.gap.xs,
mr: theme.spacing(2),
},
}}
onClick={handlePause}
@@ -265,25 +271,21 @@ const Configure = () => {
label="Remove"
sx={{
boxShadow: "none",
px: theme.gap.ml,
px: theme.spacing(8),
}}
onClick={() => setIsOpen(true)}
/>
</Box>
</Stack>
<Stack
className="config-box"
direction="row"
justifyContent="space-between"
>
<ConfigBox>
<Box>
<Typography component="h2">General settings</Typography>
<Typography component="p" sx={{ mt: theme.gap.xs }}>
<Typography component="p">
Here you can select the URL of the host, together with the
type of monitor.
</Typography>
</Box>
<Stack gap={theme.gap.xl}>
<Stack gap={theme.spacing(20)}>
<Field
type={monitor?.type === "http" ? "url" : "text"}
https={protocol === "https"}
@@ -305,20 +307,16 @@ const Configure = () => {
error={errors["name"]}
/>
</Stack>
</Stack>
<Stack
className="config-box"
direction="row"
justifyContent="space-between"
>
</ConfigBox>
<ConfigBox>
<Box>
<Typography component="h2">Incident notifications</Typography>
<Typography component="p" mt={theme.gap.xs}>
<Typography component="p">
When there is an incident, notify users.
</Typography>
</Box>
<Stack gap={theme.gap.medium}>
<Typography component="p" mt={theme.gap.small}>
<Stack gap={theme.spacing(6)}>
<Typography component="p">
When there is a new incident,
</Typography>
<Checkbox
@@ -351,7 +349,7 @@ const Configure = () => {
{monitor?.notifications?.some(
(notification) => notification.type === "emails"
) ? (
<Box mx={`calc(${theme.gap.ml} * 2)`}>
<Box mx={theme.spacing(16)}>
<Field
id="notify-email-list"
type="text"
@@ -359,7 +357,7 @@ const Configure = () => {
value=""
onChange={() => logger.warn("disabled")}
/>
<Typography mt={theme.gap.small}>
<Typography mt={theme.spacing(4)}>
You can separate multiple emails with a comma
</Typography>
</Box>
@@ -367,16 +365,12 @@ const Configure = () => {
""
)}
</Stack>
</Stack>
<Stack
className="config-box"
direction="row"
justifyContent="space-between"
>
</ConfigBox>
<ConfigBox>
<Box>
<Typography component="h2">Advanced settings</Typography>
</Box>
<Stack gap={theme.gap.xl}>
<Stack gap={theme.spacing(20)}>
<Select
id="monitor-interval-configure"
label="Check frequency"
@@ -385,13 +379,13 @@ const Configure = () => {
items={frequencies}
/>
</Stack>
</Stack>
</ConfigBox>
<Stack direction="row" justifyContent="flex-end" mt="auto">
<ButtonSpinner
isLoading={isLoading}
level="primary"
label="Save"
sx={{ px: theme.gap.large }}
sx={{ px: theme.spacing(12) }}
onClick={handleSubmit}
/>
</Stack>
@@ -406,33 +400,43 @@ const Configure = () => {
disablePortal
>
<Stack
gap={theme.gap.xs}
gap={theme.spacing(2)}
sx={{
position: "absolute",
top: "50%",
left: "50%",
transform: "translate(-50%, -50%)",
width: 400,
bgcolor: "white",
border: "solid 1px #f2f2f2",
borderRadius: `${theme.shape.borderRadius}px`,
bgcolor: theme.palette.background.main,
border: 1,
borderColor: theme.palette.border.light,
borderRadius: theme.shape.borderRadius,
boxShadow: 24,
p: "30px",
p: theme.spacing(15),
"&:focus": {
outline: "none",
},
}}
>
<Typography id="modal-delete-monitor" component="h2">
<Typography
id="modal-delete-monitor"
component="h2"
fontSize={16}
color={theme.palette.text.primary}
fontWeight={600}
>
Do you really want to delete this monitor?
</Typography>
<Typography id="delete-monitor-confirmation">
<Typography
id="delete-monitor-confirmation"
color={theme.palette.text.tertiary}
>
Once deleted, this monitor cannot be retrieved.
</Typography>
<Stack
direction="row"
gap={theme.gap.small}
mt={theme.gap.large}
gap={theme.spacing(4)}
mt={theme.spacing(12)}
justifyContent="flex-end"
>
<Button

View File

@@ -1,23 +1,11 @@
.create-monitor h1.MuiTypography-root {
font-size: var(--env-var-font-size-large-plus);
color: var(--env-var-color-1);
font-weight: 500;
}
.create-monitor h2.MuiTypography-root {
font-size: var(--env-var-font-size-large);
font-weight: 600;
}
.create-monitor p.MuiTypography-root,
.create-monitor button.MuiButtonBase-root {
font-size: var(--env-var-font-size-medium);
}
.create-monitor h2.MuiTypography-root {
color: var(--env-var-color-5);
}
.create-monitor h6.MuiTypography-root,
.create-monitor p.MuiTypography-root {
color: var(--env-var-color-2);
}
.create-monitor h6.MuiTypography-root,
.create-monitor .MuiBox-root .field + p.MuiTypography-root {
font-size: var(--env-var-font-size-small-plus);
@@ -26,11 +14,11 @@
.create-monitor button.MuiButtonBase-root {
height: 34px;
}
.create-monitor .error-container {
position: relative;
}
.create-monitor .error-container p.MuiTypography-root.input-error {
color: var(--env-var-color-24);
opacity: 0.8;
position: absolute;
top: 0;
@@ -42,30 +30,9 @@
position: absolute;
top: 100%;
}
.create-monitor .config-box {
flex-direction: row;
border: 1px solid var(--env-var-color-16);
border-radius: var(--env-var-radius-1);
background-color: var(--env-var-color-8);
}
.create-monitor .config-box > .MuiBox-root,
.create-monitor .config-box > .MuiStack-root {
flex: 1;
padding: 24px 30px;
padding-bottom: 40px;
}
.create-monitor .config-box > *:first-child {
flex: 0.7;
border-right: solid 1px var(--env-var-color-16);
}
.create-monitor .MuiStack-root .MuiButtonGroup-root button {
font-size: var(--env-var-font-size-small);
height: 28px;
padding: 8px;
}
body:has(.create-monitor) .select-dropdown .MuiMenuItem-root,
.create-monitor .select-wrapper .select-component > .MuiSelect-select {
text-transform: lowercase;
}

View File

@@ -1,19 +1,20 @@
import "./index.css";
import { useState } from "react";
import RadioButton from "../../../Components/RadioButton";
import Button from "../../../Components/Button";
import { Box, ButtonGroup, Stack, Typography } from "@mui/material";
import { useSelector, useDispatch } from "react-redux";
import { monitorValidation } from "../../../Validation/validation";
import { createUptimeMonitor } from "../../../Features/UptimeMonitors/uptimeMonitorsSlice";
import { useNavigate } from "react-router-dom";
import { useTheme } from "@emotion/react";
import { createToast } from "../../../Utils/toastUtils";
import { logger } from "../../../Utils/Logger";
import { ConfigBox } from "../styled";
import Radio from "../../../Components/Inputs/Radio";
import Button from "../../../Components/Button";
import Field from "../../../Components/Inputs/Field";
import Select from "../../../Components/Inputs/Select";
import Checkbox from "../../../Components/Inputs/Checkbox";
import { createToast } from "../../../Utils/toastUtils";
import Breadcrumbs from "../../../Components/Breadcrumbs";
import { logger } from "../../../Utils/Logger";
import "./index.css";
const CreateMonitor = () => {
const MS_PER_MINUTE = 60000;
@@ -33,7 +34,7 @@ const CreateMonitor = () => {
const [monitor, setMonitor] = useState({
url: "",
name: "",
type: "",
type: "http",
notifications: [],
interval: 1,
});
@@ -144,7 +145,14 @@ const CreateMonitor = () => {
];
return (
<Box className="create-monitor">
<Box
className="create-monitor"
sx={{
"& h1": {
color: theme.palette.text.primary,
},
}}
>
<Breadcrumbs
list={[
{ name: "monitors", path: "/monitors" },
@@ -157,14 +165,14 @@ const CreateMonitor = () => {
onSubmit={handleCreateMonitor}
noValidate
spellCheck="false"
gap={theme.gap.large}
mt={theme.gap.medium}
gap={theme.spacing(12)}
mt={theme.spacing(6)}
>
<Typography component="h1">
<Typography
component="span"
fontSize="inherit"
color={theme.palette.otherColors.bluishGray}
color={theme.palette.text.secondary}
>
Create your{" "}
</Typography>
@@ -172,15 +180,15 @@ const CreateMonitor = () => {
monitor
</Typography>
</Typography>
<Stack className="config-box">
<ConfigBox>
<Box>
<Typography component="h2">General settings</Typography>
<Typography component="p" mt={theme.gap.xs}>
<Typography component="p">
Here you can select the URL of the host, together with the type of
monitor.
</Typography>
</Box>
<Stack gap={theme.gap.xl}>
<Stack gap={theme.spacing(15)}>
<Field
type={monitor.type === "http" ? "url" : "text"}
id="monitor-url"
@@ -202,17 +210,17 @@ const CreateMonitor = () => {
error={errors["name"]}
/>
</Stack>
</Stack>
<Stack className="config-box">
</ConfigBox>
<ConfigBox>
<Box>
<Typography component="h2">Checks to perform</Typography>
<Typography component="p" mt={theme.gap.xs}>
<Typography component="p">
You can always add or remove checks after adding your site.
</Typography>
</Box>
<Stack gap={theme.gap.large}>
<Stack gap={theme.gap.medium}>
<RadioButton
<Stack gap={theme.spacing(12)}>
<Stack gap={theme.spacing(6)}>
<Radio
id="monitor-checks-http"
title="Website monitoring"
desc="Use HTTP(s) to monitor your website or API endpoint."
@@ -228,8 +236,11 @@ const CreateMonitor = () => {
label="HTTPS"
onClick={() => setHttps(true)}
sx={{
backgroundColor:
https && theme.palette.otherColors.fillGray,
backgroundColor: https && theme.palette.background.fill,
borderColor: theme.palette.border.dark,
"&:hover": {
borderColor: theme.palette.border.dark,
},
}}
/>
<Button
@@ -237,8 +248,11 @@ const CreateMonitor = () => {
label="HTTP"
onClick={() => setHttps(false)}
sx={{
backgroundColor:
!https && theme.palette.otherColors.fillGray,
backgroundColor: !https && theme.palette.background.fill,
borderColor: theme.palette.border.dark,
"&:hover": {
borderColor: theme.palette.border.dark,
},
}}
/>
</ButtonGroup>
@@ -246,7 +260,7 @@ const CreateMonitor = () => {
""
)}
</Stack>
<RadioButton
<Radio
id="monitor-checks-ping"
title="Ping monitoring"
desc="Check whether your server is available or not."
@@ -257,7 +271,11 @@ const CreateMonitor = () => {
/>
{errors["type"] ? (
<Box className="error-container">
<Typography component="p" className="input-error">
<Typography
component="p"
className="input-error"
color={theme.palette.error.text}
>
{errors["type"]}
</Typography>
</Box>
@@ -265,15 +283,15 @@ const CreateMonitor = () => {
""
)}
</Stack>
</Stack>
<Stack className="config-box">
</ConfigBox>
<ConfigBox>
<Box>
<Typography component="h2">Incident notifications</Typography>
<Typography component="p" mt={theme.gap.xs}>
<Typography component="p">
When there is an incident, notify users.
</Typography>
</Box>
<Stack gap={theme.gap.medium}>
<Stack gap={theme.spacing(6)}>
<Typography component="p">When there is a new incident,</Typography>
<Checkbox
id="notify-sms"
@@ -303,7 +321,7 @@ const CreateMonitor = () => {
{monitor.notifications.some(
(notification) => notification.type === "emails"
) ? (
<Box mx={`calc(${theme.gap.ml} * 2)`}>
<Box mx={theme.spacing(16)}>
<Field
id="notify-email-list"
type="text"
@@ -311,7 +329,7 @@ const CreateMonitor = () => {
value=""
onChange={() => logger.warn("disabled")}
/>
<Typography mt={theme.gap.small}>
<Typography mt={theme.spacing(4)}>
You can separate multiple emails with a comma
</Typography>
</Box>
@@ -319,12 +337,12 @@ const CreateMonitor = () => {
""
)}
</Stack>
</Stack>
<Stack className="config-box">
</ConfigBox>
<ConfigBox>
<Box>
<Typography component="h2">Advanced settings</Typography>
</Box>
<Stack gap={theme.gap.large}>
<Stack gap={theme.spacing(12)}>
<Select
id="monitor-interval"
label="Check frequency"
@@ -332,73 +350,8 @@ const CreateMonitor = () => {
onChange={(event) => handleChange(event, "interval")}
items={frequencies}
/>
{/* TODO */}
{/* <FlexibileTextField
id="monitor-settings-retries"
title="Maximum retries before the service is marked as down"
type="number"
value={advancedSettings.retries}
onChange={(event) =>
handleChange(event, "retries", setAdvancedSettings)
}
/>
<FlexibileTextField
id="monitor-settings-codes"
title="Accepted status codes"
type="number"
value={advancedSettings.codes}
onChange={(event) =>
handleChange(event, "codes", setAdvancedSettings)
}
/>
<FlexibileTextField
id="monitor-settings-redirects"
title="Maximum redirects"
type="number"
value={advancedSettings.redirects}
onChange={(event) =>
handleChange(event, "redirects", setAdvancedSettings)
}
/> */}
</Stack>
</Stack>
{/* TODO */}
{/*
<ConfigBox
leftLayout={
<div className="config-box-desc">
<div className="config-box-desc-title">Proxy settings</div>
</div>
}
rightLayout={
<div className="proxy-setting-config">
<CustomizableCheckBox
id="monitor-proxy-enable"
title="Enable proxy"
isChecked={proxy.enabled}
handleChange={() => handleCheck("enabled", setProxy)}
/>
<FlexibileTextField
id="monitor-proxy-protocol"
title="Proxy protocol"
value={proxy.protocol}
onChange={(event) => handleChange(event, "protocol", setProxy)}
/>
<FlexibileTextField
id="monitor-proxy-address"
title="Proxy address"
value={proxy.address}
onChange={(event) => handleChange(event, "address", setProxy)}
/>
<FlexibileTextField
id="monitor-proxy-port"
title="Proxy port"
value={proxy.proxy_port}
onChange={(event) => handleChange(event, "proxy_port", setProxy)}
/>
</div>
}
/> */}
</ConfigBox>
<Stack direction="row" justifyContent="flex-end">
<Button
id="create-monitor-btn"

View File

@@ -18,8 +18,10 @@ import { StatusLabel } from "../../../../Components/Label";
import ArrowBackRoundedIcon from "@mui/icons-material/ArrowBackRounded";
import ArrowForwardRoundedIcon from "@mui/icons-material/ArrowForwardRounded";
import { logger } from "../../../../Utils/Logger";
import { useTheme } from "@emotion/react";
const PaginationTable = ({ monitorId, dateRange }) => {
const theme = useTheme();
const { authToken } = useSelector((state) => state.auth);
const [checks, setChecks] = useState([]);
const [checksCount, setChecksCount] = useState(0);
@@ -85,15 +87,6 @@ const PaginationTable = ({ monitorId, dateRange }) => {
next: ArrowForwardRoundedIcon,
}}
{...item}
sx={{
"&:focus": {
outline: "none",
},
"& .MuiTouchRipple-root": {
pointerEvents: "none",
display: "none",
},
}}
/>
)}
/>

View File

@@ -1,25 +1,13 @@
.monitor-details h1.MuiTypography-root {
font-size: var(--env-var-font-size-large-plus);
color: var(--env-var-color-1);
font-weight: 600;
}
.monitor-details h2.MuiTypography-root {
font-size: var(--env-var-font-size-large);
}
.monitor-details h2.MuiTypography-root{
.monitor-details h2.MuiTypography-root {
font-weight: 600;
}
.monitor-details h2.MuiTypography-root,
.monitor-details h4.MuiTypography-root {
color: var(--env-var-color-5);
}
.monitor-details h6.MuiTypography-root {
color: var(--env-var-color-3);
}
.monitor-details button.MuiButtonBase-root,
.monitor-details h4.MuiTypography-root {
font-size: var(--env-var-font-size-medium);
}
.monitor-details button.MuiButtonBase-root {
height: var(--env-var-height-2);
line-height: 1;
@@ -28,28 +16,3 @@
.monitor-details p.MuiTypography-root span.MuiTypography-root {
font-size: var(--env-var-font-size-small-plus);
}
.monitor-details p.MuiTypography-root {
color: var(--env-var-color-2);
}
.monitor-details .stat-box {
flex: 1 20%;
min-width: 100px;
border: solid 1px;
border-radius: var(--env-var-radius-1);
padding: var(--env-var-spacing-1) 16px;
background-color: var(--env-var-color-8);
}
.monitor-details h6.MuiTypography-root {
font-size: var(--env-var-font-size-medium-plus);
}
.monitor-details h6.MuiTypography-root span.MuiTypography-root {
font-style: italic;
font-size: var(--env-var-font-size-medium);
color: var(--env-var-color-5);
opacity: 0.7;
}
.monitor-details button.MuiButtonBase-root,
.monitor-details .stat-box {
border-color: var(--env-var-color-16);
}

View File

@@ -1,5 +1,5 @@
import { useEffect, useState, useCallback } from "react";
import PropTypes from "prop-types";
import { useEffect, useState, useCallback } from "react";
import { Box, Skeleton, Stack, Typography, useTheme } from "@mui/material";
import { useSelector } from "react-redux";
import { useNavigate, useParams } from "react-router-dom";
@@ -19,12 +19,41 @@ import PulseDot from "../../../Components/Animated/PulseDot";
import "./index.css";
const StatBox = ({ title, value }) => {
const theme = useTheme();
return (
<Box className="stat-box">
<Typography variant="h6" mb={1} fontWeight={500}>
<Box
className="stat-box"
flex="20%"
minWidth="100px"
px={theme.spacing(8)}
py={theme.spacing(4)}
border={1}
borderColor={theme.palette.border.light}
borderRadius={theme.shape.borderRadius}
backgroundColor={theme.palette.background.main}
>
<Typography
variant="h6"
mb={theme.spacing(2)}
fontSize={14}
fontWeight={500}
color={theme.palette.common.main}
sx={{
"& span": {
color: theme.palette.text.accent,
fontSize: 13,
fontStyle: "italic",
},
}}
>
{title}
</Typography>
<Typography variant="h4" fontWeight={500}>
<Typography
variant="h4"
fontWeight={500}
fontSize={13}
color={theme.palette.text.secondary}
>
{value}
</Typography>
</Box>
@@ -47,8 +76,8 @@ const SkeletonLayout = () => {
return (
<>
<Skeleton variant="rounded" width="20%" height={34} />
<Stack gap={theme.gap.xl} mt={theme.gap.medium}>
<Stack direction="row" gap={theme.gap.small} mt={theme.gap.small}>
<Stack gap={theme.spacing(20)} mt={theme.spacing(6)}>
<Stack direction="row" gap={theme.spacing(4)} mt={theme.spacing(4)}>
<Skeleton
variant="circular"
style={{ minWidth: 24, minHeight: 24 }}
@@ -59,7 +88,7 @@ const SkeletonLayout = () => {
variant="rounded"
width="50%"
height={18}
sx={{ mt: theme.gap.small }}
sx={{ mt: theme.spacing(4) }}
/>
</Box>
<Skeleton
@@ -72,7 +101,7 @@ const SkeletonLayout = () => {
<Stack
direction="row"
justifyContent="space-between"
gap={theme.gap.large}
gap={theme.spacing(12)}
>
<Skeleton variant="rounded" width="100%" height={80} />
<Skeleton variant="rounded" width="100%" height={80} />
@@ -82,7 +111,7 @@ const SkeletonLayout = () => {
<Stack
direction="row"
justifyContent="space-between"
mb={theme.gap.ml}
mb={theme.spacing(8)}
>
<Skeleton
variant="rounded"
@@ -96,7 +125,7 @@ const SkeletonLayout = () => {
<Skeleton variant="rounded" width="100%" height="100%" />
</Box>
</Box>
<Stack gap={theme.gap.ml}>
<Stack gap={theme.spacing(8)}>
<Skeleton variant="rounded" width="20%" height={24} />
<Skeleton variant="rounded" width="100%" height={200} />
<Skeleton variant="rounded" width="100%" height={50} />
@@ -111,6 +140,7 @@ const SkeletonLayout = () => {
* @component
*/
const DetailsPage = ({ isAdmin }) => {
const theme = useTheme();
const [monitor, setMonitor] = useState({});
const { monitorId } = useParams();
const { authToken } = useSelector((state) => state.auth);
@@ -158,7 +188,6 @@ const DetailsPage = ({ isAdmin }) => {
fetchCertificate();
}, [authToken, monitorId, monitor]);
const theme = useTheme();
let loading = Object.keys(monitor).length === 0;
return (
<Box className="monitor-details">
@@ -172,26 +201,33 @@ const DetailsPage = ({ isAdmin }) => {
{ name: "details", path: `/monitors/${monitorId}` },
]}
/>
<Stack gap={theme.gap.large} mt={theme.gap.large}>
<Stack direction="row" gap={theme.gap.xs}>
<Stack gap={theme.spacing(12)} mt={theme.spacing(12)}>
<Stack direction="row" gap={theme.spacing(2)}>
<PulseDot
color={
monitor?.status
? theme.label.up.dotColor
: theme.label.down.dotColor
? theme.palette.success.main
: theme.palette.error.main
}
/>
<Box>
<Typography component="h1" sx={{ lineHeight: 1 }}>
<Typography
component="h1"
color={theme.palette.text.primary}
lineHeight={1}
>
{monitor.url?.replace(/^https?:\/\//, "") || "..."}
</Typography>
<Typography mt={theme.gap.small}>
<Typography
mt={theme.spacing(4)}
color={theme.palette.text.tertiary}
>
<Typography
component="span"
sx={{
color: monitor?.status
? "var(--env-var-color-17)"
: "var(--env-var-color-24)",
? theme.palette.success.main
: theme.palette.success.text,
}}
>
Your site is {monitor?.status ? "up" : "down"}.
@@ -207,8 +243,8 @@ const DetailsPage = ({ isAdmin }) => {
img={
<SettingsIcon
style={{
minWidth: theme.gap.mlplus,
minHeight: theme.gap.mlplus,
minWidth: theme.spacing(10),
minHeight: theme.spacing(10),
}}
/>
}
@@ -216,10 +252,10 @@ const DetailsPage = ({ isAdmin }) => {
sx={{
ml: "auto",
alignSelf: "flex-end",
backgroundColor: "#f4f4f4",
px: theme.gap.medium,
backgroundColor: theme.palette.background.fill,
px: theme.spacing(6),
"& svg": {
mr: "6px",
mr: theme.spacing(3),
},
}}
/>
@@ -228,7 +264,7 @@ const DetailsPage = ({ isAdmin }) => {
<Stack
direction="row"
justifyContent="space-between"
gap={theme.gap.large}
gap={theme.spacing(12)}
flexWrap="wrap"
>
<StatBox
@@ -281,20 +317,29 @@ const DetailsPage = ({ isAdmin }) => {
<Stack
direction="row"
justifyContent="space-between"
mb={theme.gap.ml}
mb={theme.spacing(8)}
>
<Typography component="h2" alignSelf="flex-end">
<Typography
component="h2"
alignSelf="flex-end"
color={theme.palette.text.secondary}
>
Response Times
</Typography>
<ButtonGroup>
<ButtonGroup
sx={{
"& .MuiButtonBase-root": {
borderColor: theme.palette.border.light,
},
}}
>
<Button
level="secondary"
label="Day"
onClick={() => setDateRange("day")}
sx={{
backgroundColor:
dateRange === "day" &&
theme.palette.otherColors.fillGray,
dateRange === "day" && theme.palette.background.fill,
}}
/>
<Button
@@ -303,8 +348,7 @@ const DetailsPage = ({ isAdmin }) => {
onClick={() => setDateRange("week")}
sx={{
backgroundColor:
dateRange === "week" &&
theme.palette.otherColors.fillGray,
dateRange === "week" && theme.palette.background.fill,
}}
/>
<Button
@@ -313,19 +357,18 @@ const DetailsPage = ({ isAdmin }) => {
onClick={() => setDateRange("month")}
sx={{
backgroundColor:
dateRange === "month" &&
theme.palette.otherColors.fillGray,
dateRange === "month" && theme.palette.background.fill,
}}
/>
</ButtonGroup>
</Stack>
<Box
p={theme.gap.mlplus}
pb={theme.gap.xs}
backgroundColor={theme.palette.otherColors.white}
p={theme.spacing(10)}
pb={theme.spacing(2)}
backgroundColor={theme.palette.background.main}
border={1}
borderColor={theme.palette.otherColors.graishWhite}
borderRadius={`${theme.shape.borderRadius}px`}
borderColor={theme.palette.border.light}
borderRadius={theme.shape.borderRadius}
sx={{ height: "250px" }}
>
<MonitorDetailsAreaChart
@@ -333,8 +376,10 @@ const DetailsPage = ({ isAdmin }) => {
/>
</Box>
</Box>
<Stack gap={theme.gap.ml}>
<Typography component="h2">History</Typography>
<Stack gap={theme.spacing(8)}>
<Typography component="h2" color={theme.palette.text.secondary}>
History
</Typography>
<PaginationTable monitorId={monitorId} dateRange={dateRange} />
</Stack>
</Stack>

View File

@@ -8,26 +8,31 @@ import ClockSnooze from "../../../assets/icons/clock-snooze.svg?react";
const StatusBox = ({ title, value }) => {
const theme = useTheme();
let sharedStyles = { position: "absolute", right: 8, opacity: 0.5 };
let sharedStyles = {
position: "absolute",
right: 8,
opacity: 0.5,
"& svg path": { stroke: theme.palette.other.icon },
};
let color;
let icon;
if (title === "up") {
color = theme.pie.green.stroke;
color = theme.palette.success.main;
icon = (
<Box sx={{ ...sharedStyles, top: 8 }}>
<Arrow />
</Box>
);
} else if (title === "down") {
color = theme.pie.red.stroke;
color = theme.palette.error.text;
icon = (
<Box sx={{ ...sharedStyles, transform: "rotate(180deg)", top: 5 }}>
<Arrow />
</Box>
);
} else if (title === "paused") {
color = theme.pie.yellow.stroke;
color = theme.palette.warning.main;
icon = (
<Box sx={{ ...sharedStyles, top: 12, right: 12 }}>
<ClockSnooze />
@@ -40,15 +45,15 @@ const StatusBox = ({ title, value }) => {
position="relative"
flex={1}
border={1}
borderColor={theme.palette.otherColors.graishWhite}
borderRadius={`${theme.shape.borderRadius}px`}
backgroundColor={theme.palette.otherColors.white}
px={theme.gap.large}
py={theme.gap.ml}
borderColor={theme.palette.border.light}
borderRadius={theme.shape.borderRadius}
backgroundColor={theme.palette.background.main}
px={theme.spacing(12)}
py={theme.spacing(8)}
overflow="hidden"
sx={{
"&:hover": {
backgroundColor: "#f9fafb",
backgroundColor: theme.palette.background.accent,
},
"&:after": {
position: "absolute",
@@ -67,8 +72,8 @@ const StatusBox = ({ title, value }) => {
textTransform="uppercase"
fontSize={15}
letterSpacing={0.5}
color={theme.palette.otherColors.bluishGray}
mb={theme.gap.ml}
color={theme.palette.text.secondary}
mb={theme.spacing(8)}
sx={{ opacity: 0.6 }}
>
{title}
@@ -87,7 +92,7 @@ const StatusBox = ({ title, value }) => {
component="span"
fontSize={20}
fontWeight={300}
color={theme.palette.otherColors.bluishGray}
color={theme.palette.text.secondary}
sx={{ opacity: 0.3 }}
>
#

View File

@@ -1,5 +1,7 @@
import { useState } from "react";
import { useSelector, useDispatch } from "react-redux";
import { useTheme } from "@emotion/react";
import { useNavigate } from "react-router-dom";
import { createToast } from "../../../Utils/toastUtils";
import {
IconButton,
@@ -14,10 +16,8 @@ import {
getUptimeMonitorsByTeamId,
} from "../../../Features/UptimeMonitors/uptimeMonitorsSlice";
import Settings from "../../../assets/icons/settings-bold.svg?react";
import { useTheme } from "@emotion/react";
import Button from "../../../Components/Button";
import PropTypes from "prop-types";
import { useNavigate } from "react-router-dom";
const ActionsMenu = ({ monitor, isAdmin }) => {
const [anchorEl, setAnchorEl] = useState(null);
@@ -77,6 +77,9 @@ const ActionsMenu = ({ monitor, isAdmin }) => {
"&:focus": {
outline: "none",
},
"& svg path": {
stroke: theme.palette.other.icon,
},
}}
>
<Settings />
@@ -87,6 +90,26 @@ const ActionsMenu = ({ monitor, isAdmin }) => {
anchorEl={anchorEl}
open={Boolean(anchorEl)}
onClose={(e) => closeMenu(e)}
slotProps={{
paper: {
sx: {
"& ul": {
p: theme.spacing(2.5),
minWidth: "100px",
},
"& li": {
color: theme.palette.text.secondary,
fontSize: 13,
px: theme.spacing(4),
py: theme.spacing(2.5),
borderRadius: theme.shape.borderRadius,
},
"& li:last-of-type": {
color: theme.palette.error.text,
},
},
},
}}
>
{actions.url !== null ? (
<MenuItem
@@ -137,48 +160,58 @@ const ActionsMenu = ({ monitor, isAdmin }) => {
aria-labelledby="modal-delete-monitor"
aria-describedby="delete-monitor-confirmation"
open={isOpen}
onClose={() => setIsOpen(false)}
disablePortal
onClose={(e) => {
e.stopPropagation();
setIsOpen(false);
}}
>
<Stack
gap={theme.gap.xs}
gap={theme.spacing(2)}
color={theme.palette.text.secondary}
sx={{
position: "absolute",
top: "50%",
left: "50%",
transform: "translate(-50%, -50%)",
width: 400,
bgcolor: "white",
border: "solid 1px #f2f2f2",
borderRadius: `${theme.shape.borderRadius}px`,
bgcolor: theme.palette.background.main,
border: 1,
borderColor: theme.palette.border.light,
borderRadius: theme.shape.borderRadius,
boxShadow: 24,
p: "30px",
p: theme.spacing(15),
"&:focus": {
outline: "none",
},
}}
>
<Typography id="modal-delete-monitor" component="h2">
<Typography id="modal-delete-monitor" component="h2" fontWeight={600}>
Do you really want to delete this monitor?
</Typography>
<Typography id="delete-monitor-confirmation">
<Typography id="delete-monitor-confirmation" fontSize={13}>
Once deleted, this monitor cannot be retrieved.
</Typography>
<Stack
direction="row"
gap={theme.gap.small}
mt={theme.gap.large}
gap={theme.spacing(4)}
mt={theme.spacing(12)}
justifyContent="flex-end"
>
<Button
level="tertiary"
label="Cancel"
onClick={() => setIsOpen(false)}
onClick={(e) => {
e.stopPropagation();
setIsOpen(false);
}}
/>
<Button
level="error"
label="Delete"
onClick={(e) => handleRemove(e)}
onClick={(e) => {
e.stopPropagation(e);
handleRemove(e);
}}
/>
</Stack>
</Stack>

View File

@@ -11,12 +11,13 @@ const Fallback = ({ isAdmin }) => {
return (
<Stack
alignItems="center"
backgroundColor={theme.palette.otherColors.white}
p={theme.gap.xxl}
gap={theme.gap.xs}
backgroundColor={theme.palette.background.main}
p={theme.spacing(30)}
gap={theme.spacing(2)}
border={1}
borderRadius={`${theme.shape.borderRadius}px`}
borderColor={theme.palette.otherColors.graishWhite}
borderRadius={theme.shape.borderRadius}
borderColor={theme.palette.border.light}
color={theme.palette.text.secondary}
>
<Typography component="h2">No monitors found</Typography>
<Typography>
@@ -29,7 +30,7 @@ const Fallback = ({ isAdmin }) => {
onClick={() => {
navigate("/monitors/create");
}}
sx={{ mt: theme.gap.large }}
sx={{ mt: theme.spacing(12) }}
/>
)}
</Stack>

View File

@@ -1,4 +1,4 @@
import { Stack, Typography } from "@mui/material";
import { Box, Typography } from "@mui/material";
import PropTypes from "prop-types";
/**
* Host component.
@@ -13,12 +13,39 @@ import PropTypes from "prop-types";
*/
const Host = ({ params }) => {
return (
<Stack direction="row" alignItems="baseline" className="host">
{params.title}
<Typography component="span" sx={{ color: params.percentageColor }}>
<Box className="host">
<Box
display="inline-block"
position="relative"
sx={{
fontWeight: 500,
"&:before": {
position: "absolute",
content: `""`,
width: "4px",
height: "4px",
borderRadius: "50%",
backgroundColor: "gray",
opacity: 0.8,
right: "-10px",
top: "42%",
},
}}
>
{params.title}
</Box>
<Typography
component="span"
sx={{
color: params.percentageColor,
fontWeight: 500,
ml: "15px",
}}
>
{params.percentage}%
</Typography>
</Stack>
<Box sx={{ opacity: 0.6 }}>{params.url}</Box>
</Box>
);
};

View File

@@ -1,17 +1,11 @@
.monitors h1.MuiTypography-root {
font-size: var(--env-var-font-size-large-plus);
color: var(--env-var-color-1);
font-weight: 500;
}
.monitors h2.MuiTypography-root {
font-size: var(--env-var-font-size-large);
color: var(--env-var-color-5);
font-weight: 500;
}
.monitors p.MuiTypography-root {
font-size: var(--env-var-font-size-medium);
color: var(--env-var-color-5);
}
.monitors h1.MuiTypography-root + p.MuiTypography-root {
font-size: var(--env-var-font-size-medium-plus);
}
@@ -28,36 +22,9 @@
padding: 5px;
min-width: 25px;
min-height: 25px;
background-color: var(--env-var-color-15);
border: 1px solid var(--env-var-color-6);
border-radius: 50%;
font-size: var(--env-var-font-size-medium);
font-weight: 500;
color: var(--env-var-color-1);
margin-left: 10px;
line-height: 0.8;
}
body:has(.monitors) .actions-menu .MuiPaper-root {
box-shadow: var(--env-var-shadow-1);
border: solid 1px var(--env-var-color-6);
border-radius: var(--env-var-radius-1);
gap: 1px;
}
body:has(.monitors) .actions-menu .MuiList-root {
padding: 6px 8px;
min-width: 100px;
}
body:has(.monitors) .actions-menu li.MuiButtonBase-root {
font-size: var(--env-var-font-size-medium);
color: var(--env-var-color-5);
padding: 5px 8px;
border-radius: var(--env-var-radius-1);
}
body:has(.monitors) .actions-menu li.MuiButtonBase-root:last-of-type {
color: var(--env-var-color-26);
}
body:has(.monitors) .actions-menu .MuiModal-root p.MuiTypography-root {
font-size: var(--env-var-font-size-medium);
color: var(--env-var-color-2);
}

View File

@@ -12,6 +12,7 @@ import SkeletonLayout from "./skeleton";
import Fallback from "./fallback";
import StatusBox from "./StatusBox";
import { buildData } from "./monitorData";
import Breadcrumbs from "../../../Components/Breadcrumbs";
const Monitors = ({ isAdmin }) => {
const theme = useTheme();
@@ -42,43 +43,86 @@ const Monitors = ({ isAdmin }) => {
let loading = monitorState.isLoading && monitorState.monitors.length === 0;
const now = new Date();
const hour = now.getHours();
let greeting = "";
let emoji = "";
if (hour < 12) {
greeting = "morning";
emoji = "🌅";
} else if (hour < 18) {
greeting = "afternoon";
emoji = "🌞";
} else {
greeting = "evening";
emoji = "🌙";
}
return (
<Stack className="monitors" gap={theme.gap.large}>
<Stack className="monitors" gap={theme.spacing(12)}>
{loading ? (
<SkeletonLayout />
) : (
<>
<Stack
direction="row"
justifyContent="space-between"
alignItems="center"
>
<Typography
component="h1"
sx={{ lineHeight: 1, alignSelf: "flex-end" }}
<Box>
<Breadcrumbs list={[{ name: `monitors`, path: "/monitors" }]} />
<Stack
direction="row"
justifyContent="space-between"
alignItems="center"
mt={theme.spacing(5)}
>
Hello, {authState.user.firstName}
</Typography>
{isAdmin && monitorState.monitors?.length !== 0 && (
<Button
level="primary"
label="Create monitor"
onClick={() => {
navigate("/monitors/create");
}}
sx={{ fontWeight: 500 }}
/>
)}
</Stack>
{monitorState.monitors?.length === 0 && (
<Box>
<Typography
component="h1"
lineHeight={1}
color={theme.palette.text.primary}
>
<Typography
component="span"
fontSize="inherit"
color={theme.palette.text.secondary}
>
Good {greeting},{" "}
</Typography>
<Typography
component="span"
fontSize="inherit"
fontWeight="inherit"
>
{authState.user.firstName} {emoji}
</Typography>
</Typography>
<Typography
sx={{ opacity: 0.8 }}
lineHeight={1}
fontWeight={300}
color={theme.palette.text.secondary}
>
Heres an overview of your uptime monitors.
</Typography>
</Box>
{monitorState.monitors?.length !== 0 && (
<Button
level="primary"
label="Create monitor"
onClick={() => {
navigate("/monitors/create");
}}
sx={{ fontWeight: 500 }}
/>
)}
</Stack>
</Box>
{isAdmin && monitorState.monitors?.length === 0 && (
<Fallback isAdmin={isAdmin} />
)}
{monitorState.monitors?.length !== 0 && (
<>
<Stack
gap={theme.gap.large}
gap={theme.spacing(12)}
direction="row"
justifyContent="space-between"
>
@@ -88,17 +132,32 @@ const Monitors = ({ isAdmin }) => {
</Stack>
<Box
flex={1}
p={theme.gap.lgplus}
px={theme.spacing(16)}
py={theme.spacing(12)}
border={1}
borderColor={theme.palette.otherColors.graishWhite}
backgroundColor={theme.palette.otherColors.white}
sx={{
borderRadius: `${theme.shape.borderRadius}px`,
}}
borderColor={theme.palette.border.light}
borderRadius={theme.shape.borderRadius}
backgroundColor={theme.palette.background.main}
>
<Stack direction="row" alignItems="center" mb={theme.gap.large}>
<Typography component="h2">Current monitors</Typography>
<Box className="current-monitors-counter">
<Stack
direction="row"
alignItems="center"
mb={theme.spacing(12)}
>
<Typography
component="h2"
color={theme.palette.text.secondary}
letterSpacing={-0.5}
>
Actively monitoring
</Typography>
<Box
className="current-monitors-counter"
color={theme.palette.text.primary}
border={1}
borderColor={theme.palette.border.light}
backgroundColor={theme.palette.background.accent}
>
{monitorState.monitors.length}
</Box>
{/* TODO - add search bar */}

View File

@@ -4,6 +4,7 @@ import BarChart from "../../../Components/Charts/BarChart";
import ArrowDownwardRoundedIcon from "@mui/icons-material/ArrowDownwardRounded";
import { StatusLabel } from "../../../Components/Label";
import { Box } from "@mui/material";
import { useTheme } from "@emotion/react";
const data = {
cols: [
@@ -27,14 +28,17 @@ const data = {
};
export const buildData = (monitors, isAdmin, navigate) => {
const theme = useTheme();
data.rows = monitors.map((monitor, idx) => {
const params = {
url: monitor.url,
title: monitor.name,
percentage: 100,
percentageColor:
monitor.status === true
? "var(--env-var-color-17)"
: "var(--env-var-color-19)",
? theme.palette.success.main
: theme.palette.error.text,
status: monitor.status === true ? "up" : "down",
};
@@ -43,7 +47,6 @@ export const buildData = (monitors, isAdmin, navigate) => {
return {
id: monitor._id,
// disabled for now
handleClick: () => {
navigate(`/monitors/${monitor._id}`);
},

View File

@@ -16,7 +16,7 @@ const SkeletonLayout = () => {
<Skeleton variant="rounded" width="15%" height={36} />
</Stack>
<Stack
gap={theme.gap.large}
gap={theme.spacing(12)}
direction="row"
justifyContent="space-between"
>
@@ -24,7 +24,11 @@ const SkeletonLayout = () => {
<Skeleton variant="rounded" width="100%" height={100} />
<Skeleton variant="rounded" width="100%" height={100} />
</Stack>
<Stack gap={theme.gap.large} p={theme.gap.xl} backgroundColor="#f9fafb">
<Stack
gap={theme.spacing(12)}
p={theme.spacing(20)}
backgroundColor="#f9fafb"
>
<Skeleton variant="rounded" width="50%" height={25} />
<Skeleton variant="rounded" width="100%" height={300} />
<Skeleton variant="rounded" width="100%" height={100} />

View File

@@ -0,0 +1,35 @@
import { Stack, styled } from "@mui/material";
export const ConfigBox = styled(Stack)(({ theme }) => ({
flexDirection: "row",
border: 1,
borderStyle: "solid",
borderColor: theme.palette.border.light,
borderRadius: theme.spacing(2),
backgroundColor: theme.palette.background.main,
"& > *": {
paddingTop: theme.spacing(12),
paddingBottom: theme.spacing(18),
},
"& > div:first-of-type": {
flex: 0.7,
borderRight: 1,
borderRightStyle: "solid",
borderRightColor: theme.palette.border.light,
paddingRight: theme.spacing(15),
paddingLeft: theme.spacing(15),
},
"& > div:last-of-type": {
flex: 1,
paddingRight: theme.spacing(20),
paddingLeft: theme.spacing(18),
},
"& h2": {
color: theme.palette.text.secondary,
fontSize: 15,
fontWeight: 600,
},
"& h3, & p": {
color: theme.palette.text.tertiary,
},
}));

View File

@@ -1,15 +0,0 @@
.not-found-page {
height: 100vh;
}
.not-found-page button,
.not-found-page p {
font-size: var(--env-var-font-size-medium);
}
.not-found-page h1 {
font-size: var(--env-var-font-size-large);
font-weight: 600;
}
.not-found-page h1,
.not-found-page p {
color: var(--env-var-color-5);
}

View File

@@ -1,10 +1,10 @@
import Button from "../../Components/Button";
import "./index.css";
import React from "react";
import PropTypes from "prop-types";
import NotFoundSvg from "../../../src/assets/Images/sushi_404.svg";
import { Stack, Typography } from "@mui/material";
import { useNavigate } from "react-router";
import NotFoundSvg from "../../../src/assets/Images/sushi_404.svg";
import { useTheme } from "@emotion/react";
/**
* Support for defaultProps will be removed from function components in a future major release
@@ -33,16 +33,24 @@ const DefaultValue = {
*/
const NotFound = ({ title = DefaultValue.title, desc = DefaultValue.desc }) => {
const navigate = useNavigate();
const theme = useTheme();
return (
<Stack className="not-found-page" justifyContent="center">
<Stack gap="20px" alignItems="center">
<Stack height="100vh" justifyContent="center">
<Stack
gap={theme.spacing(2)}
alignItems="center"
color={theme.palette.text.secondary}
>
<img src={NotFoundSvg} alt="404" style={{ maxHeight: "25rem" }} />
<Typography component="h1">{title}</Typography>
<Typography>{desc}</Typography>
<Typography component="h1" fontSize={16} fontWeight={600}>
{title}
</Typography>
<Typography fontSize={13}>{desc}</Typography>
<Button
label="Go to the main dashboard"
level="primary"
sx={{ mt: "24px" }}
sx={{ mt: theme.spacing(10) }}
onClick={() => navigate("/")}
/>
</Stack>

View File

@@ -1,23 +1,9 @@
.configure-pagespeed form > .MuiStack-root:nth-child(2) {
background-color: var(--env-var-color-8);
border: solid 1px var(--env-var-color-6);
border-radius: var(--env-var-radius-1);
padding: var(--env-var-font-size-large-plus) var(--env-var-font-size-xlarge);
}
.configure-pagespeed h1.MuiTypography-root {
font-size: var(--env-var-font-size-large-plus);
}
.configure-pagespeed h1.MuiTypography-root,
.configure-pagespeed h2.MuiTypography-root {
color: var(--env-var-color-1);
}
.configure-pagespeed span.MuiTypography-root {
font-size: var(--env-var-font-size-small-plus);
}
.configure-pagespeed p.MuiTypography-root,
.configure-pagespeed h3.MuiTypography-root {
color: var(--env-var-color-5);
}
.configure-pagespeed h1.MuiTypography-root,
.configure-pagespeed h3.MuiTypography-root,
.configure-pagespeed h2.MuiTypography-root {
@@ -38,13 +24,10 @@
.configure-pagespeed .checkbox-wrapper {
margin-bottom: 1px;
}
.configure-pagespeed .MuiInputBase-root:has(> .Mui-disabled) {
background-color: var(--env-var-color-13);
}
/* to be removed */
.configure-pagespeed .section-disabled {
opacity: 0.4;
background-color: #f1f1f2;
padding: 10px;
border-radius: 8px;
user-select: none;
@@ -55,11 +38,6 @@
height: var(--env-var-height-2);
}
body:has(.configure-pagespeed) .select-dropdown .MuiMenuItem-root,
.configure-pagespeed .select-wrapper .select-component > .MuiSelect-select {
text-transform: lowercase;
}
.configure-pagespeed h3.MuiTypography-root {
flex: 0.7;
}

View File

@@ -32,8 +32,8 @@ const SkeletonLayout = () => {
return (
<>
<Skeleton variant="rounded" width="15%" height={34} />
<Stack gap={theme.gap.xl} mt={theme.gap.medium} maxWidth="1000px">
<Stack direction="row" gap={theme.gap.small} mt={theme.gap.small}>
<Stack gap={theme.spacing(20)} mt={theme.spacing(6)} maxWidth="1000px">
<Stack direction="row" gap={theme.spacing(4)} mt={theme.spacing(4)}>
<Skeleton
variant="circular"
style={{ minWidth: 24, minHeight: 24 }}
@@ -43,13 +43,13 @@ const SkeletonLayout = () => {
variant="rounded"
width="50%"
height={24}
sx={{ mb: theme.gap.small }}
sx={{ mb: theme.spacing(4) }}
/>
<Skeleton variant="rounded" width="50%" height={18} />
</Box>
<Stack
direction="row"
gap={theme.gap.medium}
gap={theme.spacing(6)}
sx={{
ml: "auto",
alignSelf: "flex-end",
@@ -147,7 +147,7 @@ const PageSpeedConfigure = () => {
let loading = Object.keys(monitor).length === 0;
return (
<Stack className="configure-pagespeed" gap={theme.gap.large}>
<Stack className="configure-pagespeed" gap={theme.spacing(12)}>
{loading ? (
<SkeletonLayout />
) : (
@@ -165,21 +165,22 @@ const PageSpeedConfigure = () => {
spellCheck="false"
onSubmit={handleSave}
flex={1}
gap={theme.gap.large}
gap={theme.spacing(12)}
>
<Stack direction="row" gap={theme.gap.xs}>
<Stack direction="row" gap={theme.spacing(2)}>
<PulseDot
color={
monitor?.status
? theme.label.up.dotColor
: theme.label.down.dotColor
? theme.palette.success.main
: theme.palette.error.main
}
/>
<Box>
<Typography
component="h1"
mb={theme.gap.xs}
mb={theme.spacing(2)}
sx={{ lineHeight: 1 }}
color={theme.palette.text.primary}
>
{monitor?.url}
</Typography>
@@ -187,8 +188,8 @@ const PageSpeedConfigure = () => {
component="span"
sx={{
color: monitor?.status
? "var(--env-var-color-17)"
: "var(--env-var-color-24)",
? theme.palette.success.main
: theme.palette.error.text,
}}
>
Your pagespeed monitor is {monitor?.status ? "live" : "down"}.
@@ -201,11 +202,11 @@ const PageSpeedConfigure = () => {
animate="rotate180"
img={<PauseCircleOutlineIcon />}
sx={{
backgroundColor: theme.palette.otherColors.fillGray,
pl: theme.gap.small,
pr: theme.gap.medium,
backgroundColor: theme.palette.background.fill,
pl: theme.spacing(4),
pr: theme.spacing(6),
"& svg": {
mr: theme.gap.xs,
mr: theme.spacing(2),
},
}}
/>
@@ -214,14 +215,27 @@ const PageSpeedConfigure = () => {
label="Remove"
sx={{
boxShadow: "none",
px: theme.gap.ml,
ml: theme.gap.medium,
px: theme.spacing(8),
ml: theme.spacing(6),
}}
onClick={() => setIsOpen(true)}
/>
</Box>
</Stack>
<Stack gap={theme.gap.xl}>
<Stack
border={1}
borderColor={theme.palette.border.light}
borderRadius={theme.shape.borderRadius}
backgroundColor={theme.palette.background.main}
p={theme.spacing(20)}
pl={theme.spacing(15)}
gap={theme.spacing(20)}
sx={{
"& h3, & p": {
color: theme.palette.text.secondary,
},
}}
>
<Stack direction="row">
<Typography component="h3">Monitor display name</Typography>
<Field
@@ -233,7 +247,14 @@ const PageSpeedConfigure = () => {
error={errors.name}
/>
</Stack>
<Stack direction="row">
<Stack
direction="row"
sx={{
".MuiInputBase-root:has(> .Mui-disabled)": {
backgroundColor: theme.palette.background.accent,
},
}}
>
<Typography component="h3">URL</Typography>
<Field
type="url"
@@ -259,8 +280,11 @@ const PageSpeedConfigure = () => {
Incidents notifications{" "}
<Typography component="span">(coming soon)</Typography>
</Typography>
<Stack className="section-disabled">
<Typography mb={theme.gap.small}>
<Stack
className="section-disabled"
backgroundColor={theme.palette.background.fill}
>
<Typography mb={theme.spacing(4)}>
When there is a new incident,
</Typography>
<Checkbox
@@ -279,7 +303,7 @@ const PageSpeedConfigure = () => {
label="Notify via email to following emails"
isChecked={false}
/>
<Box mx={`calc(${theme.gap.ml} * 2)`}>
<Box mx={theme.spacing(16)}>
<Field
id="notify-emails-list"
placeholder="notifications@gmail.com"
@@ -287,7 +311,7 @@ const PageSpeedConfigure = () => {
onChange={() => logger.warn("disabled")}
error=""
/>
<Typography mt={theme.gap.small}>
<Typography mt={theme.spacing(4)}>
You can separate multiple emails with a comma
</Typography>
</Box>
@@ -300,7 +324,7 @@ const PageSpeedConfigure = () => {
level="primary"
label="Save"
onClick={handleSave}
sx={{ px: theme.gap.large, mt: theme.gap.large }}
sx={{ px: theme.spacing(12), mt: theme.spacing(12) }}
/>
</Stack>
</Stack>
@@ -314,33 +338,41 @@ const PageSpeedConfigure = () => {
disablePortal
>
<Stack
gap={theme.gap.xs}
gap={theme.spacing(2)}
sx={{
position: "absolute",
top: "50%",
left: "50%",
transform: "translate(-50%, -50%)",
width: 400,
bgcolor: "white",
border: "solid 1px #f2f2f2",
borderRadius: `${theme.shape.borderRadius}px`,
bgcolor: theme.palette.background.main,
border: 1,
borderColor: theme.palette.border.light,
borderRadius: theme.shape.borderRadius,
boxShadow: 24,
p: "30px",
p: theme.spacing(15),
"&:focus": {
outline: "none",
},
}}
>
<Typography id="modal-delete-pagespeed-monitor" component="h2">
<Typography
id="modal-delete-pagespeed-monitor"
component="h2"
color={theme.palette.text.secondary}
>
Do you really want to delete this monitor?
</Typography>
<Typography id="delete-pagespeed-monitor-confirmation">
<Typography
id="delete-pagespeed-monitor-confirmation"
color={theme.palette.text.tertiary}
>
Once deleted, this monitor cannot be retrieved.
</Typography>
<Stack
direction="row"
gap={theme.gap.small}
mt={theme.gap.large}
gap={theme.spacing(4)}
mt={theme.spacing(12)}
justifyContent="flex-end"
>
<Button

View File

@@ -1,17 +1,3 @@
.create-page-speed form > .MuiStack-root:not(:last-of-type) {
background-color: var(--env-var-color-8);
border: solid 1px var(--env-var-color-6);
border-radius: var(--env-var-radius-1);
padding: var(--env-var-font-size-large-plus) var(--env-var-font-size-xlarge);
}
.create-page-speed h1.MuiTypography-root {
font-size: 22px;
color: var(--env-var-color-1);
}
.create-page-speed p.MuiTypography-root,
.create-page-speed h3.MuiTypography-root {
color: var(--env-var-color-5);
}
.create-page-speed h1.MuiTypography-root,
.create-page-speed h3.MuiTypography-root {
font-weight: 600;
@@ -31,10 +17,10 @@
.create-page-speed .checkbox-wrapper {
margin-bottom: 1px;
}
/* to be removed */
.create-page-speed .section-disabled {
opacity: 0.4;
background-color: #f1f1f2;
padding: 10px;
border-radius: 8px;
user-select: none;
@@ -45,11 +31,6 @@
height: var(--env-var-height-2);
}
body:has(.create-page-speed) .select-dropdown .MuiMenuItem-root,
.create-page-speed .select-wrapper .select-component > .MuiSelect-select {
text-transform: lowercase;
}
.create-page-speed h3.MuiTypography-root {
flex: 0.7;
}

View File

@@ -99,7 +99,7 @@ const CreatePageSpeed = () => {
};
return (
<Stack className="create-page-speed" gap={theme.gap.mlplus}>
<Stack className="create-page-speed" gap={theme.spacing(6)}>
<Breadcrumbs
list={[
{ name: "pagespeed", path: "/pagespeed" },
@@ -111,11 +111,47 @@ const CreatePageSpeed = () => {
noValidate
spellCheck="false"
onSubmit={handleCreate}
gap={theme.gap.large}
gap={theme.spacing(12)}
flex={1}
>
<Typography component="h1">Create pagespeed monitor</Typography>
<Stack gap={theme.gap.xl}>
<Typography
component="h1"
lineHeight={1}
fontSize={21}
color={theme.palette.text.primary}
>
<Typography
component="span"
fontSize="inherit"
color={theme.palette.text.secondary}
>
Create your{" "}
</Typography>
<Typography component="span" fontSize="inherit" fontWeight="inherit">
pagespeed{" "}
</Typography>
<Typography
component="span"
fontSize="inherit"
color={theme.palette.text.secondary}
>
monitor
</Typography>
</Typography>
<Stack
border={1}
borderColor={theme.palette.border.light}
borderRadius={theme.shape.borderRadius}
backgroundColor={theme.palette.background.main}
p={theme.spacing(20)}
pl={theme.spacing(15)}
gap={theme.spacing(20)}
sx={{
"& h3, & p": {
color: theme.palette.text.secondary,
},
}}
>
<Stack direction="row">
<Typography component="h3">Monitor display name</Typography>
<Field
@@ -152,8 +188,11 @@ const CreatePageSpeed = () => {
Incidents notifications{" "}
<Typography component="span">(coming soon)</Typography>
</Typography>
<Stack className="section-disabled">
<Typography mb={theme.gap.small}>
<Stack
className="section-disabled"
backgroundColor={theme.palette.background.fill}
>
<Typography mb={theme.spacing(4)}>
When there is a new incident,
</Typography>
<Checkbox
@@ -172,7 +211,7 @@ const CreatePageSpeed = () => {
label="Notify via email to following emails"
isChecked={false}
/>
<Box mx={`calc(${theme.gap.ml} * 2)`}>
<Box mx={theme.spacing(16)}>
<Field
id="notify-emails-list"
placeholder="notifications@gmail.com"
@@ -180,7 +219,7 @@ const CreatePageSpeed = () => {
onChange={() => logger.warn("disabled")}
error=""
/>
<Typography mt={theme.gap.small}>
<Typography mt={theme.spacing(4)}>
You can separate multiple emails with a comma
</Typography>
</Box>
@@ -193,7 +232,7 @@ const CreatePageSpeed = () => {
level="primary"
label="Create"
onClick={handleCreate}
sx={{ px: theme.gap.large, mt: theme.gap.large }}
sx={{ px: theme.spacing(12), mt: theme.spacing(12) }}
/>
</Stack>
</Stack>

View File

@@ -1,6 +1,5 @@
.page-speed-details h1 {
font-size: var(--env-var-font-size-large-plus);
color: var(--env-var-color-1);
}
.page-speed-details h2,
.page-speed-details h6 {
@@ -15,13 +14,7 @@
.page-speed-details h4 > span {
font-size: var(--env-var-font-size-small-plus);
}
.page-speed-details h2,
.page-speed-details h4,
.page-speed-details p {
color: var(--env-var-color-5);
}
.page-speed-details h6 {
color: var(--env-var-color-3);
line-height: 22px;
}
.page-speed-details h1,
@@ -33,14 +26,6 @@
height: 34px;
}
.page-speed-details .stat-box,
.page-speed-details > .MuiStack-root:last-child,
.page-speed-details > .MuiBox-root:nth-last-child(3) {
border: solid 1px var(--env-var-color-6);
border-radius: var(--env-var-radius-1);
background-color: var(--env-var-color-8);
min-width: 200px;
}
.page-speed-details .stat-box {
flex: 1;
}

View File

@@ -29,17 +29,28 @@ const StatBox = ({ icon, title, value }) => {
<Stack
className="stat-box"
direction="row"
gap={theme.gap.small}
pt={theme.gap.ml}
px={theme.gap.ml}
pb={theme.gap.mlplus}
gap={theme.spacing(4)}
pt={theme.spacing(8)}
px={theme.spacing(8)}
pb={theme.spacing(10)}
border={1}
borderColor={theme.palette.border.light}
borderRadius={theme.shape.borderRadius}
backgroundColor={theme.palette.background.main}
minWidth="200px"
>
{icon}
<Box>
<Typography variant="h6" mb={theme.gap.medium}>
<Typography
variant="h6"
color={theme.palette.common.main}
mb={theme.spacing(6)}
>
{title}
</Typography>
<Typography variant="h4">{value}</Typography>
<Typography variant="h4" color={theme.palette.text.secondary}>
{value}
</Typography>
</Box>
</Stack>
);
@@ -151,7 +162,7 @@ const SkeletonLayout = () => {
return (
<>
<Skeleton variant="rounded" width="15%" height={34} />
<Stack direction="row" gap={theme.gap.small}>
<Stack direction="row" gap={theme.spacing(4)}>
<Skeleton variant="circular" style={{ minWidth: 24, minHeight: 24 }} />
<Box width="85%">
<Skeleton variant="rounded" width="50%" height={24} />
@@ -159,7 +170,7 @@ const SkeletonLayout = () => {
variant="rounded"
width="50%"
height={18}
sx={{ mt: theme.gap.small }}
sx={{ mt: theme.spacing(4) }}
/>
</Box>
<Skeleton
@@ -172,7 +183,7 @@ const SkeletonLayout = () => {
<Stack
direction="row"
justifyContent="space-between"
gap={theme.gap.xl}
gap={theme.spacing(20)}
flexWrap="wrap"
>
<Skeleton variant="rounded" width="30%" height={90} sx={{ flex: 1 }} />
@@ -237,10 +248,37 @@ const PageSpeedDetails = () => {
* @returns {{stroke: string, text: string, bg: string}} The color properties for the given performance value.
*/
const getColors = (value) => {
if (value >= 90 && value <= 100) return theme.pie.green;
else if (value >= 50 && value < 90) return theme.pie.yellow;
else if (value >= 0 && value < 50) return theme.pie.red;
return theme.pie.default;
if (value >= 90 && value <= 100)
return {
stroke: theme.palette.success.main,
strokeBg: theme.palette.success.light,
text: theme.palette.success.text,
bg: theme.palette.success.bg,
shape: "circle",
};
else if (value >= 50 && value < 90)
return {
stroke: theme.palette.warning.main,
strokeBg: theme.palette.warning.bg,
text: theme.palette.warning.text,
bg: theme.palette.warning.light,
shape: "square",
};
else if (value >= 0 && value < 50)
return {
stroke: theme.palette.error.text,
strokeBg: theme.palette.error.light,
text: theme.palette.error.text,
bg: theme.palette.error.bg,
shape: "circle",
};
return {
stroke: theme.palette.unresolved.main,
strokeBg: theme.palette.unresolved.light,
text: theme.palette.unresolved.main,
bg: theme.palette.unresolved.bg,
shape: "",
};
};
/**
@@ -312,8 +350,15 @@ const PageSpeedDetails = () => {
let loading = Object.keys(monitor).length === 0;
const data = monitor?.checks ? [...monitor.checks].reverse() : [];
let sharedStyles = {
border: 1,
borderColor: theme.palette.border.light,
borderRadius: theme.shape.borderRadius,
backgroundColor: theme.palette.background.main,
};
return (
<Stack className="page-speed-details" gap={theme.gap.large}>
<Stack className="page-speed-details" gap={theme.spacing(12)}>
{loading ? (
<SkeletonLayout />
) : (
@@ -324,25 +369,30 @@ const PageSpeedDetails = () => {
{ name: "details", path: `/pagespeed/${monitorId}` },
]}
/>
<Stack direction="row" gap={theme.gap.xs}>
<Stack direction="row" gap={theme.spacing(2)}>
<PulseDot
color={
monitor?.status
? theme.label.up.dotColor
: theme.label.down.dotColor
? theme.palette.success.main
: theme.palette.error.main
}
/>
<Box>
<Typography
component="h1"
mb={theme.gap.xs}
mb={theme.spacing(2)}
color={theme.palette.text.primary}
sx={{ lineHeight: 1 }}
>
{monitor?.url}
</Typography>
<Typography
component="span"
sx={{ color: "var(--env-var-color-17)" }}
color={
monitor?.status
? theme.palette.success.main
: theme.palette.error.text
}
>
Your pagespeed monitor is live.
</Typography>
@@ -353,15 +403,18 @@ const PageSpeedDetails = () => {
animate="rotate90"
img={
<SettingsIcon
style={{ width: theme.gap.mlplus, height: theme.gap.mlplus }}
style={{
width: theme.spacing(10),
height: theme.spacing(10),
}}
/>
}
onClick={() => navigate(`/pagespeed/configure/${monitorId}`)}
sx={{
ml: "auto",
alignSelf: "flex-end",
backgroundColor: theme.palette.otherColors.fillGray,
px: theme.gap.medium,
backgroundColor: theme.palette.background.fill,
px: theme.spacing(6),
"& svg": {
mr: "6px",
},
@@ -371,7 +424,7 @@ const PageSpeedDetails = () => {
<Stack
direction="row"
justifyContent="space-between"
gap={theme.gap.large}
gap={theme.spacing(12)}
flexWrap="wrap"
>
<StatBox
@@ -412,19 +465,39 @@ const PageSpeedDetails = () => {
value={formatDurationRounded(monitor?.interval)}
></StatBox>
</Stack>
<Typography component="h2">Score history</Typography>
<Box height="300px">
<Typography component="h2" color={theme.palette.text.secondary}>
Score history
</Typography>
<Box
height="300px"
sx={{
...sharedStyles,
}}
>
<PageSpeedLineChart pageSpeedChecks={data} />
</Box>
<Typography component="h2">Performance report</Typography>
<Stack direction="row" alignItems="center" overflow="hidden" flex={1}>
<Typography component="h2" color={theme.palette.text.secondary}>
Performance report
</Typography>
<Stack
direction="row"
alignItems="center"
overflow="hidden"
flex={1}
sx={{
"& p": {
color: theme.palette.text.secondary,
},
...sharedStyles,
}}
>
<Stack
alignItems="center"
textAlign="center"
minWidth="300px"
flex={1}
px={theme.gap.xl}
py={theme.gap.ml}
px={theme.spacing(20)}
py={theme.spacing(8)}
>
<Box onMouseLeave={() => setExpand(false)}>
{expand ? (
@@ -514,12 +587,12 @@ const PageSpeedDetails = () => {
</PieChart>
)}
</Box>
<Typography mt={theme.gap.medium}>
<Typography mt={theme.spacing(6)}>
Values are estimated and may vary.{" "}
<Typography
component="span"
sx={{
color: theme.palette.primary.main,
color: theme.palette.common.main,
fontWeight: 500,
textDecoration: "underline",
cursor: "pointer",
@@ -530,21 +603,23 @@ const PageSpeedDetails = () => {
</Typography>
</Stack>
<Box
px={theme.gap.xl}
py={theme.gap.ml}
px={theme.spacing(20)}
py={theme.spacing(8)}
height="100%"
flex={1}
sx={{
borderLeft: `solid 1px ${theme.palette.otherColors.graishWhite}`,
borderLeft: 1,
borderLeftColor: theme.palette.border.light,
}}
>
<Typography
mb={theme.gap.medium}
pb={theme.gap.ml}
color={theme.palette.secondary.main}
mb={theme.spacing(6)}
pb={theme.spacing(8)}
color={theme.palette.text.secondary}
textAlign="center"
sx={{
borderBottom: `solid 1px ${theme.palette.otherColors.graishWhite}`,
borderBottom: 1,
borderBottomColor: theme.palette.border.light,
borderBottomStyle: "dashed",
}}
>
@@ -552,7 +627,7 @@ const PageSpeedDetails = () => {
<Typography
component="span"
sx={{
color: theme.palette.primary.main,
color: theme.palette.common.main,
fontWeight: 500,
textDecoration: "underline",
cursor: "pointer",
@@ -569,8 +644,8 @@ const PageSpeedDetails = () => {
<Stack
direction="row"
flexWrap="wrap"
pt={theme.gap.ml}
gap={theme.gap.ml}
pt={theme.spacing(8)}
gap={theme.spacing(8)}
>
{Object.keys(audits).map((key) => {
if (key === "_id") return;
@@ -581,8 +656,8 @@ const PageSpeedDetails = () => {
let shape = (
<Box
sx={{
width: theme.gap.medium,
height: theme.gap.medium,
width: theme.spacing(6),
height: theme.spacing(6),
borderRadius: "50%",
backgroundColor: metricParams.stroke,
}}
@@ -592,8 +667,8 @@ const PageSpeedDetails = () => {
shape = (
<Box
sx={{
width: theme.gap.medium,
height: theme.gap.medium,
width: theme.spacing(6),
height: theme.spacing(6),
backgroundColor: metricParams.stroke,
}}
></Box>
@@ -604,10 +679,14 @@ const PageSpeedDetails = () => {
sx={{
width: 0,
height: 0,
ml: `calc((${theme.gap.medium} - ${theme.gap.small}) / -2)`,
borderLeft: `${theme.gap.small} solid transparent`,
borderRight: `${theme.gap.small} solid transparent`,
borderBottom: `${theme.gap.medium} solid ${metricParams.stroke}`,
ml: `calc((${theme.spacing(6)} - ${theme.spacing(
4
)}) / -2)`,
borderLeft: `${theme.spacing(4)} solid transparent`,
borderRight: `${theme.spacing(4)} solid transparent`,
borderBottom: `${theme.spacing(6)} solid ${
metricParams.stroke
}`,
}}
></Box>
);
@@ -630,7 +709,7 @@ const PageSpeedDetails = () => {
className="metric"
key={`${key}-box`}
direction="row"
gap={theme.gap.small}
gap={theme.spacing(4)}
>
{shape}
<Box>
@@ -650,8 +729,8 @@ const PageSpeedDetails = () => {
component="span"
ml="2px"
sx={{
color: theme.palette.secondary.main,
fontSize: "13px",
color: theme.palette.text.secondary,
fontSize: 13,
}}
>
{unit}

View File

@@ -1,10 +1,4 @@
.page-speed h1.MuiTypography-root,
.page-speed span.MuiTypography-root,
.page-speed p.MuiTypography-root {
color: var(--env-var-color-5);
}
.page-speed h2.MuiTypography-root {
color: var(--env-var-color-3);
line-height: 1.1;
}
.page-speed h1.MuiTypography-root,
@@ -19,11 +13,6 @@
.page-speed p.MuiTypography-root > span.MuiTypography-root {
font-size: var(--env-var-font-size-small-plus);
}
.page-speed .MuiGrid-item > .MuiStack-root {
border: solid 1px var(--env-var-color-6);
border-radius: var(--env-var-radius-1);
background-color: var(--env-var-color-8);
}
.page-speed .label {
padding: 7px;
height: 22px;
@@ -33,6 +22,3 @@
height: 34px;
align-self: flex-end;
}
.page-speed [class*="fallback__"] h1 {
margin-left: var(--env-var-spacing-3);
}

View File

@@ -22,19 +22,33 @@ const Card = ({ data }) => {
item
lg={6}
flexGrow={1}
sx={{ "&:hover > .MuiStack-root": { backgroundColor: "#f9fafb" } }}
sx={{
"&:hover > .MuiStack-root": {
backgroundColor: "var(--primary-bg-accent)",
},
}}
>
<Stack
direction="row"
gap={theme.gap.medium}
p={theme.gap.ml}
gap={theme.spacing(6)}
p={theme.spacing(8)}
onClick={() => navigate(`/pagespeed/${data._id}`)}
border={1}
borderColor={theme.palette.border.light}
borderRadius={theme.shape.borderRadius}
backgroundColor={theme.palette.background.main}
sx={{ cursor: "pointer" }}
>
<PageSpeedIcon style={{ width: theme.gap.ml, height: theme.gap.ml }} />
<PageSpeedIcon
style={{ width: theme.spacing(8), height: theme.spacing(8) }}
/>
<Box flex={1}>
<Stack direction="row" justifyContent="space-between">
<Typography component="h2" mb={theme.gap.xs}>
<Typography
component="h2"
mb={theme.spacing(2)}
color={theme.palette.common.main}
>
{data.name}
</Typography>
<StatusLabel
@@ -43,7 +57,7 @@ const Card = ({ data }) => {
/>
</Stack>
<Typography>{data.url.replace(/^https?:\/\//, "")}</Typography>
<Typography mt={theme.gap.large}>
<Typography mt={theme.spacing(12)}>
<Typography component="span" fontWeight={600}>
Last checked:{" "}
</Typography>
@@ -71,11 +85,11 @@ const SkeletonLayout = () => {
const theme = useTheme();
return (
<Stack gap={theme.gap.xs}>
<Stack gap={theme.spacing(2)}>
<Stack
direction="row"
justifyContent="space-between"
mb={theme.gap.large}
mb={theme.spacing(12)}
>
<Box width="80%">
<Skeleton variant="rounded" width="25%" height={24} />
@@ -83,7 +97,7 @@ const SkeletonLayout = () => {
variant="rounded"
width="50%"
height={19.5}
sx={{ mt: theme.gap.xs }}
sx={{ mt: theme.spacing(2) }}
/>
</Box>
<Skeleton
@@ -93,7 +107,7 @@ const SkeletonLayout = () => {
sx={{ alignSelf: "flex-end" }}
/>
</Stack>
<Stack direction="row" flexWrap="wrap" gap={theme.gap.large}>
<Stack direction="row" flexWrap="wrap" gap={theme.spacing(12)}>
<Skeleton
variant="rounded"
width="100%"
@@ -141,19 +155,40 @@ const PageSpeed = ({ isAdmin }) => {
let isActuallyLoading = isLoading && monitors.length === 0;
return (
<Box className="page-speed" pt={theme.gap.xl}>
<Box
className="page-speed"
pt={theme.spacing(20)}
sx={{
':has(> [class*="fallback__"])': {
position: "relative",
border: 1,
borderColor: theme.palette.border.light,
borderRadius: theme.shape.borderRadius,
borderStyle: "dashed",
backgroundColor: theme.palette.background.main,
overflow: "hidden",
},
}}
>
{isActuallyLoading ? (
<SkeletonLayout />
) : monitors?.length !== 0 ? (
<Stack gap={theme.gap.xs}>
<Stack
gap={theme.spacing(2)}
sx={{
"& h1, & span.MuiTypography-root, & p": {
color: theme.palette.text.secondary,
},
}}
>
<Stack
direction="row"
justifyContent="space-between"
mb={theme.gap.large}
mb={theme.spacing(12)}
>
<Box>
<Typography component="h1">All page speed monitors</Typography>
<Typography mt={theme.gap.xs}>
<Typography mt={theme.spacing(2)}>
Click on one of the monitors to get more site speed information.
</Typography>
</Box>
@@ -163,7 +198,7 @@ const PageSpeed = ({ isAdmin }) => {
onClick={() => navigate("/pagespeed/create")}
/>
</Stack>
<Grid container spacing={theme.gap.large}>
<Grid container spacing={theme.spacing(12)}>
{monitors?.map((monitor) => (
<Card data={monitor} key={`monitor-${monitor._id}`} />
))}
@@ -171,7 +206,7 @@ const PageSpeed = ({ isAdmin }) => {
</Stack>
) : (
<Fallback
title="page speed"
title="pagespeed monitor"
checks={[
"Report on the user experience of a page",
"Help analyze webpage speed",

View File

@@ -5,11 +5,6 @@
.settings p.MuiTypography-root {
font-size: var(--env-var-font-size-medium);
}
.settings h1.MuiTypography-root,
.settings h2.MuiTypography-root,
.settings p.MuiTypography-root {
color: var(--env-var-color-5);
}
.settings h1.MuiTypography-root {
font-size: var(--env-var-font-size-large);
}
@@ -23,21 +18,4 @@
.settings span.MuiTypography-root {
opacity: 0.6;
margin-right: 4px;
}
.settings .config-box {
padding: var(--env-var-spacing-4) 50px;
padding-bottom: 60px;
border: 1px solid var(--env-var-color-16);
border-radius: var(--env-var-radius-1);
background-color: var(--env-var-color-8);
}
.settings .config-box .MuiBox-root,
.settings .config-box .MuiStack-root {
flex: 1;
}
.settings-form {
display: flex;
flex-direction: column;
gap: var(--env-var-spacing-4);
}
}

View File

@@ -1,5 +1,5 @@
import { useTheme } from "@emotion/react";
import { Box, Stack, Typography } from "@mui/material";
import { Box, Stack, styled, Typography } from "@mui/material";
import Button from "../../Components/Button";
import Field from "../../Components/Inputs/Field";
import Link from "../../Components/Link";
@@ -10,6 +10,33 @@ import "./index.css";
const Settings = () => {
const theme = useTheme();
const ConfigBox = styled("div")({
display: "flex",
flexDirection: "row",
justifyContent: "space-between",
gap: theme.spacing(20),
paddingTop: theme.spacing(12),
paddingInline: theme.spacing(15),
paddingBottom: theme.spacing(25),
backgroundColor: theme.palette.background.main,
border: 1,
borderStyle: "solid",
borderColor: theme.palette.border.light,
borderRadius: theme.spacing(2),
"& > div:first-of-type": {
flex: 0.7,
},
"& > div:last-of-type": {
flex: 1,
},
"& h1, & h2": {
color: theme.palette.text.secondary,
},
"& p": {
color: theme.palette.text.tertiary,
},
});
return (
<Box
className="settings"
@@ -17,16 +44,16 @@ const Settings = () => {
paddingBottom: 0,
}}
>
<form className="settings-form" noValidate spellCheck="false">
<Stack
className="config-box"
direction="row"
justifyContent="space-between"
gap={theme.gap.xxl}
>
<Stack
component="form"
gap={theme.spacing(12)}
noValidate
spellCheck="false"
>
<ConfigBox>
<Box>
<Typography component="h1">General Settings</Typography>
<Typography sx={{ mt: theme.gap.small, mb: theme.gap.xs }}>
<Typography sx={{ mt: theme.spacing(2), mb: theme.spacing(2) }}>
<Typography component="span">Display timezone</Typography>- The
timezone of the dashboard you publicly display.
</Typography>
@@ -35,7 +62,7 @@ const Settings = () => {
timezone of your server.
</Typography>
</Box>
<Stack gap={theme.gap.xl}>
<Stack gap={theme.spacing(20)}>
<Select
id="display-timezone"
label="Display timezone"
@@ -51,21 +78,16 @@ const Settings = () => {
items={[{ _id: "est", name: "America / Toronto" }]}
/>
</Stack>
</Stack>
<Stack
className="config-box"
direction="row"
justifyContent="space-between"
gap={theme.gap.xxl}
>
</ConfigBox>
<ConfigBox>
<Box>
<Typography component="h1">History and monitoring</Typography>
<Typography sx={{ mt: theme.gap.small }}>
<Typography sx={{ mt: theme.spacing(2) }}>
Define here for how long you want to keep the data. You can also
remove all past data.
</Typography>
</Box>
<Stack gap={theme.gap.xl}>
<Stack gap={theme.spacing(20)}>
<Field
type="text"
id="history-monitoring"
@@ -81,24 +103,19 @@ const Settings = () => {
<Button
level="error"
label="Clear all stats"
sx={{ mt: theme.gap.small }}
sx={{ mt: theme.spacing(4) }}
/>
</Box>
</Stack>
</Stack>
<Stack
className="config-box"
direction="row"
justifyContent="space-between"
gap={theme.gap.xxl}
>
</ConfigBox>
<ConfigBox>
<Box>
<Typography component="h1">About</Typography>
</Box>
<Box>
<Typography component="h2">BlueWave Uptime v1.0.0</Typography>
<Typography
sx={{ mt: theme.gap.xs, mb: theme.gap.medium, opacity: 0.6 }}
sx={{ mt: theme.spacing(2), mb: theme.spacing(6), opacity: 0.6 }}
>
Developed by Bluewave Labs.
</Typography>
@@ -108,11 +125,15 @@ const Settings = () => {
label="https://github.com/bluewave-labs"
/>
</Box>
</Stack>
</ConfigBox>
<Stack direction="row" justifyContent="flex-end">
<Button level="primary" label="Save" sx={{ px: theme.gap.large }} />
<Button
level="primary"
label="Save"
sx={{ px: theme.spacing(12), mt: theme.spacing(20) }}
/>
</Stack>
</form>
</Stack>
</Box>
);
};

View File

@@ -1,8 +1,25 @@
import { Box } from "@mui/material";
import { useTheme } from "@emotion/react";
import Fallback from "../../Components/Fallback";
const Status = () => {
const theme = useTheme();
return (
<div className="status">
<Box
className="status"
sx={{
':has(> [class*="fallback__"])': {
position: "relative",
border: 1,
borderColor: theme.palette.border.light,
borderRadius: theme.shape.borderRadius,
borderStyle: "dashed",
backgroundColor: theme.palette.background.main,
overflow: "hidden",
},
}}
>
<Fallback
title="status page"
checks={[
@@ -11,7 +28,7 @@ const Status = () => {
"Build trust with your customers",
]}
/>
</div>
</Box>
);
};

View File

@@ -1,171 +0,0 @@
import { createTheme } from "@mui/material";
// Colors for MUI theme
const primaryMain = "#1570EF";
const secondaryMain = "#475467";
const tertiaryMain = "#475467";
const tertiaryLinkHover = "#eff8ff";
// Label Colors
const labelOrange = "#F79009";
const labelGray = "#475467";
const labelPurple = "#6941C6";
const labelGreen = "#067647";
const labelRed = "#F04438";
// Section colors
const sectionBorder = "#D0D5DD";
const sectionBg = "#F8F9F8";
// Other Colors
const otherColorsBlackish = "#101828";
const otherColorsBluishGray = "#344054";
const otherColorsGraishWhite = "#eaecf0";
const otherColorsPurple = "#7f56d9";
const otherColorsWhite = "#fff";
const otherColorsGraishWhiteLight = "#f2f2f2";
const otherColorsStrongBlue = "#f2f2f2";
const otherColorsSlateGray = "#667085";
const otherColorsFillGray = "#f4f4f4";
//box shadow
const shadow =
"0px 4px 24px -4px rgba(16, 24, 40, 0.08), 0px 3px 3px -3px rgba(16, 24, 40, 0.03)";
// Global Font Family
const fontFamilyDefault =
'"Inter","system-ui", "Avenir", "Helvetica", "Arial", sans-serif';
const theme = createTheme({
typography: { fontFamily: fontFamilyDefault, fontSize: 13 },
palette: {
primary: {
main: primaryMain,
},
secondary: {
main: secondaryMain,
},
tertiary: {
main: tertiaryMain,
linkHover: tertiaryLinkHover,
},
labelOrange: {
color: labelOrange,
},
labelGray: {
color: labelGray,
},
labelPurple: {
color: labelPurple,
},
labelGreen: {
color: labelGreen,
},
labelRed: {
color: labelRed,
},
section: {
borderColor: sectionBorder,
bgColor: sectionBg,
},
otherColors: {
blackish: otherColorsBlackish,
bluishGray: otherColorsBluishGray,
graishWhite: otherColorsGraishWhite,
purple: otherColorsPurple,
white: otherColorsWhite,
graishWhiteLight: otherColorsGraishWhiteLight,
strongBlue: otherColorsStrongBlue,
slateGray: otherColorsSlateGray,
fillGray: otherColorsFillGray,
},
},
shape: {
borderRadius: 4,
borderThick: 2,
boxShadow: shadow,
},
content: {
pX: "80px",
pY: "40px",
},
gap: {
xs: "4px",
small: "8px",
medium: "12px",
ml: "16px",
mlplus: "20px",
large: "24px",
lgplus: "32px",
xl: "40px",
xxl: "60px",
triplexl: "120px",
},
alert: {
info: {
color: secondaryMain,
bg: otherColorsWhite,
border: sectionBorder,
},
error: {
color: "#d92d20",
bg: "hsla(0, 100%, 52%, 0.03)",
border: "#f04438",
},
warning: {
color: "#DC6803",
bg: "#fffcf5",
border: "#fec84b",
},
},
//add more as needed
label: {
up: {
borderColor: "#D4F4E1",
bgColor: "#ecfdf3",
dotColor: "#17B26A",
},
down: {
borderColor: "#fbd1d1",
bgColor: "#f9eced",
dotColor: "#f04438",
},
"cannot resolve": {
borderColor: "#e2eaf7",
bgColor: "#f2f4f7",
dotColor: "#4e5ba6",
},
},
pie: {
green: {
stroke: "#17b26a",
strokeBg: "#d4f4e1",
text: "#079455",
bg: "#ecfdf3",
shape: "circle",
},
yellow: {
stroke: "#fdb022",
strokeBg: "rgba(255, 192, 34, 0.3)",
text: "#dc6803",
bg: "#fffcf5",
shape: "square",
},
red: {
stroke: "#f04438",
strokeBg: "#ffecea",
text: "#f04438",
bg: "#ffeaea",
shape: "triangle",
},
default: {
stroke: "#4e5ba6",
strokeBg: "#f2f4f7",
text: "#4e5ba6",
bg: "#f2f4f7",
shape: "",
},
},
});
export default theme;

View File

@@ -0,0 +1,181 @@
import { createTheme } from "@mui/material";
const text = {
primary: "#fafafa",
secondary: "#e6e6e6",
tertiary: "#a1a1aa",
accent: "#e6e6e6",
disabled: "rgba(172, 172, 172, 0.3)",
};
const background = {
main: "#151518",
alt: "#09090b",
fill: "#2e2e2e",
accent: "#18181a",
};
const border = { light: "#27272a", dark: "#2c2c2c" };
const fontFamilyDefault =
'"Inter","system-ui", "Avenir", "Helvetica", "Arial", sans-serif';
const shadow =
"0px 4px 24px -4px rgba(16, 24, 40, 0.08), 0px 3px 3px -3px rgba(16, 24, 40, 0.03)";
const darkTheme = createTheme({
typography: { fontFamily: fontFamilyDefault, fontSize: 13 },
palette: {
common: { main: "#1570ef" },
text: text,
background: background,
border: border,
info: {
text: "#475467",
main: "#475467",
bg: "#ffffff",
light: "#ffffff",
border: "#D0D5DD",
},
success: {
text: "#079455",
main: "#45bb7a",
light: "#93d5aa",
bg: "#27272a",
},
error: {
text: "#f04438",
main: "#d32f2f",
light: "#f04438",
bg: "#27272a",
border: "#f04438",
},
warning: {
text: "#DC6803",
main: "#e88c30",
light: "#fffcf5",
bg: "#ffecbc",
border: "#fec84b",
},
unresolved: { main: "#4e5ba6", light: "#e2eaf7", bg: "#f2f4f7" },
divider: border.light,
other: {
icon: "#e6e6e6",
line: "#27272a",
fill: "#18181a",
},
// TO BE REMOVED //
primary: {
main: "#1570ef",
},
secondary: {
main: "#e6e6e6",
},
tertiary: {
main: "#e6e6e6",
},
// ----------------- //
},
spacing: 2,
components: {
MuiButtonBase: {
defaultProps: {
disableRipple: true,
},
},
MuiIconButton: {
styleOverrides: {
root: {
padding: 4,
"&:hover": {
backgroundColor: background.fill,
},
},
},
},
MuiPaper: {
styleOverrides: {
root: {
marginTop: 4,
padding: 0,
border: 1,
borderStyle: "solid",
borderColor: border.light,
borderRadius: 4,
boxShadow: shadow,
backgroundColor: background.main,
},
},
},
MuiList: {
styleOverrides: {
root: {
padding: 0,
},
},
},
MuiMenuItem: {
styleOverrides: {
root: {
borderRadius: 4,
backgroundColor: "inherit",
padding: "4px 6px",
color: text.secondary,
fontSize: 13,
margin: 2,
minWidth: 100,
"&:hover, &.Mui-selected, &.Mui-selected:hover, &.Mui-selected.Mui-focusVisible":
{
backgroundColor: background.fill,
},
},
},
},
MuiTableCell: {
styleOverrides: {
root: {
borderBottomColor: border.light,
},
},
},
MuiTableHead: {
styleOverrides: {
root: {
backgroundColor: background.accent,
},
},
},
MuiPagination: {
styleOverrides: {
root: {
backgroundColor: background.main,
border: 1,
borderStyle: "solid",
borderColor: border.light,
"& button": {
color: text.tertiary,
borderRadius: 4,
},
"& li:first-of-type button, & li:last-of-type button": {
border: 1,
borderStyle: "solid",
borderColor: border.light,
},
},
},
},
MuiPaginationItem: {
styleOverrides: {
root: {
"&:not(.MuiPaginationItem-ellipsis):hover, &.Mui-selected": {
backgroundColor: background.fill,
},
},
},
},
},
shape: {
borderRadius: 2,
borderThick: 2,
boxShadow: shadow,
},
});
export default darkTheme;

View File

@@ -0,0 +1,181 @@
import { createTheme } from "@mui/material";
const text = {
primary: "#1c2130",
secondary: "#344054",
tertiary: "#475467",
accent: "#838c99",
};
const background = {
main: "#FFFFFF",
alt: "#FCFCFD",
fill: "#F4F4F4",
accent: "#f9fafb",
};
const border = { light: "#eaecf0", dark: "#d0d5dd" };
const fontFamilyDefault =
'"Inter","system-ui", "Avenir", "Helvetica", "Arial", sans-serif';
const shadow =
"0px 4px 24px -4px rgba(16, 24, 40, 0.08), 0px 3px 3px -3px rgba(16, 24, 40, 0.03)";
const lightTheme = createTheme({
typography: { fontFamily: fontFamilyDefault, fontSize: 13 },
palette: {
mode: "dark",
common: { main: "#1570ef" },
text: text,
background: background,
border: border,
info: {
text: "#475467",
main: "#475467",
bg: "#ffffff",
light: "#ffffff",
border: "#D0D5DD",
},
success: {
text: "#079455",
main: "#17b26a",
light: "#d4f4e1",
bg: "#ecfdf3",
},
error: {
text: "#f04438",
main: "#d32f2f",
light: "#fbd1d1",
bg: "#f9eced",
border: "#f04438",
},
warning: {
text: "#DC6803",
main: "#fdb022",
light: "#fffcf5",
bg: "#ffecbc",
border: "#fec84b",
},
unresolved: { main: "#4e5ba6", light: "#e2eaf7", bg: "#f2f4f7" },
divider: border.light,
other: {
icon: "#667085",
line: "#d6d9dd",
fill: "#e3e3e3",
},
// TO BE REMOVED //
primary: {
main: "#1570EF",
},
secondary: {
main: "#475467",
},
tertiary: {
main: "#475467",
},
// ----------------- //
},
spacing: 2,
components: {
MuiButtonBase: {
defaultProps: {
disableRipple: true,
},
},
MuiIconButton: {
styleOverrides: {
root: {
padding: 4,
"&:hover": {
backgroundColor: background.fill,
},
},
},
},
MuiPaper: {
styleOverrides: {
root: {
marginTop: 4,
border: 1,
borderStyle: "solid",
borderColor: border.light,
borderRadius: 4,
boxShadow: shadow,
backgroundColor: background.main,
},
},
},
MuiList: {
styleOverrides: {
root: {
padding: 0,
},
},
},
MuiMenuItem: {
styleOverrides: {
root: {
borderRadius: 4,
backgroundColor: "inherit",
padding: "4px 6px",
color: text.secondary,
fontSize: 13,
margin: 2,
marginBottom: 0,
minWidth: 100,
"&:hover, &.Mui-selected, &.Mui-selected:hover, &.Mui-selected.Mui-focusVisible":
{
backgroundColor: background.fill,
},
},
},
},
MuiTableCell: {
styleOverrides: {
root: {
borderBottomColor: border.light,
},
},
},
MuiTableHead: {
styleOverrides: {
root: {
backgroundColor: background.accent,
},
},
},
MuiPagination: {
styleOverrides: {
root: {
backgroundColor: background.main,
border: 1,
borderStyle: "solid",
borderColor: border.light,
"& button": {
color: text.tertiary,
borderRadius: 4,
},
"& li:first-of-type button, & li:last-of-type button": {
border: 1,
borderStyle: "solid",
borderColor: border.light,
},
},
},
},
MuiPaginationItem: {
styleOverrides: {
root: {
"&:not(.MuiPaginationItem-ellipsis):hover, &.Mui-selected": {
backgroundColor: background.fill,
},
},
},
},
},
shape: {
borderRadius: 2,
borderThick: 2,
boxShadow: shadow,
},
});
export default lightTheme;

View File

@@ -0,0 +1,5 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M12 13C12.5523 13 13 12.5523 13 12C13 11.4477 12.5523 11 12 11C11.4477 11 11 11.4477 11 12C11 12.5523 11.4477 13 12 13Z" stroke="black" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M12 6C12.5523 6 13 5.55228 13 5C13 4.44772 12.5523 4 12 4C11.4477 4 11 4.44772 11 5C11 5.55228 11.4477 6 12 6Z" stroke="black" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M12 20C12.5523 20 13 19.5523 13 19C13 18.4477 12.5523 18 12 18C11.4477 18 11 18.4477 11 19C11 19.5523 11.4477 20 12 20Z" stroke="black" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

After

Width:  |  Height:  |  Size: 733 B

View File

@@ -0,0 +1,4 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M0 8C0 3.58172 3.58172 0 8 0C12.4183 0 16 3.58172 16 8C16 12.4183 12.4183 16 8 16C3.58172 16 0 12.4183 0 8Z" fill="#1570EF"/>
<path d="M5 8C5 6.34315 6.34315 5 8 5C9.65685 5 11 6.34315 11 8C11 9.65685 9.65685 11 8 11C6.34315 11 5 9.65685 5 8Z" fill="white"/>
</svg>

After

Width:  |  Height:  |  Size: 371 B

View File

@@ -7,59 +7,12 @@
:root {
font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif;
font-weight: 400;
/* color-scheme: light dark;
color: rgba(255, 255, 255, 0.87);
background-color: #242424; */
font-synthesis: none;
text-rendering: optimizeLegibility;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
/* Generalized Stylings */
--env-var-font-familt-1: "Roboto", "Helvetica", "Arial", sans-serif;
--env-var-color-0: #fff;
--env-var-color-1: #1c2130;
--env-var-color-2: #475467;
--env-var-color-2-light: #838c99;
--env-var-color-3: #1570ef;
--env-var-color-4: #d0d5dd;
--env-var-color-5: #344054;
--env-var-color-6: #eaecf0;
--env-var-color-7: #7f56d9;
--env-var-color-8: #fff;
--env-var-color-9: #f2f2f2;
--env-var-color-10: #175cd3;
--env-var-color-11: #5d6b98;
--env-var-color-12: #182230;
--env-var-color-13: #f9fafb;
--env-var-color-14: #98a2b3;
--env-var-color-15: #f2f4f7;
--env-var-color-16: #ebebeb;
--env-var-color-17: #079455;
--env-var-color-18: #ffc301;
--env-var-color-19: #f04438;
--env-var-color-20: #ecfdf3;
--env-var-color-21: hsla(0, 100%, 52%, 0.06);
--env-var-color-22: #4e5ba6;
--env-var-color-23: #17b26a;
--env-var-color-24: #d92d20;
--env-var-color-25: #667085;
--env-var-color-26: #ff1818;
--env-var-color-27: #fecf60;
--lighter-env-var-color-27: rgba(254, 207, 96, 0.1);
--env-var-color-28: #f79009;
--env-var-color-29: #d0d5dd;
--env-var-color-30: #fcfcfd;
--env-var-color-31: #1a1919;
--env-var-color-32: #f5f5f5;
--env-var-color-33: rgba(83, 83, 83, 0.1);
--env-var-radius-1: 4px;
--env-var-radius-2: 8px;
@@ -99,48 +52,12 @@
0px 3px 3px -3px rgba(16, 24, 40, 0.03);
}
a {
font-weight: 500;
color: #646cff;
text-decoration: inherit;
}
a:hover {
color: #535bf2;
}
body {
margin: 0;
min-width: 320px;
height: 100%;
}
h1 {
font-size: 3.2em;
line-height: 1.1;
}
button {
border-radius: 8px;
border: 1px solid transparent;
padding: 0.6em 1.2em;
font-size: 1em;
font-weight: 500;
font-family: inherit;
background-color: #1a1a1a;
cursor: pointer;
transition: border-color 0.25s;
}
button:hover {
border-color: #646cff;
}
button:focus,
button:focus-visible {
outline: 4px auto -webkit-focus-ring-color;
}
.MuiInputBase-root.Mui-disabled input {
cursor: not-allowed;
}
@@ -165,7 +82,7 @@ button:focus-visible {
}
body .MuiSkeleton-root {
background-color: var(--env-var-color-15);
background-color: #f2f4f7;
}
@keyframes ripple {
@@ -178,18 +95,3 @@ body .MuiSkeleton-root {
transform: scale(2);
}
}
@media (prefers-color-scheme: light) {
:root {
color: #213547;
background-color: #ffffff;
}
a:hover {
color: #747bff;
}
button {
background-color: #f9f9f9;
}
}

Some files were not shown because too many files have changed in this diff Show More