Skip to content

Commit e6ecc39

Browse files
committed
feat(dark-mode): add toggle dark mode functionality
1 parent 9f02155 commit e6ecc39

8 files changed

+130
-43
lines changed

src/assets/darkMode.png

941 Bytes
Loading

src/assets/lightMode.png

937 Bytes
Loading

src/assets/ytLogo-dark.png

34.6 KB
Loading

src/components/DarkModeButton.jsx

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import React from "react";
2+
import { useDispatch } from "react-redux";
3+
import { setDarkMode } from "../redux/darkModeSlice";
4+
5+
function DarkModeButton() {
6+
const dispatch = useDispatch();
7+
8+
return (
9+
<button
10+
className="flex-grow flex gap-4"
11+
onClick={() => {
12+
dispatch(setDarkMode());
13+
}}
14+
>
15+
Switch Theme
16+
</button>
17+
);
18+
}
19+
20+
export default DarkModeButton;

src/components/Navbar.jsx

+87-42
Original file line numberDiff line numberDiff line change
@@ -1,69 +1,114 @@
1-
import React, { useState } from 'react'
2-
import Menu from '../assets/Menu'
3-
import logo from "../assets/ytLogo.png"
4-
import { Link } from 'react-router-dom';
5-
import { setSidebarExtendedValue } from '../redux/categorySlice';
6-
import { useNavigate } from 'react-router-dom';
7-
import { useDispatch, useSelector } from 'react-redux';
8-
import Stack from '@mui/material/Stack';
9-
import LinearProgress from '@mui/material/LinearProgress';
1+
import React, { useState } from "react";
2+
import Menu from "../assets/Menu";
3+
import logo from "../assets/ytLogo.png";
4+
import logoDark from "../assets/ytLogo-dark.png";
5+
6+
import { Link } from "react-router-dom";
7+
import { setSidebarExtendedValue } from "../redux/categorySlice";
8+
import { useNavigate } from "react-router-dom";
9+
import { useDispatch, useSelector } from "react-redux";
10+
import Stack from "@mui/material/Stack";
11+
import LinearProgress from "@mui/material/LinearProgress";
12+
import DarkModeButton from "./DarkModeButton";
1013

1114
function Navbar({ sidebarExtended, setSidebarExtended }) {
12-
const dispatch = useDispatch()
13-
const pageRoute = useNavigate()
14-
const [searchValue, setSearchValue] = useState("")
15+
const dispatch = useDispatch();
16+
const pageRoute = useNavigate();
17+
const [searchValue, setSearchValue] = useState("");
1518
const { isLoading } = useSelector((state) => state.category);
16-
const channelLoading = useSelector((state) => state.channel.isLoading)
17-
const videoLoading = useSelector((state) => state.video.isLoading)
18-
const searchLoading = useSelector((state) => state.search.isLoading)
19-
19+
const channelLoading = useSelector((state) => state.channel.isLoading);
20+
const videoLoading = useSelector((state) => state.video.isLoading);
21+
const searchLoading = useSelector((state) => state.search.isLoading);
22+
const { darkMode } = useSelector((state) => state.darkMode);
2023

2124
const handleOnSubmit = (e) => {
22-
e.preventDefault()
23-
pageRoute(`/search/${searchValue}`)
24-
e.target.value = " "
25-
}
25+
e.preventDefault();
26+
pageRoute(`/search/${searchValue}`);
27+
e.target.value = " ";
28+
};
29+
2630
return (
2731
<>
28-
<div className='h-[50px] fixed z-10 bg-[#ffff] w-[100%]'>
29-
{
30-
videoLoading || channelLoading || isLoading || searchLoading ? <Stack sx={{ width: "100%", color: "grey.500" }} spacing={2}>
32+
<div
33+
className={`h-[50px] fixed z-10 w-[100%] ${
34+
darkMode ? "bg-dark text-white" : "bg-white"
35+
}`}
36+
>
37+
{videoLoading || channelLoading || isLoading || searchLoading ? (
38+
<Stack sx={{ width: "100%", color: "grey.500" }} spacing={2}>
3139
<LinearProgress color="error" />
32-
</Stack> : ""
33-
}
40+
</Stack>
41+
) : (
42+
""
43+
)}
3444

35-
<nav className='flex h-[60px] items-center space-x-2 lg:space-x-20 xl:space-x-64'>
36-
<div className='flex items-center space-x-4 ml-3 -mt-4 pl-2'>
37-
<button className='' onClick={() => {
38-
dispatch(setSidebarExtendedValue(!sidebarExtended))
39-
setSidebarExtended(!sidebarExtended)
40-
}}>
45+
<nav className="flex h-[60px] items-center space-x-2 lg:space-x-20 xl:space-x-64">
46+
<div className="flex items-center space-x-4 ml-3 -mt-4 pl-2">
47+
<button
48+
className=""
49+
onClick={() => {
50+
dispatch(setSidebarExtendedValue(!sidebarExtended));
51+
setSidebarExtended(!sidebarExtended);
52+
}}
53+
>
4154
<Menu />
42-
4355
</button>
4456
{/* <button className='block sm:hidden' onClick={() => {
4557
}}>
4658
<Menu />
4759
4860
</button> */}
49-
<Link to='/'>
50-
51-
<img className='w-32' src={logo} alt="" />
61+
<Link to="/">
62+
{darkMode ? (
63+
<img className="w-24 ml-4" src={logoDark} alt="" />
64+
) : (
65+
<img className="w-32" src={logo} alt="" />
66+
)}
5267
</Link>
53-
5468
</div>
55-
<form onSubmit={handleOnSubmit} className='-mt-3'>
69+
<form onSubmit={handleOnSubmit} className="-mt-3">
5670
<div className="relative w-[170px] sm:w-[420px] ">
57-
<input onChange={(e) => setSearchValue(e.target.value)} type="search" name='search' id="default-search" className="block p-2 pl-10 w-full text-sm text-gray-900 bg-gray-50 rounded-lg border-[1px] border-[#cccccc] focus:outline-none" placeholder="Search" required />
58-
<button type="submit" className="text-white absolute right-0 bottom-0 top-0 font-medium text-sm px-4 py-2 bg-[#f8f8f8] border-[1px] border-[#cccccc]"> <svg className="w-5 h-5 text-gray-500 dark:text-gray-400" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"></path></svg>
71+
<input
72+
onChange={(e) => setSearchValue(e.target.value)}
73+
type="search"
74+
name="search"
75+
id="default-search"
76+
className={`block p-2 pl-10 w-full text-sm text-gray-900 ${
77+
darkMode ? "bg-dark" : "bg-gray-50"
78+
} rounded-lg border-[1px] border-[#cccccc] focus:outline-none`}
79+
placeholder="Search"
80+
required
81+
/>
82+
<button
83+
type="submit"
84+
className={`text-white absolute right-0 bottom-0 top-0 font-medium text-sm px-4 py-2 ${
85+
darkMode ? "bg-dark" : "bg-[#f8f8f8]"
86+
} border-[1px] border-[#cccccc]`}
87+
>
88+
{" "}
89+
<svg
90+
className="w-5 h-5 text-gray-500 dark:text-gray-400"
91+
fill="none"
92+
stroke="currentColor"
93+
viewBox="0 0 24 24"
94+
xmlns="http://www.w3.org/2000/svg"
95+
>
96+
<path
97+
strokeLinecap="round"
98+
strokeLinejoin="round"
99+
strokeWidth="2"
100+
d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"
101+
></path>
102+
</svg>
59103
</button>
60104
</div>
61105
</form>
62-
</nav>
63106

107+
<DarkModeButton />
108+
</nav>
64109
</div>
65110
</>
66-
)
111+
);
67112
}
68113

69-
export default Navbar
114+
export default Navbar;

src/redux/darkModeSlice.js

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import { createSlice } from "@reduxjs/toolkit";
2+
const initialState = {
3+
darkMode: false,
4+
};
5+
6+
const darkModeSlice = createSlice({
7+
name: "darkMode",
8+
initialState,
9+
reducers: {
10+
setDarkMode: (state) => {
11+
state.darkMode = !state.darkMode;
12+
},
13+
},
14+
});
15+
export const { setDarkMode } = darkModeSlice.actions;
16+
export default darkModeSlice.reducer;

src/store.js

+2
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,14 @@ import categorySlice from "./redux/categorySlice";
33
import channelSlice from "./redux/channelSlice";
44
import searchSlice from "./redux/searchSlice";
55
import videoSlice from "./redux/videoSlice";
6+
import darkModeSlice from "./redux/darkModeSlice";
67
const store = configureStore({
78
reducer: {
89
category: categorySlice,
910
channel: channelSlice,
1011
video: videoSlice,
1112
search: searchSlice,
13+
darkMode: darkModeSlice,
1214
},
1315
});
1416
export default store;

tailwind.config.js

+5-1
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,11 @@ module.exports = {
2323
},
2424
content: ["./src/**/*.{html,js,jsx}", "./public/*"],
2525
theme: {
26-
extend: {},
26+
extend: {
27+
colors: {
28+
dark: "#131417",
29+
},
30+
},
2731
},
2832
plugins: [],
2933
};

0 commit comments

Comments
 (0)