'use client'; import { websiteConfig } from '@/config/website'; import { type ReactNode, createContext, useContext, useEffect, useState, } from 'react'; const COOKIE_NAME = 'active_theme'; const DEFAULT_THEME = websiteConfig.ui.theme?.defaultTheme ?? 'default'; function setThemeCookie(theme: string) { if (typeof window === 'undefined') return; document.cookie = `${COOKIE_NAME}=${theme}; path=/; max-age=31536000; SameSite=Lax; ${ window.location.protocol === 'https:' ? 'Secure;' : '' }`; } type ThemeContextType = { activeTheme: string; setActiveTheme: (theme: string) => void; }; const ThemeContext = createContext(undefined); /** * This component is used to provide the active theme to the application * It also sets the theme cookie and updates the body class when the theme changes. * * NOTICE: Since custom theme is set in useEffect, * it will not be applied until the component is mounted, * for better user experience, we recommend to replace the * default theme with the custom theme in global.css. * * docs: * https://mksaas.com/docs/themes */ export function ActiveThemeProvider({ children, initialTheme, }: { children: ReactNode; initialTheme?: string; }) { const [activeTheme, setActiveTheme] = useState( () => initialTheme || DEFAULT_THEME ); useEffect(() => { setThemeCookie(activeTheme); Array.from(document.body.classList) .filter((className) => className.startsWith('theme-')) .forEach((className) => { document.body.classList.remove(className); }); document.body.classList.add(`theme-${activeTheme}`); }, [activeTheme]); return ( {children} ); } export function useThemeConfig() { const context = useContext(ThemeContext); if (context === undefined) { throw new Error( 'useThemeConfig must be used within an ActiveThemeProvider' ); } return context; }