All files / stores changeModeStore.ts

100% Statements 32/32
100% Branches 6/6
100% Functions 9/9
100% Lines 32/32

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120  3x 3x 3x     3x 3x 3x 3x 3x                                                     3x   3x                 2x 2x 2x       2x 2x               1x       1x 1x             7x             2x 2x 2x       2x 1x   1x   2x               2x       2x 1x   1x   2x         3x        
'use client';
import { setCookie } from 'nookies';
import { create } from 'zustand';
import { persist, createJSONStorage } from 'zustand/middleware';
import { type ThemeStore } from '../types/index';
 
const COOKIE_PATH = '/';
const MAX_AGE = 30 * 24 * 60 * 60;
const CREATE_THEME = 'createTheme';
const HIGH_CONTRAST = 'highContrast'
const HIGH_CONTRAST_OBSERVE = 'high-contrast'
 
/**
 * @module ChangeModeStore
 * @author Munir Mardinli
 *
 * Zustand store for managing theme (light/dark), language, and high contrast mode.
 *
 * @property {PaletteMode} mode - Current color mode ('light' or 'dark')
 * @property {string} language - Current language preference
 * @property {boolean} highContrast - High contrast mode enabled
 * @property {Function} toggleMode - Toggles between light and dark mode
 * @property {Function} setMode - Explicitly sets the color mode
 * @property {Function} setLanguage - Sets the language preference
 * @property {Function} toggleHighContrast - Toggles high contrast mode
 * @property {Function} setHighContrast - Explicitly sets high contrast mode
 *
 * @example
 * // Access the store in a React component
 * import { useThemeStore } from './changeModeStore';
 * const mode = useThemeStore(state => state.mode);
 *
 * @example
 * // Toggle dark/light mode
 * const toggleMode = useThemeStore(state => state.toggleMode);
 * toggleMode();
 */
export const useThemeStore = create<ThemeStore>()(
	persist(
		(set) => ({
			mode: 'dark',
			language: 'de',
			highContrast: false,
			/**
			 * Toggles between light and dark color modes
			 * @returns {void}
			 */
			toggleMode: (): void =>
				set((state) => {
					const newMode = state.mode === 'dark' ? 'light' : 'dark';
					setCookie(null, CREATE_THEME, newMode, {
						maxAge: MAX_AGE,
						path: COOKIE_PATH,
					});
					document.documentElement.setAttribute(CREATE_THEME, newMode);
					return { mode: newMode };
				}),
			/**
			 * Explicitly sets the color mode
			 * @param {PaletteMode} mode - The mode to set ('light' or 'dark')
			 * @returns {void}
			 */
			setMode: (mode): void => {
				setCookie(null, CREATE_THEME, mode, {
					maxAge: MAX_AGE,
					path: COOKIE_PATH,
				});
				document.documentElement.setAttribute(CREATE_THEME, mode);
				set({ mode });
			},
			/**
			 * Sets the language preference
			 * @param {string} language - Language code to set
			 * @returns {void}
			 */
			setLanguage: (language): void => set({ language }),
 
			/**
			 * Toggles high contrast mode
			 * @returns {void}
			 */
			toggleHighContrast: (): void =>
				set((state) => {
					const newHighContrast = !state.highContrast;
					setCookie(null, HIGH_CONTRAST, String(newHighContrast), {
						maxAge: MAX_AGE,
						path: COOKIE_PATH,
					});
					if (newHighContrast) {
						document.body.classList.add(HIGH_CONTRAST_OBSERVE);
					} else {
						document.body.classList.remove(HIGH_CONTRAST_OBSERVE);
					}
					return { highContrast: newHighContrast };
				}),
			/**
			 * Explicitly sets high contrast mode
			 * @param {boolean} highContrast - Whether to enable high contrast
			 * @returns {void}
			 */
			setHighContrast: (highContrast): void => {
				setCookie(null, HIGH_CONTRAST, String(highContrast), {
					maxAge: MAX_AGE,
					path: COOKIE_PATH,
				});
				if (highContrast) {
					document.body.classList.add(HIGH_CONTRAST_OBSERVE);
				} else {
					document.body.classList.remove(HIGH_CONTRAST_OBSERVE);
				}
				set({ highContrast });
			},
		}),
		{
			name: 'theme-store',
			storage: createJSONStorage(() => localStorage),
		},
	),
);