const themeStorageKey = 'SITE_THEME'
/**
* HTML 루트 요소에 현재 테마를 반영한다.
* @param {'light' | 'dark'} theme - 적용할 테마
* @returns {void}
*/
const applyThemeToDocument = (theme) => {
if (!import.meta.client) {
return
}
document.documentElement.dataset.theme = theme
document.documentElement.style.colorScheme = theme
}
/**
* 사용자의 시스템 테마를 조회한다.
* @returns {'light' | 'dark'} 시스템 기준 기본 테마
*/
const getSystemTheme = () => {
if (!import.meta.client) {
return 'light'
}
return window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light'
}
/**
* 사이트 라이트/다크 테마 상태를 관리한다.
* @returns {{theme: import('vue').Ref<'light' | 'dark'>, isDarkMode: import('vue').ComputedRef, toggleTheme: Function}} 테마 상태와 제어 함수
*/
export const useThemeMode = () => {
const theme = useState('site-theme-mode', () => 'light')
const isDarkMode = computed(() => theme.value === 'dark')
onMounted(() => {
const savedTheme = localStorage.getItem(themeStorageKey)
const nextTheme = savedTheme === 'light' || savedTheme === 'dark' ? savedTheme : getSystemTheme()
theme.value = nextTheme
applyThemeToDocument(nextTheme)
})
watch(theme, (nextTheme) => {
if (!import.meta.client) {
return
}
localStorage.setItem(themeStorageKey, nextTheme)
applyThemeToDocument(nextTheme)
})
/**
* 라이트/다크 테마를 전환한다.
* @returns {void}
*/
const toggleTheme = () => {
theme.value = theme.value === 'dark' ? 'light' : 'dark'
}
return {
theme,
isDarkMode,
toggleTheme
}
}