All checks were successful
build-and-deploy / build-and-deploy (push) Successful in 55s
- Mover botón editar al lado del nombre (siempre visible, sutil) - Quitar efecto hover del header - Detectar tema del sistema operativo automáticamente - Actualizar theme-color dinámicamente (azul cielo día / oscuro noche) - Usar cookies para persistir tema y filtros (1 año) - Sincronizar filtros de apps con cookies
91 lines
2.4 KiB
TypeScript
91 lines
2.4 KiB
TypeScript
/**
|
|
* Composable para manejar el tema día/noche
|
|
* Persiste la preferencia del usuario en localStorage
|
|
*/
|
|
|
|
export type Theme = 'day' | 'night'
|
|
|
|
export const useTheme = () => {
|
|
const themeCookie = useCookie<Theme>('theme', {
|
|
maxAge: 60 * 60 * 24 * 365, // 1 año
|
|
sameSite: 'lax'
|
|
})
|
|
|
|
// Estado del tema con persistencia en cookies
|
|
const currentTheme = useState<Theme>('theme', () => {
|
|
// Primero intentar obtener de la cookie
|
|
if (themeCookie.value) {
|
|
return themeCookie.value
|
|
}
|
|
|
|
// Si no hay cookie, detectar preferencia del sistema
|
|
if (import.meta.client && typeof window !== 'undefined') {
|
|
const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches
|
|
const systemTheme = prefersDark ? 'night' : 'day'
|
|
themeCookie.value = systemTheme
|
|
return systemTheme
|
|
}
|
|
|
|
return 'day'
|
|
})
|
|
|
|
// Computed para saber si es modo noche
|
|
const isNight = computed(() => currentTheme.value === 'night')
|
|
|
|
// Función para actualizar theme-color meta tag
|
|
const updateThemeColor = (theme: Theme) => {
|
|
if (import.meta.client && typeof window !== 'undefined') {
|
|
const metaThemeColor = document.querySelector('meta[name="theme-color"]')
|
|
const color = theme === 'night' ? '#0B1026' : '#87CEEB' // Cielo nocturno / Cielo diurno
|
|
if (metaThemeColor) {
|
|
metaThemeColor.setAttribute('content', color)
|
|
}
|
|
}
|
|
}
|
|
|
|
// Función para aplicar la clase dark al HTML
|
|
const applyThemeClass = (theme: Theme) => {
|
|
if (import.meta.client && typeof window !== 'undefined') {
|
|
const html = document.documentElement
|
|
if (theme === 'night') {
|
|
html.classList.add('dark')
|
|
html.classList.remove('light')
|
|
} else {
|
|
html.classList.add('light')
|
|
html.classList.remove('dark')
|
|
}
|
|
updateThemeColor(theme)
|
|
}
|
|
}
|
|
|
|
// Aplicar clase inicial al montar
|
|
if (import.meta.client) {
|
|
onMounted(() => {
|
|
applyThemeClass(currentTheme.value)
|
|
})
|
|
|
|
// Sincronizar clase cuando cambie el tema
|
|
watch(currentTheme, (newTheme) => {
|
|
applyThemeClass(newTheme)
|
|
themeCookie.value = newTheme
|
|
})
|
|
}
|
|
|
|
// Alternar tema
|
|
const toggleTheme = () => {
|
|
currentTheme.value = currentTheme.value === 'day' ? 'night' : 'day'
|
|
}
|
|
|
|
// Establecer tema específico
|
|
const setTheme = (theme: Theme) => {
|
|
currentTheme.value = theme
|
|
}
|
|
|
|
return {
|
|
currentTheme: readonly(currentTheme),
|
|
isNight,
|
|
toggleTheme,
|
|
setTheme
|
|
}
|
|
}
|