48 lines
1.3 KiB
TypeScript
48 lines
1.3 KiB
TypeScript
import { defineStore } from 'pinia'
|
|
import { computed, watchEffect } from 'vue'
|
|
import { usePreferredDark, useStorage } from '@vueuse/core'
|
|
|
|
export type ThemePreference = 'light' | 'dark' | 'system'
|
|
|
|
export const useThemeStore = defineStore('theme', () => {
|
|
const preference = useStorage<ThemePreference>('ft_theme', 'system')
|
|
const prefersDark = usePreferredDark()
|
|
|
|
const resolved = computed<'light' | 'dark'>(() => {
|
|
if (preference.value === 'system') return prefersDark.value ? 'dark' : 'light'
|
|
return preference.value
|
|
})
|
|
|
|
const isDark = computed(() => resolved.value === 'dark')
|
|
|
|
watchEffect(() => {
|
|
const root = document.documentElement
|
|
root.classList.toggle('dark', isDark.value)
|
|
root.style.colorScheme = resolved.value
|
|
})
|
|
|
|
function setPreference(value: ThemePreference) {
|
|
preference.value = value
|
|
}
|
|
|
|
function cyclePreference() {
|
|
const order: ThemePreference[] = ['light', 'dark', 'system']
|
|
const index = order.indexOf(preference.value)
|
|
preference.value = order[(index + 1) % order.length]!
|
|
}
|
|
|
|
/** Explicit light ↔ dark toggle (skips system). */
|
|
function toggleLightDark() {
|
|
preference.value = isDark.value ? 'light' : 'dark'
|
|
}
|
|
|
|
return {
|
|
preference,
|
|
resolved,
|
|
isDark,
|
|
setPreference,
|
|
cyclePreference,
|
|
toggleLightDark,
|
|
}
|
|
})
|