-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
refactor: 사용자 선호 테마 및 시스템 설정 고려하며 테마 제어하는 함수 리팩토링
관리해야 할 상태 간소화하기 위함
- Loading branch information
Showing
5 changed files
with
88 additions
and
40 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1 @@ | ||
export { useDark } from './model/use-dark'; | ||
export { useThemeStore } from './model/use-theme-store'; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,28 +1,24 @@ | ||
import { useThemeStore } from '~/entities/theme'; | ||
import { useSystemDark } from '~/entities/theme/model/use-system-dark'; | ||
import type { Theme } from '~/entities/theme/types'; | ||
import { useThemePreferenceStore } from '~/entities/theme/model/use-theme-store'; | ||
import { getEffectiveTheme, getNextTheme } from '../utils/theme-utils'; | ||
|
||
const isDarkMode = (theme?: Theme | null, isSystemDark?: boolean | null) => { | ||
return theme === 'dark' || (!!isSystemDark && theme !== 'light'); | ||
}; | ||
|
||
export const useDark = () => { | ||
const theme = useThemeStore((state) => state.theme); | ||
const toggleTheme = useThemeStore((state) => state.toggleTheme); | ||
const isSystemDark = useSystemDark(); | ||
export const useDark = (): { isDark: boolean; toggleTheme: () => void } => { | ||
const { preference, setPreference } = useThemePreferenceStore(); | ||
const isSystemDark = useSystemDark() || false; | ||
|
||
useEffect(() => { | ||
useThemeStore.setState({ isSystemDark }); | ||
}, [isSystemDark]); | ||
const effectiveTheme = useMemo( | ||
() => getEffectiveTheme(preference, isSystemDark), | ||
[preference, isSystemDark], | ||
); | ||
|
||
const isDark = useMemo(() => isDarkMode(theme, isSystemDark), [theme, isSystemDark]); | ||
const toggleTheme = useCallback(() => { | ||
const nextPreference = getNextTheme(preference, isSystemDark); | ||
setPreference(nextPreference); | ||
}, [preference, isSystemDark, setPreference]); | ||
|
||
useEffect(() => { | ||
document.documentElement.classList.toggle('dark', isDark); | ||
if ((theme === 'dark' && isSystemDark) || (theme === 'light' && !isSystemDark)) { | ||
toggleTheme(); | ||
} | ||
}, [isDark, theme, isSystemDark, toggleTheme]); | ||
document.documentElement.classList.toggle('dark', effectiveTheme === 'dark'); | ||
}, [effectiveTheme]); | ||
|
||
return { isDark, toggleTheme }; | ||
return { isDark: effectiveTheme === 'dark', toggleTheme }; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,30 +1,22 @@ | ||
import { create } from 'zustand'; | ||
import { persist } from 'zustand/middleware'; | ||
|
||
import type { Theme } from '~/entities/theme/types'; | ||
import type { ThemePreference } from '../types'; | ||
|
||
interface ThemeState { | ||
theme: Theme; | ||
isSystemDark: boolean; | ||
toggleTheme: () => void; | ||
interface ThemePreferenceState { | ||
preference: ThemePreference; | ||
setPreference: (preference: ThemePreference) => void; | ||
} | ||
|
||
export const useThemeStore = create<ThemeState>()( | ||
/** 사용자의 선호 테마 저장 및 관리 */ | ||
export const useThemePreferenceStore = create<ThemePreferenceState>()( | ||
persist( | ||
(set, get) => ({ | ||
theme: 'system', | ||
isSystemDark: false, | ||
toggleTheme: () => { | ||
const { theme, isSystemDark } = get(); | ||
if (theme === 'system') { | ||
set({ theme: isSystemDark ? 'light' : 'dark' }); | ||
} else { | ||
set({ theme: 'system' }); | ||
} | ||
}, | ||
(set) => ({ | ||
preference: 'system', | ||
setPreference: (preference: ThemePreference) => set({ preference }), | ||
}), | ||
{ | ||
name: 'theme', | ||
name: 'theme-preference', | ||
}, | ||
), | ||
); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,4 @@ | ||
export type Theme = 'system' | 'light' | 'dark'; | ||
/** 사용자 설정 테마 */ | ||
export type ThemePreference = 'system' | 'light' | 'dark'; | ||
/** 실제 적용되는 테마 */ | ||
export type EffectiveTheme = 'light' | 'dark'; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
import type { EffectiveTheme, ThemePreference } from '../types'; | ||
|
||
/** | ||
* @name getEffectiveTheme | ||
* @description | ||
* 현재 설정과 시스템 테마를 고려해 실제 적용되는 테마를 반환합니다. | ||
* ```typescript | ||
* getEffectiveTheme( | ||
* // 사용자 설정 테마 | ||
* preference: 'system' | 'light' | 'dark', | ||
* // 시스템 테마가 다크 모드인지 여부 | ||
* isSystemDark: boolean, | ||
* ): 'light' | 'dark'; | ||
* ``` | ||
* @example | ||
* getEffectiveTheme('system', true); // 'dark' | ||
* getEffectiveTheme('system', false); // 'light' | ||
* getEffectiveTheme('light', true); // 'light' | ||
* getEffectiveTheme('dark', false); // 'dark' | ||
*/ | ||
export const getEffectiveTheme = ( | ||
preference: ThemePreference, | ||
isSystemDark: boolean, | ||
): EffectiveTheme => { | ||
if (preference === 'system') { | ||
return isSystemDark ? 'dark' : 'light'; | ||
} | ||
|
||
return preference; | ||
}; | ||
|
||
/** | ||
* @name getNextTheme | ||
* @description | ||
* 현재 설정과 시스템 테마를 고려해 다음 테마를 결절해 반환합니다. | ||
* ```typescript | ||
* getNextTheme( | ||
* // 현재 설정 | ||
* currentPreference: 'system' | 'light' | 'dark', | ||
* // 시스템 테마가 다크 모드인지 여부 | ||
* isSystemDark: boolean, | ||
* ): 'system' | 'light' | 'dark'; | ||
* ``` | ||
* @example | ||
* getNextTheme('system', true); // 'light' | ||
* getNextTheme('system', false); // 'dark' | ||
* getNextTheme('light', true); // 'dark' | ||
*/ | ||
export const getNextTheme = ( | ||
currentPreference: ThemePreference, | ||
isSystemDark: boolean, | ||
): ThemePreference => { | ||
if (currentPreference === 'system') { | ||
return isSystemDark ? 'light' : 'dark'; | ||
} | ||
|
||
return 'system'; | ||
}; |