From 63b33f042676aff7bd1d91f04fa380ff516469c5 Mon Sep 17 00:00:00 2001 From: Jeet Vasoya Date: Mon, 25 May 2026 20:44:53 +0530 Subject: [PATCH] Task Done MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The animation duration is set to 300ms for a smooth but snappy feel. Test it out by clicking the theme toggle—you should see the entire UI fade smoothly between light and dark modes! --- src/App.css | 13 ++++++++++ src/components/Navbar.tsx | 47 +++++++++++++++++++++++++++++------- src/context/ThemeContext.tsx | 12 +++++++++ 3 files changed, 63 insertions(+), 9 deletions(-) diff --git a/src/App.css b/src/App.css index b9d355df..3e235b89 100644 --- a/src/App.css +++ b/src/App.css @@ -1,3 +1,16 @@ +/* Global theme transition styles */ +:root { + --transition-duration: 300ms; +} + +html.theme-transitioning, +html.theme-transitioning * { + transition: background-color var(--transition-duration) ease-in-out, + color var(--transition-duration) ease-in-out, + border-color var(--transition-duration) ease-in-out, + box-shadow var(--transition-duration) ease-in-out !important; +} + #root { max-width: 1280px; margin: 0 auto; diff --git a/src/components/Navbar.tsx b/src/components/Navbar.tsx index fd5eac86..9da9f751 100644 --- a/src/components/Navbar.tsx +++ b/src/components/Navbar.tsx @@ -1,10 +1,12 @@ import { NavLink, Link } from "react-router-dom"; -import { useState, useContext } from "react"; +import { useState, useContext, useRef } from "react"; import { ThemeContext } from "../context/ThemeContext"; import { Moon, Sun, Menu, X, Github } from "lucide-react"; const Navbar: React.FC = () => { const [isOpen, setIsOpen] = useState(false); + const [isThemeToggling, setIsThemeToggling] = useState(false); + const themeToggleRef = useRef(null); const themeContext = useContext(ThemeContext); @@ -12,6 +14,16 @@ const Navbar: React.FC = () => { const { toggleTheme, mode } = themeContext; + const handleThemeToggle = () => { + setIsThemeToggling(true); + toggleTheme(); + + // Reset animation state after transition + setTimeout(() => { + setIsThemeToggling(false); + }, 300); + }; + const navLinkStyles = ({ isActive }: { isActive: boolean }) => `px-4 py-2 rounded-xl text-sm lg:text-base font-semibold transition-all duration-300 ${ isActive @@ -59,14 +71,23 @@ const Navbar: React.FC = () => { {/* Theme Toggle */} @@ -76,14 +97,22 @@ const Navbar: React.FC = () => { {/* Theme Toggle */} diff --git a/src/context/ThemeContext.tsx b/src/context/ThemeContext.tsx index b6866e3f..85c8b295 100644 --- a/src/context/ThemeContext.tsx +++ b/src/context/ThemeContext.tsx @@ -10,6 +10,7 @@ interface ThemeContextType { export const ThemeContext = createContext(null); const THEME_STORAGE_KEY = 'theme'; +const TRANSITION_DURATION = 300; // milliseconds const ThemeWrapper = ({ children }: { children: ReactNode }) => { const [mode, setMode] = useState<'light' | 'dark'>(() => { @@ -19,12 +20,23 @@ const ThemeWrapper = ({ children }: { children: ReactNode }) => { // Sync mode with class and localStorage useEffect(() => { + // Add transition class + document.documentElement.classList.add('theme-transitioning'); + + // Apply theme change if (mode === 'dark') { document.documentElement.classList.add('dark'); } else { document.documentElement.classList.remove('dark'); } localStorage.setItem(THEME_STORAGE_KEY, mode); + + // Remove transition class after animation completes + const timer = setTimeout(() => { + document.documentElement.classList.remove('theme-transitioning'); + }, TRANSITION_DURATION); + + return () => clearTimeout(timer); }, [mode]); const toggleTheme = () => {