Skip to content
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

๐Ÿ’กโพ: Dark and light mode features enabled in UI #7

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@
},
"dependencies": {
"react": "^18.3.1",
"react-dom": "^18.3.1"
"react-dom": "^18.3.1",
"react-icons": "^5.4.0"
},
"devDependencies": {
"@crxjs/vite-plugin": "^2.0.0-beta.30",
Expand Down
12 changes: 9 additions & 3 deletions src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,14 @@
import Navbar from './components/Navbar';
import { DarkModeProvider } from './providers/DarkModeProvider';

function App() {
return (
<h1 className="my-5 text-center text-3xl font-bold">
Active Yuwa Extension
</h1>
<DarkModeProvider>
<div className="min-h-screen transition-colors duration-300 ease-in-out bg-gray-100 dark:bg-gray-900 text-gray-900 dark:text-gray-100">
<Navbar />
{/* Add your main content here */}
</div>
</DarkModeProvider>
);
}

Expand Down
15 changes: 15 additions & 0 deletions src/components/Navbar.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import React from 'react';
import ThemeToggleButton from './ui/ThemeToggleButton';

const Navbar: React.FC = () => {
return (
<nav className="flex justify-between items-center p-4 bg-white dark:bg-gray-800 text-black dark:text-white">
<h1 className="text-3xl font-bold transition-colors duration-300 ease-in-out">
Active Yuwa Extension
</h1>
<ThemeToggleButton />
</nav>
);
};

export default Navbar;
23 changes: 23 additions & 0 deletions src/components/ui/ThemeToggleButton.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import React from 'react';
import { MdDarkMode, MdLightMode } from "react-icons/md";
import { useDarkMode } from '../../providers/DarkModeProvider';

const ThemeToggleButton: React.FC = () => {
const { darkMode, toggleDarkMode } = useDarkMode();

return (
<button
onClick={toggleDarkMode}
className="p-2 transition-colors duration-300 ease-in-out"
aria-label={darkMode ? "Switch to light mode" : "Switch to dark mode"}
>
{darkMode ? (
<MdLightMode size={24} className="text-yellow-400" />
) : (
<MdDarkMode size={24} className="text-gray-600" />
)}
</button>
);
};

export default ThemeToggleButton;
7 changes: 7 additions & 0 deletions src/index.css
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
@tailwind base;
@tailwind components;
@tailwind utilities;

@layer base {
body {
@apply bg-white dark:bg-gray-900 text-gray-900 dark:text-gray-100;
transition: background-color 0.3s ease-in-out, color 0.3s ease-in-out;
}
}
6 changes: 3 additions & 3 deletions src/main.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { StrictMode } from "react";
import React from "react";
import { createRoot } from "react-dom/client";
import App from "./App.tsx";
import "./index.css";

createRoot(document.getElementById("root")!).render(
<StrictMode>
<React.StrictMode>
<App />
</StrictMode>
</React.StrictMode>
);
63 changes: 63 additions & 0 deletions src/providers/DarkModeProvider.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import React, { createContext, useContext, useEffect, useState } from 'react';

interface DarkModeContextType {
darkMode: boolean;
toggleDarkMode: () => void;
}

const DarkModeContext = createContext<DarkModeContextType>({
darkMode: false,
toggleDarkMode: () => {},
});

export const useDarkMode = () => useContext(DarkModeContext);

export const DarkModeProvider: React.FC<{ children: React.ReactNode }> = ({ children }) => {
const [darkMode, setDarkMode] = useState(() =>
window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches
);
const [hasUserPreference, setHasUserPreference] = useState(false);

useEffect(() => {
const savedMode = localStorage.getItem('darkMode');
if (savedMode !== null) {
setDarkMode(JSON.parse(savedMode));
setHasUserPreference(true);
}
}, []);

const toggleDarkMode = () => {
setDarkMode((prevMode: boolean) => {
const newMode = !prevMode;
localStorage.setItem('darkMode', JSON.stringify(newMode));
setHasUserPreference(true);
return newMode;
});
};

useEffect(() => {
const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)');
const handleChange = (e: MediaQueryListEvent) => {
if (!hasUserPreference) {
setDarkMode(e.matches);
}
};

mediaQuery.addListener(handleChange);
return () => mediaQuery.removeListener(handleChange);
}, [hasUserPreference]);

useEffect(() => {
if (darkMode) {
document.documentElement.classList.add('dark');
} else {
document.documentElement.classList.remove('dark');
}
}, [darkMode]);

return (
<DarkModeContext.Provider value={{ darkMode, toggleDarkMode }}>
{children}
</DarkModeContext.Provider>
);
};
1 change: 1 addition & 0 deletions tailwind.config.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
/** @type {import('tailwindcss').Config} */
export default {
content: ["./index.html", "./src/**/*.{js,ts,jsx,tsx}"],
darkMode: 'class',
theme: {
extend: {},
},
Expand Down
Loading