Merge pull request #148 from AmitChauhan63390/ui-fix

feat: dark theme support
This commit is contained in:
Karishma Shukla
2025-01-09 00:04:50 +05:30
committed by GitHub
28 changed files with 807 additions and 178 deletions

View File

@@ -5,19 +5,24 @@ import { useActionContext } from '../../context/browserActions';
import MaxunLogo from "../../assets/maxunlogo.png";
import { useTranslation } from 'react-i18next';
const CustomBoxContainer = styled.div`
interface CustomBoxContainerProps {
isDarkMode: boolean;
}
const CustomBoxContainer = styled.div<CustomBoxContainerProps>`
position: relative;
min-width: 250px;
width: auto;
min-height: 100px;
height: auto;
// border: 2px solid #ff00c3;
border-radius: 5px;
background-color: white;
background-color: ${({ isDarkMode }) => (isDarkMode ? '#313438' : 'white')};
color: ${({ isDarkMode }) => (isDarkMode ? 'white' : 'black')};
margin: 80px 13px 25px 13px;
box-shadow: 0px 4px 10px rgba(0, 0, 0, 0.1);
`;
const Triangle = styled.div`
const Triangle = styled.div<CustomBoxContainerProps>`
position: absolute;
top: -15px;
left: 50%;
@@ -26,7 +31,7 @@ const Triangle = styled.div`
height: 0;
border-left: 20px solid transparent;
border-right: 20px solid transparent;
border-bottom: 20px solid white;
border-bottom: 20px solid ${({ isDarkMode }) => (isDarkMode ? '#313438' : 'white')};
`;
const Logo = styled.img`
@@ -44,7 +49,8 @@ const Content = styled.div`
text-align: left;
`;
const ActionDescriptionBox = () => {
const ActionDescriptionBox = ({ isDarkMode }: { isDarkMode: boolean }) => {
const { t } = useTranslation();
const { getText, getScreenshot, getList, captureStage } = useActionContext() as {
getText: boolean;
@@ -93,9 +99,19 @@ const ActionDescriptionBox = () => {
<Checkbox
checked={index < currentStageIndex}
disabled
sx={{
color: isDarkMode ? 'white' : 'default',
'&.Mui-checked': {
color: isDarkMode ? '#90caf9' : '#1976d2',
},
}}
/>
}
label={<Typography variant="body2" gutterBottom>{text}</Typography>}
label={
<Typography variant="body2" gutterBottom color={isDarkMode ? 'white' : 'textPrimary'}>
{text}
</Typography>
}
/>
))}
</Box>
@@ -112,9 +128,9 @@ const ActionDescriptionBox = () => {
};
return (
<CustomBoxContainer>
<Logo src={MaxunLogo} alt='maxun_logo' />
<Triangle />
<CustomBoxContainer isDarkMode={isDarkMode}>
<Logo src={MaxunLogo} alt="Maxun Logo" />
<Triangle isDarkMode={isDarkMode} />
<Content>
{renderActionDescription()}
</Content>

View File

@@ -1,16 +1,15 @@
import React, { useRef } from 'react';
import styled from "styled-components";
import { Button } from "@mui/material";
//import { ActionDescription } from "../organisms/RightSidePanel";
import * as Settings from "./action-settings";
import { useSocketStore } from "../../context/socket";
interface ActionSettingsProps {
action: string;
darkMode?: boolean;
}
export const ActionSettings = ({ action }: ActionSettingsProps) => {
export const ActionSettings = ({ action, darkMode = false }: ActionSettingsProps) => {
const settingsRef = useRef<{ getSettings: () => object }>(null);
const { socket } = useSocketStore();
@@ -20,30 +19,27 @@ export const ActionSettings = ({ action }: ActionSettingsProps) => {
return <Settings.ScreenshotSettings ref={settingsRef} />;
case 'scroll':
return <Settings.ScrollSettings ref={settingsRef} />;
case 'scrape':
return <Settings.ScrapeSettings ref={settingsRef} />;
case 'scrape':
return <Settings.ScrapeSettings ref={settingsRef} />;
case 'scrapeSchema':
return <Settings.ScrapeSchemaSettings ref={settingsRef} />;
default:
return null;
}
}
};
const handleSubmit = (event: React.SyntheticEvent) => {
event.preventDefault();
//get the data from settings
const settings = settingsRef.current?.getSettings();
//Send notification to the server and generate the pair
socket?.emit(`action`, {
action,
settings
});
}
};
return (
<div>
{/* <ActionDescription>Action settings:</ActionDescription> */}
<ActionSettingsWrapper action={action}>
<ActionSettingsWrapper action={action} darkMode={darkMode}>
<form onSubmit={handleSubmit}>
<DisplaySettings />
<Button
@@ -64,10 +60,13 @@ export const ActionSettings = ({ action }: ActionSettingsProps) => {
);
};
const ActionSettingsWrapper = styled.div<{ action: string }>`
// Ensure that the Wrapper accepts the darkMode prop for styling adjustments.
const ActionSettingsWrapper = styled.div<{ action: string; darkMode: boolean }>`
display: flex;
flex-direction: column;
align-items: ${({ action }) => action === 'script' ? 'stretch' : 'center'};;
align-items: ${({ action }) => (action === 'script' ? 'stretch' : 'center')};
justify-content: center;
margin-top: 20px;
background-color: ${({ darkMode }) => (darkMode ? '#1E1E1E' : 'white')};
color: ${({ darkMode }) => (darkMode ? 'white' : 'black')};
`;

View File

@@ -1,6 +1,4 @@
import type {
FC,
} from 'react';
import type { FC } from 'react';
import styled from 'styled-components';
import ReplayIcon from '@mui/icons-material/Replay';
@@ -13,15 +11,26 @@ import { useCallback, useEffect, useState } from "react";
import { useSocketStore } from "../../context/socket";
import { getCurrentUrl } from "../../api/recording";
import { useGlobalInfoStore } from '../../context/globalInfo';
import { useThemeMode } from '../../context/theme-provider';
const StyledNavBar = styled.div<{ browserWidth: number }>`
const StyledNavBar = styled.div<{ browserWidth: number; isDarkMode: boolean }>`
display: flex;
padding: 12px 0px;
background-color: #f6f6f6;
background-color: ${({ isDarkMode }) => (isDarkMode ? '#2C2F33' : '#f6f6f6')};
width: ${({ browserWidth }) => browserWidth}px;
border-radius: 0px 5px 0px 0px;
`;
const IconButton = styled(NavBarButton)<{ mode: string }>`
background-color: ${({ mode }) => (mode === 'dark' ? '#2C2F33' : '#f6f6f6')};
transition: background-color 0.3s ease, transform 0.1s ease;
color: ${({ mode }) => (mode === 'dark' ? '#FFFFFF' : '#333')};
cursor: pointer;
&:hover {
background-color: ${({ mode }) => (mode === 'dark' ? '#586069' : '#D0D0D0')};
}
`;
interface NavBarProps {
browserWidth: number;
handleUrlChanged: (url: string) => void;
@@ -31,6 +40,7 @@ const BrowserNavBar: FC<NavBarProps> = ({
browserWidth,
handleUrlChanged,
}) => {
const isDarkMode = useThemeMode().darkMode;
const { socket } = useSocketStore();
const { recordingUrl, setRecordingUrl } = useGlobalInfoStore();
@@ -67,7 +77,7 @@ const BrowserNavBar: FC<NavBarProps> = ({
socket.off('urlChanged', handleCurrentUrlChange);
}
}
}, [socket, handleCurrentUrlChange])
}, [socket, handleCurrentUrlChange]);
const addAddress = (address: string) => {
if (socket) {
@@ -78,38 +88,41 @@ const BrowserNavBar: FC<NavBarProps> = ({
};
return (
<StyledNavBar browserWidth={900}>
<NavBarButton
<StyledNavBar browserWidth={browserWidth} isDarkMode={isDarkMode}>
<IconButton
type="button"
onClick={() => {
socket?.emit('input:back');
}}
disabled={false}
mode={isDarkMode ? 'dark' : 'light'}
>
<ArrowBackIcon />
</NavBarButton>
</IconButton>
<NavBarButton
<IconButton
type="button"
onClick={() => {
socket?.emit('input:forward');
}}
disabled={false}
mode={isDarkMode ? 'dark' : 'light'}
>
<ArrowForwardIcon />
</NavBarButton>
</IconButton>
<NavBarButton
<IconButton
type="button"
onClick={() => {
if (socket) {
handleRefresh()
handleRefresh();
}
}}
disabled={false}
mode={isDarkMode ? 'dark' : 'light'}
>
<ReplayIcon />
</NavBarButton>
</IconButton>
<UrlForm
currentAddress={recordingUrl}

View File

@@ -31,14 +31,26 @@ const BrowserRecordingSave = () => {
position: 'absolute',
background: '#ff00c3',
border: 'none',
borderRadius: '5px',
borderRadius: '0px 0px 8px 8px',
padding: '7.5px',
width: 'calc(100% - 20px)',
overflow: 'hidden',
display: 'flex',
justifyContent: 'space-between',
height:"48px"
}}>
<Button onClick={() => setOpenModal(true)} variant="outlined" style={{ marginLeft: "25px" }} size="small" color="error">
<Button
onClick={() => setOpenModal(true)}
variant="outlined"
color="error"
sx={{
marginLeft: '25px',
color: 'red !important',
borderColor: 'red !important',
backgroundColor: 'whitesmoke !important',
}}
size="small"
>
{t('right_panel.buttons.discard')}
</Button>
<GenericModal isOpen={openModal} onClose={() => setOpenModal(false)} modalStyle={modalStyle}>
@@ -48,7 +60,14 @@ const BrowserRecordingSave = () => {
<Button onClick={goToMainMenu} variant="contained" color="error">
{t('right_panel.buttons.discard')}
</Button>
<Button onClick={() => setOpenModal(false)} variant="outlined">
<Button
onClick={() => setOpenModal(false)}
variant="outlined"
sx={{
color: '#ff00c3 !important',
borderColor: '#ff00c3 !important',
backgroundColor: 'whitesmoke !important',
}} >
{t('right_panel.buttons.cancel')}
</Button>
</Box>

View File

@@ -1,8 +1,8 @@
import * as React from 'react';
import { Box, IconButton, Tab, Tabs } from "@mui/material";
import { AddButton } from "../atoms/buttons/AddButton";
import { useBrowserDimensionsStore } from "../../context/browserDimensions";
import { Close } from "@mui/icons-material";
import { useThemeMode } from '../../context/theme-provider';
interface BrowserTabsProp {
tabs: string[],
@@ -28,15 +28,16 @@ export const BrowserTabs = (
handleChangeIndex(newValue);
}
};
const isDarkMode = useThemeMode().darkMode;
return (
<Box sx={{
width: 800,
width: 800, // Fixed width
display: 'flex',
overflow: 'auto',
alignItems: 'center',
}}>
<Box sx={{ borderBottom: 1, borderColor: 'divider' }}>
<Box sx={{ borderBottom: 1, borderColor: 'divider' }}> {/* Synced border color */}
<Tabs
value={tabIndex}
onChange={handleChange}
@@ -48,7 +49,11 @@ export const BrowserTabs = (
id={`tab-${index}`}
sx={{
background: 'white',
borderRadius: '5px 5px 0px 0px'
borderRadius: '5px 5px 0px 0px',
'&.Mui-selected': {
backgroundColor:` ${isDarkMode?"#2a2a2a":"#f5f5f5"}`, // Synced selected tab color
color: '#ff00c3', // Slightly lighter text when selected
},
}}
icon={<CloseButton closeTab={() => {
tabWasClosed = true;
@@ -60,8 +65,7 @@ export const BrowserTabs = (
if (!tabWasClosed) {
handleTabChange(index)
}
}
}
}}
label={tab}
/>
);

View File

@@ -17,6 +17,7 @@ import { apiUrl } from "../../apiConfig.js";
import Cookies from 'js-cookie';
import { useTranslation } from "react-i18next";
interface IntegrationProps {
isOpen: boolean;
handleStart: (data: IntegrationSettings) => void;
@@ -29,6 +30,20 @@ export interface IntegrationSettings {
data: string;
}
// Helper functions to replace js-cookie functionality
const getCookie = (name: string): string | null => {
const value = `; ${document.cookie}`;
const parts = value.split(`; ${name}=`);
if (parts.length === 2) {
return parts.pop()?.split(';').shift() || null;
}
return null;
};
const removeCookie = (name: string): void => {
document.cookie = `${name}=; expires=Thu, 01 Jan 1970 00:00:00 GMT; path=/`;
};
export const IntegrationSettingsModal = ({
isOpen,
handleStart,
@@ -141,14 +156,14 @@ export const IntegrationSettingsModal = ({
useEffect(() => {
// Check if there is a success message in cookies
const status = Cookies.get("robot_auth_status");
const message = Cookies.get("robot_auth_message");
const status = getCookie("robot_auth_status");
const message = getCookie("robot_auth_message");
if (status === "success" && message) {
notify("success", message);
// Clear the cookies after reading
Cookies.remove("robot_auth_status");
Cookies.remove("robot_auth_message");
removeCookie("robot_auth_status");
removeCookie("robot_auth_message");
}
// Check if we're on the callback URL
@@ -309,4 +324,4 @@ export const modalStyle = {
height: "fit-content",
display: "block",
padding: "20px",
};
};

View File

@@ -17,6 +17,7 @@ import StorageIcon from '@mui/icons-material/Storage';
import ArrowUpwardIcon from '@mui/icons-material/ArrowUpward';
import { SidePanelHeader } from './SidePanelHeader';
import { useGlobalInfoStore } from '../../context/globalInfo';
import { useThemeMode } from '../../context/theme-provider';
import { useTranslation } from 'react-i18next';
interface InterpretationLogProps {
@@ -124,6 +125,8 @@ export const InterpretationLog: React.FC<InterpretationLogProps> = ({ isOpen, se
}
}, [hasScrapeListAction, hasScrapeSchemaAction, hasScreenshotAction, setIsOpen]);
const { darkMode} = useThemeMode();
return (
<Grid container>
<Grid item xs={12} md={9} lg={9}>
@@ -132,7 +135,7 @@ export const InterpretationLog: React.FC<InterpretationLogProps> = ({ isOpen, se
variant="contained"
color="primary"
sx={{
marginTop: '10px',
marginTop: '10px',
color: 'white',
position: 'absolute',
background: '#ff00c3',
@@ -157,8 +160,8 @@ export const InterpretationLog: React.FC<InterpretationLogProps> = ({ isOpen, se
onOpen={toggleDrawer(true)}
PaperProps={{
sx: {
background: 'white',
color: 'black',
background: `${darkMode ? '#1e2124' : 'white'}`,
color: `${darkMode ? 'white' : 'black'}`,
padding: '10px',
height: 500,
width: width - 10,

View File

@@ -4,17 +4,17 @@ import axios from 'axios';
import styled from "styled-components";
import { stopRecording } from "../../api/recording";
import { useGlobalInfoStore } from "../../context/globalInfo";
import { IconButton, Menu, MenuItem, Typography, Chip, Button, Modal, Tabs, Tab, Box, Snackbar } from "@mui/material";
import { AccountCircle, Logout, Clear, YouTube, X, Update, Close, Language } from "@mui/icons-material";
import { IconButton, Menu, MenuItem, Typography, Chip, Button, Modal, Tabs, Tab, Box, Snackbar, Tooltip } from "@mui/material";
import { AccountCircle, Logout, Clear, YouTube, X, Update, Close, Language, Brightness7, Brightness4 } from "@mui/icons-material";
import { useNavigate } from 'react-router-dom';
import { AuthContext } from '../../context/auth';
import { SaveRecording } from '../molecules/SaveRecording';
import DiscordIcon from '../atoms/DiscordIcon';
import { apiUrl } from '../../apiConfig';
import MaxunLogo from "../../assets/maxunlogo.png";
import { useThemeMode } from '../../context/theme-provider';
import packageJson from "../../../package.json"
interface NavBarProps {
recordingName: string;
isRecording: boolean;
@@ -28,6 +28,7 @@ export const NavBar: React.FC<NavBarProps> = ({
const { state, dispatch } = useContext(AuthContext);
const { user } = state;
const navigate = useNavigate();
const { darkMode, toggleTheme } = useThemeMode();
const { t, i18n } = useTranslation();
const [anchorEl, setAnchorEl] = useState<null | HTMLElement>(null);
@@ -102,6 +103,22 @@ export const NavBar: React.FC<NavBarProps> = ({
localStorage.setItem("language", lang);
};
const renderThemeToggle = () => (
<Tooltip title="Toggle light/dark theme">
<IconButton
onClick={toggleTheme}
sx={{
color: darkMode ? '#ffffff' : '#333333',
'&:hover': {
color: '#ff00c3'
}
}}
>
{darkMode ? <Brightness7 /> : <Brightness4 />}
</IconButton>
</Tooltip>
);
useEffect(() => {
const checkForUpdates = async () => {
const latestVersion = await fetchLatestVersion();
@@ -158,13 +175,13 @@ export const NavBar: React.FC<NavBarProps> = ({
}}
/>
)}
<NavBarWrapper>
<NavBarWrapper mode={darkMode ? 'dark' : 'light'}>
<div style={{
display: 'flex',
justifyContent: 'flex-start',
}}>
<img src={MaxunLogo} width={45} height={40} style={{ borderRadius: '5px', margin: '5px 0px 5px 15px' }} />
<div style={{ padding: '11px' }}><ProjectName>{t('navbar.project_name')}</ProjectName></div>
<div style={{ padding: '11px' }}><ProjectName mode={darkMode ? 'dark' : 'light'}>{t('navbar.project_name')}</ProjectName></div>
<Chip
label={`${currentVersion}`}
color="primary"
@@ -288,7 +305,6 @@ export const NavBar: React.FC<NavBarProps> = ({
borderRadius: '5px',
padding: '8px',
marginRight: '10px',
'&:hover': { backgroundColor: 'white', color: '#ff00c3' }
}}>
<AccountCircle sx={{ marginRight: '5px' }} />
<Typography variant="body1">{user.email}</Typography>
@@ -383,6 +399,7 @@ export const NavBar: React.FC<NavBarProps> = ({
</MenuItem>
</Menu>
</Menu>
{renderThemeToggle()}
</>
) : (
<>
@@ -402,14 +419,15 @@ export const NavBar: React.FC<NavBarProps> = ({
)}
</div>
) : (
<><IconButton
<NavBarRight>
<IconButton
onClick={handleLangMenuOpen}
sx={{
display: "flex",
alignItems: "center",
borderRadius: "5px",
padding: "8px",
marginRight: "10px",
marginRight: "8px",
}}
>
<Language sx={{ marginRight: '5px' }} /><Typography variant="body1">{t("Language")}</Typography>
@@ -467,23 +485,34 @@ export const NavBar: React.FC<NavBarProps> = ({
>
Deutsch
</MenuItem>
</Menu></>
)}
</Menu>
{renderThemeToggle()}
</NavBarRight>
)}
</NavBarWrapper>
</>
);
};
const NavBarWrapper = styled.div`
// Styled Components
const NavBarWrapper = styled.div<{ mode: 'light' | 'dark' }>`
grid-area: navbar;
background-color: white;
background-color: ${({ mode }) => (mode === 'dark' ? '#1e2124' : '#ffffff')};
padding: 5px;
display: flex;
justify-content: space-between;
border-bottom: 1px solid #e0e0e0;
border-bottom: 1px solid ${({ mode }) => (mode === 'dark' ? '#333' : '#e0e0e0')};
`;
const ProjectName = styled.b`
color: #3f4853;
const ProjectName = styled.b<{ mode: 'light' | 'dark' }>`
color: ${({ mode }) => (mode === 'dark' ? '#ffffff' : '#3f4853')};
font-size: 1.3em;
`;
const NavBarRight = styled.div`
display: flex;
align-items: center;
justify-content: flex-end;
margin-left: auto;
`;

View File

@@ -152,7 +152,16 @@ export const RobotDuplicationModal = ({ isOpen, handleStart, handleClose, initia
<Button variant="contained" color="primary" onClick={handleSave}>
{t('robot_duplication.buttons.duplicate')}
</Button>
<Button onClick={handleClose} color="primary" variant="outlined" style={{ marginLeft: '10px' }}>
<Button
onClick={handleClose}
color="primary"
variant="outlined"
style={{ marginLeft: '10px' }}
sx={{
color: '#ff00c3 !important',
borderColor: '#ff00c3 !important',
backgroundColor: 'whitesmoke !important',
}} >
{t('robot_duplication.buttons.cancel')}
</Button>
</Box>

View File

@@ -179,7 +179,11 @@ export const RobotEditModal = ({ isOpen, handleStart, handleClose, initialSettin
color="primary"
variant="outlined"
style={{ marginLeft: '10px' }}
>
sx={{
color: '#ff00c3 !important',
borderColor: '#ff00c3 !important',
backgroundColor: 'whitesmoke !important',
}}>
{t('robot_edit.cancel')}
</Button>
</Box>

View File

@@ -77,10 +77,50 @@ export const RunContent = ({ row, currentLog, interpretationInProgress, logEndRe
<Box sx={{ width: '100%' }}>
<TabContext value={tab}>
<Box sx={{ borderBottom: 1, borderColor: 'divider' }}>
<Tabs value={tab} onChange={(e, newTab) => setTab(newTab)} aria-label="run-content-tabs">
<Tab label={t('run_content.tabs.output_data')} value='output' />
<Tab label={t('run_content.tabs.log')} value='log' />
</Tabs>
<Tabs
value={tab}
onChange={(e, newTab) => setTab(newTab)}
aria-label="run-content-tabs"
sx={{
// Remove the default blue indicator
'& .MuiTabs-indicator': {
backgroundColor: '#FF00C3', // Change to pink
},
// Remove default transition effects
'& .MuiTab-root': {
'&.Mui-selected': {
color: '#FF00C3',
},
}
}}
>
<Tab
label={t('run_content.tabs.output_data')}
value='output'
sx={{
color: (theme) => theme.palette.mode === 'dark' ? '#fff' : '#000',
'&:hover': {
color: '#FF00C3'
},
'&.Mui-selected': {
color: '#FF00C3',
}
}}
/>
<Tab
label={t('run_content.tabs.log')}
value='log'
sx={{
color: (theme) => theme.palette.mode === 'dark' ? '#fff' : '#000',
'&:hover': {
color: '#FF00C3'
},
'&.Mui-selected': {
color: '#FF00C3',
}
}}
/>
</Tabs>
</Box>
<TabPanel value='log'>
<Box sx={{
@@ -161,6 +201,7 @@ export const RunContent = ({ row, currentLog, interpretationInProgress, logEndRe
background: 'rgba(0,0,0,0.06)',
maxHeight: '300px',
overflow: 'scroll',
backgroundColor: '#19171c'
}}>
<pre>
{JSON.stringify(row.serializableOutput, null, 2)}

View File

@@ -77,7 +77,21 @@ export const SaveRecording = ({ fileName }: SaveRecordingProps) => {
return (
<div>
<Button onClick={() => setOpenModal(true)} variant="outlined" sx={{ marginRight: '20px' }} size="small" color="success">
{/* <Button onClick={() => setOpenModal(true)} variant='contained' sx={{ marginRight: '20px',backgroundColor: '#ff00c3',color: 'white' }} size="small" color="success">
Finish */}
<Button
onClick={() => setOpenModal(true)}
variant="outlined"
color="success"
sx={{
marginRight: '20px',
color: '#00c853 !important',
borderColor: '#00c853 !important',
backgroundColor: 'whitesmoke !important',
}}
size="small"
>
{t('right_panel.buttons.finish')}
</Button>

View File

@@ -273,7 +273,16 @@ export const ScheduleSettingsModal = ({ isOpen, handleStart, handleClose, initia
<Button onClick={() => handleStart(settings)} variant="contained" color="primary">
{t('schedule_settings.buttons.save_schedule')}
</Button>
<Button onClick={handleClose} color="primary" variant="outlined" style={{ marginLeft: '10px' }}>
<Button
onClick={handleClose}
color="primary"
variant="outlined"
style={{ marginLeft: '10px' }}
sx={{
color: '#ff00c3 !important',
borderColor: '#ff00c3 !important',
backgroundColor: 'whitesmoke !important',
}}>
{t('schedule_settings.buttons.cancel')}
</Button>
</Box>