stores.ts
1 import { writable } from 'svelte/store'; 2 import { browser } from '$app/environment'; 3 4 function getInitialTheme() { 5 if (browser) { 6 const saved = localStorage.getItem('theme'); 7 const systemPrefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches; 8 return saved ? saved === 'dark' : systemPrefersDark; 9 } 10 return false; 11 } 12 13 export const darkMode = writable(getInitialTheme()); 14 15 function getInitialPrimaryColor() { 16 if (browser) { 17 return localStorage.getItem('primaryColor') || '#007bff'; 18 } 19 return '#007bff'; 20 } 21 22 export const primaryColor = writable(getInitialPrimaryColor()); 23 24 // Store para los parámetros de búsqueda 25 export const searchParams = writable({ 26 query: '', 27 type: 'web', 28 language: 'all' 29 }); 30 31 // Store para los mapas 32 export const mapStore = writable({ 33 center: { lat: 40.416775, lng: -3.703790 }, // Madrid por defecto 34 zoom: 13, 35 markers: [], 36 offline: true 37 }); 38 39 // Store para el modo de vista (número de columnas) 40 function getInitialViewColumns() { 41 if (browser) { 42 return parseInt(localStorage.getItem('viewColumns') || '4'); 43 } 44 return 4; 45 } 46 export const viewColumns = writable(getInitialViewColumns()); 47 48 // Store para vistas personalizadas por tipo de búsqueda 49 function getInitialViewPreferences() { 50 if (browser) { 51 const savedPrefs = localStorage.getItem('viewPreferences'); 52 if (savedPrefs) { 53 try { 54 return JSON.parse(savedPrefs); 55 } catch (e) { 56 console.error('Error parsing view preferences:', e); 57 } 58 } 59 } 60 61 // Valores por defecto 62 return { 63 web: { columns: 1 }, // Vista lista para web 64 images: { columns: 4 }, // Vista grid con 4 columnas para imágenes 65 document: { columns: 1 }, // Vista lista para documentos 66 video: { columns: 3 }, // Vista grid con 3 columnas para videos 67 app: { columns: 3 }, // Vista grid con 3 columnas para apps 68 maps: { columns: 1 }, // Vista lista para mapas 69 news: { columns: 1 } // Vista lista para noticias 70 }; 71 } 72 73 export const viewPreferences = writable(getInitialViewPreferences()); 74 75 if (browser) { 76 // Persistir las preferencias de vista por tipo 77 viewPreferences.subscribe((prefs) => { 78 localStorage.setItem('viewPreferences', JSON.stringify(prefs)); 79 }); 80 81 darkMode.subscribe((value) => { 82 if (value) { 83 document.body.classList.add('dark'); 84 } else { 85 document.body.classList.remove('dark'); 86 } 87 localStorage.setItem('theme', value ? 'dark' : 'light'); 88 89 // Actualizar el color primario al cambiar de tema 90 const currentColor = localStorage.getItem('primaryColor') || '#007bff'; 91 92 // Forzar una actualización del color primario utilizando el mismo subscriber 93 // Esto hace que la función de suscripción de primaryColor se ejecute con los ajustes 94 // específicos para el tema actual 95 primaryColor.set(currentColor); 96 }); 97 98 primaryColor.subscribe((color) => { 99 // Guardar el color original en localStorage 100 localStorage.setItem('primaryColor', color); 101 102 // Obtener valores RGB para transparencias 103 const rgbValues = hexToRgb(color); 104 105 // Aplicar de manera diferente según el tema 106 if (document.body.classList.contains('dark')) { 107 // En modo oscuro, usar un color más brillante 108 const lighterColor = adjustColorBrightness(color, 30); 109 110 // Aplicar directamente el color claro para modo oscuro 111 document.documentElement.style.setProperty('--primary', lighterColor); 112 document.documentElement.style.setProperty('--primary-dark', adjustColorBrightness(lighterColor, -10)); 113 document.documentElement.style.setProperty('--primary-light', adjustColorBrightness(lighterColor, 10)); 114 document.documentElement.style.setProperty('--link-color', lighterColor); 115 document.documentElement.style.setProperty('--shadow-color', hexToRgba(lighterColor, 0.3)); 116 117 // Aplicar también valores RGB 118 const lighterRgbValues = hexToRgb(lighterColor); 119 if (lighterRgbValues) { 120 document.documentElement.style.setProperty('--primary-rgb', lighterRgbValues); 121 } 122 } else { 123 // En modo claro, usar el color original 124 document.documentElement.style.setProperty('--primary', color); 125 document.documentElement.style.setProperty('--primary-dark', adjustColorBrightness(color, -10)); 126 document.documentElement.style.setProperty('--primary-light', adjustColorBrightness(color, 10)); 127 document.documentElement.style.setProperty('--link-color', color); 128 document.documentElement.style.setProperty('--shadow-color', hexToRgba(color, 0.3)); 129 130 // Aplicar valores RGB para modo claro 131 if (rgbValues) { 132 document.documentElement.style.setProperty('--primary-rgb', rgbValues); 133 } 134 } 135 }); 136 137 viewColumns.subscribe((cols) => { 138 localStorage.setItem('viewColumns', cols.toString()); 139 }); 140 } 141 142 function hexToRgba(hex: string, alpha: number) { 143 let r = 0, g = 0, b = 0; 144 if (hex.length === 4) { 145 r = parseInt(hex[1] + hex[1], 16); 146 g = parseInt(hex[2] + hex[2], 16); 147 b = parseInt(hex[3] + hex[3], 16); 148 } else if (hex.length === 7) { 149 r = parseInt(hex.slice(1, 3), 16); 150 g = parseInt(hex.slice(3, 5), 16); 151 b = parseInt(hex.slice(5, 7), 16); 152 } 153 return `rgba(${r}, ${g}, ${b}, ${alpha})`; 154 } 155 156 // Función para convertir color hex a formato RGB (como string) 157 function hexToRgb(hex: string): string | null { 158 // Eliminar # si existe 159 hex = hex.replace(/^#/, ''); 160 161 // Valores RGB 162 let r, g, b; 163 164 // Expandir shorthand (3 dígitos) a forma completa (6 dígitos) 165 if (hex.length === 3) { 166 r = parseInt(hex[0] + hex[0], 16); 167 g = parseInt(hex[1] + hex[1], 16); 168 b = parseInt(hex[2] + hex[2], 16); 169 } else if (hex.length === 6) { 170 r = parseInt(hex.slice(0, 2), 16); 171 g = parseInt(hex.slice(2, 4), 16); 172 b = parseInt(hex.slice(4, 6), 16); 173 } else { 174 return null; 175 } 176 177 // Comprobar si los valores son válidos 178 if (isNaN(r) || isNaN(g) || isNaN(b)) { 179 return null; 180 } 181 182 // Devolver valores como string para usar en CSS 183 return `${r}, ${g}, ${b}`; 184 } 185 186 // Función para ajustar el brillo de un color hex 187 function adjustColorBrightness(hex: string, percent: number): string { 188 // Eliminar # si existe 189 hex = hex.replace(/^#/, ''); 190 191 // Expandir shorthand (3 dígitos) a forma completa (6 dígitos) 192 if (hex.length === 3) { 193 hex = hex[0] + hex[0] + hex[1] + hex[1] + hex[2] + hex[2]; 194 } 195 196 // Convertir a RGB 197 const r = parseInt(hex.slice(0, 2), 16); 198 const g = parseInt(hex.slice(2, 4), 16); 199 const b = parseInt(hex.slice(4, 6), 16); 200 201 // Ajustar brillo 202 const adjustR = Math.max(0, Math.min(255, r + (percent * 2.55))); 203 const adjustG = Math.max(0, Math.min(255, g + (percent * 2.55))); 204 const adjustB = Math.max(0, Math.min(255, b + (percent * 2.55))); 205 206 // Convertir de vuelta a hex 207 const rHex = Math.round(adjustR).toString(16).padStart(2, '0'); 208 const gHex = Math.round(adjustG).toString(16).padStart(2, '0'); 209 const bHex = Math.round(adjustB).toString(16).padStart(2, '0'); 210 211 return `#${rHex}${gHex}${bHex}`; 212 }