diff --git a/frontend/package-lock.json b/frontend/package-lock.json
index a8f37b8f..1956c590 100644
--- a/frontend/package-lock.json
+++ b/frontend/package-lock.json
@@ -20,6 +20,8 @@
"@mui/styled-engine-sc": "^6.4.6",
"@mui/x-charts": "^7.27.1",
"@mui/x-charts-pro": "^7.27.1",
+ "@mui/x-data-grid": "^7.28.2",
+ "@mui/x-date-pickers": "^7.28.2",
"d3": "^7.9.0",
"leaflet": "^1.9.4",
"lucide-react": "^0.485.0",
@@ -1775,6 +1777,110 @@
"react": "^16.8.0 || ^17.0.0 || ^18.0.0"
}
},
+ "node_modules/@mui/x-data-grid": {
+ "version": "7.28.2",
+ "resolved": "https://registry.npmjs.org/@mui/x-data-grid/-/x-data-grid-7.28.2.tgz",
+ "integrity": "sha512-ac/CPZ/zOeHjCvv3LwTUSFy+dofELP/Cl2nXLYWrqVHUgFAkkWxhk85kiI/N1G+Rf4WiKw+oJfeyGe8ZSeY4tg==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/runtime": "^7.25.7",
+ "@mui/utils": "^5.16.6 || ^6.0.0 || ^7.0.0 || ^7.0.0-beta",
+ "@mui/x-internals": "7.28.0",
+ "clsx": "^2.1.1",
+ "prop-types": "^15.8.1",
+ "reselect": "^5.1.1",
+ "use-sync-external-store": "^1.0.0"
+ },
+ "engines": {
+ "node": ">=14.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/mui-org"
+ },
+ "peerDependencies": {
+ "@emotion/react": "^11.9.0",
+ "@emotion/styled": "^11.8.1",
+ "@mui/material": "^5.15.14 || ^6.0.0 || ^7.0.0 || ^7.0.0-beta",
+ "@mui/system": "^5.15.14 || ^6.0.0 || ^7.0.0 || ^7.0.0-beta",
+ "react": "^17.0.0 || ^18.0.0 || ^19.0.0",
+ "react-dom": "^17.0.0 || ^18.0.0 || ^19.0.0"
+ },
+ "peerDependenciesMeta": {
+ "@emotion/react": {
+ "optional": true
+ },
+ "@emotion/styled": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@mui/x-date-pickers": {
+ "version": "7.28.2",
+ "resolved": "https://registry.npmjs.org/@mui/x-date-pickers/-/x-date-pickers-7.28.2.tgz",
+ "integrity": "sha512-py8u0iOShM8m/Ocs/giS8MwTNFn+iRFG6m5L6YJ/JmKzNfQfkVJOjpbdSIWxdCJ8plJn95oar1nKUhDdwn88HA==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/runtime": "^7.25.7",
+ "@mui/utils": "^5.16.6 || ^6.0.0 || ^7.0.0 || ^7.0.0-beta",
+ "@mui/x-internals": "7.28.0",
+ "@types/react-transition-group": "^4.4.11",
+ "clsx": "^2.1.1",
+ "prop-types": "^15.8.1",
+ "react-transition-group": "^4.4.5"
+ },
+ "engines": {
+ "node": ">=14.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/mui-org"
+ },
+ "peerDependencies": {
+ "@emotion/react": "^11.9.0",
+ "@emotion/styled": "^11.8.1",
+ "@mui/material": "^5.15.14 || ^6.0.0 || ^7.0.0 || ^7.0.0-beta",
+ "@mui/system": "^5.15.14 || ^6.0.0 || ^7.0.0 || ^7.0.0-beta",
+ "date-fns": "^2.25.0 || ^3.2.0 || ^4.0.0",
+ "date-fns-jalali": "^2.13.0-0 || ^3.2.0-0 || ^4.0.0-0",
+ "dayjs": "^1.10.7",
+ "luxon": "^3.0.2",
+ "moment": "^2.29.4",
+ "moment-hijri": "^2.1.2 || ^3.0.0",
+ "moment-jalaali": "^0.7.4 || ^0.8.0 || ^0.9.0 || ^0.10.0",
+ "react": "^17.0.0 || ^18.0.0 || ^19.0.0",
+ "react-dom": "^17.0.0 || ^18.0.0 || ^19.0.0"
+ },
+ "peerDependenciesMeta": {
+ "@emotion/react": {
+ "optional": true
+ },
+ "@emotion/styled": {
+ "optional": true
+ },
+ "date-fns": {
+ "optional": true
+ },
+ "date-fns-jalali": {
+ "optional": true
+ },
+ "dayjs": {
+ "optional": true
+ },
+ "luxon": {
+ "optional": true
+ },
+ "moment": {
+ "optional": true
+ },
+ "moment-hijri": {
+ "optional": true
+ },
+ "moment-jalaali": {
+ "optional": true
+ }
+ }
+ },
"node_modules/@mui/x-internals": {
"version": "7.28.0",
"resolved": "https://registry.npmjs.org/@mui/x-internals/-/x-internals-7.28.0.tgz",
@@ -4877,6 +4983,12 @@
"integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==",
"license": "MIT"
},
+ "node_modules/reselect": {
+ "version": "5.1.1",
+ "resolved": "https://registry.npmjs.org/reselect/-/reselect-5.1.1.tgz",
+ "integrity": "sha512-K/BG6eIky/SBpzfHZv/dd+9JBFiS4SWV7FIujVyJRux6e45+73RaUHXLmIR1f7WOMaQ0U1km6qwklRQxpJJY0w==",
+ "license": "MIT"
+ },
"node_modules/resolve": {
"version": "1.22.10",
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.10.tgz",
@@ -5257,6 +5369,15 @@
"punycode": "^2.1.0"
}
},
+ "node_modules/use-sync-external-store": {
+ "version": "1.5.0",
+ "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.5.0.tgz",
+ "integrity": "sha512-Rb46I4cGGVBmjamjphe8L/UnvJD+uPPtTkNvX5mZgqdbavhI4EbgIWJiIHXJ8bc/i9EQGPRh4DwEURJ552Do0A==",
+ "license": "MIT",
+ "peerDependencies": {
+ "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0"
+ }
+ },
"node_modules/victory-vendor": {
"version": "36.9.2",
"resolved": "https://registry.npmjs.org/victory-vendor/-/victory-vendor-36.9.2.tgz",
diff --git a/frontend/package.json b/frontend/package.json
index df91891e..48ec181c 100644
--- a/frontend/package.json
+++ b/frontend/package.json
@@ -22,6 +22,8 @@
"@mui/styled-engine-sc": "^6.4.6",
"@mui/x-charts": "^7.27.1",
"@mui/x-charts-pro": "^7.27.1",
+ "@mui/x-data-grid": "^7.28.2",
+ "@mui/x-date-pickers": "^7.28.2",
"d3": "^7.9.0",
"leaflet": "^1.9.4",
"lucide-react": "^0.485.0",
diff --git a/frontend/src/App.jsx b/frontend/src/App.jsx
index ef1a6a29..2c6e512d 100644
--- a/frontend/src/App.jsx
+++ b/frontend/src/App.jsx
@@ -1,44 +1,26 @@
-import React, { useState } from 'react';
-import Navbar from './components/Navbar';
-import Dashboard from './components/Dashboard';
-import CheckLog from './components/CheckLog';
-import ChartLine from './components/ChartLine';
-import LogOut from './components/LogOut';
-import Collab from './components/Collab';
-import './App.css';
-
-function App() {
- const [activeTab, setActiveTab] = useState('dashboard');
-
- const renderContent = () => {
- switch (activeTab) {
- case 'dashboard':
- return ;
- case 'checkLog':
- return ;
- case 'chartLine':
- return ;
- case 'logOut':
- return ;
- default:
- return ;
- }
- };
+import * as React from "react";
+import CssBaseline from "@mui/material/CssBaseline";
+import Divider from "@mui/material/Divider";
+import AppTheme from "./theme/AppTheme";
+import AppAppBar from "./components/AppAppBar";
+import Hero from "./components/Hero";
+import Features from "./components/Features";
+import FAQ from "./components/FAQ";
+import Footer from "./components/Footer";
+export default function App(props) {
return (
-
-
-
-
-
- {renderContent()}
+
+
+
+
+
-
-
-
-
-
+
);
}
-
-export default App;
diff --git a/frontend/src/assets/assets.js b/frontend/src/assets/assets.js
deleted file mode 100644
index 61d54887..00000000
--- a/frontend/src/assets/assets.js
+++ /dev/null
@@ -1,13 +0,0 @@
-import user1 from './user1.png'
-import user2 from './user2.png'
-import user3 from './user3.png'
-import user4 from './user4.png'
-import user5 from './user5.png'
-
-export const assets = {
- user1,
- user2,
- user3,
- user4,
- user5
-}
\ No newline at end of file
diff --git a/frontend/src/assets/dashboard.png b/frontend/src/assets/dashboard.png
new file mode 100644
index 00000000..89aef989
Binary files /dev/null and b/frontend/src/assets/dashboard.png differ
diff --git a/frontend/src/assets/user1.png b/frontend/src/assets/user1.png
deleted file mode 100644
index 18cc06f4..00000000
Binary files a/frontend/src/assets/user1.png and /dev/null differ
diff --git a/frontend/src/assets/user2.png b/frontend/src/assets/user2.png
deleted file mode 100644
index c3bd39e7..00000000
Binary files a/frontend/src/assets/user2.png and /dev/null differ
diff --git a/frontend/src/assets/user3.png b/frontend/src/assets/user3.png
deleted file mode 100644
index 696e5730..00000000
Binary files a/frontend/src/assets/user3.png and /dev/null differ
diff --git a/frontend/src/assets/user4.png b/frontend/src/assets/user4.png
deleted file mode 100644
index 7e2afc01..00000000
Binary files a/frontend/src/assets/user4.png and /dev/null differ
diff --git a/frontend/src/assets/user5.png b/frontend/src/assets/user5.png
deleted file mode 100644
index cfba57ba..00000000
Binary files a/frontend/src/assets/user5.png and /dev/null differ
diff --git a/frontend/src/components/AppAppBar.jsx b/frontend/src/components/AppAppBar.jsx
new file mode 100644
index 00000000..f990a128
--- /dev/null
+++ b/frontend/src/components/AppAppBar.jsx
@@ -0,0 +1,142 @@
+import * as React from "react";
+import { styled, alpha } from "@mui/material/styles";
+import Box from "@mui/material/Box";
+import AppBar from "@mui/material/AppBar";
+import Toolbar from "@mui/material/Toolbar";
+import Button from "@mui/material/Button";
+import IconButton from "@mui/material/IconButton";
+import Container from "@mui/material/Container";
+import Divider from "@mui/material/Divider";
+import MenuItem from "@mui/material/MenuItem";
+import Drawer from "@mui/material/Drawer";
+import MenuIcon from "@mui/icons-material/Menu";
+import CloseRoundedIcon from "@mui/icons-material/CloseRounded";
+import ColorModeIconDropdown from "../theme/ColorModeIconDropdown";
+import Sitemark from "./SitemarkIcon";
+
+const StyledToolbar = styled(Toolbar)(({ theme }) => ({
+ display: "flex",
+ alignItems: "center",
+ justifyContent: "space-between",
+ flexShrink: 0,
+ borderRadius: `calc(${theme.shape.borderRadius}px + 8px)`,
+ backdropFilter: "blur(24px)",
+ border: "1px solid",
+ borderColor: (theme.vars || theme).palette.divider,
+ backgroundColor: theme.vars
+ ? `rgba(${theme.vars.palette.background.defaultChannel} / 0.4)`
+ : alpha(theme.palette.background.default, 0.4),
+ boxShadow: (theme.vars || theme).shadows[1],
+ padding: "8px 12px",
+}));
+
+export default function AppAppBar() {
+ const [open, setOpen] = React.useState(false);
+
+ const toggleDrawer = (newOpen) => () => {
+ setOpen(newOpen);
+ };
+
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+}
diff --git a/frontend/src/components/ChartLine.jsx b/frontend/src/components/ChartLine.jsx
deleted file mode 100644
index d31e8ebf..00000000
--- a/frontend/src/components/ChartLine.jsx
+++ /dev/null
@@ -1,217 +0,0 @@
-import React, { useState } from 'react'
-import { PieChart } from '@mui/x-charts/PieChart'
-
-const pieChartsData = {
- userLogon: [
- { id: 0, label: 'Administrator', value: 30 },
- { id: 1, label: 'Orion11s', value: 25 },
- { id: 2, label: 'System', value: 20 },
- { id: 3, label: 'Local Users', value: 5 },
- { id: 4, label: 'Guest', value: 10 },
- { id: 5, label: 'Developer', value: 15 },
- { id: 6, label: 'Service Account', value: 8 },
- { id: 7, label: 'Others', value: 20 },
- ],
- logonFailures: [
- { id: 0, label: 'Password Error', value: 40 },
- { id: 1, label: 'Account Locked', value: 30 },
- { id: 2, label: 'Unknown User', value: 30 },
- { id: 3, label: 'MFA Failure', value: 25 },
- { id: 4, label: 'Account Disabled', value: 15 },
- ],
- issueType: [
- { id: 0, label: 'Hardware', value: 25 },
- { id: 1, label: 'Software', value: 50 },
- { id: 2, label: 'Hybrid', value: 25 },
- { id: 3, label: 'Other', value: 10 },
- ],
- fixationStatus: [
- { id: 0, label: 'Fixed', value: 60 },
- { id: 1, label: 'Not Fixed', value: 40 },
- { id: 2, label: 'In Progress', value: 20 },
- ],
- errorSeverity: [
- { id: 0, label: 'Critical', value: 35 },
- { id: 1, label: 'Major', value: 40 },
- { id: 2, label: 'Minor', value: 25 },
- ],
- errorCategory: [
- { id: 0, label: 'Syntax Error', value: 30 },
- { id: 1, label: 'Runtime Error', value: 40 },
- { id: 2, label: 'Database Error', value: 20 },
- { id: 3, label: 'Network Error', value: 10 },
- { id: 4, label: 'Other', value: 15 },
- ],
-}
-
-function LogonFailuresPieChart({ title, data }) {
- const [selected, setSelected] = useState(null)
-
- const handleClick = (event, params) => {
- setSelected(params.label)
- }
-
- return (
-
-
-
{title}
- {selected &&
Selected: {selected}
}
-
- );
-}
-
-
-function IssueTypePieChart({ title, data }) {
- const [selected, setSelected] = useState(null)
-
- const handleClick = (event, params) => {
- setSelected(params.label)
- }
-
- return (
-
-
-
{title}
- {selected &&
Selected: {selected}
}
-
- );
-}
-
-function FixationStatusPieChart({ title, data }) {
- const [selected, setSelected] = useState(null)
-
- const handleClick = (event, params) => {
- setSelected(params.label)
- }
-
- return (
-
-
-
{title}
- {selected &&
Selected: {selected}
}
-
- );
-}
-
-function ErrorCategoryPieChart({ title, data }) {
- const [selected, setSelected] = useState(null)
-
- const handleClick = (event, params) => {
- setSelected(params.label)
- }
-
- return (
-
-
-
{title}
- {selected &&
Selected: {selected}
}
-
- );
-}
-
-
-const ChartLine = () => {
- return (
-
- )
-}
-
-export default ChartLine
\ No newline at end of file
diff --git a/frontend/src/components/ChatBox.jsx b/frontend/src/components/ChatBox.jsx
deleted file mode 100644
index e14e8b1f..00000000
--- a/frontend/src/components/ChatBox.jsx
+++ /dev/null
@@ -1,31 +0,0 @@
-import React, { useState } from 'react'
-
-function ChatBox() {
- const [input, setInput] = useState('')
-
- const handleChat = () => {
- // Here you can pass the input or log details to your chat interface.
- // For now, we simulate opening a new tab with a chat window.
- window.open('/chat', '_blank')
- }
-
- return (
-
- setInput(e.target.value)}
- className="border border-r-0 border-gray-400 px-2 py-1 flex-1"
- />
-
-
- )
-}
-
-export default ChatBox
diff --git a/frontend/src/components/CheckLog.jsx b/frontend/src/components/CheckLog.jsx
deleted file mode 100644
index 21f44d29..00000000
--- a/frontend/src/components/CheckLog.jsx
+++ /dev/null
@@ -1,80 +0,0 @@
-import React, { useState, useEffect } from 'react'
-import sampleHistory from '../data/sampleLogs.json'
-import LogItem from './LogItem'
-
-function CheckLog() {
- const [logs, setLogs] = useState([])
- const [sortOrder, setSortOrder] = useState("desc")
- const [searchQuery, setSearchQuery] = useState("")
- const [visibleCount, setVisibleCount] = useState(8)
-
- useEffect(() => {
- // Load sample logs on mount.
- setLogs(sampleHistory)
- }, [])
-
- // Toggle sort order between ascending and descending.
- const handleSort = () => {
- setSortOrder((prev) => (prev === "desc" ? "asc" : "desc"))
- }
-
- // Filter logs by checking if any relevant fields contain the search query.
- const filteredLogs = logs.filter((log) => {
- const combined = `${log.date} ${log.logMessage} ${log.eventIDs.join(" ")} ${log.issueType} ${log.fixableType} ${log.userType} ${log.riskPriority}`.toLowerCase()
- return combined.includes(searchQuery.toLowerCase())
- })
-
- // Sort logs based on the date field.
- const sortedLogs = [...filteredLogs].sort((a, b) => {
- const dateA = new Date(a.date)
- const dateB = new Date(b.date)
- return sortOrder === "asc" ? dateA - dateB : dateB - dateA
- })
-
- // Slice the sorted logs based on the visible count.
- const visibleLogs = sortedLogs.slice(0, visibleCount)
-
- // Load more logs by increasing visible count.
- const loadMore = () => {
- setVisibleCount((prev) => prev + 5)
- }
-
- return (
-
-
Check Previous Logs
-
-
- setSearchQuery(e.target.value)}
- />
-
-
-
- {visibleLogs.map((log, idx) => (
-
- ))}
-
- {visibleCount < sortedLogs.length && (
-
-
-
- )}
-
- )
-}
-
-export default CheckLog
diff --git a/frontend/src/components/Collab.jsx b/frontend/src/components/Collab.jsx
deleted file mode 100644
index 63fa4dd9..00000000
--- a/frontend/src/components/Collab.jsx
+++ /dev/null
@@ -1,106 +0,0 @@
-import React, { useState } from 'react';
-import { FaRegEnvelope } from 'react-icons/fa';
-import { assets } from '../assets/assets';
-
-const usersData = [
- {
- id: 1,
- name: "Alice Johnson",
- bio: "Frontend Developer.",
- profilePic: assets.user2,
- active: true,
- lastSeen: "Active now"
- },
- {
- id: 2,
- name: "Bob Smith",
- bio: "Backend Developer.",
- profilePic: assets.user5,
- active: false,
- lastSeen: "1 hour ago"
- },
- {
- id: 3,
- name: "Carol White",
- bio: "Fullstack Engineer.",
- profilePic: assets.user4,
- active: true,
- lastSeen: "Active now"
- },
- {
- id: 4,
- name: "David Green",
- bio: "Data Scientist.",
- profilePic: assets.user1,
- active: false,
- lastSeen: "30 min ago"
- },
- {
- id: 5,
- name: "Eve Black",
- bio: "DevOps Engineer.",
- profilePic: assets.user3,
- active: true,
- lastSeen: "Active now"
- },
-];
-
-const Collaboration = () => {
- const [showActive, setShowActive] = useState(true);
-
- // Filter users based on the toggle state
- const filteredUsers = usersData.filter(user => user.active === showActive);
-
- return (
-
- {/* Top toggle switch for Active/Inactive users */}
-
-
Collaboration
-
-
- {showActive ? 'Active Users' : 'Inactive Users'}
-
-
-
-
-
- {/* User cards */}
-
- {filteredUsers.map(user => (
-
-

-
-
{user.name}
-
{user.bio}
-
- {user.active ? 'Active' : `Last seen: ${user.lastSeen}`}
-
-
-
-
-
-
-
- ))}
-
-
- );
-};
-
-export default Collaboration;
diff --git a/frontend/src/components/DailyLogsBarGraph.jsx b/frontend/src/components/DailyLogsBarGraph.jsx
deleted file mode 100644
index 5582db59..00000000
--- a/frontend/src/components/DailyLogsBarGraph.jsx
+++ /dev/null
@@ -1,62 +0,0 @@
-import React from 'react'
-import { AreaChart, Area, XAxis, YAxis, Tooltip, ResponsiveContainer } from 'recharts';
-
-const data = [
- { date: '2023-02-01', logs: 12 },
- { date: '2023-02-02', logs: 18 },
- { date: '2023-02-03', logs: 9 },
- { date: '2023-02-04', logs: 15 },
- { date: '2023-02-05', logs: 20 },
- { date: '2023-02-06', logs: 14 },
- { date: '2023-02-07', logs: 22 },
- { date: '2023-02-08', logs: 17 },
- { date: '2023-02-09', logs: 11 },
- { date: '2023-02-10', logs: 19 },
- { date: '2023-02-11', logs: 16 },
- { date: '2023-02-12', logs: 23 },
- { date: '2023-02-13', logs: 13 },
- { date: '2023-02-14', logs: 20 },
- { date: '2023-02-15', logs: 15 }
-]
-
-// Function to convert date string to day of the week
-const getDayName = (dateString) => {
- const date = new Date(dateString);
- const options = { weekday: 'short' };
- return date.toLocaleDateString('en-US', options);
-};
-
-// Map data to include day names
-const formattedData = data.map(item => ({
- ...item,
- day: getDayName(item.date),
-}));
-
-// Custom tooltip component for the area chart
-const CustomTooltip = ({ active, payload }) => {
- if (active && payload && payload.length) {
- return (
-
-
{`Logs: ${payload[0].value}`}
-
- );
- }
- return null;
-};
-
-function DailyLogsAreaChart() {
- return (
-
-
Overview
-
-
-
- } />
-
-
-
-
- );
-}
-
-export default DailyLogsAreaChart;
\ No newline at end of file
diff --git a/frontend/src/components/Dashboard.jsx b/frontend/src/components/Dashboard.jsx
deleted file mode 100644
index b1101ce4..00000000
--- a/frontend/src/components/Dashboard.jsx
+++ /dev/null
@@ -1,276 +0,0 @@
-import React, { useState, useEffect, useRef } from 'react'
-import DailyLogsBarGraph from './DailyLogsBarGraph'
-import { PieChart } from '@mui/x-charts/PieChart'
-import { MapContainer, TileLayer, CircleMarker, Tooltip } from 'react-leaflet';
-import 'leaflet/dist/leaflet.css';
-import * as d3 from 'd3';
-
-const pieChartsData = {
- userLogon: [
- { id: 0, label: 'Administrator', value: 30 },
- { id: 1, label: 'Orion11s', value: 25 },
- { id: 2, label: 'System', value: 20 },
- { id: 3, label: 'Local Users', value: 5 },
- { id: 4, label: 'Guest', value: 10 },
- { id: 5, label: 'Developer', value: 15 },
- { id: 6, label: 'Service Account', value: 8 },
- { id: 7, label: 'Others', value: 20 },
- ],
- logonFailures: [
- { id: 0, label: 'Password Error', value: 40 },
- { id: 1, label: 'Account Locked', value: 30 },
- { id: 2, label: 'Unknown User', value: 30 },
- { id: 3, label: 'MFA Failure', value: 25 },
- { id: 4, label: 'Account Disabled', value: 15 },
- ],
- issueType: [
- { id: 0, label: 'Hardware', value: 25 },
- { id: 1, label: 'Software', value: 50 },
- { id: 2, label: 'Hybrid', value: 25 },
- { id: 3, label: 'Other', value: 10 },
- ],
- fixationStatus: [
- { id: 0, label: 'Fixed', value: 60 },
- { id: 1, label: 'Not Fixed', value: 40 },
- { id: 2, label: 'In Progress', value: 20 },
- ],
- errorSeverity: [
- { id: 0, label: 'Critical', value: 35 },
- { id: 1, label: 'Major', value: 40 },
- { id: 2, label: 'Minor', value: 25 },
- ],
- errorCategory: [
- { id: 0, label: 'Syntax Error', value: 30 },
- { id: 1, label: 'Runtime Error', value: 40 },
- { id: 2, label: 'Database Error', value: 20 },
- { id: 3, label: 'Network Error', value: 10 },
- { id: 4, label: 'Other', value: 15 },
- ],
-}
-
-const heatmapData = [
- { x: 'Mon', y: '00:00', value: 5 },
- { x: 'Mon', y: '01:00', value: 8 },
- { x: 'Mon', y: '02:00', value: 6 },
- { x: 'Tue', y: '00:00', value: 7 },
- { x: 'Tue', y: '01:00', value: 3 },
- { x: 'Tue', y: '02:00', value: 4 },
- { x: 'Wed', y: '00:00', value: 9 },
- { x: 'Wed', y: '01:00', value: 2 },
- { x: 'Wed', y: '02:00', value: 5 },
- { x: 'Thu', y: '00:00', value: 6 },
- { x: 'Thu', y: '01:00', value: 7 },
- { x: 'Thu', y: '02:00', value: 8 },
- { x: 'Fri', y: '00:00', value: 4 },
- { x: 'Fri', y: '01:00', value: 5 },
- { x: 'Fri', y: '02:00', value: 6 },
- { x: 'Sat', y: '00:00', value: 3 },
- { x: 'Sat', y: '01:00', value: 4 },
- { x: 'Sat', y: '02:00', value: 2 },
- { x: 'Sun', y: '00:00', value: 8 },
- { x: 'Sun', y: '01:00', value: 7 },
- { x: 'Sun', y: '02:00', value: 9 },
-];
-
-const userLocations = [
- { lat: 37.7749, lng: -122.4194, count: 150 }, // San Francisco
- { lat: 34.0522, lng: -118.2437, count: 200 }, // Los Angeles
- { lat: 40.7128, lng: -74.0060, count: 250 }, // New York
- { lat: 51.5074, lng: -0.1278, count: 180 }, // London
- { lat: 48.8566, lng: 2.3522, count: 220 }, // Paris
- { lat: 35.6895, lng: 139.6917, count: 300 }, // Tokyo
- { lat: -33.8688, lng: 151.2093, count: 170 }, // Sydney
- { lat: 55.7558, lng: 37.6176, count: 190 }, // Moscow
- { lat: 39.9042, lng: 116.4074, count: 280 }, // Beijing
- { lat: -23.5505, lng: -46.6333, count: 160 }, // São Paulo
- { lat: 19.0760, lng: 72.8777, count: 210 }, // Mumbai
- { lat: 52.5200, lng: 13.4050, count: 200 }, // Berlin
-];
-
-
-function LogUserPie({ title, data }) {
- const [selected, setSelected] = useState(null)
-
- const handleClick = (event, params) => {
- setSelected(params.label)
- }
-
- return (
-
-
{title}
-
- {selected &&
Selected: {selected}
}
-
- )
-}
-
-
-function GeographicalUserDistributionMap() {
- return (
-
-
- {userLocations.map((location, index) => (
-
- {`Users: ${location.count}`}
-
- ))}
-
- );
-}
-
-
-function HeatMapChart({ data }) {
- const svgRef = useRef();
-
- useEffect(() => {
- const margin = { top: 0, right: 0, bottom: 30, left: 40 };
- const width = 450 - margin.left - margin.right;
- const height = 250 - margin.top - margin.bottom;
-
- // Clear previous SVG content if any
- d3.select(svgRef.current).selectAll('*').remove();
-
- const svg = d3.select(svgRef.current)
- .attr('width', width + margin.left + margin.right)
- .attr('height', height + margin.top + margin.bottom)
- .append('g')
- .attr('transform', `translate(${margin.left},${margin.top})`);
-
- const xLabels = Array.from(new Set(data.map(d => d.x)));
- const yLabels = Array.from(new Set(data.map(d => d.y)));
-
- const xScale = d3.scaleBand()
- .domain(xLabels)
- .range([0, width])
- .padding(0.05);
-
- const yScale = d3.scaleBand()
- .domain(yLabels)
- .range([height, 0])
- .padding(0.05);
-
- svg.append('g')
- .attr('transform', `translate(0, ${height})`)
- .call(d3.axisBottom(xScale));
-
- svg.append('g')
- .call(d3.axisLeft(yScale));
-
- const colorScale = d3.scaleSequential(d3.interpolatePurples)
- .domain([0, d3.max(data, d => d.value)]);
-
- // Create a tooltip div that is hidden by default
- const tooltip = d3.select('body').append('div')
- .style('position', 'absolute')
- .style('background-color', 'white')
- .style('border', 'solid')
- .style('border-width', '1px')
- .style('border-radius', '5px')
- .style('padding', '10px')
- .style('opacity', 0);
-
- // Functions to handle mouse events
- const handleMouseOver = function (event, d) {
- tooltip.style('opacity', 1);
- d3.select(this).style('stroke', 'black').style('opacity', 1);
- };
-
- const handleMouseMove = function (event, d) {
- tooltip
- .html(`No. of Users: ${d.value}`)
- .style('left', (event.pageX + 10) + 'px')
- .style('top', (event.pageY - 28) + 'px')
- .style('font-size', '12px');
- };
-
- const handleMouseLeave = function (event, d) {
- tooltip.style('opacity', 0);
- d3.select(this).style('stroke', 'none').style('opacity', 0.8);
- };
-
- svg.selectAll()
- .data(data, d => `${d.x}:${d.y}`)
- .enter()
- .append('rect')
- .attr('x', d => xScale(d.x))
- .attr('y', d => yScale(d.y))
- .attr('width', xScale.bandwidth())
- .attr('height', yScale.bandwidth())
- .style('fill', d => colorScale(d.value))
- .style('stroke-width', 0)
- .style('stroke', 'none')
- .style('opacity', 0.8)
- .style('cursor', 'pointer')
- .on('mouseover', handleMouseOver)
- .on('mousemove', handleMouseMove)
- .on('mouseleave', handleMouseLeave);
-
- // Cleanup function to remove the tooltip when the component unmounts
- return () => {
- tooltip.remove();
- };
- }, [data]);
-
- return
;
-}
-
-
-function Dashboard() {
- return (
-
-
Primary
-
Dashboard
-
-
-
-
-
-
-
- )
-}
-
-export default Dashboard
diff --git a/frontend/src/components/FAQ.jsx b/frontend/src/components/FAQ.jsx
new file mode 100644
index 00000000..fab2bcbd
--- /dev/null
+++ b/frontend/src/components/FAQ.jsx
@@ -0,0 +1,152 @@
+import * as React from "react";
+import Accordion from "@mui/material/Accordion";
+import AccordionDetails from "@mui/material/AccordionDetails";
+import AccordionSummary from "@mui/material/AccordionSummary";
+import Box from "@mui/material/Box";
+import Container from "@mui/material/Container";
+import Link from "@mui/material/Link";
+import Typography from "@mui/material/Typography";
+import ExpandMoreIcon from "@mui/icons-material/ExpandMore";
+
+export default function FAQ() {
+ const [expanded, setExpanded] = React.useState([]);
+
+ const handleChange = (panel) => (event, isExpanded) => {
+ setExpanded(
+ isExpanded
+ ? [...expanded, panel]
+ : expanded.filter((item) => item !== panel)
+ );
+ };
+
+ return (
+
+
+ ❓ Frequently Asked Questions (FAQ)
+
+
+
+ }
+ aria-controls="panel1d-content"
+ id="panel1d-header"
+ >
+
+ What is this log analyzer, and how does it work?
+
+
+
+
+ Our log analyzer helps you
+ detect errors, troubleshoot issues, and gain insights from
+ system logs. Simply upload your logs, and our AI-powered engine
+ will analyze them, highlighting potential problems and suggesting
+ fixes.
+
+
+
+
+ }
+ aria-controls="panel2d-content"
+ id="panel2d-header"
+ >
+
+ What types of logs does it support?
+
+
+
+
+ We support system logs, server logs, application logs, network
+ logs, and more, including formats like CSV and log files from
+ Linux, Windows, and cloud platforms.
+
+
+
+
+ }
+ aria-controls="panel3d-content"
+ id="panel3d-header"
+ >
+
+ Do I need technical expertise to use it?
+
+
+
+
+ Not at all! Our tool is designed for both developers and
+ non-technical users, providing an easy-to-use dashboard with
+ simple explanations and actionable insights.
+
+
+
+
+ }
+ aria-controls="panel4d-content"
+ id="panel4d-header"
+ >
+
+ How do I get started?
+
+
+
+
+ Click "Get Started", sign up, and upload your first log to begin
+ analyzing errors and improving your system performance. It's that
+ simple!
+
+
+
+
+
+ );
+}
diff --git a/frontend/src/components/Features.jsx b/frontend/src/components/Features.jsx
new file mode 100644
index 00000000..fd287a21
--- /dev/null
+++ b/frontend/src/components/Features.jsx
@@ -0,0 +1,264 @@
+import * as React from "react";
+import Box from "@mui/material/Box";
+import Button from "@mui/material/Button";
+import Card from "@mui/material/Card";
+import MuiChip from "@mui/material/Chip";
+import Container from "@mui/material/Container";
+import Typography from "@mui/material/Typography";
+import { styled } from "@mui/material/styles";
+
+import DevicesRoundedIcon from "@mui/icons-material/DevicesRounded";
+import EdgesensorHighRoundedIcon from "@mui/icons-material/EdgesensorHighRounded";
+import ViewQuiltRoundedIcon from "@mui/icons-material/ViewQuiltRounded";
+
+const items = [
+ {
+ icon:
,
+ title: "AI-Powered Insights",
+ description:
+ "Automatically analyzes logs and CSV files, providing instant error highlights and suggested solutions.",
+ imageLight: `url("${"https://mui.com"}/static/images/templates/templates-images/dash-light.png")`,
+ imageDark: `url("${"https://mui.com"}/static/images/templates/templates-images/dash-dark.png")`,
+ },
+ {
+ icon:
,
+ title: "Cross-Platform Compatibility",
+ description:
+ "Supports log files from any OS, ensuring seamless analysis across Windows, macOS, Linux, and more.",
+ imageLight: `url("${"https://mui.com"}/static/images/templates/templates-images/mobile-light.png")`,
+ imageDark: `url("${"https://mui.com"}/static/images/templates/templates-images/mobile-dark.png")`,
+ },
+ {
+ icon:
,
+ title: "Interactive Issue Resolution",
+ description:
+ "Chat with AI for detailed explanations and step-by-step guidance on fixing detected issues.",
+ imageLight: `url("${"https://mui.com"}/static/images/templates/templates-images/devices-light.png")`,
+ imageDark: `url("${"https://mui.com"}/static/images/templates/templates-images/devices-dark.png")`,
+ },
+];
+
+const Chip = styled(MuiChip)(({ theme }) => ({
+ variants: [
+ {
+ props: ({ selected }) => selected,
+ style: {
+ background:
+ "linear-gradient(to bottom right, hsl(210, 98%, 48%), hsl(210, 98%, 35%))",
+ color: "hsl(0, 0%, 100%)",
+ borderColor: (theme.vars || theme).palette.primary.light,
+ "& .MuiChip-label": {
+ color: "hsl(0, 0%, 100%)",
+ },
+ ...theme.applyStyles("dark", {
+ borderColor: (theme.vars || theme).palette.primary.dark,
+ }),
+ },
+ },
+ ],
+}));
+
+export function MobileLayout({
+ selectedItemIndex,
+ handleItemClick,
+ selectedFeature,
+}) {
+ if (!items[selectedItemIndex]) {
+ return null;
+ }
+
+ return (
+
+
+ {items.map(({ title }, index) => (
+ handleItemClick(index)}
+ selected={selectedItemIndex === index}
+ />
+ ))}
+
+
+ ({
+ mb: 2,
+ backgroundSize: "cover",
+ backgroundPosition: "center",
+ minHeight: 280,
+ backgroundImage: "var(--items-imageLight)",
+ ...theme.applyStyles("dark", {
+ backgroundImage: "var(--items-imageDark)",
+ }),
+ })}
+ style={
+ items[selectedItemIndex]
+ ? {
+ "--items-imageLight": items[selectedItemIndex].imageLight,
+ "--items-imageDark": items[selectedItemIndex].imageDark,
+ }
+ : {}
+ }
+ />
+
+
+ {selectedFeature.title}
+
+
+ {selectedFeature.description}
+
+
+
+
+ );
+}
+
+export default function Features() {
+ const [selectedItemIndex, setSelectedItemIndex] = React.useState(0);
+
+ const handleItemClick = (index) => {
+ setSelectedItemIndex(index);
+ };
+
+ const selectedFeature = items[selectedItemIndex];
+
+ return (
+
+
+
+ Log Analyzer features
+
+
+ Discover the powerful features of our log analyzer, designed to help
+ you diagnose system issues faster and more efficiently. Our intuitive
+ platform combines AI capabilities with user-friendly interfaces to
+ transform complex log data into actionable insights.
+
+
+
+
+
+ {items.map(({ icon, title, description }, index) => (
+ handleItemClick(index)}
+ sx={[
+ (theme) => ({
+ p: 2,
+ height: "100%",
+ width: "100%",
+ "&:hover": {
+ backgroundColor: (theme.vars || theme).palette.action
+ .hover,
+ },
+ }),
+ selectedItemIndex === index && {
+ backgroundColor: "action.selected",
+ },
+ ]}
+ >
+
+ {icon}
+
+ {title}
+ {description}
+
+
+ ))}
+
+
+
+
+
+ ({
+ m: "auto",
+ width: 420,
+ height: 500,
+ backgroundSize: "contain",
+ backgroundImage: "var(--items-imageLight)",
+ ...theme.applyStyles("dark", {
+ backgroundImage: "var(--items-imageDark)",
+ }),
+ })}
+ style={
+ items[selectedItemIndex]
+ ? {
+ "--items-imageLight": items[selectedItemIndex].imageLight,
+ "--items-imageDark": items[selectedItemIndex].imageDark,
+ }
+ : {}
+ }
+ />
+
+
+
+
+ );
+}
diff --git a/frontend/src/components/Footer.jsx b/frontend/src/components/Footer.jsx
new file mode 100644
index 00000000..cd0ac55e
--- /dev/null
+++ b/frontend/src/components/Footer.jsx
@@ -0,0 +1,179 @@
+import * as React from "react";
+import Box from "@mui/material/Box";
+import Button from "@mui/material/Button";
+import Container from "@mui/material/Container";
+import IconButton from "@mui/material/IconButton";
+import Link from "@mui/material/Link";
+import Stack from "@mui/material/Stack";
+import Typography from "@mui/material/Typography";
+import GitHubIcon from "@mui/icons-material/GitHub";
+import LinkedInIcon from "@mui/icons-material/LinkedIn";
+import TwitterIcon from "@mui/icons-material/X";
+import SitemarkIcon from "./SitemarkIcon";
+
+function Copyright() {
+ return (
+
+ {"Copyright © "}
+
+ Log Analyzer
+
+
+ {new Date().getFullYear()}
+
+ );
+}
+
+export default function Footer() {
+ return (
+
+
+
+
+
+
+ Get started with our log analyzer today!{" "}
+
+
+ and fix the issues with your system.
+
+
+
+
+
+
+ Product
+
+
+ Features
+
+
+ FAQs
+
+
+ About us
+
+
+
+
+ Legal
+
+
+ Terms
+
+
+ Privacy
+
+
+ Contact
+
+
+
+
+
+
+ Privacy Policy
+
+
+ •
+
+
+ Terms of Service
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+}
diff --git a/frontend/src/components/Hero.jsx b/frontend/src/components/Hero.jsx
new file mode 100644
index 00000000..fc008790
--- /dev/null
+++ b/frontend/src/components/Hero.jsx
@@ -0,0 +1,149 @@
+import * as React from "react";
+import Box from "@mui/material/Box";
+import Button from "@mui/material/Button";
+import Container from "@mui/material/Container";
+import Link from "@mui/material/Link";
+import Stack from "@mui/material/Stack";
+import Typography from "@mui/material/Typography";
+import { styled } from "@mui/material/styles";
+import dashboardImage from "../assets/dashboard.png";
+
+const StyledBox = styled("div")(({ theme }) => ({
+ alignSelf: "center",
+ width: "100%",
+ height: 400,
+ marginTop: theme.spacing(8),
+ borderRadius: (theme.vars || theme).shape.borderRadius,
+ outline: "6px solid",
+ outlineColor: "hsla(220, 25%, 80%, 0.2)",
+ border: "1px solid",
+ borderColor: (theme.vars || theme).palette.grey[200],
+ boxShadow: "0 0 12px 8px hsla(220, 25%, 80%, 0.2)",
+ backgroundImage: `url(${dashboardImage})`,
+ backgroundSize: "cover",
+ [theme.breakpoints.up("sm")]: {
+ marginTop: theme.spacing(10),
+ height: 700,
+ },
+ ...theme.applyStyles("dark", {
+ boxShadow: "0 0 24px 12px hsla(210, 100%, 25%, 0.2)",
+ backgroundImage: `url(${dashboardImage})`,
+ outlineColor: "hsla(220, 20%, 42%, 0.1)",
+ borderColor: (theme.vars || theme).palette.grey[700],
+ }),
+}));
+
+export default function Hero() {
+ return (
+
({
+ width: "100%",
+ backgroundRepeat: "no-repeat",
+ display: "flex",
+ justifyContent: "center",
+ backgroundImage:
+ "radial-gradient(ellipse 80% 50% at 50% -20%, hsl(210, 100%, 90%), transparent)",
+ ...theme.applyStyles("dark", {
+ backgroundImage:
+ "radial-gradient(ellipse 80% 50% at 50% -20%, hsl(210, 100%, 16%), transparent)",
+ }),
+ })}
+ >
+
+
+
+ Analyze & Fix Logs,
+ ({
+ fontSize: "inherit",
+ color: "primary.main",
+ ...theme.applyStyles("dark", {
+ color: "primary.light",
+ }),
+ })}
+ >
+ Instantly!
+
+
+
+ Fix errors fast with AI-powered log analysis. Get real-time insights
+ and instant issue detection—no more endless log sifting! 🚀
+
+
+
+
+
+
+
+ By clicking "Get Started" you agree to our
+
+ Terms & Conditions
+
+ .
+
+
+
+
+
+ );
+}
diff --git a/frontend/src/components/LogItem.jsx b/frontend/src/components/LogItem.jsx
deleted file mode 100644
index 9b6a5156..00000000
--- a/frontend/src/components/LogItem.jsx
+++ /dev/null
@@ -1,62 +0,0 @@
-import React, { useState } from 'react'
-import ChatBox from './ChatBox'
-
-function LogItem({ log }) {
- const [expanded, setExpanded] = useState(false)
-
- // Return Tailwind color classes based on risk priority.
- const getRiskColor = (risk) => {
- switch (risk.toLowerCase()) {
- case "high":
- return "text-red-500"
- case "medium":
- return "text-yellow-500"
- case "low":
- return "text-green-500"
- default:
- return ""
- }
- }
-
- return (
-
-
-
-
{log.date}
-
{log.time}
-
{log.userType}
-
- {log.riskPriority}
-
-
-
-
- {expanded && (
-
-
- {log.logMessage}
-
-
-
Event IDs:
{log.eventIDs.join(', ')}
-
-
-
Type of Issue:
{log.issueType}
-
-
-
Fixable Type:
{log.fixableType}
-
-
-
-
-
- )}
-
- )
-}
-
-export default LogItem
diff --git a/frontend/src/components/LogOut.jsx b/frontend/src/components/LogOut.jsx
deleted file mode 100644
index afd86d09..00000000
--- a/frontend/src/components/LogOut.jsx
+++ /dev/null
@@ -1,9 +0,0 @@
-import React from 'react'
-
-const LogOut = () => {
- return (
-
LogOut
- )
-}
-
-export default LogOut;
\ No newline at end of file
diff --git a/frontend/src/components/Navbar.jsx b/frontend/src/components/Navbar.jsx
deleted file mode 100644
index 6dbf469e..00000000
--- a/frontend/src/components/Navbar.jsx
+++ /dev/null
@@ -1,64 +0,0 @@
-import React from 'react';
-import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
-import { faHouse, faFileLines, faChartLine, faRightFromBracket } from '@fortawesome/free-solid-svg-icons';
-import { faPiedPiperAlt } from '@fortawesome/free-brands-svg-icons';
-
-function Navbar({ activeTab, setActiveTab }) {
- return (
-
- );
-}
-
-export default Navbar;
diff --git a/frontend/src/components/Pricing.jsx b/frontend/src/components/Pricing.jsx
new file mode 100644
index 00000000..3e18d42d
--- /dev/null
+++ b/frontend/src/components/Pricing.jsx
@@ -0,0 +1,217 @@
+import * as React from "react";
+import Box from "@mui/material/Box";
+import Button from "@mui/material/Button";
+import Card from "@mui/material/Card";
+import Chip from "@mui/material/Chip";
+import CardActions from "@mui/material/CardActions";
+import CardContent from "@mui/material/CardContent";
+import Container from "@mui/material/Container";
+import Divider from "@mui/material/Divider";
+import Grid from "@mui/material/Grid";
+import Typography from "@mui/material/Typography";
+import AutoAwesomeIcon from "@mui/icons-material/AutoAwesome";
+import CheckCircleRoundedIcon from "@mui/icons-material/CheckCircleRounded";
+
+const tiers = [
+ {
+ title: "Free",
+ price: "0",
+ description: [
+ "10 users included",
+ "2 GB of storage",
+ "Help center access",
+ "Email support",
+ ],
+ buttonText: "Sign up for free",
+ buttonVariant: "outlined",
+ buttonColor: "primary",
+ },
+ {
+ title: "Professional",
+ subheader: "Recommended",
+ price: "15",
+ description: [
+ "20 users included",
+ "10 GB of storage",
+ "Help center access",
+ "Priority email support",
+ "Dedicated team",
+ "Best deals",
+ ],
+ buttonText: "Start now",
+ buttonVariant: "contained",
+ buttonColor: "secondary",
+ },
+ {
+ title: "Enterprise",
+ price: "30",
+ description: [
+ "50 users included",
+ "30 GB of storage",
+ "Help center access",
+ "Phone & email support",
+ ],
+ buttonText: "Contact us",
+ buttonVariant: "outlined",
+ buttonColor: "primary",
+ },
+];
+
+export default function Pricing() {
+ return (
+
+
+
+ Pricing
+
+
+ Quickly build an effective pricing table for your potential customers
+ with this layout.
+ It's built with default Material UI components with little
+ customization.
+
+
+
+ {tiers.map((tier) => (
+
+ ({
+ border: "none",
+ background:
+ "radial-gradient(circle at 50% 0%, hsl(220, 20%, 35%), hsl(220, 30%, 6%))",
+ boxShadow: `0 8px 12px hsla(220, 20%, 42%, 0.2)`,
+ ...theme.applyStyles("dark", {
+ background:
+ "radial-gradient(circle at 50% 0%, hsl(220, 20%, 20%), hsl(220, 30%, 16%))",
+ boxShadow: `0 8px 12px hsla(0, 0%, 0%, 0.8)`,
+ }),
+ })),
+ ]}
+ >
+
+
+
+ {tier.title}
+
+ {tier.title === "Professional" && (
+ } label={tier.subheader} />
+ )}
+
+
+
+ ${tier.price}
+
+
+ per month
+
+
+
+ {tier.description.map((line) => (
+
+
+
+ {line}
+
+
+ ))}
+
+
+
+
+
+
+ ))}
+
+
+ );
+}
diff --git a/frontend/src/components/SitemarkIcon.jsx b/frontend/src/components/SitemarkIcon.jsx
new file mode 100644
index 00000000..a1ec4935
--- /dev/null
+++ b/frontend/src/components/SitemarkIcon.jsx
@@ -0,0 +1,37 @@
+import * as React from "react";
+import SvgIcon from "@mui/material/SvgIcon";
+
+export default function SitemarkIcon() {
+ return (
+
+
+
+ );
+}
diff --git a/frontend/src/data/sampleLogs.json b/frontend/src/data/sampleLogs.json
deleted file mode 100644
index 3f819231..00000000
--- a/frontend/src/data/sampleLogs.json
+++ /dev/null
@@ -1,536 +0,0 @@
-[
- {
- "date": "2023-03-01",
- "time": "10:15:30",
- "userType": "User Logon",
- "riskPriority": "High",
- "logMessage": "SyntaxError: Unexpected token '}' in config file at line 23",
- "eventIDs": [
- "E101",
- "E102"
- ],
- "issueType": "Software",
- "fixableType": "Fixable"
- },
- {
- "date": "2023-03-01",
- "time": "11:20:45",
- "userType": "System CTL",
- "riskPriority": "Medium",
- "logMessage": "ReferenceError: variable x is not defined in main.js",
- "eventIDs": [
- "E103"
- ],
- "issueType": "Software",
- "fixableType": "Fixable"
- },
- {
- "date": "2023-03-02",
- "time": "09:05:10",
- "userType": "Kernel",
- "riskPriority": "High",
- "logMessage": "Kernel panic: Fatal exception in interrupt handler",
- "eventIDs": [
- "E104",
- "E105"
- ],
- "issueType": "Hardware",
- "fixableType": "Non-Fixable"
- },
- {
- "date": "2023-03-02",
- "time": "14:40:00",
- "userType": "User Logon",
- "riskPriority": "Low",
- "logMessage": "Warning: Login attempt failed due to incorrect password",
- "eventIDs": [
- "E106"
- ],
- "issueType": "Hybrid",
- "fixableType": "Fixable"
- },
- {
- "date": "2023-03-03",
- "time": "08:30:25",
- "userType": "System CTL",
- "riskPriority": "Medium",
- "logMessage": "Error: Unable to connect to database on port 5432",
- "eventIDs": [
- "E107"
- ],
- "issueType": "Software",
- "fixableType": "Fixable"
- },
- {
- "date": "2023-03-03",
- "time": "12:15:00",
- "userType": "Kernel",
- "riskPriority": "High",
- "logMessage": "Critical: Overheating detected in CPU, system halted",
- "eventIDs": [
- "E108",
- "E109"
- ],
- "issueType": "Hardware",
- "fixableType": "Non-Fixable"
- },
- {
- "date": "2023-03-04",
- "time": "16:05:55",
- "userType": "User Logon",
- "riskPriority": "Low",
- "logMessage": "Notice: User login successful after multiple attempts",
- "eventIDs": [
- "E110"
- ],
- "issueType": "Hybrid",
- "fixableType": "Fixable"
- },
- {
- "date": "2023-03-04",
- "time": "18:20:30",
- "userType": "System CTL",
- "riskPriority": "Medium",
- "logMessage": "Error: Memory allocation failed in process scheduler",
- "eventIDs": [
- "E111"
- ],
- "issueType": "Software",
- "fixableType": "Fixable"
- },
- {
- "date": "2023-03-05",
- "time": "07:45:00",
- "userType": "Kernel",
- "riskPriority": "High",
- "logMessage": "Panic: Null pointer dereference in module xyz",
- "eventIDs": [
- "E112"
- ],
- "issueType": "Hardware",
- "fixableType": "Non-Fixable"
- },
- {
- "date": "2023-03-05",
- "time": "13:30:15",
- "userType": "User Logon",
- "riskPriority": "Low",
- "logMessage": "Info: User login from remote terminal established",
- "eventIDs": [
- "E113"
- ],
- "issueType": "Hybrid",
- "fixableType": "Fixable"
- },
- {
- "date": "2023-03-06",
- "time": "09:10:00",
- "userType": "User Logon",
- "riskPriority": "Medium",
- "logMessage": "SyntaxError: Unexpected end of input in script.js",
- "eventIDs": [
- "E114"
- ],
- "issueType": "Software",
- "fixableType": "Fixable"
- },
- {
- "date": "2023-03-06",
- "time": "10:22:15",
- "userType": "System CTL",
- "riskPriority": "High",
- "logMessage": "ReferenceError: Cannot access variable before initialization",
- "eventIDs": [
- "E115",
- "E116"
- ],
- "issueType": "Software",
- "fixableType": "Fixable"
- },
- {
- "date": "2023-03-07",
- "time": "11:35:20",
- "userType": "Kernel",
- "riskPriority": "High",
- "logMessage": "Kernel panic: Fatal error in module ABC",
- "eventIDs": [
- "E117"
- ],
- "issueType": "Hardware",
- "fixableType": "Non-Fixable"
- },
- {
- "date": "2023-03-07",
- "time": "14:50:00",
- "userType": "User Logon",
- "riskPriority": "Low",
- "logMessage": "Warning: Suspicious login activity detected",
- "eventIDs": [
- "E118"
- ],
- "issueType": "Hybrid",
- "fixableType": "Fixable"
- },
- {
- "date": "2023-03-08",
- "time": "08:00:00",
- "userType": "System CTL",
- "riskPriority": "Medium",
- "logMessage": "Error: Database connection timeout",
- "eventIDs": [
- "E119"
- ],
- "issueType": "Software",
- "fixableType": "Fixable"
- },
- {
- "date": "2023-03-08",
- "time": "12:30:45",
- "userType": "Kernel",
- "riskPriority": "High",
- "logMessage": "Critical: Overheating detected, shutting down",
- "eventIDs": [
- "E120"
- ],
- "issueType": "Hardware",
- "fixableType": "Non-Fixable"
- },
- {
- "date": "2023-03-09",
- "time": "09:55:30",
- "userType": "User Logon",
- "riskPriority": "Low",
- "logMessage": "Notice: Login successful from new device",
- "eventIDs": [
- "E121"
- ],
- "issueType": "Hybrid",
- "fixableType": "Fixable"
- },
- {
- "date": "2023-03-09",
- "time": "15:45:10",
- "userType": "System CTL",
- "riskPriority": "Medium",
- "logMessage": "Error: Failed to load configuration file",
- "eventIDs": [
- "E122"
- ],
- "issueType": "Software",
- "fixableType": "Fixable"
- },
- {
- "date": "2023-03-10",
- "time": "07:20:00",
- "userType": "Kernel",
- "riskPriority": "High",
- "logMessage": "Panic: System halt due to unknown error",
- "eventIDs": [
- "E123"
- ],
- "issueType": "Hardware",
- "fixableType": "Non-Fixable"
- },
- {
- "date": "2023-03-10",
- "time": "11:11:11",
- "userType": "User Logon",
- "riskPriority": "Low",
- "logMessage": "Info: User logged in successfully",
- "eventIDs": [
- "E124"
- ],
- "issueType": "Hybrid",
- "fixableType": "Fixable"
- },
- {
- "date": "2023-03-11",
- "time": "10:05:00",
- "userType": "System CTL",
- "riskPriority": "Medium",
- "logMessage": "Error: Unexpected null value in data stream",
- "eventIDs": [
- "E125"
- ],
- "issueType": "Software",
- "fixableType": "Fixable"
- },
- {
- "date": "2023-03-11",
- "time": "13:15:30",
- "userType": "Kernel",
- "riskPriority": "High",
- "logMessage": "Critical: Memory leak detected in module XYZ",
- "eventIDs": [
- "E126",
- "E127"
- ],
- "issueType": "Hardware",
- "fixableType": "Non-Fixable"
- },
- {
- "date": "2023-03-12",
- "time": "09:00:00",
- "userType": "User Logon",
- "riskPriority": "Low",
- "logMessage": "Notice: User session expired after inactivity",
- "eventIDs": [
- "E128"
- ],
- "issueType": "Hybrid",
- "fixableType": "Fixable"
- },
- {
- "date": "2023-03-12",
- "time": "14:10:20",
- "userType": "System CTL",
- "riskPriority": "Medium",
- "logMessage": "Error: Failed to update system settings",
- "eventIDs": [
- "E129"
- ],
- "issueType": "Software",
- "fixableType": "Fixable"
- },
- {
- "date": "2023-03-13",
- "time": "08:40:00",
- "userType": "Kernel",
- "riskPriority": "High",
- "logMessage": "Panic: Critical error in kernel module",
- "eventIDs": [
- "E130"
- ],
- "issueType": "Hardware",
- "fixableType": "Non-Fixable"
- },
- {
- "date": "2023-03-13",
- "time": "12:20:15",
- "userType": "User Logon",
- "riskPriority": "Low",
- "logMessage": "Warning: Multiple failed login attempts detected",
- "eventIDs": [
- "E131"
- ],
- "issueType": "Hybrid",
- "fixableType": "Fixable"
- },
- {
- "date": "2023-03-14",
- "time": "07:30:45",
- "userType": "System CTL",
- "riskPriority": "Medium",
- "logMessage": "Error: Connection reset during data transmission",
- "eventIDs": [
- "E132"
- ],
- "issueType": "Software",
- "fixableType": "Fixable"
- },
- {
- "date": "2023-03-14",
- "time": "10:55:20",
- "userType": "Kernel",
- "riskPriority": "High",
- "logMessage": "Critical: CPU temperature exceeded safe threshold",
- "eventIDs": [
- "E133"
- ],
- "issueType": "Hardware",
- "fixableType": "Non-Fixable"
- },
- {
- "date": "2023-03-15",
- "time": "08:05:00",
- "userType": "User Logon",
- "riskPriority": "Low",
- "logMessage": "Notice: Successful login after password reset",
- "eventIDs": [
- "E134"
- ],
- "issueType": "Hybrid",
- "fixableType": "Fixable"
- },
- {
- "date": "2023-03-15",
- "time": "11:30:45",
- "userType": "System CTL",
- "riskPriority": "Medium",
- "logMessage": "Error: File system read error detected",
- "eventIDs": [
- "E135"
- ],
- "issueType": "Software",
- "fixableType": "Fixable"
- },
- {
- "date": "2023-03-16",
- "time": "09:15:30",
- "userType": "Kernel",
- "riskPriority": "High",
- "logMessage": "Panic: System halted due to critical hardware failure",
- "eventIDs": [
- "E136"
- ],
- "issueType": "Hardware",
- "fixableType": "Non-Fixable"
- },
- {
- "date": "2023-03-16",
- "time": "13:45:00",
- "userType": "User Logon",
- "riskPriority": "Low",
- "logMessage": "Info: User login successful with MFA",
- "eventIDs": [
- "E137"
- ],
- "issueType": "Hybrid",
- "fixableType": "Fixable"
- },
- {
- "date": "2023-03-17",
- "time": "08:20:15",
- "userType": "System CTL",
- "riskPriority": "Medium",
- "logMessage": "Error: Unexpected response from authentication server",
- "eventIDs": [
- "E138"
- ],
- "issueType": "Software",
- "fixableType": "Fixable"
- },
- {
- "date": "2023-03-17",
- "time": "12:35:50",
- "userType": "Kernel",
- "riskPriority": "High",
- "logMessage": "Critical: Disk failure imminent",
- "eventIDs": [
- "E139",
- "E140"
- ],
- "issueType": "Hardware",
- "fixableType": "Non-Fixable"
- },
- {
- "date": "2023-03-18",
- "time": "09:50:00",
- "userType": "User Logon",
- "riskPriority": "Low",
- "logMessage": "Notice: User logged out successfully",
- "eventIDs": [
- "E141"
- ],
- "issueType": "Hybrid",
- "fixableType": "Fixable"
- },
- {
- "date": "2023-03-18",
- "time": "14:25:30",
- "userType": "System CTL",
- "riskPriority": "Medium",
- "logMessage": "Error: Configuration file not found",
- "eventIDs": [
- "E142"
- ],
- "issueType": "Software",
- "fixableType": "Fixable"
- },
- {
- "date": "2023-03-19",
- "time": "08:10:00",
- "userType": "Kernel",
- "riskPriority": "High",
- "logMessage": "Panic: Memory corruption detected",
- "eventIDs": [
- "E143"
- ],
- "issueType": "Hardware",
- "fixableType": "Non-Fixable"
- },
- {
- "date": "2023-03-19",
- "time": "12:00:00",
- "userType": "User Logon",
- "riskPriority": "Low",
- "logMessage": "Warning: Login attempt from unrecognized device",
- "eventIDs": [
- "E144"
- ],
- "issueType": "Hybrid",
- "fixableType": "Fixable"
- },
- {
- "date": "2023-03-20",
- "time": "09:05:30",
- "userType": "System CTL",
- "riskPriority": "Medium",
- "logMessage": "Error: Timeout while connecting to server",
- "eventIDs": [
- "E145"
- ],
- "issueType": "Software",
- "fixableType": "Fixable"
- },
- {
- "date": "2023-03-20",
- "time": "13:40:00",
- "userType": "Kernel",
- "riskPriority": "High",
- "logMessage": "Critical: Hardware failure in RAID array",
- "eventIDs": [
- "E146"
- ],
- "issueType": "Hardware",
- "fixableType": "Non-Fixable"
- },
- {
- "date": "2023-03-21",
- "time": "08:30:00",
- "userType": "User Logon",
- "riskPriority": "Low",
- "logMessage": "Notice: User account unlocked after verification",
- "eventIDs": [
- "E147"
- ],
- "issueType": "Hybrid",
- "fixableType": "Fixable"
- },
- {
- "date": "2023-03-21",
- "time": "11:50:20",
- "userType": "System CTL",
- "riskPriority": "Medium",
- "logMessage": "Error: Failed to load user profile",
- "eventIDs": [
- "E148"
- ],
- "issueType": "Software",
- "fixableType": "Fixable"
- },
- {
- "date": "2023-03-22",
- "time": "09:00:00",
- "userType": "Kernel",
- "riskPriority": "High",
- "logMessage": "Panic: Critical error in firmware",
- "eventIDs": [
- "E149"
- ],
- "issueType": "Hardware",
- "fixableType": "Non-Fixable"
- },
- {
- "date": "2023-03-22",
- "time": "14:15:30",
- "userType": "User Logon",
- "riskPriority": "Low",
- "logMessage": "Warning: Multiple login attempts detected",
- "eventIDs": [
- "E150"
- ],
- "issueType": "Hybrid",
- "fixableType": "Fixable"
- }
-]
\ No newline at end of file
diff --git a/frontend/src/main.jsx b/frontend/src/main.jsx
index 5fb72d83..a6156fea 100644
--- a/frontend/src/main.jsx
+++ b/frontend/src/main.jsx
@@ -1,22 +1,23 @@
-import { StrictMode } from 'react';
-import { createRoot } from 'react-dom/client';
-import { BrowserRouter as Router, Routes, Route } from 'react-router-dom';
-import App from './App.jsx';
-import './index.css';
+import { StrictMode } from "react";
+import { createRoot } from "react-dom/client";
+import { BrowserRouter as Router, Routes, Route } from "react-router-dom";
+import { StyledEngineProvider } from "@mui/material/styles";
+import App from "./App.jsx";
+import "./index.css";
-const Dashboard = () => (
-
-
Dashboard Coming Soon
-
-);
+function Dashboard() {
+ return
Dashboard
;
+}
-createRoot(document.getElementById('root')).render(
+createRoot(document.getElementById("root")).render(
-
-
- } />
- } />
-
-
+
+
+
+ } />
+ } />
+
+
+
-)
+);
diff --git a/frontend/src/theme/AppTheme.jsx b/frontend/src/theme/AppTheme.jsx
new file mode 100644
index 00000000..b3ad5a4d
--- /dev/null
+++ b/frontend/src/theme/AppTheme.jsx
@@ -0,0 +1,43 @@
+import * as React from "react";
+import { ThemeProvider, createTheme } from "@mui/material/styles";
+import { inputsCustomizations } from "./customizations/inputs";
+import { dataDisplayCustomizations } from "./customizations/dataDisplay";
+import { feedbackCustomizations } from "./customizations/feedback";
+import { navigationCustomizations } from "./customizations/navigation";
+import { surfacesCustomizations } from "./customizations/surfaces";
+import { colorSchemes, typography, shadows, shape } from "./themePrimitives";
+
+export default function AppTheme(props) {
+ const { children, disableCustomTheme, themeComponents } = props;
+ const theme = React.useMemo(() => {
+ return disableCustomTheme
+ ? {}
+ : createTheme({
+ // For more details about CSS variables configuration, see https://mui.com/material-ui/customization/css-theme-variables/configuration/
+ cssVariables: {
+ colorSchemeSelector: "data-mui-color-scheme",
+ cssVarPrefix: "template",
+ },
+ colorSchemes, // Recently added in v6 for building light & dark mode app, see https://mui.com/material-ui/customization/palette/#color-schemes
+ typography,
+ shadows,
+ shape,
+ components: {
+ ...inputsCustomizations,
+ ...dataDisplayCustomizations,
+ ...feedbackCustomizations,
+ ...navigationCustomizations,
+ ...surfacesCustomizations,
+ ...themeComponents,
+ },
+ });
+ }, [disableCustomTheme, themeComponents]);
+ if (disableCustomTheme) {
+ return
{children};
+ }
+ return (
+
+ {children}
+
+ );
+}
diff --git a/frontend/src/theme/ColorModeIconDropdown.jsx b/frontend/src/theme/ColorModeIconDropdown.jsx
new file mode 100644
index 00000000..08a2a13b
--- /dev/null
+++ b/frontend/src/theme/ColorModeIconDropdown.jsx
@@ -0,0 +1,89 @@
+import * as React from "react";
+import DarkModeIcon from "@mui/icons-material/DarkModeRounded";
+import LightModeIcon from "@mui/icons-material/LightModeRounded";
+import Box from "@mui/material/Box";
+import IconButton from "@mui/material/IconButton";
+import Menu from "@mui/material/Menu";
+import MenuItem from "@mui/material/MenuItem";
+import { useColorScheme } from "@mui/material/styles";
+
+export default function ColorModeIconDropdown(props) {
+ const { mode, systemMode, setMode } = useColorScheme();
+ const [anchorEl, setAnchorEl] = React.useState(null);
+ const open = Boolean(anchorEl);
+ const handleClick = (event) => {
+ setAnchorEl(event.currentTarget);
+ };
+ const handleClose = () => {
+ setAnchorEl(null);
+ };
+ const handleMode = (targetMode) => () => {
+ setMode(targetMode);
+ handleClose();
+ };
+ if (!mode) {
+ return (
+
({
+ verticalAlign: "bottom",
+ display: "inline-flex",
+ width: "2.25rem",
+ height: "2.25rem",
+ borderRadius: (theme.vars || theme).shape.borderRadius,
+ border: "1px solid",
+ borderColor: (theme.vars || theme).palette.divider,
+ })}
+ />
+ );
+ }
+ const resolvedMode = systemMode || mode;
+ const icon = {
+ light: ,
+ dark: ,
+ }[resolvedMode];
+ return (
+
+
+ {icon}
+
+
+
+ );
+}
diff --git a/frontend/src/theme/ColorModeSelect.jsx b/frontend/src/theme/ColorModeSelect.jsx
new file mode 100644
index 00000000..b56bb8b5
--- /dev/null
+++ b/frontend/src/theme/ColorModeSelect.jsx
@@ -0,0 +1,25 @@
+import * as React from "react";
+import { useColorScheme } from "@mui/material/styles";
+import MenuItem from "@mui/material/MenuItem";
+import Select from "@mui/material/Select";
+
+export default function ColorModeSelect(props) {
+ const { mode, setMode } = useColorScheme();
+ if (!mode) {
+ return null;
+ }
+ return (
+
+ );
+}
diff --git a/frontend/src/theme/customizations/charts.js b/frontend/src/theme/customizations/charts.js
new file mode 100644
index 00000000..7e075bcb
--- /dev/null
+++ b/frontend/src/theme/customizations/charts.js
@@ -0,0 +1,73 @@
+import { axisClasses, legendClasses, chartsGridClasses } from '@mui/x-charts';
+import { gray } from '../themePrimitives';
+
+export const chartsCustomizations = {
+ MuiChartsAxis: {
+ styleOverrides: {
+ root: ({ theme }) => ({
+ [`& .${axisClasses.line}`]: {
+ stroke: gray[300],
+ },
+ [`& .${axisClasses.tick}`]: { stroke: gray[300] },
+ [`& .${axisClasses.tickLabel}`]: {
+ fill: gray[500],
+ fontWeight: 500,
+ },
+ ...theme.applyStyles('dark', {
+ [`& .${axisClasses.line}`]: {
+ stroke: gray[700],
+ },
+ [`& .${axisClasses.tick}`]: { stroke: gray[700] },
+ [`& .${axisClasses.tickLabel}`]: {
+ fill: gray[300],
+ fontWeight: 500,
+ },
+ }),
+ }),
+ },
+ },
+ MuiChartsTooltip: {
+ styleOverrides: {
+ mark: ({ theme }) => ({
+ ry: 6,
+ boxShadow: 'none',
+ border: `1px solid ${(theme.vars || theme).palette.divider}`,
+ }),
+ table: ({ theme }) => ({
+ border: `1px solid ${(theme.vars || theme).palette.divider}`,
+ borderRadius: theme.shape.borderRadius,
+ background: 'hsl(0, 0%, 100%)',
+ ...theme.applyStyles('dark', {
+ background: gray[900],
+ }),
+ }),
+ },
+ },
+ MuiChartsLegend: {
+ styleOverrides: {
+ root: {
+ [`& .${legendClasses.mark}`]: {
+ ry: 6,
+ },
+ },
+ },
+ },
+ MuiChartsGrid: {
+ styleOverrides: {
+ root: ({ theme }) => ({
+ [`& .${chartsGridClasses.line}`]: {
+ stroke: gray[200],
+ strokeDasharray: '4 2',
+ strokeWidth: 0.8,
+ },
+ ...theme.applyStyles('dark', {
+ [`& .${chartsGridClasses.line}`]: {
+ stroke: gray[700],
+ strokeDasharray: '4 2',
+ strokeWidth: 0.8,
+ },
+ }),
+ }),
+ },
+ },
+};
diff --git a/frontend/src/theme/customizations/dataDisplay.jsx b/frontend/src/theme/customizations/dataDisplay.jsx
new file mode 100644
index 00000000..7e0d71a8
--- /dev/null
+++ b/frontend/src/theme/customizations/dataDisplay.jsx
@@ -0,0 +1,232 @@
+import { alpha } from "@mui/material/styles";
+import { svgIconClasses } from "@mui/material/SvgIcon";
+import { typographyClasses } from "@mui/material/Typography";
+import { buttonBaseClasses } from "@mui/material/ButtonBase";
+import { chipClasses } from "@mui/material/Chip";
+import { iconButtonClasses } from "@mui/material/IconButton";
+import { gray, red, green } from "../themePrimitives";
+
+export const dataDisplayCustomizations = {
+ MuiList: {
+ styleOverrides: {
+ root: {
+ padding: "8px",
+ display: "flex",
+ flexDirection: "column",
+ gap: 0,
+ },
+ },
+ },
+ MuiListItem: {
+ styleOverrides: {
+ root: ({ theme }) => ({
+ [`& .${svgIconClasses.root}`]: {
+ width: "1rem",
+ height: "1rem",
+ color: (theme.vars || theme).palette.text.secondary,
+ },
+ [`& .${typographyClasses.root}`]: {
+ fontWeight: 500,
+ },
+ [`& .${buttonBaseClasses.root}`]: {
+ display: "flex",
+ gap: 8,
+ padding: "2px 8px",
+ borderRadius: (theme.vars || theme).shape.borderRadius,
+ opacity: 0.7,
+ "&.Mui-selected": {
+ opacity: 1,
+ backgroundColor: alpha(theme.palette.action.selected, 0.3),
+ [`& .${svgIconClasses.root}`]: {
+ color: (theme.vars || theme).palette.text.primary,
+ },
+ "&:focus-visible": {
+ backgroundColor: alpha(theme.palette.action.selected, 0.3),
+ },
+ "&:hover": {
+ backgroundColor: alpha(theme.palette.action.selected, 0.5),
+ },
+ },
+ "&:focus-visible": {
+ backgroundColor: "transparent",
+ },
+ },
+ }),
+ },
+ },
+ MuiListItemText: {
+ styleOverrides: {
+ primary: ({ theme }) => ({
+ fontSize: theme.typography.body2.fontSize,
+ fontWeight: 500,
+ lineHeight: theme.typography.body2.lineHeight,
+ }),
+ secondary: ({ theme }) => ({
+ fontSize: theme.typography.caption.fontSize,
+ lineHeight: theme.typography.caption.lineHeight,
+ }),
+ },
+ },
+ MuiListSubheader: {
+ styleOverrides: {
+ root: ({ theme }) => ({
+ backgroundColor: "transparent",
+ padding: "4px 8px",
+ fontSize: theme.typography.caption.fontSize,
+ fontWeight: 500,
+ lineHeight: theme.typography.caption.lineHeight,
+ }),
+ },
+ },
+ MuiListItemIcon: {
+ styleOverrides: {
+ root: {
+ minWidth: 0,
+ },
+ },
+ },
+ MuiChip: {
+ defaultProps: {
+ size: "small",
+ },
+ styleOverrides: {
+ root: ({ theme }) => ({
+ border: "1px solid",
+ borderRadius: "999px",
+ [`& .${chipClasses.label}`]: {
+ fontWeight: 600,
+ },
+ variants: [
+ {
+ props: {
+ color: "default",
+ },
+ style: {
+ borderColor: gray[200],
+ backgroundColor: gray[100],
+ [`& .${chipClasses.label}`]: {
+ color: gray[500],
+ },
+ [`& .${chipClasses.icon}`]: {
+ color: gray[500],
+ },
+ ...theme.applyStyles("dark", {
+ borderColor: gray[700],
+ backgroundColor: gray[800],
+ [`& .${chipClasses.label}`]: {
+ color: gray[300],
+ },
+ [`& .${chipClasses.icon}`]: {
+ color: gray[300],
+ },
+ }),
+ },
+ },
+ {
+ props: {
+ color: "success",
+ },
+ style: {
+ borderColor: green[200],
+ backgroundColor: green[50],
+ [`& .${chipClasses.label}`]: {
+ color: green[500],
+ },
+ [`& .${chipClasses.icon}`]: {
+ color: green[500],
+ },
+ ...theme.applyStyles("dark", {
+ borderColor: green[800],
+ backgroundColor: green[900],
+ [`& .${chipClasses.label}`]: {
+ color: green[300],
+ },
+ [`& .${chipClasses.icon}`]: {
+ color: green[300],
+ },
+ }),
+ },
+ },
+ {
+ props: {
+ color: "error",
+ },
+ style: {
+ borderColor: red[100],
+ backgroundColor: red[50],
+ [`& .${chipClasses.label}`]: {
+ color: red[500],
+ },
+ [`& .${chipClasses.icon}`]: {
+ color: red[500],
+ },
+ ...theme.applyStyles("dark", {
+ borderColor: red[800],
+ backgroundColor: red[900],
+ [`& .${chipClasses.label}`]: {
+ color: red[200],
+ },
+ [`& .${chipClasses.icon}`]: {
+ color: red[300],
+ },
+ }),
+ },
+ },
+ {
+ props: { size: "small" },
+ style: {
+ maxHeight: 20,
+ [`& .${chipClasses.label}`]: {
+ fontSize: theme.typography.caption.fontSize,
+ },
+ [`& .${svgIconClasses.root}`]: {
+ fontSize: theme.typography.caption.fontSize,
+ },
+ },
+ },
+ {
+ props: { size: "medium" },
+ style: {
+ [`& .${chipClasses.label}`]: {
+ fontSize: theme.typography.caption.fontSize,
+ },
+ },
+ },
+ ],
+ }),
+ },
+ },
+ MuiTablePagination: {
+ styleOverrides: {
+ actions: {
+ display: "flex",
+ gap: 8,
+ marginRight: 6,
+ [`& .${iconButtonClasses.root}`]: {
+ minWidth: 0,
+ width: 36,
+ height: 36,
+ },
+ },
+ },
+ },
+ MuiIcon: {
+ defaultProps: {
+ fontSize: "small",
+ },
+ styleOverrides: {
+ root: {
+ variants: [
+ {
+ props: {
+ fontSize: "small",
+ },
+ style: {
+ fontSize: "1rem",
+ },
+ },
+ ],
+ },
+ },
+ },
+};
diff --git a/frontend/src/theme/customizations/dataGrid.js b/frontend/src/theme/customizations/dataGrid.js
new file mode 100644
index 00000000..6127b19b
--- /dev/null
+++ b/frontend/src/theme/customizations/dataGrid.js
@@ -0,0 +1,130 @@
+import { paperClasses } from '@mui/material/Paper';
+import { alpha } from '@mui/material/styles';
+import { menuItemClasses } from '@mui/material/MenuItem';
+import { listItemIconClasses } from '@mui/material/ListItemIcon';
+import { iconButtonClasses } from '@mui/material/IconButton';
+import { checkboxClasses } from '@mui/material/Checkbox';
+import { listClasses } from '@mui/material/List';
+import { gridClasses } from '@mui/x-data-grid';
+import { tablePaginationClasses } from '@mui/material/TablePagination';
+import { gray } from '../themePrimitives';
+
+export const dataGridCustomizations= {
+ MuiDataGrid: {
+ styleOverrides: {
+ root: ({ theme }) => ({
+ '--DataGrid-overlayHeight': '300px',
+ overflow: 'clip',
+ borderColor: (theme.vars || theme).palette.divider,
+ backgroundColor: (theme.vars || theme).palette.background.default,
+ [`& .${gridClasses.columnHeader}`]: {
+ backgroundColor: (theme.vars || theme).palette.background.paper,
+ },
+ [`& .${gridClasses.footerContainer}`]: {
+ backgroundColor: (theme.vars || theme).palette.background.paper,
+ },
+ [`& .${checkboxClasses.root}`]: {
+ padding: theme.spacing(0.5),
+ '& > svg': {
+ fontSize: '1rem',
+ },
+ },
+ [`& .${tablePaginationClasses.root}`]: {
+ marginRight: theme.spacing(1),
+ '& .MuiIconButton-root': {
+ maxHeight: 32,
+ maxWidth: 32,
+ '& > svg': {
+ fontSize: '1rem',
+ },
+ },
+ },
+ }),
+ cell: ({ theme }) => ({ borderTopColor: (theme.vars || theme).palette.divider }),
+ menu: ({ theme }) => ({
+ borderRadius: theme.shape.borderRadius,
+ backgroundImage: 'none',
+ [`& .${paperClasses.root}`]: {
+ border: `1px solid ${(theme.vars || theme).palette.divider}`,
+ },
+
+ [`& .${menuItemClasses.root}`]: {
+ margin: '0 4px',
+ },
+ [`& .${listItemIconClasses.root}`]: {
+ marginRight: 0,
+ },
+ [`& .${listClasses.root}`]: {
+ paddingLeft: 0,
+ paddingRight: 0,
+ },
+ }),
+
+ row: ({ theme }) => ({
+ '&:last-of-type': { borderBottom: `1px solid ${(theme.vars || theme).palette.divider}` },
+ '&:hover': {
+ backgroundColor: (theme.vars || theme).palette.action.hover,
+ },
+ '&.Mui-selected': {
+ background: (theme.vars || theme).palette.action.selected,
+ '&:hover': {
+ backgroundColor: (theme.vars || theme).palette.action.hover,
+ },
+ },
+ }),
+ iconButtonContainer: ({ theme }) => ({
+ [`& .${iconButtonClasses.root}`]: {
+ border: 'none',
+ backgroundColor: 'transparent',
+ '&:hover': {
+ backgroundColor: alpha(theme.palette.action.selected, 0.3),
+ },
+ '&:active': {
+ backgroundColor: gray[200],
+ },
+ ...theme.applyStyles('dark', {
+ color: gray[50],
+ '&:hover': {
+ backgroundColor: gray[800],
+ },
+ '&:active': {
+ backgroundColor: gray[900],
+ },
+ }),
+ },
+ }),
+ menuIconButton: ({ theme }) => ({
+ border: 'none',
+ backgroundColor: 'transparent',
+ '&:hover': {
+ backgroundColor: gray[100],
+ },
+ '&:active': {
+ backgroundColor: gray[200],
+ },
+ ...theme.applyStyles('dark', {
+ color: gray[50],
+ '&:hover': {
+ backgroundColor: gray[800],
+ },
+ '&:active': {
+ backgroundColor: gray[900],
+ },
+ }),
+ }),
+ filterForm: ({ theme }) => ({
+ gap: theme.spacing(1),
+ alignItems: 'flex-end',
+ }),
+ columnsManagementHeader: ({ theme }) => ({
+ paddingRight: theme.spacing(3),
+ paddingLeft: theme.spacing(3),
+ }),
+ columnHeaderTitleContainer: {
+ flexGrow: 1,
+ justifyContent: 'space-between',
+ },
+ columnHeaderDraggableContainer: { paddingRight: 2 },
+ },
+ },
+};
diff --git a/frontend/src/theme/customizations/datePickers.js b/frontend/src/theme/customizations/datePickers.js
new file mode 100644
index 00000000..58e5e08a
--- /dev/null
+++ b/frontend/src/theme/customizations/datePickers.js
@@ -0,0 +1,170 @@
+import { alpha } from '@mui/material/styles';
+import { pickersYearClasses, pickersMonthClasses, pickersDayClasses } from '@mui/x-date-pickers';
+import { menuItemClasses } from '@mui/material/MenuItem';
+import { gray, brand } from '../themePrimitives';
+
+export const datePickersCustomizations= {
+ MuiPickersPopper: {
+ styleOverrides: {
+ paper: ({ theme }) => ({
+ marginTop: 4,
+ borderRadius: theme.shape.borderRadius,
+ border: `1px solid ${(theme.vars || theme).palette.divider}`,
+ backgroundImage: 'none',
+ background: 'hsl(0, 0%, 100%)',
+ boxShadow:
+ 'hsla(220, 30%, 5%, 0.07) 0px 4px 16px 0px, hsla(220, 25%, 10%, 0.07) 0px 8px 16px -5px',
+ [`& .${menuItemClasses.root}`]: {
+ borderRadius: 6,
+ margin: '0 6px',
+ },
+ ...theme.applyStyles('dark', {
+ background: gray[900],
+ boxShadow:
+ 'hsla(220, 30%, 5%, 0.7) 0px 4px 16px 0px, hsla(220, 25%, 10%, 0.8) 0px 8px 16px -5px',
+ }),
+ }),
+ },
+ },
+ MuiPickersArrowSwitcher: {
+ styleOverrides: {
+ spacer: { width: 16 },
+ button: ({ theme }) => ({
+ backgroundColor: 'transparent',
+ color: (theme.vars || theme).palette.grey[500],
+ ...theme.applyStyles('dark', {
+ color: (theme.vars || theme).palette.grey[400],
+ }),
+ }),
+ },
+ },
+ MuiPickersCalendarHeader: {
+ styleOverrides: {
+ switchViewButton: {
+ padding: 0,
+ border: 'none',
+ },
+ },
+ },
+ MuiPickersMonth: {
+ styleOverrides: {
+ monthButton: ({ theme }) => ({
+ fontSize: theme.typography.body1.fontSize,
+ color: (theme.vars || theme).palette.grey[600],
+ padding: theme.spacing(0.5),
+ borderRadius: theme.shape.borderRadius,
+ '&:hover': {
+ backgroundColor: (theme.vars || theme).palette.action.hover,
+ },
+ [`&.${pickersMonthClasses.selected}`]: {
+ backgroundColor: gray[700],
+ fontWeight: theme.typography.fontWeightMedium,
+ },
+ '&:focus': {
+ outline: `3px solid ${alpha(brand[500], 0.5)}`,
+ outlineOffset: '2px',
+ backgroundColor: 'transparent',
+ [`&.${pickersMonthClasses.selected}`]: { backgroundColor: gray[700] },
+ },
+ ...theme.applyStyles('dark', {
+ color: (theme.vars || theme).palette.grey[300],
+ '&:hover': {
+ backgroundColor: (theme.vars || theme).palette.action.hover,
+ },
+ [`&.${pickersMonthClasses.selected}`]: {
+ color: (theme.vars || theme).palette.common.black,
+ fontWeight: theme.typography.fontWeightMedium,
+ backgroundColor: gray[300],
+ },
+ '&:focus': {
+ outline: `3px solid ${alpha(brand[500], 0.5)}`,
+ outlineOffset: '2px',
+ backgroundColor: 'transparent',
+ [`&.${pickersMonthClasses.selected}`]: { backgroundColor: gray[300] },
+ },
+ }),
+ }),
+ },
+ },
+ MuiPickersYear: {
+ styleOverrides: {
+ yearButton: ({ theme }) => ({
+ fontSize: theme.typography.body1.fontSize,
+ color: (theme.vars || theme).palette.grey[600],
+ padding: theme.spacing(0.5),
+ borderRadius: theme.shape.borderRadius,
+ height: 'fit-content',
+ '&:hover': {
+ backgroundColor: (theme.vars || theme).palette.action.hover,
+ },
+ [`&.${pickersYearClasses.selected}`]: {
+ backgroundColor: gray[700],
+ fontWeight: theme.typography.fontWeightMedium,
+ },
+ '&:focus': {
+ outline: `3px solid ${alpha(brand[500], 0.5)}`,
+ outlineOffset: '2px',
+ backgroundColor: 'transparent',
+ [`&.${pickersYearClasses.selected}`]: { backgroundColor: gray[700] },
+ },
+ ...theme.applyStyles('dark', {
+ color: (theme.vars || theme).palette.grey[300],
+ '&:hover': {
+ backgroundColor: (theme.vars || theme).palette.action.hover,
+ },
+ [`&.${pickersYearClasses.selected}`]: {
+ color: (theme.vars || theme).palette.common.black,
+ fontWeight: theme.typography.fontWeightMedium,
+ backgroundColor: gray[300],
+ },
+ '&:focus': {
+ outline: `3px solid ${alpha(brand[500], 0.5)}`,
+ outlineOffset: '2px',
+ backgroundColor: 'transparent',
+ [`&.${pickersYearClasses.selected}`]: { backgroundColor: gray[300] },
+ },
+ }),
+ }),
+ },
+ },
+ MuiPickersDay: {
+ styleOverrides: {
+ root: ({ theme }) => ({
+ fontSize: theme.typography.body1.fontSize,
+ color: (theme.vars || theme).palette.grey[600],
+ padding: theme.spacing(0.5),
+ borderRadius: theme.shape.borderRadius,
+ '&:hover': {
+ backgroundColor: (theme.vars || theme).palette.action.hover,
+ },
+ [`&.${pickersDayClasses.selected}`]: {
+ backgroundColor: gray[700],
+ fontWeight: theme.typography.fontWeightMedium,
+ },
+ '&:focus': {
+ outline: `3px solid ${alpha(brand[500], 0.5)}`,
+ outlineOffset: '2px',
+ backgroundColor: 'transparent',
+ [`&.${pickersDayClasses.selected}`]: { backgroundColor: gray[700] },
+ },
+ ...theme.applyStyles('dark', {
+ color: (theme.vars || theme).palette.grey[300],
+ '&:hover': {
+ backgroundColor: (theme.vars || theme).palette.action.hover,
+ },
+ [`&.${pickersDayClasses.selected}`]: {
+ color: (theme.vars || theme).palette.common.black,
+ fontWeight: theme.typography.fontWeightMedium,
+ backgroundColor: gray[300],
+ },
+ '&:focus': {
+ outline: `3px solid ${alpha(brand[500], 0.5)}`,
+ outlineOffset: '2px',
+ backgroundColor: 'transparent',
+ [`&.${pickersDayClasses.selected}`]: { backgroundColor: gray[300] },
+ },
+ }),
+ }),
+ },
+ },
+};
diff --git a/frontend/src/theme/customizations/feedback.jsx b/frontend/src/theme/customizations/feedback.jsx
new file mode 100644
index 00000000..067aef40
--- /dev/null
+++ b/frontend/src/theme/customizations/feedback.jsx
@@ -0,0 +1,45 @@
+import { alpha } from "@mui/material/styles";
+import { gray, orange } from "../themePrimitives";
+
+export const feedbackCustomizations = {
+ MuiAlert: {
+ styleOverrides: {
+ root: ({ theme }) => ({
+ borderRadius: 10,
+ backgroundColor: orange[100],
+ color: (theme.vars || theme).palette.text.primary,
+ border: `1px solid ${alpha(orange[300], 0.5)}`,
+ "& .MuiAlert-icon": {
+ color: orange[500],
+ },
+ ...theme.applyStyles("dark", {
+ backgroundColor: `${alpha(orange[900], 0.5)}`,
+ border: `1px solid ${alpha(orange[800], 0.5)}`,
+ }),
+ }),
+ },
+ },
+ MuiDialog: {
+ styleOverrides: {
+ root: ({ theme }) => ({
+ "& .MuiDialog-paper": {
+ borderRadius: "10px",
+ border: "1px solid",
+ borderColor: (theme.vars || theme).palette.divider,
+ },
+ }),
+ },
+ },
+ MuiLinearProgress: {
+ styleOverrides: {
+ root: ({ theme }) => ({
+ height: 8,
+ borderRadius: 8,
+ backgroundColor: gray[200],
+ ...theme.applyStyles("dark", {
+ backgroundColor: gray[800],
+ }),
+ }),
+ },
+ },
+};
diff --git a/frontend/src/theme/customizations/inputs.jsx b/frontend/src/theme/customizations/inputs.jsx
new file mode 100644
index 00000000..07db6419
--- /dev/null
+++ b/frontend/src/theme/customizations/inputs.jsx
@@ -0,0 +1,452 @@
+import * as React from "react";
+import { alpha } from "@mui/material/styles";
+import { outlinedInputClasses } from "@mui/material/OutlinedInput";
+import { svgIconClasses } from "@mui/material/SvgIcon";
+import { toggleButtonGroupClasses } from "@mui/material/ToggleButtonGroup";
+import { toggleButtonClasses } from "@mui/material/ToggleButton";
+import CheckBoxOutlineBlankRoundedIcon from "@mui/icons-material/CheckBoxOutlineBlankRounded";
+import CheckRoundedIcon from "@mui/icons-material/CheckRounded";
+import RemoveRoundedIcon from "@mui/icons-material/RemoveRounded";
+import { gray, brand } from "../themePrimitives";
+
+export const inputsCustomizations = {
+ MuiButtonBase: {
+ defaultProps: {
+ disableTouchRipple: true,
+ disableRipple: true,
+ },
+ styleOverrides: {
+ root: ({ theme }) => ({
+ boxSizing: "border-box",
+ transition: "all 100ms ease-in",
+ "&:focus-visible": {
+ outline: `3px solid ${alpha(theme.palette.primary.main, 0.5)}`,
+ outlineOffset: "2px",
+ },
+ }),
+ },
+ },
+ MuiButton: {
+ styleOverrides: {
+ root: ({ theme }) => ({
+ boxShadow: "none",
+ borderRadius: (theme.vars || theme).shape.borderRadius,
+ textTransform: "none",
+ variants: [
+ {
+ props: {
+ size: "small",
+ },
+ style: {
+ height: "2.25rem",
+ padding: "8px 12px",
+ },
+ },
+ {
+ props: {
+ size: "medium",
+ },
+ style: {
+ height: "2.5rem", // 40px
+ },
+ },
+ {
+ props: {
+ color: "primary",
+ variant: "contained",
+ },
+ style: {
+ color: "white",
+ backgroundColor: gray[900],
+ backgroundImage: `linear-gradient(to bottom, ${gray[700]}, ${gray[800]})`,
+ boxShadow: `inset 0 1px 0 ${gray[600]}, inset 0 -1px 0 1px hsl(220, 0%, 0%)`,
+ border: `1px solid ${gray[700]}`,
+ "&:hover": {
+ backgroundImage: "none",
+ backgroundColor: gray[700],
+ boxShadow: "none",
+ },
+ "&:active": {
+ backgroundColor: gray[800],
+ },
+ ...theme.applyStyles("dark", {
+ color: "black",
+ backgroundColor: gray[50],
+ backgroundImage: `linear-gradient(to bottom, ${gray[100]}, ${gray[50]})`,
+ boxShadow: "inset 0 -1px 0 hsl(220, 30%, 80%)",
+ border: `1px solid ${gray[50]}`,
+ "&:hover": {
+ backgroundImage: "none",
+ backgroundColor: gray[300],
+ boxShadow: "none",
+ },
+ "&:active": {
+ backgroundColor: gray[400],
+ },
+ }),
+ },
+ },
+ {
+ props: {
+ color: "secondary",
+ variant: "contained",
+ },
+ style: {
+ color: "white",
+ backgroundColor: brand[300],
+ backgroundImage: `linear-gradient(to bottom, ${alpha(
+ brand[400],
+ 0.8
+ )}, ${brand[500]})`,
+ boxShadow: `inset 0 2px 0 ${alpha(
+ brand[200],
+ 0.2
+ )}, inset 0 -2px 0 ${alpha(brand[700], 0.4)}`,
+ border: `1px solid ${brand[500]}`,
+ "&:hover": {
+ backgroundColor: brand[700],
+ boxShadow: "none",
+ },
+ "&:active": {
+ backgroundColor: brand[700],
+ backgroundImage: "none",
+ },
+ },
+ },
+ {
+ props: {
+ variant: "outlined",
+ },
+ style: {
+ color: (theme.vars || theme).palette.text.primary,
+ border: "1px solid",
+ borderColor: gray[200],
+ backgroundColor: alpha(gray[50], 0.3),
+ "&:hover": {
+ backgroundColor: gray[100],
+ borderColor: gray[300],
+ },
+ "&:active": {
+ backgroundColor: gray[200],
+ },
+ ...theme.applyStyles("dark", {
+ backgroundColor: gray[800],
+ borderColor: gray[700],
+
+ "&:hover": {
+ backgroundColor: gray[900],
+ borderColor: gray[600],
+ },
+ "&:active": {
+ backgroundColor: gray[900],
+ },
+ }),
+ },
+ },
+ {
+ props: {
+ color: "secondary",
+ variant: "outlined",
+ },
+ style: {
+ color: brand[700],
+ border: "1px solid",
+ borderColor: brand[200],
+ backgroundColor: brand[50],
+ "&:hover": {
+ backgroundColor: brand[100],
+ borderColor: brand[400],
+ },
+ "&:active": {
+ backgroundColor: alpha(brand[200], 0.7),
+ },
+ ...theme.applyStyles("dark", {
+ color: brand[50],
+ border: "1px solid",
+ borderColor: brand[900],
+ backgroundColor: alpha(brand[900], 0.3),
+ "&:hover": {
+ borderColor: brand[700],
+ backgroundColor: alpha(brand[900], 0.6),
+ },
+ "&:active": {
+ backgroundColor: alpha(brand[900], 0.5),
+ },
+ }),
+ },
+ },
+ {
+ props: {
+ variant: "text",
+ },
+ style: {
+ color: gray[600],
+ "&:hover": {
+ backgroundColor: gray[100],
+ },
+ "&:active": {
+ backgroundColor: gray[200],
+ },
+ ...theme.applyStyles("dark", {
+ color: gray[50],
+ "&:hover": {
+ backgroundColor: gray[700],
+ },
+ "&:active": {
+ backgroundColor: alpha(gray[700], 0.7),
+ },
+ }),
+ },
+ },
+ {
+ props: {
+ color: "secondary",
+ variant: "text",
+ },
+ style: {
+ color: brand[700],
+ "&:hover": {
+ backgroundColor: alpha(brand[100], 0.5),
+ },
+ "&:active": {
+ backgroundColor: alpha(brand[200], 0.7),
+ },
+ ...theme.applyStyles("dark", {
+ color: brand[100],
+ "&:hover": {
+ backgroundColor: alpha(brand[900], 0.5),
+ },
+ "&:active": {
+ backgroundColor: alpha(brand[900], 0.3),
+ },
+ }),
+ },
+ },
+ ],
+ }),
+ },
+ },
+ MuiIconButton: {
+ styleOverrides: {
+ root: ({ theme }) => ({
+ boxShadow: "none",
+ borderRadius: (theme.vars || theme).shape.borderRadius,
+ textTransform: "none",
+ fontWeight: theme.typography.fontWeightMedium,
+ letterSpacing: 0,
+ color: (theme.vars || theme).palette.text.primary,
+ border: "1px solid ",
+ borderColor: gray[200],
+ backgroundColor: alpha(gray[50], 0.3),
+ "&:hover": {
+ backgroundColor: gray[100],
+ borderColor: gray[300],
+ },
+ "&:active": {
+ backgroundColor: gray[200],
+ },
+ ...theme.applyStyles("dark", {
+ backgroundColor: gray[800],
+ borderColor: gray[700],
+ "&:hover": {
+ backgroundColor: gray[900],
+ borderColor: gray[600],
+ },
+ "&:active": {
+ backgroundColor: gray[900],
+ },
+ }),
+ variants: [
+ {
+ props: {
+ size: "small",
+ },
+ style: {
+ width: "2.25rem",
+ height: "2.25rem",
+ padding: "0.25rem",
+ [`& .${svgIconClasses.root}`]: { fontSize: "1rem" },
+ },
+ },
+ {
+ props: {
+ size: "medium",
+ },
+ style: {
+ width: "2.5rem",
+ height: "2.5rem",
+ },
+ },
+ ],
+ }),
+ },
+ },
+ MuiToggleButtonGroup: {
+ styleOverrides: {
+ root: ({ theme }) => ({
+ borderRadius: "10px",
+ boxShadow: `0 4px 16px ${alpha(gray[400], 0.2)}`,
+ [`& .${toggleButtonGroupClasses.selected}`]: {
+ color: brand[500],
+ },
+ ...theme.applyStyles("dark", {
+ [`& .${toggleButtonGroupClasses.selected}`]: {
+ color: "#fff",
+ },
+ boxShadow: `0 4px 16px ${alpha(brand[700], 0.5)}`,
+ }),
+ }),
+ },
+ },
+ MuiToggleButton: {
+ styleOverrides: {
+ root: ({ theme }) => ({
+ padding: "12px 16px",
+ textTransform: "none",
+ borderRadius: "10px",
+ fontWeight: 500,
+ ...theme.applyStyles("dark", {
+ color: gray[400],
+ boxShadow: "0 4px 16px rgba(0, 0, 0, 0.5)",
+ [`&.${toggleButtonClasses.selected}`]: {
+ color: brand[300],
+ },
+ }),
+ }),
+ },
+ },
+ MuiCheckbox: {
+ defaultProps: {
+ disableRipple: true,
+ icon: (
+
+ ),
+ checkedIcon: ,
+ indeterminateIcon: ,
+ },
+ styleOverrides: {
+ root: ({ theme }) => ({
+ margin: 10,
+ height: 16,
+ width: 16,
+ borderRadius: 5,
+ border: "1px solid ",
+ borderColor: alpha(gray[300], 0.8),
+ boxShadow: "0 0 0 1.5px hsla(210, 0%, 0%, 0.04) inset",
+ backgroundColor: alpha(gray[100], 0.4),
+ transition: "border-color, background-color, 120ms ease-in",
+ "&:hover": {
+ borderColor: brand[300],
+ },
+ "&.Mui-focusVisible": {
+ outline: `3px solid ${alpha(brand[500], 0.5)}`,
+ outlineOffset: "2px",
+ borderColor: brand[400],
+ },
+ "&.Mui-checked": {
+ color: "white",
+ backgroundColor: brand[500],
+ borderColor: brand[500],
+ boxShadow: `none`,
+ "&:hover": {
+ backgroundColor: brand[600],
+ },
+ },
+ ...theme.applyStyles("dark", {
+ borderColor: alpha(gray[700], 0.8),
+ boxShadow: "0 0 0 1.5px hsl(210, 0%, 0%) inset",
+ backgroundColor: alpha(gray[900], 0.8),
+ "&:hover": {
+ borderColor: brand[300],
+ },
+ "&.Mui-focusVisible": {
+ borderColor: brand[400],
+ outline: `3px solid ${alpha(brand[500], 0.5)}`,
+ outlineOffset: "2px",
+ },
+ }),
+ }),
+ },
+ },
+ MuiInputBase: {
+ styleOverrides: {
+ root: {
+ border: "none",
+ },
+ input: {
+ "&::placeholder": {
+ opacity: 0.7,
+ color: gray[500],
+ },
+ },
+ },
+ },
+ MuiOutlinedInput: {
+ styleOverrides: {
+ input: {
+ padding: 0,
+ },
+ root: ({ theme }) => ({
+ padding: "8px 12px",
+ color: (theme.vars || theme).palette.text.primary,
+ borderRadius: (theme.vars || theme).shape.borderRadius,
+ border: `1px solid ${(theme.vars || theme).palette.divider}`,
+ backgroundColor: (theme.vars || theme).palette.background.default,
+ transition: "border 120ms ease-in",
+ "&:hover": {
+ borderColor: gray[400],
+ },
+ [`&.${outlinedInputClasses.focused}`]: {
+ outline: `3px solid ${alpha(brand[500], 0.5)}`,
+ borderColor: brand[400],
+ },
+ ...theme.applyStyles("dark", {
+ "&:hover": {
+ borderColor: gray[500],
+ },
+ }),
+ variants: [
+ {
+ props: {
+ size: "small",
+ },
+ style: {
+ height: "2.25rem",
+ },
+ },
+ {
+ props: {
+ size: "medium",
+ },
+ style: {
+ height: "2.5rem",
+ },
+ },
+ ],
+ }),
+ notchedOutline: {
+ border: "none",
+ },
+ },
+ },
+ MuiInputAdornment: {
+ styleOverrides: {
+ root: ({ theme }) => ({
+ color: (theme.vars || theme).palette.grey[500],
+ ...theme.applyStyles("dark", {
+ color: (theme.vars || theme).palette.grey[400],
+ }),
+ }),
+ },
+ },
+ MuiFormLabel: {
+ styleOverrides: {
+ root: ({ theme }) => ({
+ typography: theme.typography.caption,
+ marginBottom: 8,
+ }),
+ },
+ },
+};
diff --git a/frontend/src/theme/customizations/navigation.jsx b/frontend/src/theme/customizations/navigation.jsx
new file mode 100644
index 00000000..9e9ae493
--- /dev/null
+++ b/frontend/src/theme/customizations/navigation.jsx
@@ -0,0 +1,280 @@
+import * as React from "react";
+import { alpha } from "@mui/material/styles";
+import { buttonBaseClasses } from "@mui/material/ButtonBase";
+import { dividerClasses } from "@mui/material/Divider";
+import { menuItemClasses } from "@mui/material/MenuItem";
+import { selectClasses } from "@mui/material/Select";
+import { tabClasses } from "@mui/material/Tab";
+import UnfoldMoreRoundedIcon from "@mui/icons-material/UnfoldMoreRounded";
+import { gray, brand } from "../themePrimitives";
+
+export const navigationCustomizations = {
+ MuiMenuItem: {
+ styleOverrides: {
+ root: ({ theme }) => ({
+ borderRadius: (theme.vars || theme).shape.borderRadius,
+ padding: "6px 8px",
+ [`&.${menuItemClasses.focusVisible}`]: {
+ backgroundColor: "transparent",
+ },
+ [`&.${menuItemClasses.selected}`]: {
+ [`&.${menuItemClasses.focusVisible}`]: {
+ backgroundColor: alpha(theme.palette.action.selected, 0.3),
+ },
+ },
+ }),
+ },
+ },
+ MuiMenu: {
+ styleOverrides: {
+ list: {
+ gap: "0px",
+ [`&.${dividerClasses.root}`]: {
+ margin: "0 -8px",
+ },
+ },
+ paper: ({ theme }) => ({
+ marginTop: "4px",
+ borderRadius: (theme.vars || theme).shape.borderRadius,
+ border: `1px solid ${(theme.vars || theme).palette.divider}`,
+ backgroundImage: "none",
+ background: "hsl(0, 0%, 100%)",
+ boxShadow:
+ "hsla(220, 30%, 5%, 0.07) 0px 4px 16px 0px, hsla(220, 25%, 10%, 0.07) 0px 8px 16px -5px",
+ [`& .${buttonBaseClasses.root}`]: {
+ "&.Mui-selected": {
+ backgroundColor: alpha(theme.palette.action.selected, 0.3),
+ },
+ },
+ ...theme.applyStyles("dark", {
+ background: gray[900],
+ boxShadow:
+ "hsla(220, 30%, 5%, 0.7) 0px 4px 16px 0px, hsla(220, 25%, 10%, 0.8) 0px 8px 16px -5px",
+ }),
+ }),
+ },
+ },
+ MuiSelect: {
+ defaultProps: {
+ IconComponent: React.forwardRef((props, ref) => (
+
+ )),
+ },
+ styleOverrides: {
+ root: ({ theme }) => ({
+ borderRadius: (theme.vars || theme).shape.borderRadius,
+ border: "1px solid",
+ borderColor: gray[200],
+ backgroundColor: (theme.vars || theme).palette.background.paper,
+ boxShadow: `inset 0 1px 0 1px hsla(220, 0%, 100%, 0.6), inset 0 -1px 0 1px hsla(220, 35%, 90%, 0.5)`,
+ "&:hover": {
+ borderColor: gray[300],
+ backgroundColor: (theme.vars || theme).palette.background.paper,
+ boxShadow: "none",
+ },
+ [`&.${selectClasses.focused}`]: {
+ outlineOffset: 0,
+ borderColor: gray[400],
+ },
+ "&:before, &:after": {
+ display: "none",
+ },
+
+ ...theme.applyStyles("dark", {
+ borderRadius: (theme.vars || theme).shape.borderRadius,
+ borderColor: gray[700],
+ backgroundColor: (theme.vars || theme).palette.background.paper,
+ boxShadow: `inset 0 1px 0 1px ${alpha(
+ gray[700],
+ 0.15
+ )}, inset 0 -1px 0 1px hsla(220, 0%, 0%, 0.7)`,
+ "&:hover": {
+ borderColor: alpha(gray[700], 0.7),
+ backgroundColor: (theme.vars || theme).palette.background.paper,
+ boxShadow: "none",
+ },
+ [`&.${selectClasses.focused}`]: {
+ outlineOffset: 0,
+ borderColor: gray[900],
+ },
+ "&:before, &:after": {
+ display: "none",
+ },
+ }),
+ }),
+ select: ({ theme }) => ({
+ display: "flex",
+ alignItems: "center",
+ ...theme.applyStyles("dark", {
+ display: "flex",
+ alignItems: "center",
+ "&:focus-visible": {
+ backgroundColor: gray[900],
+ },
+ }),
+ }),
+ },
+ },
+ MuiLink: {
+ defaultProps: {
+ underline: "none",
+ },
+ styleOverrides: {
+ root: ({ theme }) => ({
+ color: (theme.vars || theme).palette.text.primary,
+ fontWeight: 500,
+ position: "relative",
+ textDecoration: "none",
+ width: "fit-content",
+ "&::before": {
+ content: '""',
+ position: "absolute",
+ width: "100%",
+ height: "1px",
+ bottom: 0,
+ left: 0,
+ backgroundColor: (theme.vars || theme).palette.text.secondary,
+ opacity: 0.3,
+ transition: "width 0.3s ease, opacity 0.3s ease",
+ },
+ "&:hover::before": {
+ width: 0,
+ },
+ "&:focus-visible": {
+ outline: `3px solid ${alpha(brand[500], 0.5)}`,
+ outlineOffset: "4px",
+ borderRadius: "2px",
+ },
+ }),
+ },
+ },
+ MuiDrawer: {
+ styleOverrides: {
+ paper: ({ theme }) => ({
+ backgroundColor: (theme.vars || theme).palette.background.default,
+ }),
+ },
+ },
+ MuiPaginationItem: {
+ styleOverrides: {
+ root: ({ theme }) => ({
+ "&.Mui-selected": {
+ color: "white",
+ backgroundColor: (theme.vars || theme).palette.grey[900],
+ },
+ ...theme.applyStyles("dark", {
+ "&.Mui-selected": {
+ color: "black",
+ backgroundColor: (theme.vars || theme).palette.grey[50],
+ },
+ }),
+ }),
+ },
+ },
+ MuiTabs: {
+ styleOverrides: {
+ root: { minHeight: "fit-content" },
+ indicator: ({ theme }) => ({
+ backgroundColor: (theme.vars || theme).palette.grey[800],
+ ...theme.applyStyles("dark", {
+ backgroundColor: (theme.vars || theme).palette.grey[200],
+ }),
+ }),
+ },
+ },
+ MuiTab: {
+ styleOverrides: {
+ root: ({ theme }) => ({
+ padding: "6px 8px",
+ marginBottom: "8px",
+ textTransform: "none",
+ minWidth: "fit-content",
+ minHeight: "fit-content",
+ color: (theme.vars || theme).palette.text.secondary,
+ borderRadius: (theme.vars || theme).shape.borderRadius,
+ border: "1px solid",
+ borderColor: "transparent",
+ ":hover": {
+ color: (theme.vars || theme).palette.text.primary,
+ backgroundColor: gray[100],
+ borderColor: gray[200],
+ },
+ [`&.${tabClasses.selected}`]: {
+ color: gray[900],
+ },
+ ...theme.applyStyles("dark", {
+ ":hover": {
+ color: (theme.vars || theme).palette.text.primary,
+ backgroundColor: gray[800],
+ borderColor: gray[700],
+ },
+ [`&.${tabClasses.selected}`]: {
+ color: "#fff",
+ },
+ }),
+ }),
+ },
+ },
+ MuiStepConnector: {
+ styleOverrides: {
+ line: ({ theme }) => ({
+ borderTop: "1px solid",
+ borderColor: (theme.vars || theme).palette.divider,
+ flex: 1,
+ borderRadius: "99px",
+ }),
+ },
+ },
+ MuiStepIcon: {
+ styleOverrides: {
+ root: ({ theme }) => ({
+ color: "transparent",
+ border: `1px solid ${gray[400]}`,
+ width: 12,
+ height: 12,
+ borderRadius: "50%",
+ "& text": {
+ display: "none",
+ },
+ "&.Mui-active": {
+ border: "none",
+ color: (theme.vars || theme).palette.primary.main,
+ },
+ "&.Mui-completed": {
+ border: "none",
+ color: (theme.vars || theme).palette.success.main,
+ },
+ ...theme.applyStyles("dark", {
+ border: `1px solid ${gray[700]}`,
+ "&.Mui-active": {
+ border: "none",
+ color: (theme.vars || theme).palette.primary.light,
+ },
+ "&.Mui-completed": {
+ border: "none",
+ color: (theme.vars || theme).palette.success.light,
+ },
+ }),
+ variants: [
+ {
+ props: { completed: true },
+ style: {
+ width: 12,
+ height: 12,
+ },
+ },
+ ],
+ }),
+ },
+ },
+ MuiStepLabel: {
+ styleOverrides: {
+ label: ({ theme }) => ({
+ "&.Mui-completed": {
+ opacity: 0.6,
+ ...theme.applyStyles("dark", { opacity: 0.5 }),
+ },
+ }),
+ },
+ },
+};
diff --git a/frontend/src/theme/customizations/surfaces.js b/frontend/src/theme/customizations/surfaces.js
new file mode 100644
index 00000000..674e77ac
--- /dev/null
+++ b/frontend/src/theme/customizations/surfaces.js
@@ -0,0 +1,112 @@
+import { alpha } from '@mui/material/styles';
+import { gray } from '../themePrimitives';
+
+export const surfacesCustomizations = {
+ MuiAccordion: {
+ defaultProps: {
+ elevation: 0,
+ disableGutters: true,
+ },
+ styleOverrides: {
+ root: ({ theme }) => ({
+ padding: 4,
+ overflow: 'clip',
+ backgroundColor: (theme.vars || theme).palette.background.default,
+ border: '1px solid',
+ borderColor: (theme.vars || theme).palette.divider,
+ ':before': {
+ backgroundColor: 'transparent',
+ },
+ '&:not(:last-of-type)': {
+ borderBottom: 'none',
+ },
+ '&:first-of-type': {
+ borderTopLeftRadius: (theme.vars || theme).shape.borderRadius,
+ borderTopRightRadius: (theme.vars || theme).shape.borderRadius,
+ },
+ '&:last-of-type': {
+ borderBottomLeftRadius: (theme.vars || theme).shape.borderRadius,
+ borderBottomRightRadius: (theme.vars || theme).shape.borderRadius,
+ },
+ }),
+ },
+ },
+ MuiAccordionSummary: {
+ styleOverrides: {
+ root: ({ theme }) => ({
+ border: 'none',
+ borderRadius: 8,
+ '&:hover': { backgroundColor: gray[50] },
+ '&:focus-visible': { backgroundColor: 'transparent' },
+ ...theme.applyStyles('dark', {
+ '&:hover': { backgroundColor: gray[800] },
+ }),
+ }),
+ },
+ },
+ MuiAccordionDetails: {
+ styleOverrides: {
+ root: { mb: 20, border: 'none' },
+ },
+ },
+ MuiPaper: {
+ defaultProps: {
+ elevation: 0,
+ },
+ },
+ MuiCard: {
+ styleOverrides: {
+ root: ({ theme }) => {
+ return {
+ padding: 16,
+ gap: 16,
+ transition: 'all 100ms ease',
+ backgroundColor: gray[50],
+ borderRadius: (theme.vars || theme).shape.borderRadius,
+ border: `1px solid ${(theme.vars || theme).palette.divider}`,
+ boxShadow: 'none',
+ ...theme.applyStyles('dark', {
+ backgroundColor: gray[800],
+ }),
+ variants: [
+ {
+ props: {
+ variant: 'outlined',
+ },
+ style: {
+ border: `1px solid ${(theme.vars || theme).palette.divider}`,
+ boxShadow: 'none',
+ background: 'hsl(0, 0%, 100%)',
+ ...theme.applyStyles('dark', {
+ background: alpha(gray[900], 0.4),
+ }),
+ },
+ },
+ ],
+ };
+ },
+ },
+ },
+ MuiCardContent: {
+ styleOverrides: {
+ root: {
+ padding: 0,
+ '&:last-child': { paddingBottom: 0 },
+ },
+ },
+ },
+ MuiCardHeader: {
+ styleOverrides: {
+ root: {
+ padding: 0,
+ },
+ },
+ },
+ MuiCardActions: {
+ styleOverrides: {
+ root: {
+ padding: 0,
+ },
+ },
+ },
+};
diff --git a/frontend/src/theme/customizations/treeView.js b/frontend/src/theme/customizations/treeView.js
new file mode 100644
index 00000000..88d3c57b
--- /dev/null
+++ b/frontend/src/theme/customizations/treeView.js
@@ -0,0 +1,60 @@
+import { alpha } from '@mui/material/styles';
+import { gray, brand } from '../themePrimitives';
+
+export const treeViewCustomizations = {
+ MuiTreeItem2: {
+ styleOverrides: {
+ root: ({ theme }) => ({
+ position: 'relative',
+ boxSizing: 'border-box',
+ padding: theme.spacing(0, 1),
+ '& .groupTransition': {
+ marginLeft: theme.spacing(2),
+ padding: theme.spacing(0),
+ borderLeft: '1px solid',
+ borderColor: (theme.vars || theme).palette.divider,
+ },
+ '&:focus-visible .focused': {
+ outline: `3px solid ${alpha(brand[500], 0.5)}`,
+ outlineOffset: '2px',
+ '&:hover': {
+ backgroundColor: alpha(gray[300], 0.2),
+ outline: `3px solid ${alpha(brand[500], 0.5)}`,
+ outlineOffset: '2px',
+ },
+ },
+ }),
+ content: ({ theme }) => ({
+ marginTop: theme.spacing(1),
+ padding: theme.spacing(0.5, 1),
+ overflow: 'clip',
+ '&:hover': {
+ backgroundColor: alpha(gray[300], 0.2),
+ },
+
+ '&.selected': {
+ backgroundColor: alpha(gray[300], 0.4),
+ '&:hover': {
+ backgroundColor: alpha(gray[300], 0.6),
+ },
+ },
+ ...theme.applyStyles('dark', {
+ '&:hover': {
+ backgroundColor: alpha(gray[500], 0.2),
+ },
+ '&:focus-visible': {
+ '&:hover': {
+ backgroundColor: alpha(gray[500], 0.2),
+ },
+ },
+ '&.selected': {
+ backgroundColor: alpha(gray[500], 0.4),
+ '&:hover': {
+ backgroundColor: alpha(gray[500], 0.6),
+ },
+ },
+ }),
+ }),
+ },
+ },
+};
diff --git a/frontend/src/theme/themePrimitives.js b/frontend/src/theme/themePrimitives.js
new file mode 100644
index 00000000..9aa79fe2
--- /dev/null
+++ b/frontend/src/theme/themePrimitives.js
@@ -0,0 +1,376 @@
+import { createTheme, alpha } from '@mui/material/styles';
+
+const defaultTheme = createTheme();
+
+const customShadows = [...defaultTheme.shadows];
+
+export const brand = {
+ 50: 'hsl(210, 100%, 95%)',
+ 100: 'hsl(210, 100%, 92%)',
+ 200: 'hsl(210, 100%, 80%)',
+ 300: 'hsl(210, 100%, 65%)',
+ 400: 'hsl(210, 98%, 48%)',
+ 500: 'hsl(210, 98%, 42%)',
+ 600: 'hsl(210, 98%, 55%)',
+ 700: 'hsl(210, 100%, 35%)',
+ 800: 'hsl(210, 100%, 16%)',
+ 900: 'hsl(210, 100%, 21%)',
+};
+
+export const gray = {
+ 50: 'hsl(220, 35%, 97%)',
+ 100: 'hsl(220, 30%, 94%)',
+ 200: 'hsl(220, 20%, 88%)',
+ 300: 'hsl(220, 20%, 80%)',
+ 400: 'hsl(220, 20%, 65%)',
+ 500: 'hsl(220, 20%, 42%)',
+ 600: 'hsl(220, 20%, 35%)',
+ 700: 'hsl(220, 20%, 25%)',
+ 800: 'hsl(220, 30%, 6%)',
+ 900: 'hsl(220, 35%, 3%)',
+};
+
+export const green = {
+ 50: 'hsl(120, 80%, 98%)',
+ 100: 'hsl(120, 75%, 94%)',
+ 200: 'hsl(120, 75%, 87%)',
+ 300: 'hsl(120, 61%, 77%)',
+ 400: 'hsl(120, 44%, 53%)',
+ 500: 'hsl(120, 59%, 30%)',
+ 600: 'hsl(120, 70%, 25%)',
+ 700: 'hsl(120, 75%, 16%)',
+ 800: 'hsl(120, 84%, 10%)',
+ 900: 'hsl(120, 87%, 6%)',
+};
+
+export const orange = {
+ 50: 'hsl(45, 100%, 97%)',
+ 100: 'hsl(45, 92%, 90%)',
+ 200: 'hsl(45, 94%, 80%)',
+ 300: 'hsl(45, 90%, 65%)',
+ 400: 'hsl(45, 90%, 40%)',
+ 500: 'hsl(45, 90%, 35%)',
+ 600: 'hsl(45, 91%, 25%)',
+ 700: 'hsl(45, 94%, 20%)',
+ 800: 'hsl(45, 95%, 16%)',
+ 900: 'hsl(45, 93%, 12%)',
+};
+
+export const red = {
+ 50: 'hsl(0, 100%, 97%)',
+ 100: 'hsl(0, 92%, 90%)',
+ 200: 'hsl(0, 94%, 80%)',
+ 300: 'hsl(0, 90%, 65%)',
+ 400: 'hsl(0, 90%, 40%)',
+ 500: 'hsl(0, 90%, 30%)',
+ 600: 'hsl(0, 91%, 25%)',
+ 700: 'hsl(0, 94%, 18%)',
+ 800: 'hsl(0, 95%, 12%)',
+ 900: 'hsl(0, 93%, 6%)',
+};
+
+export const getDesignTokens = (mode) => {
+ customShadows[1] =
+ mode === 'dark'
+ ? 'hsla(220, 30%, 5%, 0.7) 0px 4px 16px 0px, hsla(220, 25%, 10%, 0.8) 0px 8px 16px -5px'
+ : 'hsla(220, 30%, 5%, 0.07) 0px 4px 16px 0px, hsla(220, 25%, 10%, 0.07) 0px 8px 16px -5px';
+
+ return {
+ palette: {
+ mode,
+ primary: {
+ light: brand[200],
+ main: brand[400],
+ dark: brand[700],
+ contrastText: brand[50],
+ ...(mode === 'dark' && {
+ contrastText: brand[50],
+ light: brand[300],
+ main: brand[400],
+ dark: brand[700],
+ }),
+ },
+ info: {
+ light: brand[100],
+ main: brand[300],
+ dark: brand[600],
+ contrastText: gray[50],
+ ...(mode === 'dark' && {
+ contrastText: brand[300],
+ light: brand[500],
+ main: brand[700],
+ dark: brand[900],
+ }),
+ },
+ warning: {
+ light: orange[300],
+ main: orange[400],
+ dark: orange[800],
+ ...(mode === 'dark' && {
+ light: orange[400],
+ main: orange[500],
+ dark: orange[700],
+ }),
+ },
+ error: {
+ light: red[300],
+ main: red[400],
+ dark: red[800],
+ ...(mode === 'dark' && {
+ light: red[400],
+ main: red[500],
+ dark: red[700],
+ }),
+ },
+ success: {
+ light: green[300],
+ main: green[400],
+ dark: green[800],
+ ...(mode === 'dark' && {
+ light: green[400],
+ main: green[500],
+ dark: green[700],
+ }),
+ },
+ grey: {
+ ...gray,
+ },
+ divider: mode === 'dark' ? alpha(gray[700], 0.6) : alpha(gray[300], 0.4),
+ background: {
+ default: 'hsl(0, 0%, 99%)',
+ paper: 'hsl(220, 35%, 97%)',
+ ...(mode === 'dark' && { default: gray[900], paper: 'hsl(220, 30%, 7%)' }),
+ },
+ text: {
+ primary: gray[800],
+ secondary: gray[600],
+ warning: orange[400],
+ ...(mode === 'dark' && { primary: 'hsl(0, 0%, 100%)', secondary: gray[400] }),
+ },
+ action: {
+ hover: alpha(gray[200], 0.2),
+ selected: `${alpha(gray[200], 0.3)}`,
+ ...(mode === 'dark' && {
+ hover: alpha(gray[600], 0.2),
+ selected: alpha(gray[600], 0.3),
+ }),
+ },
+ },
+ typography: {
+ fontFamily: 'Inter, sans-serif',
+ h1: {
+ fontSize: defaultTheme.typography.pxToRem(48),
+ fontWeight: 600,
+ lineHeight: 1.2,
+ letterSpacing: -0.5,
+ },
+ h2: {
+ fontSize: defaultTheme.typography.pxToRem(36),
+ fontWeight: 600,
+ lineHeight: 1.2,
+ },
+ h3: {
+ fontSize: defaultTheme.typography.pxToRem(30),
+ lineHeight: 1.2,
+ },
+ h4: {
+ fontSize: defaultTheme.typography.pxToRem(24),
+ fontWeight: 600,
+ lineHeight: 1.5,
+ },
+ h5: {
+ fontSize: defaultTheme.typography.pxToRem(20),
+ fontWeight: 600,
+ },
+ h6: {
+ fontSize: defaultTheme.typography.pxToRem(18),
+ fontWeight: 600,
+ },
+ subtitle1: {
+ fontSize: defaultTheme.typography.pxToRem(18),
+ },
+ subtitle2: {
+ fontSize: defaultTheme.typography.pxToRem(14),
+ fontWeight: 500,
+ },
+ body1: {
+ fontSize: defaultTheme.typography.pxToRem(14),
+ },
+ body2: {
+ fontSize: defaultTheme.typography.pxToRem(14),
+ fontWeight: 400,
+ },
+ caption: {
+ fontSize: defaultTheme.typography.pxToRem(12),
+ fontWeight: 400,
+ },
+ },
+ shape: {
+ borderRadius: 8,
+ },
+ shadows: customShadows,
+ };
+};
+
+export const colorSchemes = {
+ light: {
+ palette: {
+ primary: {
+ light: brand[200],
+ main: brand[400],
+ dark: brand[700],
+ contrastText: brand[50],
+ },
+ info: {
+ light: brand[100],
+ main: brand[300],
+ dark: brand[600],
+ contrastText: gray[50],
+ },
+ warning: {
+ light: orange[300],
+ main: orange[400],
+ dark: orange[800],
+ },
+ error: {
+ light: red[300],
+ main: red[400],
+ dark: red[800],
+ },
+ success: {
+ light: green[300],
+ main: green[400],
+ dark: green[800],
+ },
+ grey: {
+ ...gray,
+ },
+ divider: alpha(gray[300], 0.4),
+ background: {
+ default: 'hsl(0, 0%, 99%)',
+ paper: 'hsl(220, 35%, 97%)',
+ },
+ text: {
+ primary: gray[800],
+ secondary: gray[600],
+ warning: orange[400],
+ },
+ action: {
+ hover: alpha(gray[200], 0.2),
+ selected: `${alpha(gray[200], 0.3)}`,
+ },
+ baseShadow:
+ 'hsla(220, 30%, 5%, 0.07) 0px 4px 16px 0px, hsla(220, 25%, 10%, 0.07) 0px 8px 16px -5px',
+ },
+ },
+ dark: {
+ palette: {
+ primary: {
+ contrastText: brand[50],
+ light: brand[300],
+ main: brand[400],
+ dark: brand[700],
+ },
+ info: {
+ contrastText: brand[300],
+ light: brand[500],
+ main: brand[700],
+ dark: brand[900],
+ },
+ warning: {
+ light: orange[400],
+ main: orange[500],
+ dark: orange[700],
+ },
+ error: {
+ light: red[400],
+ main: red[500],
+ dark: red[700],
+ },
+ success: {
+ light: green[400],
+ main: green[500],
+ dark: green[700],
+ },
+ grey: {
+ ...gray,
+ },
+ divider: alpha(gray[700], 0.6),
+ background: {
+ default: gray[900],
+ paper: 'hsl(220, 30%, 7%)',
+ },
+ text: {
+ primary: 'hsl(0, 0%, 100%)',
+ secondary: gray[400],
+ },
+ action: {
+ hover: alpha(gray[600], 0.2),
+ selected: alpha(gray[600], 0.3),
+ },
+ baseShadow:
+ 'hsla(220, 30%, 5%, 0.7) 0px 4px 16px 0px, hsla(220, 25%, 10%, 0.8) 0px 8px 16px -5px',
+ },
+ },
+};
+
+export const typography = {
+ fontFamily: 'Inter, sans-serif',
+ h1: {
+ fontSize: defaultTheme.typography.pxToRem(48),
+ fontWeight: 600,
+ lineHeight: 1.2,
+ letterSpacing: -0.5,
+ },
+ h2: {
+ fontSize: defaultTheme.typography.pxToRem(36),
+ fontWeight: 600,
+ lineHeight: 1.2,
+ },
+ h3: {
+ fontSize: defaultTheme.typography.pxToRem(30),
+ lineHeight: 1.2,
+ },
+ h4: {
+ fontSize: defaultTheme.typography.pxToRem(24),
+ fontWeight: 600,
+ lineHeight: 1.5,
+ },
+ h5: {
+ fontSize: defaultTheme.typography.pxToRem(20),
+ fontWeight: 600,
+ },
+ h6: {
+ fontSize: defaultTheme.typography.pxToRem(18),
+ fontWeight: 600,
+ },
+ subtitle1: {
+ fontSize: defaultTheme.typography.pxToRem(18),
+ },
+ subtitle2: {
+ fontSize: defaultTheme.typography.pxToRem(14),
+ fontWeight: 500,
+ },
+ body1: {
+ fontSize: defaultTheme.typography.pxToRem(14),
+ },
+ body2: {
+ fontSize: defaultTheme.typography.pxToRem(14),
+ fontWeight: 400,
+ },
+ caption: {
+ fontSize: defaultTheme.typography.pxToRem(12),
+ fontWeight: 400,
+ },
+};
+
+export const shape = {
+ borderRadius: 8,
+};
+
+const defaultShadows = [
+ 'none',
+ 'var(--template-palette-baseShadow)',
+ ...defaultTheme.shadows.slice(2),
+];
+export const shadows = defaultShadows;
diff --git a/frontend/src/utils/api.js b/frontend/src/utils/api.js
deleted file mode 100644
index ee174650..00000000
--- a/frontend/src/utils/api.js
+++ /dev/null
@@ -1,26 +0,0 @@
-export async function sendChatMessage(message) {
- try {
- const response = await fetch('https://api.gemini.com/v1/chat', {
- method: 'POST',
- headers: {
- 'Content-Type': 'application/json',
- 'Authorization': `Bearer ${import.meta.env.VITE_GEMINI_API_KEY}`
- },
- body: JSON.stringify({
- // Adjust the payload according to the Gemini API documentation.
- query: message,
- // Optionally include additional parameters
- })
- })
-
- if (!response.ok) {
- throw new Error(`API error: ${response.status}`)
- }
- const data = await response.json()
- // Assuming the response has a property 'reply'
- return data.reply || 'No reply from API.'
- } catch (error) {
- console.error('Error calling Gemini API:', error)
- throw error
- }
-}