diff --git a/Client/package-lock.json b/Client/package-lock.json index cbe559889..095a013f7 100644 --- a/Client/package-lock.json +++ b/Client/package-lock.json @@ -8,12 +8,12 @@ "name": "client", "version": "0.0.0", "dependencies": { - "@emotion/react": "^11.11.4", - "@emotion/styled": "^11.11.5", + "@emotion/react": "^11.13.3", + "@emotion/styled": "^11.13.0", "@fontsource/roboto": "^5.0.13", "@mui/icons-material": "^5.15.17", "@mui/lab": "^5.0.0-alpha.170", - "@mui/material": "^5.15.16", + "@mui/material": "^5.16.7", "@mui/x-charts": "^7.5.1", "@mui/x-data-grid": "7.22.2", "@mui/x-date-pickers": "7.22.2", @@ -304,9 +304,9 @@ } }, "node_modules/@babel/runtime": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.25.9.tgz", - "integrity": "sha512-4zpTHZ9Cm6L9L+uIqghQX8ZXg8HKFcjYO3qHoO8zTmRm6HQUJ8SSJ+KRvbMBZn0EGVlT4DRYeQ/6hjlyXBh+Kg==", + "version": "7.26.0", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.26.0.tgz", + "integrity": "sha512-FDSOghenHTiToteC/QRlv2q3DhPZ/oOXTBoirfWNx1Cx3TMVcGWQtMMmQcSvb/JjpNeGzx8Pq/b4fKEJuWm1sw==", "license": "MIT", "dependencies": { "regenerator-runtime": "^0.14.0" @@ -1356,12 +1356,12 @@ } }, "node_modules/@mui/types": { - "version": "7.2.15", - "resolved": "https://registry.npmjs.org/@mui/types/-/types-7.2.15.tgz", - "integrity": "sha512-nbo7yPhtKJkdf9kcVOF8JZHPZTmqXjJ/tI0bdWgHg5tp9AnIN4Y7f7wm9T+0SyGYJk76+GYZ8Q5XaTYAsUHN0Q==", + "version": "7.2.19", + "resolved": "https://registry.npmjs.org/@mui/types/-/types-7.2.19.tgz", + "integrity": "sha512-6XpZEM/Q3epK9RN8ENoXuygnqUQxE+siN/6rGRi2iwJPgBUR25mphYQ9ZI87plGh58YoZ5pp40bFvKYOCDJ3tA==", "license": "MIT", "peerDependencies": { - "@types/react": "^17.0.0 || ^18.0.0" + "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0" }, "peerDependenciesMeta": { "@types/react": { @@ -2350,9 +2350,9 @@ "license": "MIT" }, "node_modules/@types/prop-types": { - "version": "15.7.12", - "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.12.tgz", - "integrity": "sha512-5zvhXYtRNRluoE/jAp4GVsSduVUzNWKkOZrCDBWYtE7biZywwdC2AcEzg+cSMLFRfVgeAFqpfNabiPjxFddV1Q==", + "version": "15.7.13", + "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.13.tgz", + "integrity": "sha512-hCZTSvwbzWGvhqxp/RqVqwU999pBf2vp7hzIjiYOsl8wqOmUxkQ6ddw1cV3l8811+kdUFus/q4d1Y3E3SyEifA==", "license": "MIT" }, "node_modules/@types/react": { diff --git a/Client/package.json b/Client/package.json index eec7eea4b..a13ee09ae 100644 --- a/Client/package.json +++ b/Client/package.json @@ -11,12 +11,12 @@ "preview": "vite preview" }, "dependencies": { - "@emotion/react": "^11.11.4", - "@emotion/styled": "^11.11.5", + "@emotion/react": "^11.13.3", + "@emotion/styled": "^11.13.0", "@fontsource/roboto": "^5.0.13", "@mui/icons-material": "^5.15.17", "@mui/lab": "^5.0.0-alpha.170", - "@mui/material": "^5.15.16", + "@mui/material": "^5.16.7", "@mui/x-charts": "^7.5.1", "@mui/x-data-grid": "7.22.2", "@mui/x-date-pickers": "7.22.2", diff --git a/Client/src/App.css b/Client/src/App.css deleted file mode 100644 index 44e06cd5f..000000000 --- a/Client/src/App.css +++ /dev/null @@ -1,7 +0,0 @@ -.card { - padding: 2em; -} - -.read-the-docs { - color: #888; -} diff --git a/Client/src/App.jsx b/Client/src/App.jsx index 6cb2f433a..151512701 100644 --- a/Client/src/App.jsx +++ b/Client/src/App.jsx @@ -1,14 +1,12 @@ import { useEffect } from "react"; -import { Routes, Route } from "react-router-dom"; +import { Routes, Route, Navigate } from "react-router-dom"; import { useSelector } from "react-redux"; import { useDispatch } from "react-redux"; -// import "./App.css"; import "react-toastify/dist/ReactToastify.css"; import { ToastContainer } from "react-toastify"; import NotFound from "./Pages/NotFound"; import Login from "./Pages/Auth/Login"; import Register from "./Pages/Auth/Register/Register"; -import HomeLayout from "./Layouts/HomeLayout"; import Account from "./Pages/Account"; import Monitors from "./Pages/Monitors/Home"; import CreateMonitor from "./Pages/Monitors/CreateMonitor"; @@ -30,15 +28,17 @@ import CreatePageSpeed from "./Pages/PageSpeed/CreatePageSpeed"; import CreateNewMaintenanceWindow from "./Pages/Maintenance/CreateMaintenance"; import PageSpeedDetails from "./Pages/PageSpeed/Details"; import PageSpeedConfigure from "./Pages/PageSpeed/Configure"; -import withAdminCheck from "./HOC/withAdminCheck"; -import withAdminProp from "./HOC/withAdminProp"; +import HomeLayout from "./Components/Layouts/HomeLayout"; +import withAdminCheck from "./Components/HOC/withAdminCheck"; +import withAdminProp from "./Components/HOC/withAdminProp"; import { ThemeProvider } from "@emotion/react"; import lightTheme from "./Utils/Theme/lightTheme"; import darkTheme from "./Utils/Theme/darkTheme"; -import { CssBaseline } from "@mui/material"; +import { CssBaseline, GlobalStyles } from "@mui/material"; import { getAppSettings } from "./Features/Settings/settingsSlice"; import { logger } from "./Utils/Logger"; // Import the logger import { networkService } from "./main"; +import { Infrastructure } from "./Pages/Infrastructure"; function App() { const AdminCheckedRegister = withAdminCheck(Register); const MonitorsWithAdminProp = withAdminProp(Monitors); @@ -67,8 +67,19 @@ function App() { }, []); return ( + /* Extract Themeprovider, baseline and global styles to Styles */ + { + return { + body: { + backgroundImage: `radial-gradient(circle, ${palette.gradient.color1}, ${palette.gradient.color2}, ${palette.gradient.color3}, ${palette.gradient.color4}, ${palette.gradient.color5})`, + }, + }; + }} + /> + {/* Extract Routes to Routes */} } + element={} /> } /> + } + /> + } + /> + } + /> + } + /> + } + /> + } @@ -152,22 +184,6 @@ function App() { /> } /> - } - /> - } - /> - } - /> - } - /> { const theme = useTheme(); + /* TODO + This needs fixing. text bg and border not necessarilly exist. Probably text becomes contrastText. border becomes contrastText. bg becomes dark. + Check possible variants, see implementation in light and dark theme, and adjust */ const { text, bg, border } = theme.palette[variant]; const icon = icons[variant]; diff --git a/Client/src/Components/Charts/BarChart/index.jsx b/Client/src/Components/Charts/BarChart/index.jsx index 5c58a143a..70fd66390 100644 --- a/Client/src/Components/Charts/BarChart/index.jsx +++ b/Client/src/Components/Charts/BarChart/index.jsx @@ -5,6 +5,7 @@ import { useEffect, useState } from "react"; import "./index.css"; import { useSelector } from "react-redux"; +/* TODO add prop validation and jsdocs */ const BarChart = ({ checks = [] }) => { const theme = useTheme(); const [animate, setAnimate] = useState(false); @@ -65,7 +66,9 @@ const BarChart = ({ checks = [] }) => { width={theme.spacing(4)} height={theme.spacing(4)} backgroundColor={ - check.status ? theme.palette.success.main : theme.palette.error.text + check.status + ? theme.palette.success.main + : theme.palette.error.contrastText } sx={{ borderRadius: "50%" }} /> @@ -111,7 +114,7 @@ const BarChart = ({ checks = [] }) => { ], sx: { "& .MuiTooltip-tooltip": { - backgroundColor: theme.palette.background.main, + backgroundColor: theme.palette.secondary.main, border: 1, borderColor: theme.palette.border.dark, borderRadius: theme.shape.borderRadius, @@ -138,7 +141,9 @@ const BarChart = ({ checks = [] }) => { width="9px" height="100%" backgroundColor={ - check.status ? theme.palette.success.bg : theme.palette.error.bg + check.status + ? theme.palette.success.contrastText + : theme.palette.error.dark } sx={{ borderRadius: theme.spacing(1.5), @@ -153,7 +158,9 @@ const BarChart = ({ checks = [] }) => { width="100%" height={`${animate ? check.responseTime : 0}%`} backgroundColor={ - check.status ? theme.palette.success.main : theme.palette.error.text + check.status + ? theme.palette.success.main + : theme.palette.error.contrastText } sx={{ borderRadius: theme.spacing(1.5), diff --git a/Client/src/Components/Check/Check.jsx b/Client/src/Components/Check/Check.jsx index 01a023345..3219fec29 100644 --- a/Client/src/Components/Check/Check.jsx +++ b/Client/src/Components/Check/Check.jsx @@ -24,7 +24,7 @@ const Check = ({ text, noHighlightText, variant = "info", outlined = false }) => const theme = useTheme(); const colors = { success: theme.palette.success.main, - error: theme.palette.error.text, + error: theme.palette.error.contrastText, info: theme.palette.info.border, }; diff --git a/Client/src/HOC/withAdminCheck.jsx b/Client/src/Components/HOC/withAdminCheck.jsx similarity index 85% rename from Client/src/HOC/withAdminCheck.jsx rename to Client/src/Components/HOC/withAdminCheck.jsx index fb672f0b5..8edf7a02b 100644 --- a/Client/src/HOC/withAdminCheck.jsx +++ b/Client/src/Components/HOC/withAdminCheck.jsx @@ -1,8 +1,8 @@ -import React, { useEffect } from "react"; +import { useEffect } from "react"; import { useNavigate } from "react-router-dom"; -import { logger } from "../Utils/Logger"; -import { networkService } from "../main"; +import { logger } from "../../Utils/Logger"; +import { networkService } from "../../main"; const withAdminCheck = (WrappedComponent) => { const WithAdminCheck = (props) => { diff --git a/Client/src/HOC/withAdminProp.jsx b/Client/src/Components/HOC/withAdminProp.jsx similarity index 100% rename from Client/src/HOC/withAdminProp.jsx rename to Client/src/Components/HOC/withAdminProp.jsx diff --git a/Client/src/Components/Heading/index.jsx b/Client/src/Components/Heading/index.jsx new file mode 100644 index 000000000..a82165e61 --- /dev/null +++ b/Client/src/Components/Heading/index.jsx @@ -0,0 +1,29 @@ +import { Typography } from "@mui/material"; +import PropTypes from "prop-types"; + +/** + * A heading component that renders text with a specific heading level. + * + * @param {Object} props - The properties passed to the Heading component. + * @param {('h1'|'h2'|'h3')} props.component - The heading level for the component. + * @param {string} props.children - The content to display inside the heading. + * @returns {JSX.Element} The Typography component with specified heading properties. + */ + +function Heading({ component, children }) { + return ( + + {children} + + ); +} + +Heading.propTypes = { + component: PropTypes.oneOf(["h1", "h2", "h3"]).isRequired, + children: PropTypes.string.isRequired, +}; +export { Heading }; diff --git a/Client/src/Components/Inputs/Field/index.jsx b/Client/src/Components/Inputs/Field/index.jsx index 4ead8a705..ccb0c1e37 100644 --- a/Client/src/Components/Inputs/Field/index.jsx +++ b/Client/src/Components/Inputs/Field/index.jsx @@ -67,7 +67,7 @@ const Field = forwardRef( borderColor: theme.palette.border.dark, }, "&:has(.input-error) .MuiOutlinedInput-root fieldset": { - borderColor: theme.palette.error.text, + borderColor: theme.palette.error.contrastText, }, display: hidden ? "none" : "", }} @@ -83,7 +83,7 @@ const Field = forwardRef( * @@ -189,7 +189,7 @@ const Field = forwardRef( { color: "transparent", width: 16, height: 16, - boxShadow: "inset 0 0 0 1px #656a74", + boxShadow: `inset 0 0 0 1px ${theme.palette.secondary.main}`, mt: theme.spacing(0.5), }} /> diff --git a/Client/src/Components/Inputs/Search/index.jsx b/Client/src/Components/Inputs/Search/index.jsx index 3de2cbe07..9044f7c0d 100644 --- a/Client/src/Components/Inputs/Search/index.jsx +++ b/Client/src/Components/Inputs/Search/index.jsx @@ -99,7 +99,7 @@ const Search = ({ { className="label" sx={{ borderRadius: borderRadius, - borderColor: theme.palette.text.tertiary, + border: `1px solid ${theme.palette.text.tertiary}`, color: theme.palette.text.tertiary, padding: padding, ...styles, @@ -127,22 +127,22 @@ const StatusLabel = ({ status, text, customStyles }) => { const colors = { up: { dotColor: theme.palette.success.main, - bgColor: theme.palette.success.bg, - borderColor: theme.palette.success.light, + bgColor: theme.palette.success./* dark */ contrastText, + borderColor: theme.palette.success.main /* light */, }, down: { - dotColor: theme.palette.error.text, - bgColor: theme.palette.error.bg, + dotColor: theme.palette.error.contrastText, + bgColor: theme.palette.error.dark, borderColor: theme.palette.error.light, }, paused: { dotColor: theme.palette.warning.main, - bgColor: theme.palette.warning.bg, + bgColor: theme.palette.warning.dark, borderColor: theme.palette.warning.light, }, pending: { dotColor: theme.palette.warning.main, - bgColor: theme.palette.warning.bg, + bgColor: theme.palette.warning.dark, borderColor: theme.palette.warning.light, }, "cannot resolve": { diff --git a/Client/src/Layouts/HomeLayout/index.css b/Client/src/Components/Layouts/HomeLayout/index.css similarity index 100% rename from Client/src/Layouts/HomeLayout/index.css rename to Client/src/Components/Layouts/HomeLayout/index.css diff --git a/Client/src/Layouts/HomeLayout/index.jsx b/Client/src/Components/Layouts/HomeLayout/index.jsx similarity index 85% rename from Client/src/Layouts/HomeLayout/index.jsx rename to Client/src/Components/Layouts/HomeLayout/index.jsx index 0fe787fd6..b605a0d53 100644 --- a/Client/src/Layouts/HomeLayout/index.jsx +++ b/Client/src/Components/Layouts/HomeLayout/index.jsx @@ -1,4 +1,4 @@ -import Sidebar from "../../Components/Sidebar"; +import Sidebar from "../../Sidebar"; import { Outlet } from "react-router"; import { Stack } from "@mui/material"; diff --git a/Client/src/Components/ProgressBars/index.jsx b/Client/src/Components/ProgressBars/index.jsx index 46b2efab1..198f740aa 100644 --- a/Client/src/Components/ProgressBars/index.jsx +++ b/Client/src/Components/ProgressBars/index.jsx @@ -34,11 +34,11 @@ const ProgressUpload = ({ icon, label, size, progress = 0, onClick, error }) => backgroundColor: theme.palette.background.fill, "&:has(.input-error)": { borderColor: theme.palette.error.main, - backgroundColor: theme.palette.error.bg, + backgroundColor: theme.palette.error.dark, py: theme.spacing(4), px: theme.spacing(8), "& > .MuiStack-root > svg": { - fill: theme.palette.error.text, + fill: theme.palette.error.contrastText, width: "20px", height: "20px", }, @@ -85,7 +85,7 @@ const ProgressUpload = ({ icon, label, size, progress = 0, onClick, error }) => {error} diff --git a/Client/src/Components/Sidebar/index.jsx b/Client/src/Components/Sidebar/index.jsx index 9135dcefa..2e91289f8 100644 --- a/Client/src/Components/Sidebar/index.jsx +++ b/Client/src/Components/Sidebar/index.jsx @@ -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 { setMode, toggleSidebar } from "../../Features/UI/uiSlice"; +import { toggleSidebar } from "../../Features/UI/uiSlice"; import { clearUptimeMonitorState } from "../../Features/UptimeMonitors/uptimeMonitorsSlice"; import Avatar from "../Avatar"; import LockSvg from "../../assets/icons/lock.svg?react"; @@ -29,7 +29,6 @@ import LogoutSvg from "../../assets/icons/logout.svg?react"; import Support from "../../assets/icons/support.svg?react"; import Dashboard from "../../assets/icons/dashboard.svg?react"; import Account from "../../assets/icons/user-edit.svg?react"; -import StatusPages from "../../assets/icons/status-pages.svg?react"; import Maintenance from "../../assets/icons/maintenance.svg?react"; import Monitors from "../../assets/icons/monitors.svg?react"; import Incidents from "../../assets/icons/incidents.svg?react"; @@ -54,6 +53,7 @@ const menu = [ nested: [ { name: "Monitors", path: "monitors", icon: }, { name: "Pagespeed", path: "pagespeed", icon: }, + { name: "Infrastructure", path: "infrastructure", icon: }, ], }, { name: "Incidents", path: "incidents", icon: }, @@ -113,7 +113,6 @@ function Sidebar() { const [popup, setPopup] = useState(); const { user } = useSelector((state) => state.auth); - // Remove demo password if demo const accountMenuItem = menu.find((item) => item.name === "Account"); if (user.role?.includes("demo") && accountMenuItem) { accountMenuItem.nested = accountMenuItem.nested.filter((item) => { @@ -148,7 +147,9 @@ function Sidebar() { if (matchedKey) { setOpen((prev) => ({ ...prev, [PATH_MAP[matchedKey]]: true })); } - }, []); + }, [location]); + + /* TODO refactor this, there are a some ternaries and comments in the return */ return ( window.open("https://github.com/bluewave-labs/bluewave-uptime", "_blank", "noreferrer")} + onClick={() => + window.open( + "https://github.com/bluewave-labs/bluewave-uptime", + "_blank", + "noreferrer" + ) + } sx={{ cursor: "pointer" }} > ) : collapsed ? ( + /* TODO Do we ever get here? */ )} {collapsed && } - {/* { - dispatch(setMode("light")); - closePopup(); - }} - > - Light - - { - dispatch(setMode("dark")); - closePopup(); - }} - > - Dark - */} + + Infrastructure monitors + + ); +} + +export { Infrastructure }; diff --git a/Client/src/Pages/Maintenance/MaintenanceTable/ActionsMenu/index.jsx b/Client/src/Pages/Maintenance/MaintenanceTable/ActionsMenu/index.jsx index 8928b1e05..35a28f6da 100644 --- a/Client/src/Pages/Maintenance/MaintenanceTable/ActionsMenu/index.jsx +++ b/Client/src/Pages/Maintenance/MaintenanceTable/ActionsMenu/index.jsx @@ -114,7 +114,7 @@ const ActionsMenu = ({ /* isAdmin, */ maintenanceWindow, updateCallback }) => { "& ul": { p: theme.spacing(2.5) }, "& li": { m: 0 }, "& li:last-of-type": { - color: theme.palette.error.text, + color: theme.palette.error.contrastText, }, }, }, diff --git a/Client/src/Pages/Monitors/CreateMonitor/index.jsx b/Client/src/Pages/Monitors/CreateMonitor/index.jsx index 18c1df0b4..84e599322 100644 --- a/Client/src/Pages/Monitors/CreateMonitor/index.jsx +++ b/Client/src/Pages/Monitors/CreateMonitor/index.jsx @@ -333,7 +333,7 @@ const CreateMonitor = () => { {errors["type"]} diff --git a/Client/src/Pages/Monitors/Details/Charts/index.jsx b/Client/src/Pages/Monitors/Details/Charts/index.jsx index 52b677495..915ee0933 100644 --- a/Client/src/Pages/Monitors/Details/Charts/index.jsx +++ b/Client/src/Pages/Monitors/Details/Charts/index.jsx @@ -61,7 +61,7 @@ const UpBarChart = memo(({ data, type, onBarHover }) => { ? { main: theme.palette.success.main, light: theme.palette.success.light } : uptime > 50 ? { main: theme.palette.warning.main, light: theme.palette.warning.light } - : { main: theme.palette.error.text, light: theme.palette.error.light }; + : { main: theme.palette.error.contrastText, light: theme.palette.error.light }; }; // TODO - REMOVE THIS LATER @@ -201,10 +201,10 @@ const DownBarChart = memo(({ data, type, onBarHover }) => { key={`cell-${entry.time}`} fill={ hoveredBarIndex === index - ? theme.palette.error.text + ? theme.palette.error.contrastText : chartHovered ? theme.palette.error.light - : theme.palette.error.text + : theme.palette.error.contrastText } onMouseEnter={() => { setHoveredBarIndex(index); @@ -246,24 +246,24 @@ const ResponseGaugeChart = ({ data }) => { ? { category: "Excellent", main: theme.palette.success.main, - bg: theme.palette.success.bg, + bg: theme.palette.success.dark, } : responseTime <= 500 ? { category: "Fair", main: theme.palette.success.main, - bg: theme.palette.success.bg, + bg: theme.palette.success.dark, } : responseTime <= 600 ? { category: "Acceptable", main: theme.palette.warning.main, - bg: theme.palette.warning.bg, + bg: theme.palette.warning.dark, } : { category: "Poor", - main: theme.palette.error.text, - bg: theme.palette.error.bg, + main: theme.palette.error.contrastText, + bg: theme.palette.error.dark, }; return ( diff --git a/Client/src/Pages/Monitors/Home/CurrentMonitoring/index.jsx b/Client/src/Pages/Monitors/Home/CurrentMonitoring/index.jsx index 613c280a4..a7f70d96e 100644 --- a/Client/src/Pages/Monitors/Home/CurrentMonitoring/index.jsx +++ b/Client/src/Pages/Monitors/Home/CurrentMonitoring/index.jsx @@ -1,10 +1,11 @@ import { useTheme } from "@emotion/react"; -import { Box, Stack, Typography } from "@mui/material"; +import { Box, Stack } from "@mui/material"; import Search from "../../../../Components/Inputs/Search"; import MemoizedMonitorTable from "../MonitorTable"; import { useState } from "react"; import useDebounce from "../../../../Utils/debounce"; import PropTypes from "prop-types"; +import { Heading } from "../../../../Components/Heading"; const CurrentMonitoring = ({ totalMonitors, monitors, isAdmin }) => { const theme = useTheme(); @@ -18,26 +19,15 @@ const CurrentMonitoring = ({ totalMonitors, monitors, isAdmin }) => { return ( - - Actively monitoring - + Actively monitoring + { ); } else if (title === "down") { - color = theme.palette.error.text; + color = theme.palette.error.main; icon = ( diff --git a/Client/src/Pages/Monitors/Home/actionsMenu.jsx b/Client/src/Pages/Monitors/Home/actionsMenu.jsx index 7efffa93c..4ab601fea 100644 --- a/Client/src/Pages/Monitors/Home/actionsMenu.jsx +++ b/Client/src/Pages/Monitors/Home/actionsMenu.jsx @@ -109,7 +109,7 @@ const ActionsMenu = ({ monitor, isAdmin, updateCallback }) => { "& ul": { p: theme.spacing(2.5) }, "& li": { m: 0 }, "& li:last-of-type": { - color: theme.palette.error.text, + color: theme.palette.error.contrastText, }, }, }, diff --git a/Client/src/Pages/Monitors/Home/index.css b/Client/src/Pages/Monitors/Home/index.css index 29f9d49d2..80916dce8 100644 --- a/Client/src/Pages/Monitors/Home/index.css +++ b/Client/src/Pages/Monitors/Home/index.css @@ -1,3 +1,4 @@ +/* TODO take these from here and declare using emotion. Plus, the values should live in the theme */ .monitors .MuiStack-root > button:not(.MuiIconButton-root) { font-size: var(--env-var-font-size-medium); height: var(--env-var-height-2); diff --git a/Client/src/Pages/Monitors/utils.jsx b/Client/src/Pages/Monitors/utils.jsx index 826a92bbb..4dc4260cd 100644 --- a/Client/src/Pages/Monitors/utils.jsx +++ b/Client/src/Pages/Monitors/utils.jsx @@ -28,20 +28,20 @@ const useUtils = () => { }; const statusStyles = { up: { - backgroundColor: theme.palette.success.bg, - background: `linear-gradient(340deg, ${theme.palette.success.light} -60%, ${theme.palette.success.bg} 35%)`, + backgroundColor: theme.palette.success.dark, + background: `linear-gradient(340deg, ${theme.palette.success.light} -60%, ${theme.palette.success.dark} 35%)`, borderColor: theme.palette.success.light, "& h2": { color: theme.palette.success.main }, }, down: { - backgroundColor: theme.palette.error.bg, - background: `linear-gradient(340deg, ${theme.palette.error.light} -60%, ${theme.palette.error.bg} 35%)`, + backgroundColor: theme.palette.error.dark, + background: `linear-gradient(340deg, ${theme.palette.error.light} -60%, ${theme.palette.error.dark} 35%)`, borderColor: theme.palette.error.light, "& h2": { color: theme.palette.error.main }, }, paused: { - backgroundColor: theme.palette.warning.bg, - background: `linear-gradient(340deg, ${theme.palette.warning.light} -60%, ${theme.palette.warning.bg} 35%)`, + backgroundColor: theme.palette.warning.dark, + background: `linear-gradient(340deg, ${theme.palette.warning.light} -60%, ${theme.palette.warning.dark} 35%)`, borderColor: theme.palette.warning.light, "& h2": { color: theme.palette.warning.main }, }, @@ -54,22 +54,22 @@ const useUtils = () => { }; const pagespeedStyles = { up: { - bg: theme.palette.success.bg, + bg: theme.palette.success.dark, light: theme.palette.success.light, stroke: theme.palette.success.main, }, down: { - bg: theme.palette.error.bg, + bg: theme.palette.error.dark, light: theme.palette.error.light, stroke: theme.palette.error.main, }, paused: { - bg: theme.palette.warning.bg, + bg: theme.palette.warning.dark, light: theme.palette.warning.light, stroke: theme.palette.warning.main, }, pending: { - bg: theme.palette.warning.bg, + bg: theme.palette.warning.dark, light: theme.palette.warning.light, stroke: theme.palette.warning.main, }, diff --git a/Client/src/Pages/PageSpeed/CreatePageSpeed/index.jsx b/Client/src/Pages/PageSpeed/CreatePageSpeed/index.jsx index 162b231a2..f771c3988 100644 --- a/Client/src/Pages/PageSpeed/CreatePageSpeed/index.jsx +++ b/Client/src/Pages/PageSpeed/CreatePageSpeed/index.jsx @@ -1,11 +1,14 @@ import { useState } from "react"; import { Box, Button, ButtonGroup, Stack, Typography } from "@mui/material"; -import LoadingButton from '@mui/lab/LoadingButton'; +import LoadingButton from "@mui/lab/LoadingButton"; import { useSelector, useDispatch } from "react-redux"; import { monitorValidation } from "../../../Validation/validation"; import { useNavigate } from "react-router-dom"; import { useTheme } from "@emotion/react"; -import { createPageSpeed, checkEndpointResolution } from "../../../Features/PageSpeedMonitor/pageSpeedMonitorSlice"; +import { + createPageSpeed, + checkEndpointResolution, +} from "../../../Features/PageSpeedMonitor/pageSpeedMonitorSlice"; import { createToast } from "../../../Utils/toastUtils"; import { logger } from "../../../Utils/Logger"; import { ConfigBox } from "../../Monitors/styled"; @@ -17,12 +20,12 @@ import Breadcrumbs from "../../../Components/Breadcrumbs"; import "./index.css"; const CreatePageSpeed = () => { - const MS_PER_MINUTE = 60000; - const { user, authToken } = useSelector((state) => state.auth); - const { isLoading } = useSelector((state) => state.pageSpeedMonitors); - const dispatch = useDispatch(); - const navigate = useNavigate(); - const theme = useTheme(); + const MS_PER_MINUTE = 60000; + const { user, authToken } = useSelector((state) => state.auth); + const { isLoading } = useSelector((state) => state.pageSpeedMonitors); + const dispatch = useDispatch(); + const navigate = useNavigate(); + const theme = useTheme(); const idMap = { "monitor-url": "url", @@ -105,252 +108,260 @@ const CreatePageSpeed = () => { abortEarly: false, }); - if (error) { - const newErrors = {}; - error.details.forEach((err) => { - newErrors[err.path[0]] = err.message; - }); - setErrors(newErrors); - createToast({ body: "Error validation data." }); - } else { - const checkEndpointAction = await dispatch( - checkEndpointResolution({ authToken, monitorURL: form.url }) - ) - if (checkEndpointAction.meta.requestStatus === "rejected") { - createToast({ body: "The endpoint you entered doesn't resolve. Check the URL again." }); - setErrors({ url: "The entered URL is not reachable." }); - return; - } + if (error) { + const newErrors = {}; + error.details.forEach((err) => { + newErrors[err.path[0]] = err.message; + }); + setErrors(newErrors); + createToast({ body: "Error validation data." }); + } else { + const checkEndpointAction = await dispatch( + checkEndpointResolution({ authToken, monitorURL: form.url }) + ); + if (checkEndpointAction.meta.requestStatus === "rejected") { + createToast({ + body: "The endpoint you entered doesn't resolve. Check the URL again.", + }); + setErrors({ url: "The entered URL is not reachable." }); + return; + } - form = { - ...form, - description: form.name, - teamId: user.teamId, - userId: user._id, - notifications: monitor.notifications, - }; - const action = await dispatch( - createPageSpeed({ authToken, monitor: form }) - ); - if (action.meta.requestStatus === "fulfilled") { - createToast({ body: "Monitor created successfully!" }); - navigate("/pagespeed"); - } else { - createToast({ body: "Failed to create monitor." }); - } - } - }; + form = { + ...form, + description: form.name, + teamId: user.teamId, + userId: user._id, + notifications: monitor.notifications, + }; + const action = await dispatch(createPageSpeed({ authToken, monitor: form })); + if (action.meta.requestStatus === "fulfilled") { + createToast({ body: "Monitor created successfully!" }); + navigate("/pagespeed"); + } else { + createToast({ body: "Failed to create monitor." }); + } + } + }; - //select values - const frequencies = [ - { _id: 3, name: "3 minutes" }, - { _id: 5, name: "5 minutes" }, - { _id: 10, name: "10 minutes" }, - { _id: 20, name: "20 minutes" }, - { _id: 60, name: "1 hour" }, - { _id: 1440, name: "1 day" }, - { _id: 10080, name: "1 week" }, - ]; - return ( - - - - - - Create your{" "} - - - pagespeed monitor - - - - - General settings - - Here you can select the URL of the host, together with the type of - monitor. - - - - - - - - - - Checks to perform - - You can always add or remove checks after adding your site. - - - - - handleChange(event)} - /> - - - - - - {errors["type"] ? ( - - - {errors["type"]} - - - ) : ( - "" - )} - - - - - Incident notifications - - When there is an incident, notify users. - - - - When there is a new incident, - logger.warn("disabled")} - isDisabled={true} - /> - notification.type === "email" - )} - value={user?.email} - onChange={(event) => handleChange(event)} - /> - logger.warn("disabled")} - isDisabled={true} - /> - {monitor.notifications.some( - (notification) => notification.type === "emails" - ) ? ( - - logger.warn("disabled")} - /> - - You can separate multiple emails with a comma - - - ) : ( - "" - )} - - - - - Advanced settings - - - handleChange(event, "interval")} + items={frequencies} + /> + + + + + Create monitor + + + + + ); }; export default CreatePageSpeed; diff --git a/Client/src/Pages/PageSpeed/Details/Charts/PieChart.jsx b/Client/src/Pages/PageSpeed/Details/Charts/PieChart.jsx index a330c3c12..d1d106c11 100644 --- a/Client/src/Pages/PageSpeed/Details/Charts/PieChart.jsx +++ b/Client/src/Pages/PageSpeed/Details/Charts/PieChart.jsx @@ -127,22 +127,22 @@ const PieChart = ({ audits }) => { return { stroke: theme.palette.success.main, strokeBg: theme.palette.success.light, - text: theme.palette.success.text, - bg: theme.palette.success.bg, + text: theme.palette.success.contrastText, + bg: theme.palette.success.dark, }; else if (value >= 50 && value < 90) return { stroke: theme.palette.warning.main, strokeBg: theme.palette.warning.light, - text: theme.palette.warning.text, - bg: theme.palette.warning.bg, + text: theme.palette.warning.contrastText, + bg: theme.palette.warning.dark, }; else if (value >= 0 && value < 50) return { - stroke: theme.palette.error.text, + stroke: theme.palette.error.contrastText, strokeBg: theme.palette.error.light, - text: theme.palette.error.text, - bg: theme.palette.error.bg, + text: theme.palette.error.contrastText, + bg: theme.palette.error.dark, }; return { stroke: theme.palette.unresolved.main, diff --git a/Client/src/Pages/PageSpeed/Details/index.jsx b/Client/src/Pages/PageSpeed/Details/index.jsx index 015a17c6b..ca852e124 100644 --- a/Client/src/Pages/PageSpeed/Details/index.jsx +++ b/Client/src/Pages/PageSpeed/Details/index.jsx @@ -362,7 +362,7 @@ const PageSpeedDetails = ({ isAdmin }) => { : score >= 50 ? theme.palette.warning.main : score >= 0 - ? theme.palette.error.text + ? theme.palette.error.contrastText : theme.palette.unresolved.main; // Find the position where the number ends and the unit begins diff --git a/Client/src/Pages/ReadMe.md b/Client/src/Pages/ReadMe.md deleted file mode 100644 index 45ec6ce12..000000000 --- a/Client/src/Pages/ReadMe.md +++ /dev/null @@ -1 +0,0 @@ -#Pages Folder diff --git a/Client/src/Utils/Theme/constants.js b/Client/src/Utils/Theme/constants.js new file mode 100644 index 000000000..0626edbaa --- /dev/null +++ b/Client/src/Utils/Theme/constants.js @@ -0,0 +1,244 @@ +const typographyBase = 14; + +/* TODO +Check for px in codebase. All font sizes should be in REM and should live here. +Rest should be checked on each case +*/ +const typographyLevels = { + base: typographyBase, + xs: `${(typographyBase - 4) / 16}rem`, + s: `${(typographyBase - 2) / 16}rem`, + m: `${typographyBase / 16}rem`, + l: `${(typographyBase + 2) / 16}rem`, + xl: `${(typographyBase + 10) / 16}rem`, +}; + +/* TODO Review color palette and semantic colors */ +const paletteColors = { + white: "#FFFFFF", + gray50: "#FEFEFE", + gray60: "#FEFDFE", + gray70: "#FDFDFD", + gray80: "#FDFCFD", + gray90: "#FCFCFD", + gray100: "#F4F4F4", + gray200: "#E3E3E3", + gray300: "#A2A3A3", + gray500: "#838C99", + gray600: "#454546", + gray750: "#36363E", + gray800: "#2D2D33", + gray850: "#131315", + gray860: "#111113", + gray870: "#0F0F11", + gray880: "#0C0C0E", + gray890: "#09090B", + blueGray20: "#E8F0FE", + blueGray150: "#667085", + blueGray200: "#475467", + blueGray400: "#344054", + blueGray900: "#1c2130", + blueBlueWave: "#1570EF", + blue700: "#4E5BA6", + purple300: "#664EFF", + purple400: "#3A1BFF", + green50: "#D4F4E1", + green150: "#45BB7A", + green400: "#079455", + green800: "#1C4428", + green900: "#12261E", + red50: "#F9ECED", + red100: "#FBD1D1", + red200: "#F04438", + red300: "#D32F2F", + red700: "#542426", + red800: "#301A1F", + orange50: "#FEF8EA", + orange100: "#FFECBC", + orange300: "#FDB022", + orange400: "#FF9F00", + orange500: "#E88C30", + orange600: "#DC6803", + orange800: "#624711", +}; + +const semanticColors = { + primary: { + main: { + light: paletteColors.blueBlueWave, + dark: paletteColors.blueBlueWave, + }, + // TODO we dont have primary light, dark or contrast text + }, + secondary: { + main: { + light: paletteColors.gray100, + dark: paletteColors.gray800, + }, + contrastText: { + light: paletteColors.blueGray200, + dark: paletteColors.blueGray200, + }, + light: { + light: paletteColors.gray200, + dark: paletteColors.gray200, + }, + dark: { + light: paletteColors.gray200, + dark: paletteColors.gray200, + }, + }, + success: { + main: { + light: paletteColors.green400, + dark: paletteColors.green400, + }, + contrastText: { + light: paletteColors.green50, + dark: paletteColors.green900, + }, + light: { + light: paletteColors.green50, + dark: paletteColors.green150, + }, + dark: { + light: paletteColors.green800, + dark: paletteColors.green900, + }, + }, + error: { + main: { + light: paletteColors.red300, + dark: paletteColors.red300, + }, + contrastText: { + light: paletteColors.gray50, + dark: paletteColors.gray50, + }, + light: { + light: paletteColors.red100, + dark: paletteColors.red700, + }, + dark: { + light: paletteColors.red50, + dark: paletteColors.red800, + }, + }, + warning: { + main: { + light: paletteColors.orange300, + dark: paletteColors.orange400, + }, + contrastText: { + light: paletteColors.orange600, + dark: paletteColors.orange500, + }, + light: { + light: paletteColors.orange100, + dark: paletteColors.orange800, + }, + dark: { + light: paletteColors.orange50, + dark: paletteColors.gray800, + }, + }, + /* From this part on, try to create semantic structure, not feature based structure */ + gradient: { + color1: { + light: paletteColors.gray90, + dark: paletteColors.gray890, + }, + color2: { + light: paletteColors.gray80, + dark: paletteColors.gray880, + }, + color3: { + light: paletteColors.gray70, + dark: paletteColors.gray870, + }, + color4: { + light: paletteColors.gray60, + dark: paletteColors.gray860, + }, + color5: { + light: paletteColors.gray50, + dark: paletteColors.gray850, + }, + }, + background: { + main: { + light: paletteColors.white, + dark: paletteColors.gray850, + }, + alt: { + light: paletteColors.gray90, + dark: paletteColors.gray890, + }, + fill: { + light: paletteColors.gray100, + dark: paletteColors.gray800, + }, + accent: { + light: paletteColors.gray100, + dark: paletteColors.gray850, + }, + }, + text: { + primary: { + light: paletteColors.blueGray900, + dark: paletteColors.gray100, + }, + secondary: { + light: paletteColors.blueGray400, + dark: paletteColors.gray200, + }, + tertiary: { + light: paletteColors.blueGray200, + dark: paletteColors.gray300, + }, + accent: { + light: paletteColors.gray500, + dark: paletteColors.gray500, + }, + }, + border: { + light: { + light: paletteColors.gray200, + dark: paletteColors.gray800, + }, + dark: { + light: paletteColors.gray200, + dark: paletteColors.gray750, + }, + }, + unresolved: { + main: { + light: paletteColors.blue700, + dark: paletteColors.purple300, + }, + light: { + light: paletteColors.blueGray20, + dark: paletteColors.purple400, + }, + bg: { + light: paletteColors.gray100, + dark: paletteColors.gray100, + }, + }, + other: { + icon: { + light: paletteColors.blueGray150, + }, + line: { + light: paletteColors.gray200, + }, + grid: { + light: paletteColors.gray300, + dark: paletteColors.gray600, + }, + autofill: { + light: paletteColors.blueGray20, + }, + }, +}; +export { typographyLevels, semanticColors as colors }; diff --git a/Client/src/Utils/Theme/darkTheme.js b/Client/src/Utils/Theme/darkTheme.js index 6eca20aa3..0f4a391de 100644 --- a/Client/src/Utils/Theme/darkTheme.js +++ b/Client/src/Utils/Theme/darkTheme.js @@ -1,267 +1,108 @@ import { createTheme } from "@mui/material"; +import { baseTheme } from "./globalTheme"; +import { colors } from "./constants"; -const text = { - primary: "#fafafa", - secondary: "#e6e6e6", - tertiary: "#a1a1aa", - accent: "#8e8e8f", - disabled: "rgba(172, 172, 172, 0.3)", -}; -const background = { - main: "#151518", - alt: "#09090b", - fill: "#2D2D33", - accent: "#18181a", -}; -const border = { light: "#27272a", dark: "#36363e" }; +const { + primary, + secondary, + success, + error, + warning, + gradient: { + color1: { dark: color1 }, + color2: { dark: color2 }, + color3: { dark: color3 }, + color4: { dark: color4 }, + color5: { dark: color5 }, + }, + background, + text, + border, + unresolved, + other, +} = colors; -const fontFamilyDefault = - '"Inter","system-ui", "Avenir", "Helvetica", "Arial", sans-serif'; -const shadow = - "0px 4px 24px -4px rgba(255, 255, 255, 0.03), 0px 3px 3px -3px rgba(255, 255, 255, 0.01)"; +const palette = { + primary: { main: primary.main.dark }, + secondary: { + main: secondary.main.dark, + contrastText: secondary.contrastText.dark, + light: secondary.dark.dark, + dark: secondary.dark.dark, + }, + success: { + main: success.main.dark, + contrastText: success.contrastText.dark, + light: success.light.dark, + dark: success.dark.dark, + }, + error: { + main: error.main.dark, + contrastText: error.contrastText.dark, + light: error.light.dark, + dark: error.dark.dark, + }, + warning: { + main: warning.main.dark, + light: warning.light.dark, + contrastText: warning.contrastText.dark, + dark: warning.dark.dark, + }, + /* From this part on, try to create semantic structure, not feature based structure */ + percentage: { + uptimePoor: error.main.dark, + uptimeFair: warning.contrastText.dark, + uptimeGood: warning.main.dark /* Change for a success color? ?*/, + uptimeExcellent: success.main.dark, + }, + unresolved: { + main: unresolved.main.dark, + light: unresolved.light.dark, + bg: unresolved.bg.dark, + }, + divider: border.light.dark, + other: { + icon: text.secondary.dark, + line: border.light.dark, + fill: background.accent.dark, + grid: other.grid.dark, + autofill: secondary.main.dark, + }, + gradient: { + color1, + color2, + color3, + color4, + color5, + }, + text: { + primary: text.primary.dark, + secondary: text.secondary.dark, + tertiary: text.tertiary.dark, + accent: text.accent.dark, + }, + background: { + main: background.main.dark, + alt: background.alt.dark, + fill: background.fill.dark, + accent: background.accent.dark, + }, + border: { + light: border.light.dark, + dark: border.dark.dark, + }, + info: { + text: text.primary.dark, + main: text.secondary.dark, + bg: background.main.dark, + light: background.main.dark, + border: border.light.dark, + }, +}; const darkTheme = createTheme({ - typography: { - fontFamily: fontFamilyDefault, - fontSize: 13, - h1: { fontSize: 22, color: text.primary, fontWeight: 500 }, - h2: { fontSize: 14.5, color: text.secondary, fontWeight: 400 }, - body1: { fontSize: 13, color: text.tertiary, fontWeight: 400 }, - body2: { fontSize: 12, color: text.tertiary, fontWeight: 400 }, - }, - chart: { - header: { - fontWeight: 400, - fill: text.tertiary, - fontSize: 11, - }, - subheader: { - fontWeight: 400, - fill: text.tertiary, - fontSize: 9, - }, - }, - palette: { - mode: "dark", - primary: { main: "#1570ef" }, - secondary: { main: "#2D2D33" }, - text: text, - background: background, - border: border, - info: { - text: text.primary, - main: text.secondary, - bg: background.main, - light: background.main, - border: border.light, - }, - success: { - text: "#079455", - main: "#45bb7a", - light: "#1c4428", - bg: "#12261e", - }, - error: { - text: "#f04438", - main: "#d32f2f", - light: "#542426", - bg: "#301a1f", - dark: "#932020", - border: "#f04438", - }, - warning: { - text: "#e88c30", - main: "#FF9F00", - light: "#624711", - bg: "#262115", - border: "#e88c30", - }, - percentage: { - uptimePoor: "#d32f2f", - uptimeFair: "#e88c30", - uptimeGood: "#ffd600", - uptimeExcellent: "#079455", - }, - unresolved: { main: "#664eff", light: "#3a1bff", bg: "#f2f4f7" }, - divider: border.light, - other: { - icon: "#e6e6e6", - line: "#27272a", - fill: "#18181a", - grid: "#454546", - autofill: "#2d2d33", - }, - }, - spacing: 2, - components: { - MuiCssBaseline: { - styleOverrides: { - body: { - backgroundImage: - "radial-gradient(circle, #09090b, #0c0c0e, #0f0f11, #111113, #131315, #131315, #131315, #131315, #111113, #0f0f11, #0c0c0e, #09090b)", - lineHeight: "inherit", - paddingLeft: "calc(100vw - 100%)", - }, - }, - }, - MuiButton: { - defaultProps: { - disableRipple: true, - }, - styleOverrides: { - root: ({ theme }) => ({ - variants: [ - { - props: (props) => props.variant === "group", - style: { - color: theme.palette.secondary.contrastText, - backgroundColor: theme.palette.background.main, - border: 1, - borderStyle: "solid", - borderColor: theme.palette.border.light, - }, - }, - { - props: (props) => props.variant === "group" && props.filled === "true", - style: { - backgroundColor: theme.palette.secondary.main, - }, - }, - { - props: (props) => - props.variant === "contained" && props.color === "secondary", - style: { - border: 1, - borderStyle: "solid", - borderColor: theme.palette.border.dark, - }, - }, - ], - fontWeight: 400, - borderRadius: 4, - boxShadow: "none", - textTransform: "none", - "&:focus": { - outline: "none", - }, - "&:hover": { - boxShadow: "none", - }, - }), - }, - }, - MuiIconButton: { - styleOverrides: { - root: { - padding: 4, - transition: "none", - "&:hover": { - backgroundColor: border.light, - }, - }, - }, - }, - MuiPaper: { - styleOverrides: { - root: { - marginTop: 4, - padding: 0, - border: 1, - borderStyle: "solid", - borderColor: border.light, - borderRadius: 4, - boxShadow: shadow, - backgroundColor: background.main, - backgroundImage: "none", - }, - }, - }, - MuiList: { - styleOverrides: { - root: { - padding: 0, - }, - }, - }, - MuiListItemButton: { - styleOverrides: { - root: { - transition: "none", - }, - }, - }, - 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, - }, - }, - }, - }, - MuiSkeleton: { - styleOverrides: { - root: { - backgroundColor: "#151518", - }, - }, - }, - }, - shape: { - borderRadius: 2, - borderThick: 2, - boxShadow: shadow, - }, + palette, + ...baseTheme(palette), }); export default darkTheme; diff --git a/Client/src/Utils/Theme/globalTheme.js b/Client/src/Utils/Theme/globalTheme.js new file mode 100644 index 000000000..7737d396e --- /dev/null +++ b/Client/src/Utils/Theme/globalTheme.js @@ -0,0 +1,220 @@ +import { typographyLevels } from "./constants"; + +const fontFamilyPrimary = '"Inter" , sans-serif'; +// const fontFamilySecondary = '"Avenir", sans-serif'; + +/* TODO take the color out from here */ +const shadow = + "0px 4px 24px -4px rgba(16, 24, 40, 0.08), 0px 3px 3px -3px rgba(16, 24, 40, 0.03)"; + +const baseTheme = (palette) => ({ + typography: { + fontFamily: fontFamilyPrimary, + fontSize: 14, + h1: { + fontSize: typographyLevels.xl, + color: palette.text.primary, + fontWeight: 500, + }, + h2: { + fontSize: typographyLevels.l, + color: palette.text.secondary, + fontWeight: 400, + }, + body1: { + fontSize: typographyLevels.m, + color: palette.text.tertiary, + fontWeight: 400, + }, + body2: { + fontSize: typographyLevels.s, + color: palette.text.tertiary, + fontWeight: 400, + }, + }, + /* TODO take chart from here, it should live inside of the gauge, and get info from the theme */ + chart: { + header: { + fontWeight: 400, + fill: palette.text.tertiary, + fontSize: typographyLevels.m, + }, + subheader: { + fontWeight: 400, + fill: palette.text.tertiary, + fontSize: typographyLevels.xs, + }, + }, + spacing: 2, + /* TODO All these should live inside of a component*/ + components: { + MuiButton: { + defaultProps: { + disableRipple: true, + }, + styleOverrides: { + root: ({ theme }) => ({ + variants: [ + { + props: (props) => props.variant === "group", + style: { + color: theme.palette.secondary.contrastText, + backgroundColor: theme.palette.background.main, + border: 1, + borderStyle: "solid", + borderColor: theme.palette.border.light, + }, + }, + { + props: (props) => props.variant === "group" && props.filled === "true", + style: { + backgroundColor: theme.palette.secondary.main, + }, + }, + { + props: (props) => + props.variant === "contained" && props.color === "secondary", + style: { + border: 1, + borderStyle: "solid", + borderColor: theme.palette.border.light, + }, + }, + { + props: (props) => props.variant === "contained" && props.disabled, + style: { + backgroundColor: `${theme.palette.secondary.main} !important`, + color: `${theme.palette.secondary.contrastText} !important`, + }, + }, + ], + fontWeight: 400, + borderRadius: 4, + boxShadow: "none", + textTransform: "none", + "&:focus": { + outline: "none", + }, + "&:hover": { + boxShadow: "none", + }, + }), + }, + }, + MuiIconButton: { + styleOverrides: { + root: ({ theme }) => ({ + padding: 4, + transition: "none", + "&:hover": { + backgroundColor: theme.palette.background.fill, + }, + }), + }, + }, + MuiPaper: { + styleOverrides: { + root: ({ theme }) => { + return { + marginTop: 4, + padding: 0, + border: 1, + borderStyle: "solid", + borderColor: theme.palette.border.light, + borderRadius: 4, + boxShadow: shadow, + backgroundColor: theme.palette.background.main, + backgroundImage: "none", + }; + }, + }, + }, + MuiList: { + styleOverrides: { + root: { + padding: 0, + }, + }, + }, + MuiListItemButton: { + styleOverrides: { + root: { + transition: "none", + }, + }, + }, + MuiMenuItem: { + styleOverrides: { + root: ({ theme }) => ({ + borderRadius: 4, + backgroundColor: "inherit", + padding: "4px 6px", + color: theme.palette.text.secondary, + fontSize: 13, + margin: 2, + minWidth: 100, + "&:hover, &.Mui-selected, &.Mui-selected:hover, &.Mui-selected.Mui-focusVisible": + { + backgroundColor: theme.palette.background.fill, + }, + }), + }, + }, + MuiTableCell: { + styleOverrides: { + root: ({ theme }) => ({ + borderBottomColor: theme.palette.border.light, + }), + }, + }, + MuiTableHead: { + styleOverrides: { + root: ({ theme }) => ({ + backgroundColor: theme.palette.background.accent, + }), + }, + }, + MuiPagination: { + styleOverrides: { + root: ({ theme }) => ({ + backgroundColor: theme.palette.background.main, + border: 1, + borderStyle: "solid", + borderColor: theme.palette.border.light, + "& button": { + color: theme.palette.text.tertiary, + borderRadius: 4, + }, + "& li:first-of-type button, & li:last-of-type button": { + border: 1, + borderStyle: "solid", + borderColor: theme.palette.border.light, + }, + }), + }, + }, + MuiPaginationItem: { + styleOverrides: { + root: ({ theme }) => ({ + "&:not(.MuiPaginationItem-ellipsis):hover, &.Mui-selected": { + backgroundColor: theme.palette.background.fill, + }, + }), + }, + }, + MuiSkeleton: { + styleOverrides: { + root: ({ theme }) => ({ + backgroundColor: theme.palette.unresolved.bg, + }), + }, + }, + }, + shape: { + borderRadius: 2, + borderThick: 2, + boxShadow: shadow, + }, +}); + +export { baseTheme }; diff --git a/Client/src/Utils/Theme/lightTheme.js b/Client/src/Utils/Theme/lightTheme.js index e6335a062..8bc6434c6 100644 --- a/Client/src/Utils/Theme/lightTheme.js +++ b/Client/src/Utils/Theme/lightTheme.js @@ -1,265 +1,114 @@ import { createTheme } from "@mui/material"; +import { baseTheme } from "./globalTheme"; +import { colors } from "./constants"; -const text = { - primary: "#1c2130", - secondary: "#344054", - tertiary: "#475467", - accent: "#838c99", -}; -const background = { - main: "#FFFFFF", - alt: "#FCFCFD", - fill: "#F4F4F4", - accent: "#f9fafb", +/* +TODO +Next step: check if all keys here are being used in the codebase. e.g.: Search codebase for palette.primary; also check for destructuring palette ('= theme.palette') +*/ + +const { + primary, + secondary, + success, + error, + warning, + gradient: { + color1: { light: color1 }, + color2: { light: color2 }, + color3: { light: color3 }, + color4: { light: color4 }, + color5: { light: color5 }, + }, + background, + text, + border, + unresolved, + other, +} = colors; + +const palette = { + primary: { main: primary.main.light }, + secondary: { + main: secondary.main.light, + contrastText: secondary.contrastText.light, + light: secondary.dark.light, + dark: secondary.dark.light, + }, + success: { + main: success.main.light, + contrastText: success.contrastText.light, + light: success.light.light, + dark: success.dark.light, + }, + error: { + main: error.main.light, + contrastText: error.contrastText.light, + light: error.light.light, + dark: error.dark.light, + }, + warning: { + main: warning.main.light, + light: warning.light.light, + contrastText: warning.contrastText.light, + dark: warning.dark.light, + }, + /* From this part on, try to create semantic structure, not feature based structure */ + percentage: { + uptimePoor: error.main.light, + uptimeFair: warning.contrastText.light, + uptimeGood: warning.main.light /* Change for a success color? */, + uptimeExcellent: success.main.light, + }, + unresolved: { + main: unresolved.main.light, + light: unresolved.light.light, + bg: unresolved.bg.light, + }, + divider: border.light.light, + other: { + icon: other.icon.light, + line: other.line.light, + fill: secondary.dark.light, + grid: other.grid.light, + autofill: other.autofill.light, + }, + gradient: { + color1, + color2, + color3, + color4, + color5, + }, + text: { + primary: text.primary.light, + secondary: text.secondary.light, + tertiary: text.tertiary.light, + accent: text.accent.light, + }, + background: { + main: background.main.light, + alt: background.alt.light, + fill: background.fill.light, + accent: background.accent.light, + }, + border: { + light: border.light.light, + dark: border.dark.light, + }, + info: { + text: text.primary.light, + main: text.tertiary.light, + bg: background.main.light, + light: background.main.light, + border: border.dark.light, + }, }; -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)"; - +/* TODO I figured out we could have just one theme by passing mode as parameter for theme function. Implement later */ const lightTheme = createTheme({ - typography: { - fontFamily: fontFamilyDefault, - fontSize: 13, - h1: { fontSize: 22, color: text.primary, fontWeight: 500 }, - h2: { fontSize: 14.5, color: text.secondary, fontWeight: 400 }, - body1: { fontSize: 13, color: text.tertiary, fontWeight: 400 }, - body2: { fontSize: 12, color: text.tertiary, fontWeight: 400 }, - }, - chart: { - header: { - fontWeight: 400, - fill: text.tertiary, - fontSize: 11, - }, - subheader: { - fontWeight: 400, - fill: text.tertiary, - fontSize: 9, - }, - }, - palette: { - primary: { main: "#1570EF" }, - secondary: { main: "#F4F4F4", dark: "#e3e3e3", contrastText: "#475467" }, - text: text, - background: background, - border: border, - info: { - text: text.primary, - main: text.tertiary, - bg: background.main, - light: background.main, - border: border.dark, - }, - 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: "#ffecbc", - bg: "#fef8ea", - border: "#fec84b", - }, - percentage: { - uptimePoor: "#d32f2f", - uptimeFair: "#ec8013", - uptimeGood: "#ffb800", - uptimeExcellent: "#079455", - }, - unresolved: { main: "#4e5ba6", light: "#e2eaf7", bg: "#f2f4f7" }, - divider: border.light, - other: { - icon: "#667085", - line: "#d6d9dd", - fill: "#e3e3e3", - grid: "#a2a3a3", - autofill: "#e8f0fe", - }, - }, - spacing: 2, - components: { - MuiCssBaseline: { - styleOverrides: { - body: { - backgroundImage: - "radial-gradient(circle, #fcfcfd, #fdfcfd, #fdfdfd, #fefdfe, #fefefe, #fefefe, #fefefe, #fefefe, #fefdfe, #fdfdfd, #fdfcfd, #fcfcfd)", - lineHeight: "inherit", - paddingLeft: "calc(100vw - 100%)", - }, - }, - }, - MuiButton: { - defaultProps: { - disableRipple: true, - }, - styleOverrides: { - root: ({ theme }) => ({ - variants: [ - { - props: (props) => props.variant === "group", - style: { - color: theme.palette.secondary.contrastText, - backgroundColor: theme.palette.background.main, - border: 1, - borderStyle: "solid", - borderColor: theme.palette.border.light, - }, - }, - { - props: (props) => props.variant === "group" && props.filled === "true", - style: { - backgroundColor: theme.palette.secondary.main, - }, - }, - { - props: (props) => - props.variant === "contained" && props.color === "secondary", - style: { - border: 1, - borderStyle: "solid", - borderColor: theme.palette.border.light, - }, - }, - ], - fontWeight: 400, - borderRadius: 4, - boxShadow: "none", - textTransform: "none", - "&:focus": { - outline: "none", - }, - "&:hover": { - boxShadow: "none", - }, - }), - }, - }, - MuiIconButton: { - styleOverrides: { - root: { - padding: 4, - transition: "none", - "&: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, - backgroundImage: "none", - }, - }, - }, - MuiList: { - styleOverrides: { - root: { - padding: 0, - }, - }, - }, - MuiListItemButton: { - styleOverrides: { - root: { - transition: "none", - }, - }, - }, - 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, - }, - }, - }, - }, - MuiSkeleton: { - styleOverrides: { - root: { - backgroundColor: "#f2f4f7", - }, - }, - }, - }, - shape: { - borderRadius: 2, - borderThick: 2, - boxShadow: shadow, - }, + palette, + ...baseTheme(palette), }); export default lightTheme;