AutoLoop / components /theme-provider.tsx
shubhjn's picture
feat: Introduce a comprehensive automation and content management system with workflow management, social media integration, and email capabilities.
b8dc207
"use client";
import { createContext, useContext, useEffect, useState, type MouseEvent, type ReactNode } from "react";
type Theme = "light" | "dark";
interface ThemeContextType {
theme: Theme;
toggleTheme: (event?: MouseEvent) => void;
}
const ThemeContext = createContext<ThemeContextType | undefined>(undefined);
export function ThemeProvider({ children }: { children: ReactNode }) {
const [theme, setTheme] = useState<Theme>("light");
useEffect(() => {
const savedTheme = localStorage.getItem("theme") as Theme | null;
if (savedTheme) {
// eslint-disable-next-line
setTheme(savedTheme);
document.documentElement.classList.toggle("dark", savedTheme === "dark");
} else {
// Check system preference
const prefersDark = window.matchMedia("(prefers-color-scheme: dark)").matches;
const initialTheme = prefersDark ? "dark" : "light";
setTheme(initialTheme);
document.documentElement.classList.toggle("dark", initialTheme === "dark");
}
}, []);
const toggleTheme = (event?: React.MouseEvent) => {
const newTheme = theme === "light" ? "dark" : "light";
// Create circular animation if click event provided
// eslint-disable-next-line @typescript-eslint/no-explicit-any
if (event && (document as any).startViewTransition) {
const x = event.clientX;
const y = event.clientY;
const endRadius = Math.hypot(
Math.max(x, window.innerWidth - x),
Math.max(y, window.innerHeight - y)
);
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const transition = (document as any).startViewTransition(() => {
setTheme(newTheme);
localStorage.setItem("theme", newTheme);
document.documentElement.classList.toggle("dark", newTheme === "dark");
});
transition.ready.then(() => {
const clipPath = [
`circle(0px at ${x}px ${y}px)`,
`circle(${endRadius}px at ${x}px ${y}px)`
];
document.documentElement.animate(
{ clipPath },
{
duration: 500,
easing: "ease-in-out",
pseudoElement: "::view-transition-new(root)"
}
);
});
} else {
setTheme(newTheme);
localStorage.setItem("theme", newTheme);
document.documentElement.classList.toggle("dark", newTheme === "dark");
}
};
return (
<ThemeContext.Provider value={{ theme, toggleTheme }}>
{children}
</ThemeContext.Provider>
);
}
export function useTheme() {
const context = useContext(ThemeContext);
if (context === undefined) {
throw new Error("useTheme must be used within a ThemeProvider");
}
return context;
}