diff --git a/src/App.css b/src/App.css index e08ec61..8a76684 100644 --- a/src/App.css +++ b/src/App.css @@ -1,12 +1,12 @@ .App { text-align: center; - background-color: black; + background-color: var(--background-primary); position: absolute; top: 0px; right: 0px; left: 0px; font-family: "Gill Sans", "Gill Sans MT", Calibri, "Trebuchet MS", sans-serif; - color: azure; + color: var(--text-primary); overflow-x: hidden; scroll-behavior: smooth; } @@ -38,18 +38,18 @@ section.visible { } .App-header { - background-color: black; + background-color: var(--background-primary); min-height: 100vh; display: flex; flex-direction: column; align-items: center; justify-content: center; font-size: calc(10px + 2vmin); - color: white; + color: var(--text-primary); } .App-link { - color: #61dafb; + color: var(--accent-primary); } @keyframes App-logo-spin { @@ -74,7 +74,7 @@ hr { width: 70%; margin-left: 15% !important; margin-right: 15% !important; - border: 10px solid aquamarine; + border: 10px solid var(--hr-color); } .publications, .Experience, .DevTools, .Contact { diff --git a/src/App.js b/src/App.js index 3adf82a..4f04da7 100644 --- a/src/App.js +++ b/src/App.js @@ -5,6 +5,9 @@ import { Routes, useLocation, } from "react-router-dom"; +import { ThemeProvider, useTheme } from './context/ThemeContext'; +import './css/theme.css'; +import ThemeToggle from './components/ThemeToggle'; import { CSSTransition, TransitionGroup } from "react-transition-group"; import "./App.css"; import "./css/home.css"; @@ -17,6 +20,8 @@ import DevToolsComponent from "./components/devtools"; import SocialMedia from "./components/SocialMedia"; function Portfolio() { + const { isDarkMode } = useTheme(); + useEffect(() => { const observer = new IntersectionObserver((entries) => { entries.forEach(entry => { @@ -36,6 +41,7 @@ function Portfolio() { return (
+ @@ -88,8 +94,11 @@ function Books() { } function Home() { + const { isDarkMode } = useTheme(); + return (
+

Welcome to Aman Tahiliani's Space

@@ -121,15 +130,17 @@ function Home() { function App() { return ( - -
- - } /> - } /> - } /> - -
-
+ + +
+ + } /> + } /> + } /> + +
+
+
); } export default App; diff --git a/src/components/ThemeToggle.js b/src/components/ThemeToggle.js new file mode 100644 index 0000000..451e6a8 --- /dev/null +++ b/src/components/ThemeToggle.js @@ -0,0 +1,19 @@ +import React from 'react'; +import { useTheme } from '../context/ThemeContext'; +import '../css/ThemeToggle.css'; + +const ThemeToggle = () => { + const { isDarkMode, toggleTheme } = useTheme(); + + return ( + + ); +}; + +export default ThemeToggle; \ No newline at end of file diff --git a/src/context/ThemeContext.js b/src/context/ThemeContext.js new file mode 100644 index 0000000..25087a3 --- /dev/null +++ b/src/context/ThemeContext.js @@ -0,0 +1,26 @@ +import React, { createContext, useState, useContext } from 'react'; + +const ThemeContext = createContext(); + +export const ThemeProvider = ({ children }) => { + const [isDarkMode, setIsDarkMode] = useState(true); + + const toggleTheme = () => { + setIsDarkMode(!isDarkMode); + document.documentElement.setAttribute('data-theme', !isDarkMode ? 'dark' : 'light'); + }; + + return ( + + {children} + + ); +}; + +export const useTheme = () => { + const context = useContext(ThemeContext); + if (context === undefined) { + throw new Error('useTheme must be used within a ThemeProvider'); + } + return context; +}; \ No newline at end of file diff --git a/src/css/ThemeToggle.css b/src/css/ThemeToggle.css new file mode 100644 index 0000000..69539b5 --- /dev/null +++ b/src/css/ThemeToggle.css @@ -0,0 +1,30 @@ +.theme-toggle { + position: fixed; + top: 20px; + right: 20px; + z-index: 1000; + background: none; + border: 2px solid var(--accent-primary); + color: var(--text-primary); + width: 40px; + height: 40px; + border-radius: 50%; + cursor: pointer; + font-size: 20px; + display: flex; + align-items: center; + justify-content: center; + transition: all 0.3s ease; + padding: 0; +} + +.theme-toggle:hover { + transform: scale(1.1); + background-color: var(--accent-primary); + color: var(--background-primary); +} + +.theme-toggle:focus { + outline: none; + box-shadow: 0 0 0 2px var(--accent-secondary); +} \ No newline at end of file diff --git a/src/css/home.css b/src/css/home.css index f8d6c25..dc36a9d 100644 --- a/src/css/home.css +++ b/src/css/home.css @@ -3,7 +3,7 @@ flex-direction: column; justify-content: space-between; min-height: 100vh; - background-color: #f0f0f0; + background-color: var(--background-primary); } .content { @@ -22,13 +22,13 @@ .intro h1 { font-size: 3em; - color: #333; + color: var(--text-primary); animation: slideIn 1s ease-in-out; } .intro p { font-size: 1.5em; - color: #666; + color: var(--text-secondary); animation: slideIn 1s ease-in-out; } @@ -45,7 +45,7 @@ .intro nav ul li a { text-decoration: none; - color: #3498db; + color: var(--link-color); font-size: 1.2em; } @@ -97,7 +97,6 @@ .footer { width: 100%; padding: 20px 0; - background-color: #f0f0f0; + background-color: var(--background-primary); text-align: center; - } \ No newline at end of file diff --git a/src/css/theme.css b/src/css/theme.css new file mode 100644 index 0000000..38ef2b2 --- /dev/null +++ b/src/css/theme.css @@ -0,0 +1,30 @@ +:root[data-theme='light'] { + --background-primary: #f0f0f0; + --background-secondary: #ffffff; + --text-primary: #333333; + --text-secondary: #666666; + --accent-primary: #3498db; + --accent-secondary: #2980b9; + --border-color: #dddddd; + --section-title: #e74c3c; + --link-color: #3498db; + --hr-color: #2ecc71; +} + +:root[data-theme='dark'] { + --background-primary: #000000; + --background-secondary: #1a1a1a; + --text-primary: #ffffff; + --text-secondary: #cccccc; + --accent-primary: #61dafb; + --accent-secondary: #4fa3d1; + --border-color: #333333; + --section-title: #ff6b6b; + --link-color: #61dafb; + --hr-color: #00ffbf; +} + +/* Theme transition */ +* { + transition: background-color 0.3s ease, color 0.3s ease; +} \ No newline at end of file