-
Notifications
You must be signed in to change notification settings - Fork 209
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Feat: Add dark mode switch #1409
Changes from 12 commits
55225ad
6d6a13a
80dee67
dd488fe
efa106f
a97b2f0
3ab8b12
cdcefb1
c565cc7
e6faf96
0e8b82b
663f233
acefedd
7c5c350
76dc4eb
b97e70f
4e85e60
9ef1c35
3f7d3ef
b5a125b
0c16a62
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,98 @@ | ||
import { useTheme } from "@mui/material"; | ||
import "./index.css"; | ||
|
||
const SunAndMoonIcon = () => { | ||
const theme = useTheme(); | ||
|
||
return ( | ||
<svg | ||
className="sun-and-moon" | ||
aria-hidden="true" | ||
width="24" | ||
height="24" | ||
viewBox="0 0 24 24" | ||
> | ||
<mask | ||
className="moon" | ||
id="moon-mask" | ||
> | ||
<rect | ||
x="0" | ||
y="0" | ||
width="100%" | ||
height="100%" | ||
fill="#fff" | ||
/> | ||
<circle | ||
cx="24" | ||
cy="10" | ||
r="6" | ||
fill="#000" | ||
/> | ||
</mask> | ||
<circle | ||
className="sun" | ||
cx="12" | ||
cy="12" | ||
r="6" | ||
fill={theme.palette.text.secondary} | ||
mask="url(#moon-mask)" | ||
/> | ||
<g | ||
className="sun-beams" | ||
stroke={theme.palette.text.secondary} | ||
> | ||
<line | ||
x1="12" | ||
y1="1" | ||
x2="12" | ||
y2="3" | ||
/> | ||
<line | ||
x1="12" | ||
y1="21" | ||
x2="12" | ||
y2="23" | ||
/> | ||
<line | ||
x1="4.22" | ||
y1="4.22" | ||
x2="5.64" | ||
y2="5.64" | ||
/> | ||
<line | ||
x1="18.36" | ||
y1="18.36" | ||
x2="19.78" | ||
y2="19.78" | ||
/> | ||
<line | ||
x1="1" | ||
y1="12" | ||
x2="3" | ||
y2="12" | ||
/> | ||
<line | ||
x1="21" | ||
y1="12" | ||
x2="23" | ||
y2="12" | ||
/> | ||
<line | ||
x1="4.22" | ||
y1="19.78" | ||
x2="5.64" | ||
y2="18.36" | ||
/> | ||
<line | ||
x1="18.36" | ||
y1="5.64" | ||
x2="19.78" | ||
y2="4.22" | ||
/> | ||
</g> | ||
</svg> | ||
); | ||
}; | ||
|
||
export default SunAndMoonIcon; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
.sun-and-moon > :is(.moon, .sun, .sun-beams) { | ||
transform-origin: center; | ||
} | ||
|
||
.theme-toggle .sun-and-moon > .sun-beams { | ||
stroke-width: 2px; | ||
} | ||
|
||
[data-theme="dark"] .sun-and-moon > .sun { | ||
transform: scale(1.75); | ||
} | ||
|
||
[data-theme="dark"] .sun-and-moon > .sun-beams { | ||
opacity: 0; | ||
} | ||
|
||
[data-theme="dark"] .sun-and-moon > .moon > circle { | ||
transform: translateX(-7px); | ||
} | ||
|
||
@supports (cx: 1) { | ||
[data-theme="dark"] .sun-and-moon > .moon > circle { | ||
cx: 17; | ||
transform: translateX(0); | ||
} | ||
} | ||
|
||
@media (prefers-reduced-motion: no-preference) { | ||
.sun-and-moon > .sun { | ||
transition: transform 0.5s var(--ease-elastic-3); | ||
} | ||
|
||
.sun-and-moon > .sun-beams { | ||
transition: | ||
transform 0.5s var(--ease-elastic-4), | ||
opacity 0.5s var(--ease-3); | ||
} | ||
|
||
.sun-and-moon .moon > circle { | ||
transition: transform 0.25s var(--ease-out-5); | ||
} | ||
|
||
@supports (cx: 1) { | ||
.sun-and-moon .moon > circle { | ||
transition: cx 0.25s var(--ease-out-5); | ||
} | ||
} | ||
|
||
[data-theme="dark"] .sun-and-moon > .sun { | ||
transition-timing-function: var(--ease-3); | ||
transition-duration: 0.25s; | ||
transform: scale(1.75); | ||
} | ||
|
||
[data-theme="dark"] .sun-and-moon > .sun-beams { | ||
transition-duration: 0.15s; | ||
transform: rotateZ(-25deg); | ||
} | ||
|
||
[data-theme="dark"] .sun-and-moon > .moon > circle { | ||
transition-duration: 0.5s; | ||
transition-delay: 0.25s; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
import React, { useEffect, useState } from "react"; | ||
import { IconButton } from "@mui/material"; | ||
import SunAndMoonIcon from "./SunAndMoonIcon"; | ||
import "./index.css"; | ||
import { useDispatch, useSelector } from "react-redux"; | ||
import { setMode } from "../../Features/UI/uiSlice"; | ||
|
||
const ThemeSwitch = () => { | ||
const mode = useSelector((state) => state.ui.mode); | ||
const dispatch = useDispatch(); | ||
|
||
const toggleTheme = () => { | ||
dispatch(setMode(mode === "light" ? "dark" : "light")); | ||
}; | ||
|
||
useEffect(() => { | ||
document.body.setAttribute("data-theme", mode); | ||
}, [mode]); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I understand the logic from this implementation relies on data-attributes. But we already have a theme on redux. I suggest adapting that to rely on our theme as well. This way you can ditch this useEffect There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Got it. Let me update the component. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Here is the commit for the changes I made: 7c5c350 |
||
|
||
return ( | ||
<IconButton | ||
id="theme-toggle" | ||
title="Toggles light & dark" | ||
aria-label="auto" | ||
aria-live="polite" | ||
onClick={toggleTheme} | ||
sx={{ | ||
width: 48, | ||
height: 48, | ||
display: "flex", | ||
alignItems: "center", | ||
justifyContent: "center", | ||
}} | ||
> | ||
<SunAndMoonIcon /> | ||
</IconButton> | ||
); | ||
}; | ||
|
||
export default ThemeSwitch; |
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
@@ -17,6 +17,7 @@ import ArrowBackRoundedIcon from "@mui/icons-material/ArrowBackRounded"; | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
import PropTypes from "prop-types"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
import { logger } from "../../Utils/Logger"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
import "./index.css"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
import ThemeSwitch from "../../Components/ThemeSwitch"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
const DEMO = import.meta.env.VITE_APP_DEMO; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
/** | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
@@ -327,33 +328,25 @@ const StepTwo = ({ form, errors, onSubmit, onChange, onBack }) => { | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
</LoadingButton> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
</Stack> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
</Box> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
<Box | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
textAlign="center" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
sx={{ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
position: "absolute", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
bottom: 0, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
left: "50%", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
transform: `translate(-50%, 150%)`, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
}} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
<Typography | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
className="forgot-p" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
display="inline-block" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
color={theme.palette.primary.main} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Forgot password? | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
</Typography> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
<Typography | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
component="span" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
color={theme.palette.primary.main} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
ml={theme.spacing(2)} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
sx={{ userSelect: "none" }} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
onClick={handleNavigate} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Reset password | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
</Typography> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
</Box> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
</Stack> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
<Box textAlign="center"> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
<Typography | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
className="forgot-p" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
display="inline-block" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
color={theme.palette.primary.main} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Forgot password? | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
</Typography> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
<Typography | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
component="span" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
color={theme.palette.primary.main} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
ml={theme.spacing(2)} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
sx={{ userSelect: "none" }} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
onClick={handleNavigate} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Reset password | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
</Typography> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
</Box> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Improve keyboard accessibility for password reset The password reset section could benefit from better keyboard accessibility. Consider this improvement: <Typography
component="span"
color={theme.palette.primary.main}
ml={theme.spacing(2)}
- sx={{ userSelect: "none" }}
+ sx={{
+ userSelect: "none",
+ cursor: "pointer",
+ "&:focus-visible": {
+ outline: `2px solid ${theme.palette.primary.main}`,
+ outlineOffset: "2px",
+ }
+ }}
+ tabIndex={0}
+ role="button"
+ onKeyDown={(e) => e.key === "Enter" && handleNavigate()}
onClick={handleNavigate}
> 📝 Committable suggestion
Suggested change
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
</> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
}; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
@@ -520,6 +513,7 @@ const Login = () => { | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
px={{ xs: theme.spacing(12), lg: theme.spacing(20) }} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
pb={theme.spacing(20)} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
mx="auto" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
gap={theme.spacing(8)} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
sx={{ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
"& > .MuiStack-root": { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
border: 1, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
@@ -554,6 +548,9 @@ const Login = () => { | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
/> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
)} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
<Box marginX={"auto"}> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
<ThemeSwitch /> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
</Box> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
</Stack> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
</Stack> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,5 @@ | ||
@import url("https://fonts.googleapis.com/css2?family=Inter:ital,opsz,wght@0,14..32,100..900;1,14..32,100..900&display=swap"); | ||
@import "https://unpkg.com/open-props/easings.min.css"; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What is this for? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think this one is responsible for importing the easing functions that is being used by the toggle switch. I found it here in the code of the css file https://web.dev/patterns/theming/theme-switch. This are currently the easing variables that is being used:
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @peterpardo we don't want the project to depened on a CDN that we can't guarantee is going to be available at all times. Can you please copy only the css that is needed from that css file and add it locally? We can drop the import then and ensure the code wil be working at all times. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Got it. I'll check how they did the animation. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Here are the new changes. I've removed the import and instead just took the code needed for the smooth animation of the toggle to work. |
||
|
||
* { | ||
box-sizing: border-box; | ||
|
This comment was marked as off-topic.
Sorry, something went wrong.