From 6a9723f53b75876271d285e40f8ddc3306ff3bc6 Mon Sep 17 00:00:00 2001 From: Pragati more Date: Mon, 25 May 2026 20:58:21 +0530 Subject: [PATCH] Fix #521: add smooth theme transition animation --- src/components/Navbar.tsx | 6 +++--- src/context/ThemeContext.tsx | 12 +++++++++--- src/index.css | 34 ++++++++++++++++++++++++++++++++++ 3 files changed, 46 insertions(+), 6 deletions(-) diff --git a/src/components/Navbar.tsx b/src/components/Navbar.tsx index fd5eac86..82302f34 100644 --- a/src/components/Navbar.tsx +++ b/src/components/Navbar.tsx @@ -64,9 +64,9 @@ const Navbar: React.FC = () => { aria-label="Toggle Theme" > {mode === "dark" ? ( - + ) : ( - + )} @@ -83,7 +83,7 @@ const Navbar: React.FC = () => { {mode === "dark" ? ( ) : ( - + )} diff --git a/src/context/ThemeContext.tsx b/src/context/ThemeContext.tsx index b6866e3f..f03fa2d3 100644 --- a/src/context/ThemeContext.tsx +++ b/src/context/ThemeContext.tsx @@ -27,9 +27,15 @@ const ThemeWrapper = ({ children }: { children: ReactNode }) => { localStorage.setItem(THEME_STORAGE_KEY, mode); }, [mode]); - const toggleTheme = () => { - setMode((prevMode) => (prevMode === 'light' ? 'dark' : 'light')); - }; + const toggleTheme = () => { + document.documentElement.classList.add("theme-transitioning"); + + window.setTimeout(() => { + document.documentElement.classList.remove("theme-transitioning"); + }, 650); + + setMode((prevMode) => (prevMode === "light" ? "dark" : "light")); +}; const muiTheme: Theme = useMemo( () => createTheme({ palette: { mode } }), diff --git a/src/index.css b/src/index.css index 3f5943c5..cf61745b 100644 --- a/src/index.css +++ b/src/index.css @@ -89,3 +89,37 @@ .icon-issue-closed { color: #cf222e; } + +html.theme-transitioning, +html.theme-transitioning *, +html.theme-transitioning *::before, +html.theme-transitioning *::after { + transition-property: background-color, border-color, color, fill, stroke, box-shadow, opacity, transform; + transition-duration: 600ms; + transition-timing-function: ease-in-out; +} + +@media (prefers-reduced-motion: reduce) { + html.theme-transitioning, + html.theme-transitioning *, + html.theme-transitioning *::before, + html.theme-transitioning *::after { + transition-duration: 0ms; + } +} + +@keyframes theme-icon-pop { + 0% { + opacity: 0; + transform: rotate(-90deg) scale(0.75); + } + + 100% { + opacity: 1; + transform: rotate(0deg) scale(1); + } +} + +.theme-toggle-icon { + animation: theme-icon-pop 500ms ease-out; +} \ No newline at end of file