Files
sori.studio/composables/useThemeMode.js
zenn 797a6dd5a0 테마 깜빡임·로딩 스플래시 및 메인 커버 저장 흐름 수정
head 인라인 스크립트로 data-theme 선적용, 로고 캐시 스플래시 추가.
메인 커버는 업로드 후 저장 버튼에서 이미지·텍스트 일괄 반영.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-18 18:44:17 +09:00

74 lines
1.9 KiB
JavaScript

import {
SITE_THEME_STORAGE_KEY,
resolveSiteTheme
} from '~/lib/site-theme-init.js'
/**
* 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<boolean>, toggleTheme: Function}} 테마 상태와 제어 함수
*/
export const useThemeMode = () => {
const theme = useState('site-theme-mode', () => 'light')
const isDarkMode = computed(() => theme.value === 'dark')
if (import.meta.client) {
const fromDocument = document.documentElement.dataset.theme
if (fromDocument === 'light' || fromDocument === 'dark') {
theme.value = fromDocument
} else {
const savedTheme = localStorage.getItem(SITE_THEME_STORAGE_KEY)
theme.value = resolveSiteTheme(savedTheme, getSystemTheme() === 'dark')
applyThemeToDocument(theme.value)
}
}
watch(theme, (nextTheme) => {
if (!import.meta.client) {
return
}
localStorage.setItem(SITE_THEME_STORAGE_KEY, nextTheme)
applyThemeToDocument(nextTheme)
})
/**
* 라이트/다크 테마를 전환한다.
* @returns {void}
*/
const toggleTheme = () => {
theme.value = theme.value === 'dark' ? 'light' : 'dark'
}
return {
theme,
isDarkMode,
toggleTheme
}
}