dark theme added

This commit is contained in:
amit
2024-11-07 00:46:47 +05:30
parent 04ed79b337
commit f4a0327c9a
4 changed files with 154 additions and 183 deletions

View File

@@ -1,96 +1,22 @@
import React from 'react'; import React from 'react';
import { Routes, Route } from 'react-router-dom'; import { Routes, Route } from 'react-router-dom';
import { ThemeProvider, createTheme } from "@mui/material/styles"; import { createTheme } from "@mui/material/styles";
import { GlobalInfoProvider } from "./context/globalInfo"; import { GlobalInfoProvider } from "./context/globalInfo";
import { PageWrapper } from "./pages/PageWrappper"; import { PageWrapper } from "./pages/PageWrappper";
import ThemeModeProvider from './context/theme-provider';
const theme = createTheme({
palette: {
primary: {
main: "#ff00c3",
contrastText: "#ffffff",
},
},
components: {
MuiButton: {
styleOverrides: {
root: {
// Default styles for all buttons (optional)
textTransform: "none",
},
containedPrimary: {
// Styles for 'contained' variant with 'primary' color
'&:hover': {
backgroundColor: "#ff66d9",
},
},
outlined: {
// Apply white background for all 'outlined' variant buttons
backgroundColor: "#ffffff",
'&:hover': {
backgroundColor: "#f0f0f0", // Optional lighter background on hover
},
},
},
},
MuiLink: {
styleOverrides: {
root: {
'&:hover': {
color: "#ff00c3",
},
},
},
},
MuiIconButton: {
styleOverrides: {
root: {
// '&:hover': {
// color: "#ff66d9",
// },
},
},
},
MuiTab: {
styleOverrides: {
root: {
textTransform: "none",
},
},
},
MuiAlert: {
styleOverrides: {
standardInfo: {
backgroundColor: "#fce1f4",
color: "#ff00c3",
'& .MuiAlert-icon': {
color: "#ff00c3",
},
},
},
},
MuiAlertTitle: {
styleOverrides: {
root: {
'& .MuiAlert-icon': {
color: "#ffffff",
},
},
},
},
},
});
function App() { function App() {
return ( return (
<ThemeProvider theme={theme}> <ThemeModeProvider>
<GlobalInfoProvider> <GlobalInfoProvider>
<Routes> <Routes>
<Route path="/*" element={<PageWrapper />} /> <Route path="/*" element={<PageWrapper />} />
</Routes> </Routes>
</GlobalInfoProvider> </GlobalInfoProvider>
</ThemeProvider> </ThemeModeProvider>
); );
} }

View File

@@ -3,14 +3,15 @@ import axios from 'axios';
import styled from "styled-components"; import styled from "styled-components";
import { stopRecording } from "../../api/recording"; import { stopRecording } from "../../api/recording";
import { useGlobalInfoStore } from "../../context/globalInfo"; import { useGlobalInfoStore } from "../../context/globalInfo";
import { IconButton, Menu, MenuItem, Typography, Avatar } from "@mui/material"; import { IconButton, Menu, MenuItem, Typography, Avatar, Tooltip } from "@mui/material";
import { AccountCircle, Logout, Clear } from "@mui/icons-material"; import { AccountCircle, Logout, Clear, Brightness4, Brightness7 } from "@mui/icons-material";
import { useNavigate } from 'react-router-dom'; import { useNavigate } from 'react-router-dom';
import { AuthContext } from '../../context/auth'; import { AuthContext } from '../../context/auth';
import { SaveRecording } from '../molecules/SaveRecording'; import { SaveRecording } from '../molecules/SaveRecording';
import DiscordIcon from '../atoms/DiscordIcon'; import DiscordIcon from '../atoms/DiscordIcon';
import { apiUrl } from '../../apiConfig'; import { apiUrl } from '../../apiConfig';
import MaxunLogo from "../../assets/maxunlogo.png"; import MaxunLogo from "../../assets/maxunlogo.png";
import { useThemeMode } from '../../context/theme-provider';
interface NavBarProps { interface NavBarProps {
recordingName: string; recordingName: string;
@@ -18,10 +19,11 @@ interface NavBarProps {
} }
export const NavBar: React.FC<NavBarProps> = ({ recordingName, isRecording }) => { export const NavBar: React.FC<NavBarProps> = ({ recordingName, isRecording }) => {
const { notify, browserId, setBrowserId, recordingUrl } = useGlobalInfoStore(); const { notify, browserId, setBrowserId } = useGlobalInfoStore();
const { state, dispatch } = useContext(AuthContext); const { state, dispatch } = useContext(AuthContext);
const { user } = state; const { user } = state;
const navigate = useNavigate(); const navigate = useNavigate();
const { darkMode, toggleTheme } = useThemeMode();
const [anchorEl, setAnchorEl] = useState<null | HTMLElement>(null); const [anchorEl, setAnchorEl] = useState<null | HTMLElement>(null);
@@ -51,20 +53,18 @@ export const NavBar: React.FC<NavBarProps> = ({ recordingName, isRecording }) =>
}; };
return ( return (
<NavBarWrapper> <NavBarWrapper mode={darkMode ? 'dark' : 'light'}>
<div style={{ <div style={{ display: 'flex', justifyContent: 'flex-start' }}>
display: 'flex',
justifyContent: 'flex-start',
}}>
<img src={MaxunLogo} width={45} height={40} style={{ borderRadius: '5px', margin: '5px 0px 5px 15px' }} /> <img src={MaxunLogo} width={45} height={40} style={{ borderRadius: '5px', margin: '5px 0px 5px 15px' }} />
<div style={{ padding: '11px' }}><ProjectName>Maxun</ProjectName></div> <div style={{ padding: '11px' }}>
<ProjectName mode={darkMode ? 'dark' : 'light'}>Maxun</ProjectName>
</div>
</div> </div>
{ {user ? (
user ? ( <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'flex-end' }}>
<div style={{ display: 'flex', alignItems: 'center', justifyContent: 'flex-end' }}> {!isRecording ? (
{!isRecording ? ( <>
<> <IconButton
<IconButton
component="a" component="a"
href="https://discord.gg/NFhWDCdb" href="https://discord.gg/NFhWDCdb"
target="_blank" target="_blank"
@@ -76,72 +76,71 @@ export const NavBar: React.FC<NavBarProps> = ({ recordingName, isRecording }) =>
padding: '8px', padding: '8px',
marginRight: '10px', marginRight: '10px',
}} }}
> >
<DiscordIcon sx={{ marginRight: '5px' }} /> <DiscordIcon sx={{ marginRight: '5px' }} />
</IconButton> </IconButton>
<iframe src="https://ghbtns.com/github-btn.html?user=getmaxun&repo=maxun&type=star&count=true&size=large" frameBorder="0" scrolling="0" width="170" height="30" title="GitHub"></iframe> <iframe src="https://ghbtns.com/github-btn.html?user=getmaxun&repo=maxun&type=star&count=true&size=large" frameBorder="0" scrolling="0" width="170" height="30" title="GitHub"></iframe>
<IconButton onClick={handleMenuOpen} sx={{ <IconButton onClick={handleMenuOpen} sx={{
display: 'flex', display: 'flex',
alignItems: 'center', alignItems: 'center',
borderRadius: '5px', borderRadius: '5px',
padding: '8px', padding: '8px',
marginRight: '10px', marginRight: '10px',
'&:hover': { backgroundColor: 'white', color: '#ff00c3' } '&:hover': { backgroundColor: 'white', color: '#ff00c3' }
}}> }}>
<AccountCircle sx={{ marginRight: '5px' }} /> <AccountCircle sx={{ marginRight: '5px' }} />
<Typography variant="body1">{user.email}</Typography> <Typography variant="body1">{user.email}</Typography>
</IconButton>
<Menu
anchorEl={anchorEl}
open={Boolean(anchorEl)}
onClose={handleMenuClose}
anchorOrigin={{ vertical: 'bottom', horizontal: 'right' }}
transformOrigin={{ vertical: 'top', horizontal: 'right' }}
>
<MenuItem onClick={() => { handleMenuClose(); logout(); }}>
<Logout sx={{ marginRight: '5px' }} /> Logout
</MenuItem>
</Menu>
{/* Theme Toggle Button */}
<Tooltip title="Toggle light/dark theme">
<IconButton onClick={toggleTheme} color="inherit">
{darkMode ? <Brightness7 /> : <Brightness4 />}
</IconButton> </IconButton>
<Menu </Tooltip>
anchorEl={anchorEl} </>
open={Boolean(anchorEl)} ) : (
onClose={handleMenuClose} <>
anchorOrigin={{ <IconButton onClick={goToMainMenu} sx={{
vertical: 'bottom', borderRadius: '5px',
horizontal: 'right', padding: '8px',
}} background: 'red',
transformOrigin={{ color: 'white',
vertical: 'top', marginRight: '10px',
horizontal: 'right', '&:hover': { color: 'white', backgroundColor: 'red' }
}} }}>
> <Clear sx={{ marginRight: '5px' }} />
<MenuItem onClick={() => { handleMenuClose(); logout(); }}> Discard
<Logout sx={{ marginRight: '5px' }} /> Logout </IconButton>
</MenuItem> <SaveRecording fileName={recordingName} />
</Menu> </>
</> )}
) : ( </div>
<> ) : null}
<IconButton onClick={goToMainMenu} sx={{
borderRadius: '5px',
padding: '8px',
background: 'red',
color: 'white',
marginRight: '10px',
'&:hover': { color: 'white', backgroundColor: 'red' }
}}>
<Clear sx={{ marginRight: '5px' }} />
Discard
</IconButton>
<SaveRecording fileName={recordingName} />
</>
)}
</div>
) : ""
}
</NavBarWrapper> </NavBarWrapper>
); );
}; };
const NavBarWrapper = styled.div` const NavBarWrapper = styled.div<{ mode: 'light' | 'dark' }>`
grid-area: navbar; grid-area: navbar;
background-color: white; background-color: ${({ mode }) => (mode === 'dark' ? '#1e2124' : '#ffffff')};
padding:5px; padding: 5px;
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
border-bottom: 1px solid #e0e0e0; border-bottom: 1px solid ${({ mode }) => (mode === 'dark' ? '#333' : '#e0e0e0')};
`; `;
const ProjectName = styled.b` const ProjectName = styled.b<{ mode: 'light' | 'dark' }>`
color: #3f4853; color: ${({ mode }) => (mode === 'dark' ? 'white' : 'black')};
font-size: 1.3em; font-size: 1.3em;
`; `;

View File

@@ -1,10 +1,9 @@
import * as React from 'react'; import React from 'react';
import Tabs from '@mui/material/Tabs'; import Tabs from '@mui/material/Tabs';
import Tab from '@mui/material/Tab'; import Tab from '@mui/material/Tab';
import Box from '@mui/material/Box'; import Box from '@mui/material/Box';
import { Paper, Button } from "@mui/material"; import { Paper, Button, useTheme } from "@mui/material";
import { AutoAwesome, FormatListBulleted, VpnKey, Usb, Article, Link, CloudQueue } from "@mui/icons-material"; import { AutoAwesome, FormatListBulleted, VpnKey, Usb, Article, CloudQueue } from "@mui/icons-material";
import { apiUrl } from "../../apiConfig";
interface MainMenuProps { interface MainMenuProps {
value: string; value: string;
@@ -12,6 +11,7 @@ interface MainMenuProps {
} }
export const MainMenu = ({ value = 'recordings', handleChangeContent }: MainMenuProps) => { export const MainMenu = ({ value = 'recordings', handleChangeContent }: MainMenuProps) => {
const theme = useTheme();
const handleChange = (event: React.SyntheticEvent, newValue: string) => { const handleChange = (event: React.SyntheticEvent, newValue: string) => {
handleChangeContent(newValue); handleChangeContent(newValue);
@@ -22,16 +22,14 @@ export const MainMenu = ({ value = 'recordings', handleChangeContent }: MainMenu
sx={{ sx={{
height: 'auto', height: 'auto',
width: '250px', width: '250px',
backgroundColor: 'white', backgroundColor: theme.palette.background.paper,
paddingTop: '0.5rem', paddingTop: '0.5rem',
color: theme.palette.text.primary,
}} }}
variant="outlined" variant="outlined"
square square
> >
<Box sx={{ <Box sx={{ width: '100%', paddingBottom: '1rem' }}>
width: '100%',
paddingBottom: '1rem',
}}>
<Tabs <Tabs
value={value} value={value}
onChange={handleChange} onChange={handleChange}
@@ -41,44 +39,28 @@ export const MainMenu = ({ value = 'recordings', handleChangeContent }: MainMenu
sx={{ alignItems: 'flex-start' }} sx={{ alignItems: 'flex-start' }}
> >
<Tab <Tab
sx={{ sx={{ justifyContent: 'flex-start', textAlign: 'left', fontSize: 'medium', color: theme.palette.text.primary }}
justifyContent: 'flex-start',
textAlign: 'left',
fontSize: 'medium',
}}
value="recordings" value="recordings"
label="Robots" label="Robots"
icon={<AutoAwesome />} icon={<AutoAwesome />}
iconPosition="start" iconPosition="start"
/> />
<Tab <Tab
sx={{ sx={{ justifyContent: 'flex-start', textAlign: 'left', fontSize: 'medium', color: theme.palette.text.primary }}
justifyContent: 'flex-start',
textAlign: 'left',
fontSize: 'medium',
}}
value="runs" value="runs"
label="Runs" label="Runs"
icon={<FormatListBulleted />} icon={<FormatListBulleted />}
iconPosition="start" iconPosition="start"
/> />
<Tab <Tab
sx={{ sx={{ justifyContent: 'flex-start', textAlign: 'left', fontSize: 'medium', color: theme.palette.text.primary }}
justifyContent: 'flex-start',
textAlign: 'left',
fontSize: 'medium',
}}
value="proxy" value="proxy"
label="Proxy" label="Proxy"
icon={<Usb />} icon={<Usb />}
iconPosition="start" iconPosition="start"
/> />
<Tab <Tab
sx={{ sx={{ justifyContent: 'flex-start', textAlign: 'left', fontSize: 'medium', color: theme.palette.text.primary }}
justifyContent: 'flex-start',
textAlign: 'left',
fontSize: 'medium',
}}
value="apikey" value="apikey"
label="API Key" label="API Key"
icon={<VpnKey />} icon={<VpnKey />}
@@ -87,7 +69,7 @@ export const MainMenu = ({ value = 'recordings', handleChangeContent }: MainMenu
</Tabs> </Tabs>
<hr /> <hr />
<Box sx={{ display: 'flex', flexDirection: 'column', gap: '1rem', textAlign: 'left' }}> <Box sx={{ display: 'flex', flexDirection: 'column', gap: '1rem', textAlign: 'left' }}>
<Button href={`${apiUrl}/api-docs/`} target="_blank" rel="noopener noreferrer" sx={buttonStyles} startIcon={<Article />}> <Button href="/api-docs" target="_blank" rel="noopener noreferrer" sx={buttonStyles} startIcon={<Article />}>
API Docs API Docs
</Button> </Button>
<Button href="https://forms.gle/hXjgqDvkEhPcaBW76" target="_blank" rel="noopener noreferrer" sx={buttonStyles} startIcon={<CloudQueue />}> <Button href="https://forms.gle/hXjgqDvkEhPcaBW76" target="_blank" rel="noopener noreferrer" sx={buttonStyles} startIcon={<CloudQueue />}>
@@ -97,17 +79,17 @@ export const MainMenu = ({ value = 'recordings', handleChangeContent }: MainMenu
</Box> </Box>
</Paper> </Paper>
); );
} };
const buttonStyles = { const buttonStyles = {
justifyContent: 'flex-start', justifyContent: 'flex-start',
textAlign: 'left', textAlign: 'left',
fontSize: 'medium', fontSize: 'medium',
padding: '6px 16px 6px 22px', padding: '6px 16px 6px 22px',
minHeight: '48px', minHeight: '48px',
minWidth: '100%', minWidth: '100%',
display: 'flex', display: 'flex',
alignItems: 'center', alignItems: 'center',
textTransform: 'none', textTransform: 'none',
color: '#6C6C6C !important', color: 'inherit',
}; };

View File

@@ -0,0 +1,64 @@
import React, { createContext, useContext, useState } from 'react';
import { ThemeProvider, createTheme } from '@mui/material/styles';
import CssBaseline from '@mui/material/CssBaseline';
const lightTheme = createTheme({
palette: {
mode: 'light',
primary: {
main: '#1e88e5',
},
background: {
default: '#ffffff',
paper: '#f5f5f5',
},
text: {
primary: '#000000',
},
},
});
const darkTheme = createTheme({
palette: {
mode: 'dark',
primary: {
main: '#90caf9',
},
background: {
default: '#121212',
paper: '#1e2124',
},
text: {
primary: '#ffffff',
},
},
});
// Create context for theme mode with state for current mode
// In theme-provider.tsx
const ThemeModeContext = createContext({
toggleTheme: () => {},
darkMode: false, // Add darkMode to context
});
export const useThemeMode = () => useContext(ThemeModeContext);
const ThemeModeProvider = ({ children }: { children: React.ReactNode }) => {
const [darkMode, setDarkMode] = useState(false);
const toggleTheme = () => {
setDarkMode((prevMode) => !prevMode);
};
return (
<ThemeModeContext.Provider value={{ toggleTheme, darkMode }}> {/* Pass darkMode here */}
<ThemeProvider theme={darkMode ? darkTheme : lightTheme}>
<CssBaseline />
{children}
</ThemeProvider>
</ThemeModeContext.Provider>
);
};
export default ThemeModeProvider;