Files
perfil/nuxt4/app/composables/useTheme.ts
josedario87 9a3dc1f0e6
All checks were successful
build-and-deploy / build-and-deploy (push) Successful in 55s
Feature: Mejorar UX del tema y persistencia
- 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
2025-10-16 23:03:43 -06:00

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
}
}