mirror of
https://github.com/Qortal/Qortal-Hub.git
synced 2025-06-06 16:36:58 +00:00
Add themeSelector component
This commit is contained in:
parent
57e33c97a3
commit
d92d75040d
@ -1596,7 +1596,7 @@ function App() {
|
||||
}}
|
||||
>
|
||||
<Spacer height="20px" />
|
||||
|
||||
|
||||
{!isMobile && (
|
||||
<>
|
||||
<Spacer height="20px" />
|
||||
|
@ -1,11 +1,16 @@
|
||||
import React, { useCallback, useContext, useEffect, useRef, useState } from "react";
|
||||
import React, {
|
||||
useCallback,
|
||||
useContext,
|
||||
useEffect,
|
||||
useRef,
|
||||
useState,
|
||||
} from "react";
|
||||
import { Spacer } from "../common/Spacer";
|
||||
import { CustomButton, TextItalic, TextP, TextSpan } from "../App-styles";
|
||||
import { CustomButton, TextP, TextSpan } from "../App-styles";
|
||||
import {
|
||||
Box,
|
||||
Button,
|
||||
ButtonBase,
|
||||
Checkbox,
|
||||
Dialog,
|
||||
DialogActions,
|
||||
DialogContent,
|
||||
@ -16,37 +21,33 @@ import {
|
||||
Switch,
|
||||
Typography,
|
||||
} from "@mui/material";
|
||||
import Logo1 from "../assets/svgs/Logo1.svg";
|
||||
import Logo1Dark from "../assets/svgs/Logo1Dark.svg";
|
||||
import Info from "../assets/svgs/Info.svg";
|
||||
import HelpIcon from '@mui/icons-material/Help';
|
||||
import HelpIcon from "@mui/icons-material/Help";
|
||||
import { CustomizedSnackbars } from "../components/Snackbar/Snackbar";
|
||||
import { set } from "lodash";
|
||||
import { cleanUrl, gateways, isUsingLocal } from "../background";
|
||||
import { cleanUrl, gateways } from "../background";
|
||||
import { GlobalContext } from "../App";
|
||||
import Tooltip, { TooltipProps, tooltipClasses } from '@mui/material/Tooltip';
|
||||
import Tooltip, { TooltipProps, tooltipClasses } from "@mui/material/Tooltip";
|
||||
import ThemeSelector from "../components/Theme/ThemeSelector";
|
||||
|
||||
const manifestData = {
|
||||
version: "0.5.2",
|
||||
};
|
||||
|
||||
|
||||
export const HtmlTooltip = styled(({ className, ...props }: TooltipProps) => (
|
||||
<Tooltip {...props} classes={{ popper: className }} />
|
||||
))(({ theme }) => ({
|
||||
[`& .${tooltipClasses.tooltip}`]: {
|
||||
backgroundColor: '#232428',
|
||||
color: 'white',
|
||||
backgroundColor: "#232428",
|
||||
color: "white",
|
||||
maxWidth: 320,
|
||||
padding: '20px',
|
||||
padding: "20px",
|
||||
fontSize: theme.typography.pxToRem(12),
|
||||
},
|
||||
}));
|
||||
function removeTrailingSlash(url) {
|
||||
return url.replace(/\/+$/, '');
|
||||
return url.replace(/\/+$/, "");
|
||||
}
|
||||
|
||||
|
||||
export const NotAuthenticated = ({
|
||||
getRootProps,
|
||||
getInputProps,
|
||||
@ -58,8 +59,8 @@ export const NotAuthenticated = ({
|
||||
handleSetGlobalApikey,
|
||||
currentNode,
|
||||
setCurrentNode,
|
||||
useLocalNode,
|
||||
setUseLocalNode
|
||||
useLocalNode,
|
||||
setUseLocalNode,
|
||||
}) => {
|
||||
const [isValidApiKey, setIsValidApiKey] = useState<boolean | null>(null);
|
||||
const [hasLocalNode, setHasLocalNode] = useState<boolean | null>(null);
|
||||
@ -78,7 +79,7 @@ export const NotAuthenticated = ({
|
||||
const [customApikey, setCustomApiKey] = React.useState("");
|
||||
const [customNodeToSaveIndex, setCustomNodeToSaveIndex] =
|
||||
React.useState(null);
|
||||
const { showTutorial, hasSeenGettingStarted } = useContext(GlobalContext);
|
||||
const { showTutorial, hasSeenGettingStarted } = useContext(GlobalContext);
|
||||
|
||||
const importedApiKeyRef = useRef(null);
|
||||
const currentNodeRef = useRef(null);
|
||||
@ -92,34 +93,32 @@ export const NotAuthenticated = ({
|
||||
const text = e.target.result; // Get the file content
|
||||
|
||||
setImportedApiKey(text); // Store the file content in the state
|
||||
if(customNodes){
|
||||
setCustomNodes((prev)=> {
|
||||
const copyPrev = [...prev]
|
||||
const findLocalIndex = copyPrev?.findIndex((item)=> item?.url === 'http://127.0.0.1:12391')
|
||||
if(findLocalIndex === -1){
|
||||
if (customNodes) {
|
||||
setCustomNodes((prev) => {
|
||||
const copyPrev = [...prev];
|
||||
const findLocalIndex = copyPrev?.findIndex(
|
||||
(item) => item?.url === "http://127.0.0.1:12391"
|
||||
);
|
||||
if (findLocalIndex === -1) {
|
||||
copyPrev.unshift({
|
||||
url: "http://127.0.0.1:12391",
|
||||
apikey: text
|
||||
})
|
||||
apikey: text,
|
||||
});
|
||||
} else {
|
||||
copyPrev[findLocalIndex] = {
|
||||
url: "http://127.0.0.1:12391",
|
||||
apikey: text
|
||||
}
|
||||
apikey: text,
|
||||
};
|
||||
}
|
||||
window
|
||||
.sendMessage("setCustomNodes", copyPrev)
|
||||
.catch((error) => {
|
||||
window.sendMessage("setCustomNodes", copyPrev).catch((error) => {
|
||||
console.error(
|
||||
"Failed to set custom nodes:",
|
||||
error.message || "An error occurred"
|
||||
);
|
||||
});
|
||||
return copyPrev
|
||||
})
|
||||
|
||||
return copyPrev;
|
||||
});
|
||||
}
|
||||
|
||||
};
|
||||
reader.readAsText(file); // Read the file as text
|
||||
}
|
||||
@ -137,14 +136,12 @@ export const NotAuthenticated = ({
|
||||
const data = await response.json();
|
||||
if (data?.height) {
|
||||
setHasLocalNode(true);
|
||||
return true
|
||||
return true;
|
||||
}
|
||||
return false
|
||||
|
||||
return false;
|
||||
} catch (error) {
|
||||
return false
|
||||
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
@ -155,18 +152,20 @@ export const NotAuthenticated = ({
|
||||
window
|
||||
.sendMessage("getCustomNodesFromStorage")
|
||||
.then((response) => {
|
||||
|
||||
setCustomNodes(response || []);
|
||||
if(window?.electronAPI?.setAllowedDomains){
|
||||
window.electronAPI.setAllowedDomains(response?.map((node)=> node.url))
|
||||
setCustomNodes(response || []);
|
||||
if (window?.electronAPI?.setAllowedDomains) {
|
||||
window.electronAPI.setAllowedDomains(
|
||||
response?.map((node) => node.url)
|
||||
);
|
||||
}
|
||||
if (Array.isArray(response)) {
|
||||
const findLocal = response?.find(
|
||||
(item) => item?.url === "http://127.0.0.1:12391"
|
||||
);
|
||||
if (findLocal && findLocal?.apikey) {
|
||||
setImportedApiKey(findLocal?.apikey);
|
||||
}
|
||||
if(Array.isArray(response)){
|
||||
const findLocal = response?.find((item)=> item?.url === 'http://127.0.0.1:12391')
|
||||
if(findLocal && findLocal?.apikey){
|
||||
setImportedApiKey(findLocal?.apikey)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error(
|
||||
@ -187,48 +186,50 @@ export const NotAuthenticated = ({
|
||||
hasLocalNodeRef.current = hasLocalNode;
|
||||
}, [hasLocalNode]);
|
||||
|
||||
|
||||
|
||||
const validateApiKey = useCallback(async (key, fromStartUp) => {
|
||||
try {
|
||||
if(key === "isGateway") return
|
||||
if (key === "isGateway") return;
|
||||
const isLocalKey = cleanUrl(key?.url) === "127.0.0.1:12391";
|
||||
if (fromStartUp && key?.url && key?.apikey && !isLocalKey && !gateways.some(gateway => key?.url?.includes(gateway))) {
|
||||
if (
|
||||
fromStartUp &&
|
||||
key?.url &&
|
||||
key?.apikey &&
|
||||
!isLocalKey &&
|
||||
!gateways.some((gateway) => key?.url?.includes(gateway))
|
||||
) {
|
||||
setCurrentNode({
|
||||
url: key?.url,
|
||||
apikey: key?.apikey,
|
||||
});
|
||||
|
||||
let isValid = false
|
||||
let isValid = false;
|
||||
|
||||
|
||||
const url = `${key?.url}/admin/settings/localAuthBypassEnabled`;
|
||||
const response = await fetch(url);
|
||||
|
||||
// Assuming the response is in plain text and will be 'true' or 'false'
|
||||
const data = await response.text();
|
||||
if(data && data === 'true'){
|
||||
isValid = true
|
||||
if (data && data === "true") {
|
||||
isValid = true;
|
||||
} else {
|
||||
const url2 = `${key?.url}/admin/apikey/test?apiKey=${key?.apikey}`;
|
||||
const response2 = await fetch(url2);
|
||||
|
||||
|
||||
// Assuming the response is in plain text and will be 'true' or 'false'
|
||||
const data2 = await response2.text();
|
||||
if (data2 === "true") {
|
||||
isValid = true
|
||||
isValid = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (isValid) {
|
||||
setIsValidApiKey(true);
|
||||
setUseLocalNode(true);
|
||||
return
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
if (!currentNodeRef.current) return;
|
||||
const stillHasLocal = await checkIfUserHasLocalNode()
|
||||
const stillHasLocal = await checkIfUserHasLocalNode();
|
||||
|
||||
if (isLocalKey && !stillHasLocal && !fromStartUp) {
|
||||
throw new Error("Please turn on your local node");
|
||||
@ -252,27 +253,25 @@ export const NotAuthenticated = ({
|
||||
} else if (currentNodeRef.current) {
|
||||
payload = currentNodeRef.current;
|
||||
}
|
||||
let isValid = false
|
||||
let isValid = false;
|
||||
|
||||
|
||||
const url = `${payload?.url}/admin/settings/localAuthBypassEnabled`;
|
||||
const response = await fetch(url);
|
||||
|
||||
// Assuming the response is in plain text and will be 'true' or 'false'
|
||||
const data = await response.text();
|
||||
if(data && data === 'true'){
|
||||
isValid = true
|
||||
if (data && data === "true") {
|
||||
isValid = true;
|
||||
} else {
|
||||
const url2 = `${payload?.url}/admin/apikey/test?apiKey=${payload?.apikey}`;
|
||||
const response2 = await fetch(url2);
|
||||
|
||||
|
||||
// Assuming the response is in plain text and will be 'true' or 'false'
|
||||
const data2 = await response2.text();
|
||||
if (data2 === "true") {
|
||||
isValid = true
|
||||
isValid = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (isValid) {
|
||||
window
|
||||
@ -296,14 +295,13 @@ export const NotAuthenticated = ({
|
||||
} else {
|
||||
setIsValidApiKey(false);
|
||||
setUseLocalNode(false);
|
||||
if(!fromStartUp){
|
||||
if (!fromStartUp) {
|
||||
setInfoSnack({
|
||||
type: "error",
|
||||
message: "Select a valid apikey",
|
||||
});
|
||||
setOpenSnack(true);
|
||||
}
|
||||
|
||||
}
|
||||
} catch (error) {
|
||||
setIsValidApiKey(false);
|
||||
@ -326,15 +324,15 @@ export const NotAuthenticated = ({
|
||||
error.message || "An error occurred"
|
||||
);
|
||||
});
|
||||
return
|
||||
return;
|
||||
}
|
||||
if (!fromStartUp) {
|
||||
setInfoSnack({
|
||||
type: "error",
|
||||
message: error?.message || "Select a valid apikey",
|
||||
});
|
||||
setOpenSnack(true);
|
||||
}
|
||||
if(!fromStartUp){
|
||||
setInfoSnack({
|
||||
type: "error",
|
||||
message: error?.message || "Select a valid apikey",
|
||||
});
|
||||
setOpenSnack(true);
|
||||
}
|
||||
console.error("Error validating API key:", error);
|
||||
}
|
||||
}, []);
|
||||
@ -363,7 +361,7 @@ export const NotAuthenticated = ({
|
||||
}
|
||||
|
||||
setCustomNodes(nodes);
|
||||
|
||||
|
||||
setCustomNodeToSaveIndex(null);
|
||||
if (!nodes) return;
|
||||
window
|
||||
@ -373,9 +371,11 @@ export const NotAuthenticated = ({
|
||||
setMode("list");
|
||||
setUrl("https://");
|
||||
setCustomApiKey("");
|
||||
if(window?.electronAPI?.setAllowedDomains){
|
||||
window.electronAPI.setAllowedDomains(nodes?.map((node) => node.url))
|
||||
}
|
||||
if (window?.electronAPI?.setAllowedDomains) {
|
||||
window.electronAPI.setAllowedDomains(
|
||||
nodes?.map((node) => node.url)
|
||||
);
|
||||
}
|
||||
// add alert if needed
|
||||
}
|
||||
})
|
||||
@ -404,15 +404,20 @@ export const NotAuthenticated = ({
|
||||
sx={{
|
||||
textAlign: "center",
|
||||
lineHeight: 1.2,
|
||||
fontSize: '18px'
|
||||
fontSize: "18px",
|
||||
}}
|
||||
>
|
||||
WELCOME TO
|
||||
<TextSpan sx={{
|
||||
fontSize: '18px'
|
||||
}}> QORTAL</TextSpan>
|
||||
WELCOME TO
|
||||
<TextSpan
|
||||
sx={{
|
||||
fontSize: "18px",
|
||||
}}
|
||||
>
|
||||
{" "}
|
||||
QORTAL
|
||||
</TextSpan>
|
||||
</TextP>
|
||||
|
||||
|
||||
<Spacer height="30px" />
|
||||
<Box
|
||||
sx={{
|
||||
@ -421,21 +426,31 @@ export const NotAuthenticated = ({
|
||||
alignItems: "center",
|
||||
}}
|
||||
>
|
||||
<HtmlTooltip
|
||||
disableHoverListener={hasSeenGettingStarted === true}
|
||||
placement="left"
|
||||
title={
|
||||
<React.Fragment>
|
||||
<Typography color="inherit" sx={{
|
||||
fontSize: '16px'
|
||||
}}>Your wallet is like your digital ID on Qortal, and is how you will login to the Qortal User Interface. It holds your public address and the Qortal name you will eventually choose. Every transaction you make is linked to your ID, and this is where you manage all your QORT and other tradeable cryptocurrencies on Qortal.</Typography>
|
||||
</React.Fragment>
|
||||
}
|
||||
>
|
||||
<CustomButton onClick={()=> setExtstate('wallets')}>
|
||||
{/* <input {...getInputProps()} /> */}
|
||||
Accounts
|
||||
</CustomButton>
|
||||
<HtmlTooltip
|
||||
disableHoverListener={hasSeenGettingStarted === true}
|
||||
placement="left"
|
||||
title={
|
||||
<React.Fragment>
|
||||
<Typography
|
||||
color="inherit"
|
||||
sx={{
|
||||
fontSize: "16px",
|
||||
}}
|
||||
>
|
||||
Your wallet is like your digital ID on Qortal, and is how you
|
||||
will login to the Qortal User Interface. It holds your public
|
||||
address and the Qortal name you will eventually choose. Every
|
||||
transaction you make is linked to your ID, and this is where you
|
||||
manage all your QORT and other tradeable cryptocurrencies on
|
||||
Qortal.
|
||||
</Typography>
|
||||
</React.Fragment>
|
||||
}
|
||||
>
|
||||
<CustomButton onClick={() => setExtstate("wallets")}>
|
||||
{/* <input {...getInputProps()} /> */}
|
||||
Accounts
|
||||
</CustomButton>
|
||||
</HtmlTooltip>
|
||||
{/* <Tooltip title="Authenticate by importing your Qortal JSON file" arrow>
|
||||
<img src={Info} />
|
||||
@ -448,42 +463,55 @@ export const NotAuthenticated = ({
|
||||
display: "flex",
|
||||
gap: "10px",
|
||||
alignItems: "center",
|
||||
|
||||
}}
|
||||
>
|
||||
<HtmlTooltip
|
||||
disableHoverListener={hasSeenGettingStarted === true}
|
||||
placement="right"
|
||||
title={
|
||||
<React.Fragment>
|
||||
<Typography color="inherit" sx={{
|
||||
fontWeight: 'bold',
|
||||
fontSize: '18px'
|
||||
}}>New users start here!</Typography>
|
||||
<Spacer height='10px'/>
|
||||
<Typography color="inherit" sx={{
|
||||
fontSize: '16px'
|
||||
}}>Creating an account means creating a new wallet and digital ID to start using Qortal. Once you have made your account, you can start doing things like obtaining some QORT, buying a name and avatar, publishing videos and blogs, and much more.</Typography>
|
||||
</React.Fragment>
|
||||
}
|
||||
>
|
||||
<CustomButton
|
||||
onClick={() => {
|
||||
setExtstate("create-wallet");
|
||||
}}
|
||||
sx={{
|
||||
backgroundColor: hasSeenGettingStarted === false && 'var(--green)',
|
||||
color: hasSeenGettingStarted === false && 'black',
|
||||
"&:hover": {
|
||||
backgroundColor: hasSeenGettingStarted === false && 'var(--green)',
|
||||
color: hasSeenGettingStarted === false && 'black'
|
||||
}
|
||||
}}
|
||||
disableHoverListener={hasSeenGettingStarted === true}
|
||||
placement="right"
|
||||
title={
|
||||
<React.Fragment>
|
||||
<Typography
|
||||
color="inherit"
|
||||
sx={{
|
||||
fontWeight: "bold",
|
||||
fontSize: "18px",
|
||||
}}
|
||||
>
|
||||
New users start here!
|
||||
</Typography>
|
||||
<Spacer height="10px" />
|
||||
<Typography
|
||||
color="inherit"
|
||||
sx={{
|
||||
fontSize: "16px",
|
||||
}}
|
||||
>
|
||||
Creating an account means creating a new wallet and digital ID
|
||||
to start using Qortal. Once you have made your account, you can
|
||||
start doing things like obtaining some QORT, buying a name and
|
||||
avatar, publishing videos and blogs, and much more.
|
||||
</Typography>
|
||||
</React.Fragment>
|
||||
}
|
||||
>
|
||||
Create account
|
||||
</CustomButton>
|
||||
<CustomButton
|
||||
onClick={() => {
|
||||
setExtstate("create-wallet");
|
||||
}}
|
||||
sx={{
|
||||
backgroundColor:
|
||||
hasSeenGettingStarted === false && "var(--green)",
|
||||
color: hasSeenGettingStarted === false && "black",
|
||||
"&:hover": {
|
||||
backgroundColor:
|
||||
hasSeenGettingStarted === false && "var(--green)",
|
||||
color: hasSeenGettingStarted === false && "black",
|
||||
},
|
||||
}}
|
||||
>
|
||||
Create account
|
||||
</CustomButton>
|
||||
</HtmlTooltip>
|
||||
|
||||
</Box>
|
||||
<Spacer height="15px" />
|
||||
|
||||
@ -503,15 +531,19 @@ export const NotAuthenticated = ({
|
||||
gap: "10px",
|
||||
alignItems: "center",
|
||||
flexDirection: "column",
|
||||
outline: '0.5px solid rgba(255, 255, 255, 0.5)',
|
||||
padding: '20px 30px',
|
||||
borderRadius: '5px',
|
||||
outline: "0.5px solid rgba(255, 255, 255, 0.5)",
|
||||
padding: "20px 30px",
|
||||
borderRadius: "5px",
|
||||
}}
|
||||
>
|
||||
<>
|
||||
<Typography sx={{
|
||||
textDecoration: 'underline'
|
||||
}}>For advanced users</Typography>
|
||||
<Typography
|
||||
sx={{
|
||||
textDecoration: "underline",
|
||||
}}
|
||||
>
|
||||
For advanced users
|
||||
</Typography>
|
||||
<Box
|
||||
sx={{
|
||||
display: "flex",
|
||||
@ -522,12 +554,11 @@ export const NotAuthenticated = ({
|
||||
}}
|
||||
>
|
||||
<FormControlLabel
|
||||
sx={{
|
||||
"& .MuiFormControlLabel-label": {
|
||||
fontSize: '14px'
|
||||
}
|
||||
|
||||
}}
|
||||
sx={{
|
||||
"& .MuiFormControlLabel-label": {
|
||||
fontSize: "14px",
|
||||
},
|
||||
}}
|
||||
control={
|
||||
<Switch
|
||||
sx={{
|
||||
@ -857,17 +888,25 @@ export const NotAuthenticated = ({
|
||||
</DialogActions>
|
||||
</Dialog>
|
||||
)}
|
||||
<ButtonBase onClick={()=> {
|
||||
showTutorial('create-account', true)
|
||||
}} sx={{
|
||||
position: 'fixed',
|
||||
bottom: '25px',
|
||||
right: '25px'
|
||||
}}>
|
||||
<HelpIcon sx={{
|
||||
color: 'var(--unread)'
|
||||
}} />
|
||||
</ButtonBase>
|
||||
|
||||
<ThemeSelector style={{ position: "fixed", bottom: "1%", left: "1%" }}/>
|
||||
|
||||
<ButtonBase
|
||||
onClick={() => {
|
||||
showTutorial("create-account", true);
|
||||
}}
|
||||
sx={{
|
||||
position: "fixed",
|
||||
bottom: "25px",
|
||||
right: "25px",
|
||||
}}
|
||||
>
|
||||
<HelpIcon
|
||||
sx={{
|
||||
color: "var(--unread)",
|
||||
}}
|
||||
/>
|
||||
</ButtonBase>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
@ -1,86 +1,110 @@
|
||||
import { Box, ButtonBase } from '@mui/material';
|
||||
import React from 'react'
|
||||
import { Box, ButtonBase } from "@mui/material";
|
||||
import React from "react";
|
||||
import { HomeIcon } from "../assets/Icons/HomeIcon";
|
||||
import { MessagingIcon } from "../assets/Icons/MessagingIcon";
|
||||
import { Save } from "./Save/Save";
|
||||
import { HubsIcon } from "../assets/Icons/HubsIcon";
|
||||
import { CoreSyncStatus } from "./CoreSyncStatus";
|
||||
import { IconWrapper } from './Desktop/DesktopFooter';
|
||||
import { IconWrapper } from "./Desktop/DesktopFooter";
|
||||
import AppIcon from "./../assets/svgs/AppIcon.svg";
|
||||
import { useRecoilState } from 'recoil';
|
||||
import { enabledDevModeAtom } from '../atoms/global';
|
||||
import { AppsIcon } from '../assets/Icons/AppsIcon';
|
||||
import { useRecoilState } from "recoil";
|
||||
import { enabledDevModeAtom } from "../atoms/global";
|
||||
import { AppsIcon } from "../assets/Icons/AppsIcon";
|
||||
import ThemeSelector from "./Theme/ThemeSelector";
|
||||
|
||||
export const DesktopSideBar = ({goToHome, setDesktopSideView, toggleSideViewDirects, hasUnreadDirects, isDirects, toggleSideViewGroups,hasUnreadGroups, isGroups, isApps, setDesktopViewMode, desktopViewMode, myName }) => {
|
||||
const [isEnabledDevMode, setIsEnabledDevMode] = useRecoilState(enabledDevModeAtom)
|
||||
export const DesktopSideBar = ({
|
||||
goToHome,
|
||||
setDesktopSideView,
|
||||
toggleSideViewDirects,
|
||||
hasUnreadDirects,
|
||||
isDirects,
|
||||
toggleSideViewGroups,
|
||||
hasUnreadGroups,
|
||||
isGroups,
|
||||
isApps,
|
||||
setDesktopViewMode,
|
||||
desktopViewMode,
|
||||
myName,
|
||||
}) => {
|
||||
const [isEnabledDevMode, setIsEnabledDevMode] =
|
||||
useRecoilState(enabledDevModeAtom);
|
||||
|
||||
return (
|
||||
<Box sx={{
|
||||
width: '60px',
|
||||
flexDirection: 'column',
|
||||
height: '100vh',
|
||||
alignItems: 'center',
|
||||
display: 'flex',
|
||||
gap: '25px'
|
||||
}}>
|
||||
<ButtonBase
|
||||
sx={{
|
||||
width: '60px',
|
||||
height: '60px',
|
||||
paddingTop: '23px'
|
||||
}}
|
||||
onClick={() => {
|
||||
goToHome();
|
||||
|
||||
}}
|
||||
>
|
||||
|
||||
<HomeIcon
|
||||
height={34}
|
||||
color={desktopViewMode === 'home' ? 'white': "rgba(250, 250, 250, 0.5)"}
|
||||
|
||||
/>
|
||||
|
||||
</ButtonBase>
|
||||
<ButtonBase
|
||||
onClick={() => {
|
||||
setDesktopViewMode('apps')
|
||||
// setIsOpenSideViewDirects(false)
|
||||
// setIsOpenSideViewGroups(false)
|
||||
}}
|
||||
>
|
||||
<IconWrapper
|
||||
color={isApps ? 'white' : "rgba(250, 250, 250, 0.5)"}
|
||||
label="Apps"
|
||||
selected={isApps}
|
||||
disableWidth
|
||||
>
|
||||
<AppsIcon color={isApps ? 'white' : "rgba(250, 250, 250, 0.5)"} height={30} />
|
||||
</IconWrapper>
|
||||
</ButtonBase>
|
||||
<ButtonBase
|
||||
onClick={() => {
|
||||
setDesktopViewMode('chat')
|
||||
}}
|
||||
>
|
||||
<Box
|
||||
sx={{
|
||||
width: "60px",
|
||||
flexDirection: "column",
|
||||
height: "100vh",
|
||||
alignItems: "center",
|
||||
display: "flex",
|
||||
gap: "25px",
|
||||
}}
|
||||
>
|
||||
<ButtonBase
|
||||
sx={{
|
||||
width: "60px",
|
||||
height: "60px",
|
||||
paddingTop: "23px",
|
||||
}}
|
||||
onClick={() => {
|
||||
goToHome();
|
||||
}}
|
||||
>
|
||||
<HomeIcon
|
||||
height={34}
|
||||
color={
|
||||
desktopViewMode === "home" ? "white" : "rgba(250, 250, 250, 0.5)"
|
||||
}
|
||||
/>
|
||||
</ButtonBase>
|
||||
<ButtonBase
|
||||
onClick={() => {
|
||||
setDesktopViewMode("apps");
|
||||
// setIsOpenSideViewDirects(false)
|
||||
// setIsOpenSideViewGroups(false)
|
||||
}}
|
||||
>
|
||||
<IconWrapper
|
||||
color={(hasUnreadDirects || hasUnreadGroups) ? "var(--unread)" : desktopViewMode === 'chat' ? 'white' :"rgba(250, 250, 250, 0.5)"}
|
||||
label="Chat"
|
||||
disableWidth
|
||||
>
|
||||
<MessagingIcon
|
||||
height={30}
|
||||
color={
|
||||
(hasUnreadDirects || hasUnreadGroups)
|
||||
? "var(--unread)"
|
||||
: desktopViewMode === 'chat'
|
||||
? "white"
|
||||
: "rgba(250, 250, 250, 0.5)"
|
||||
}
|
||||
/>
|
||||
</IconWrapper>
|
||||
</ButtonBase>
|
||||
{/* <ButtonBase
|
||||
color={isApps ? "white" : "rgba(250, 250, 250, 0.5)"}
|
||||
label="Apps"
|
||||
selected={isApps}
|
||||
disableWidth
|
||||
>
|
||||
<AppsIcon
|
||||
color={isApps ? "white" : "rgba(250, 250, 250, 0.5)"}
|
||||
height={30}
|
||||
/>
|
||||
</IconWrapper>
|
||||
</ButtonBase>
|
||||
<ButtonBase
|
||||
onClick={() => {
|
||||
setDesktopViewMode("chat");
|
||||
}}
|
||||
>
|
||||
<IconWrapper
|
||||
color={
|
||||
hasUnreadDirects || hasUnreadGroups
|
||||
? "var(--unread)"
|
||||
: desktopViewMode === "chat"
|
||||
? "white"
|
||||
: "rgba(250, 250, 250, 0.5)"
|
||||
}
|
||||
label="Chat"
|
||||
disableWidth
|
||||
>
|
||||
<MessagingIcon
|
||||
height={30}
|
||||
color={
|
||||
hasUnreadDirects || hasUnreadGroups
|
||||
? "var(--unread)"
|
||||
: desktopViewMode === "chat"
|
||||
? "white"
|
||||
: "rgba(250, 250, 250, 0.5)"
|
||||
}
|
||||
/>
|
||||
</IconWrapper>
|
||||
</ButtonBase>
|
||||
{/* <ButtonBase
|
||||
onClick={() => {
|
||||
setDesktopSideView("groups");
|
||||
toggleSideViewGroups()
|
||||
@ -98,23 +122,32 @@ export const DesktopSideBar = ({goToHome, setDesktopSideView, toggleSideViewDire
|
||||
/>
|
||||
|
||||
</ButtonBase> */}
|
||||
<Save isDesktop disableWidth myName={myName} />
|
||||
{/* <CoreSyncStatus imageSize="30px" position="left" /> */}
|
||||
{isEnabledDevMode && (
|
||||
<ButtonBase
|
||||
<Save isDesktop disableWidth myName={myName} />
|
||||
{/* <CoreSyncStatus imageSize="30px" position="left" /> */}
|
||||
{isEnabledDevMode && (
|
||||
<ButtonBase
|
||||
onClick={() => {
|
||||
setDesktopViewMode('dev')
|
||||
setDesktopViewMode("dev");
|
||||
}}
|
||||
>
|
||||
<IconWrapper
|
||||
color={desktopViewMode === 'dev' ? 'white' : "rgba(250, 250, 250, 0.5)"}
|
||||
color={
|
||||
desktopViewMode === "dev" ? "white" : "rgba(250, 250, 250, 0.5)"
|
||||
}
|
||||
label="Dev"
|
||||
disableWidth
|
||||
>
|
||||
<AppsIcon color={desktopViewMode === 'dev' ? 'white' : "rgba(250, 250, 250, 0.5)"} height={30} />
|
||||
<AppsIcon
|
||||
color={
|
||||
desktopViewMode === "dev" ? "white" : "rgba(250, 250, 250, 0.5)"
|
||||
}
|
||||
height={30}
|
||||
/>
|
||||
</IconWrapper>
|
||||
</ButtonBase>
|
||||
)}
|
||||
</Box>
|
||||
)
|
||||
}
|
||||
)}
|
||||
|
||||
<ThemeSelector style={{ position: "fixed", bottom: "1%" }} />
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
23
src/components/Theme/ThemeContext.tsx
Normal file
23
src/components/Theme/ThemeContext.tsx
Normal file
@ -0,0 +1,23 @@
|
||||
import { createContext, useContext, useState, useMemo } from 'react';
|
||||
import { ThemeProvider as MuiThemeProvider } from '@mui/material/styles';
|
||||
import { darkTheme, lightTheme } from '../../styles/theme';
|
||||
|
||||
const ThemeContext = createContext({ themeMode: 'light', toggleTheme: () => {} });
|
||||
|
||||
export const ThemeProvider = ({ children }: { children: React.ReactNode }) => {
|
||||
const [themeMode, setThemeMode] = useState('light');
|
||||
|
||||
const theme = useMemo(() => (themeMode === 'light' ? lightTheme : darkTheme), [themeMode]);
|
||||
|
||||
const toggleTheme = () => {
|
||||
setThemeMode((prevMode) => (prevMode === 'light' ? 'dark' : 'light'));
|
||||
};
|
||||
|
||||
return (
|
||||
<ThemeContext.Provider value={{ themeMode, toggleTheme }}>
|
||||
<MuiThemeProvider theme={theme}>{children}</MuiThemeProvider>
|
||||
</ThemeContext.Provider>
|
||||
);
|
||||
};
|
||||
|
||||
export const useThemeContext = () => useContext(ThemeContext);
|
18
src/components/Theme/ThemeSelector.tsx
Normal file
18
src/components/Theme/ThemeSelector.tsx
Normal file
@ -0,0 +1,18 @@
|
||||
import { useThemeContext } from "./ThemeContext";
|
||||
import { Switch } from "@mui/material";
|
||||
import { Brightness4, Brightness7 } from "@mui/icons-material";
|
||||
|
||||
const ThemeSelector = ({ style }) => {
|
||||
const { themeMode, toggleTheme } = useThemeContext();
|
||||
|
||||
return (
|
||||
<div
|
||||
style={{ display: "flex", flexDirection: "column", alignItems: "center", gap: "1px", ...style }}
|
||||
>
|
||||
{themeMode === "dark" ? <Brightness7 /> : <Brightness4 />}
|
||||
<Switch checked={themeMode === "dark"} onChange={toggleTheme} />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default ThemeSelector;
|
208
src/main.tsx
208
src/main.tsx
@ -1,81 +1,139 @@
|
||||
import React from 'react'
|
||||
import ReactDOM from 'react-dom/client'
|
||||
import App from './App.tsx'
|
||||
import './index.css'
|
||||
import "./messaging/messagesToBackground";
|
||||
import { ThemeProvider, createTheme } from '@mui/material/styles';
|
||||
import { CssBaseline } from '@mui/material';
|
||||
import { MessageQueueProvider } from './MessageQueueContext.tsx';
|
||||
import { RecoilRoot } from 'recoil';
|
||||
const theme = createTheme({
|
||||
palette: {
|
||||
primary: {
|
||||
main: '#232428', // Primary color (e.g., used for buttons, headers, etc.)
|
||||
},
|
||||
secondary: {
|
||||
main: '#232428', // Secondary color
|
||||
},
|
||||
background: {
|
||||
default: '#27282c', // Default background color
|
||||
paper: '#1d1d1d', // Paper component background (for dropdowns, dialogs, etc.)
|
||||
},
|
||||
text: {
|
||||
primary: '#ffffff', // White as the primary text color
|
||||
secondary: '#b0b0b0', // Light gray for secondary text
|
||||
disabled: '#808080', // Gray for disabled text
|
||||
},
|
||||
action: {
|
||||
// disabledBackground: 'set color of background here',
|
||||
disabled: 'rgb(255 255 255 / 70%)'
|
||||
}
|
||||
},
|
||||
typography: {
|
||||
fontFamily: '"Inter", "Roboto", "Helvetica", "Arial", sans-serif', // Font family
|
||||
h1: {
|
||||
color: '#ffffff', // White color for h1 elements
|
||||
},
|
||||
h2: {
|
||||
color: '#ffffff', // White color for h2 elements
|
||||
},
|
||||
body1: {
|
||||
color: '#ffffff', // Default body text color
|
||||
},
|
||||
body2: {
|
||||
color: '#b0b0b0', // Lighter text for body2, often used for secondary text
|
||||
},
|
||||
},
|
||||
components: {
|
||||
MuiOutlinedInput: {
|
||||
styleOverrides: {
|
||||
root: {
|
||||
".MuiOutlinedInput-notchedOutline": {
|
||||
borderColor: "white", // ⚪ Default outline color
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
MuiSelect: {
|
||||
styleOverrides: {
|
||||
icon: {
|
||||
color: "white", // ✅ Caret (dropdown arrow) color
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
import React from "react";
|
||||
import ReactDOM from "react-dom/client";
|
||||
import App from "./App.tsx";
|
||||
import "./index.css";
|
||||
import "./messaging/messagesToBackground";
|
||||
import { CssBaseline } from "@mui/material";
|
||||
import { MessageQueueProvider } from "./MessageQueueContext.tsx";
|
||||
import { RecoilRoot } from "recoil";
|
||||
import { ThemeProvider } from "./components/Theme/ThemeContext.tsx";
|
||||
|
||||
export default theme;
|
||||
// const darkTheme: ThemeOptions = {
|
||||
// palette: {
|
||||
// primary: {
|
||||
// main: "#232428", // Primary color (e.g., used for buttons, headers, etc.)
|
||||
// },
|
||||
// secondary: {
|
||||
// main: "#232428", // Secondary color
|
||||
// },
|
||||
// background: {
|
||||
// default: "#27282c", // Default background color
|
||||
// paper: "#1d1d1d", // Paper component background (for dropdowns, dialogs, etc.)
|
||||
// },
|
||||
// text: {
|
||||
// primary: "#ffffff", // White as the primary text color
|
||||
// secondary: "#b0b0b0", // Light gray for secondary text
|
||||
// disabled: "#808080", // Gray for disabled text
|
||||
// },
|
||||
// action: {
|
||||
// // disabledBackground: 'set color of background here',
|
||||
// disabled: "rgb(255 255 255 / 70%)",
|
||||
// },
|
||||
// },
|
||||
// typography: {
|
||||
// fontFamily: '"Inter", "Roboto", "Helvetica", "Arial", sans-serif', // Font family
|
||||
// h1: {
|
||||
// color: "#ffffff", // White color for h1 elements
|
||||
// },
|
||||
// h2: {
|
||||
// color: "#ffffff", // White color for h2 elements
|
||||
// },
|
||||
// body1: {
|
||||
// color: "#ffffff", // Default body text color
|
||||
// },
|
||||
// body2: {
|
||||
// color: "#b0b0b0", // Lighter text for body2, often used for secondary text
|
||||
// },
|
||||
// },
|
||||
// components: {
|
||||
// MuiOutlinedInput: {
|
||||
// styleOverrides: {
|
||||
// root: {
|
||||
// ".MuiOutlinedInput-notchedOutline": {
|
||||
// borderColor: "white", // ⚪ Default outline color
|
||||
// },
|
||||
// },
|
||||
// },
|
||||
// },
|
||||
// MuiSelect: {
|
||||
// styleOverrides: {
|
||||
// icon: {
|
||||
// color: "white", // ✅ Caret (dropdown arrow) color
|
||||
// },
|
||||
// },
|
||||
// },
|
||||
// },
|
||||
// }
|
||||
|
||||
// const lightTheme: ThemeOptions = {
|
||||
// palette: {
|
||||
// primary: {
|
||||
// main: "#1976d2", // Primary color for buttons, headers, etc.
|
||||
// },
|
||||
// secondary: {
|
||||
// main: "#ff4081", // Secondary color with a vibrant pink touch
|
||||
// },
|
||||
// background: {
|
||||
// default: "#f5f5f5", // Light background color for the main UI
|
||||
// paper: "#ffffff", // Background color for Paper components (dialogs, dropdowns, etc.)
|
||||
// },
|
||||
// text: {
|
||||
// primary: "#212121", // Dark text for contrast and readability
|
||||
// secondary: "#616161", // Medium gray for secondary text
|
||||
// disabled: "#9e9e9e", // Light gray for disabled text
|
||||
// },
|
||||
// action: {
|
||||
// disabled: "rgb(0 0 0 / 50%)", // Color for disabled actions
|
||||
// },
|
||||
// },
|
||||
// typography: {
|
||||
// fontFamily: '"Inter", "Roboto", "Helvetica", "Arial", sans-serif', // Font family for consistency
|
||||
// h1: {
|
||||
// color: "#ffffff", // Dark color for main headings (h1)
|
||||
// },
|
||||
// h2: {
|
||||
// color: "#ffffff", // Dark color for subheadings (h2)
|
||||
// },
|
||||
// body1: {
|
||||
// color: "#ffffff", // Default body text color
|
||||
// },
|
||||
// body2: {
|
||||
// color: "#ffffff", // Lighter text for secondary content
|
||||
// },
|
||||
// },
|
||||
// components: {
|
||||
// MuiOutlinedInput: {
|
||||
// styleOverrides: {
|
||||
// root: {
|
||||
// ".MuiOutlinedInput-notchedOutline": {
|
||||
// borderColor: "#ffffff", // Darker outline for better input field visibility
|
||||
// },
|
||||
// },
|
||||
// },
|
||||
// },
|
||||
// MuiSelect: {
|
||||
// styleOverrides: {
|
||||
// icon: {
|
||||
// color: "#212121", // Dark dropdown arrow icon for contrast
|
||||
// },
|
||||
// },
|
||||
// },
|
||||
// },
|
||||
// };
|
||||
|
||||
ReactDOM.createRoot(document.getElementById('root')!).render(
|
||||
// const theme = createTheme(lightTheme);
|
||||
|
||||
// export default theme;
|
||||
|
||||
ReactDOM.createRoot(document.getElementById("root")!).render(
|
||||
<>
|
||||
<ThemeProvider theme={theme}>
|
||||
<ThemeProvider>
|
||||
<CssBaseline />
|
||||
<MessageQueueProvider>
|
||||
<RecoilRoot>
|
||||
<App />
|
||||
</RecoilRoot>
|
||||
</MessageQueueProvider>
|
||||
<MessageQueueProvider>
|
||||
<RecoilRoot>
|
||||
<App />
|
||||
</RecoilRoot>
|
||||
</MessageQueueProvider>
|
||||
</ThemeProvider>
|
||||
</>,
|
||||
)
|
||||
</>
|
||||
);
|
||||
|
Loading…
x
Reference in New Issue
Block a user