Rafael Lopez

fix nav teclado

This diff is collapsed. Click to expand it.
...@@ -21,6 +21,7 @@ ...@@ -21,6 +21,7 @@
21 "dependencies": { 21 "dependencies": {
22 "@observablehq/plot": "^0.6.17", 22 "@observablehq/plot": "^0.6.17",
23 "@supabase/supabase-js": "^2.98.0", 23 "@supabase/supabase-js": "^2.98.0",
24 + "@sveltejs/adapter-node": "^5.5.4",
24 "d3": "^7.9.0", 25 "d3": "^7.9.0",
25 "fuse.js": "^7.1.0", 26 "fuse.js": "^7.1.0",
26 "hyparquet": "^1.25.1", 27 "hyparquet": "^1.25.1",
......
No preview for this file type
...@@ -133,22 +133,31 @@ ...@@ -133,22 +133,31 @@
133 <a 133 <a
134 href="/" 134 href="/"
135 onclick={closeDrawer} 135 onclick={closeDrawer}
136 - class="w-full flex items-center gap-3 px-3 py-3 rounded-lg transition-colors text-left mb-4" 136 + class="w-full flex items-center px-3 py-2.5 rounded-lg transition-colors text-left"
137 style="background-color: {$page.url.pathname === '/' ? 'var(--theme-fill)' : 'transparent'};" 137 style="background-color: {$page.url.pathname === '/' ? 'var(--theme-fill)' : 'transparent'};"
138 onmouseenter={(e) => e.currentTarget.style.backgroundColor = 'var(--theme-fill)'} 138 onmouseenter={(e) => e.currentTarget.style.backgroundColor = 'var(--theme-fill)'}
139 onmouseleave={(e) => e.currentTarget.style.backgroundColor = $page.url.pathname === '/' ? 'var(--theme-fill)' : 'transparent'} 139 onmouseleave={(e) => e.currentTarget.style.backgroundColor = $page.url.pathname === '/' ? 'var(--theme-fill)' : 'transparent'}
140 > 140 >
141 - <svg class="w-4 h-4 flex-shrink-0" style="color: var(--theme-texto);" fill="currentColor" viewBox="0 0 20 20"> 141 + <span class="text-sm" style="color: var(--theme-titulo);">Inicio / Buscador</span>
142 - <rect x="2" y="2" width="7" height="7" rx="1.5"/>
143 - <rect x="11" y="2" width="7" height="7" rx="1.5"/>
144 - <rect x="2" y="11" width="7" height="7" rx="1.5"/>
145 - <rect x="11" y="11" width="7" height="7" rx="1.5"/>
146 - </svg>
147 - <span class="font-medium text-sm" style="color: var(--theme-titulo);">Inicio / Buscador</span>
148 </a> 142 </a>
149 143
144 + <!-- Descargas -->
145 + <a
146 + href="/descargas"
147 + onclick={closeDrawer}
148 + class="w-full flex items-center px-3 py-2.5 rounded-lg transition-colors text-left mb-4"
149 + style="background-color: {$page.url.pathname === '/descargas' ? 'var(--theme-fill)' : 'transparent'};"
150 + onmouseenter={(e) => e.currentTarget.style.backgroundColor = 'var(--theme-fill)'}
151 + onmouseleave={(e) => e.currentTarget.style.backgroundColor = $page.url.pathname === '/descargas' ? 'var(--theme-fill)' : 'transparent'}
152 + >
153 + <span class="text-sm" style="color: var(--theme-titulo);">Descargas</span>
154 + </a>
155 +
156 + <!-- Separador -->
157 + <div class="border-t mb-4" style="border-color: var(--theme-borde);"></div>
158 +
150 <!-- Clasificadores --> 159 <!-- Clasificadores -->
151 - <div class="mb-6"> 160 + <div class="mb-4">
152 <h3 class="text-xs font-semibold uppercase tracking-wider mb-3 px-2" style="color: var(--theme-texto);"> 161 <h3 class="text-xs font-semibold uppercase tracking-wider mb-3 px-2" style="color: var(--theme-texto);">
153 Navegar por clasificadores 162 Navegar por clasificadores
154 </h3> 163 </h3>
...@@ -157,13 +166,13 @@ ...@@ -157,13 +166,13 @@
157 <a 166 <a
158 href={c.href} 167 href={c.href}
159 onclick={closeDrawer} 168 onclick={closeDrawer}
160 - class="w-full flex items-center justify-between px-3 py-2.5 rounded-lg transition-colors text-left group" 169 + class="w-full flex items-center justify-between px-3 py-2 rounded-lg transition-colors text-left group"
161 style="background-color: {isActive(c.href) ? 'var(--theme-fill)' : 'transparent'};" 170 style="background-color: {isActive(c.href) ? 'var(--theme-fill)' : 'transparent'};"
162 onmouseenter={(e) => e.currentTarget.style.backgroundColor = 'var(--theme-fill)'} 171 onmouseenter={(e) => e.currentTarget.style.backgroundColor = 'var(--theme-fill)'}
163 onmouseleave={(e) => e.currentTarget.style.backgroundColor = isActive(c.href) ? 'var(--theme-fill)' : 'transparent'} 172 onmouseleave={(e) => e.currentTarget.style.backgroundColor = isActive(c.href) ? 'var(--theme-fill)' : 'transparent'}
164 > 173 >
165 <div class="flex-1 min-w-0"> 174 <div class="flex-1 min-w-0">
166 - <span class="text-sm font-medium block" style="color: var(--theme-titulo);">{c.nombre}</span> 175 + <span class="text-sm block" style="color: var(--theme-titulo);">{c.nombre}</span>
167 <span class="text-xs" style="color: var(--theme-texto);">{c.desc}</span> 176 <span class="text-xs" style="color: var(--theme-texto);">{c.desc}</span>
168 </div> 177 </div>
169 <svg 178 <svg
...@@ -178,86 +187,52 @@ ...@@ -178,86 +187,52 @@
178 </svg> 187 </svg>
179 </a> 188 </a>
180 {/each} 189 {/each}
181 - </div>
182 - </div>
183 -
184 - <!-- Ver todos los clasificadores -->
185 <a 190 <a
186 href="/clasificadores" 191 href="/clasificadores"
187 onclick={closeDrawer} 192 onclick={closeDrawer}
188 - class="w-full flex items-center gap-3 px-3 py-3 rounded-lg transition-colors text-left mb-6" 193 + class="w-full flex items-center px-3 py-2 rounded-lg transition-colors text-left mt-1"
189 style="background-color: {$page.url.pathname === '/clasificadores' ? 'var(--theme-fill)' : 'transparent'};" 194 style="background-color: {$page.url.pathname === '/clasificadores' ? 'var(--theme-fill)' : 'transparent'};"
190 onmouseenter={(e) => e.currentTarget.style.backgroundColor = 'var(--theme-fill)'} 195 onmouseenter={(e) => e.currentTarget.style.backgroundColor = 'var(--theme-fill)'}
191 onmouseleave={(e) => e.currentTarget.style.backgroundColor = $page.url.pathname === '/clasificadores' ? 'var(--theme-fill)' : 'transparent'} 196 onmouseleave={(e) => e.currentTarget.style.backgroundColor = $page.url.pathname === '/clasificadores' ? 'var(--theme-fill)' : 'transparent'}
192 > 197 >
193 - <svg class="w-4 h-4 flex-shrink-0" style="color: var(--theme-accent);" fill="none" stroke="currentColor" viewBox="0 0 24 24" stroke-width="1.5"> 198 + <span class="text-xs" style="color: var(--theme-texto);">Ver todos los clasificadores</span>
194 - <path stroke-linecap="round" stroke-linejoin="round" d="M3.75 6A2.25 2.25 0 016 3.75h2.25A2.25 2.25 0 0110.5 6v2.25a2.25 2.25 0 01-2.25 2.25H6a2.25 2.25 0 01-2.25-2.25V6zM3.75 15.75A2.25 2.25 0 016 13.5h2.25a2.25 2.25 0 012.25 2.25V18a2.25 2.25 0 01-2.25 2.25H6A2.25 2.25 0 013.75 18v-2.25zM13.5 6a2.25 2.25 0 012.25-2.25H18A2.25 2.25 0 0120.25 6v2.25A2.25 2.25 0 0118 10.5h-2.25a2.25 2.25 0 01-2.25-2.25V6zM13.5 15.75a2.25 2.25 0 012.25-2.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-2.25A2.25 2.25 0 0113.5 18v-2.25z"/>
195 - </svg>
196 - <span class="text-sm" style="color: var(--theme-accent);">Ver todos los clasificadores</span>
197 </a> 199 </a>
200 + </div>
201 + </div>
198 202
199 <!-- Separador --> 203 <!-- Separador -->
200 - <div class="border-t my-4" style="border-color: var(--theme-borde);"></div> 204 + <div class="border-t mb-4" style="border-color: var(--theme-borde);"></div>
201 205
202 <!-- Enlaces --> 206 <!-- Enlaces -->
203 <div class="space-y-1"> 207 <div class="space-y-1">
204 <a 208 <a
205 href="/documentacion" 209 href="/documentacion"
206 onclick={closeDrawer} 210 onclick={closeDrawer}
207 - class="w-full flex items-center gap-3 px-3 py-2.5 rounded-lg transition-colors text-left" 211 + class="w-full flex items-center px-3 py-2 rounded-lg transition-colors text-left"
208 onmouseenter={(e) => e.currentTarget.style.backgroundColor = 'var(--theme-fill)'} 212 onmouseenter={(e) => e.currentTarget.style.backgroundColor = 'var(--theme-fill)'}
209 onmouseleave={(e) => e.currentTarget.style.backgroundColor = 'transparent'} 213 onmouseleave={(e) => e.currentTarget.style.backgroundColor = 'transparent'}
210 > 214 >
211 - <svg class="w-4 h-4 flex-shrink-0" style="color: var(--theme-texto);" fill="none" stroke="currentColor" viewBox="0 0 24 24" stroke-width="1.5">
212 - <path stroke-linecap="round" stroke-linejoin="round" d="M12 6.042A8.967 8.967 0 006 3.75c-1.052 0-2.062.18-3 .512v14.25A8.987 8.987 0 016 18c2.305 0 4.408.867 6 2.292m0-14.25a8.966 8.966 0 016-2.292c1.052 0 2.062.18 3 .512v14.25A8.987 8.987 0 0018 18a8.967 8.967 0 00-6 2.292m0-14.25v14.25"/>
213 - </svg>
214 <span class="text-sm" style="color: var(--theme-titulo);">Documentación</span> 215 <span class="text-sm" style="color: var(--theme-titulo);">Documentación</span>
215 </a> 216 </a>
216 <a 217 <a
217 href="/sobre" 218 href="/sobre"
218 onclick={closeDrawer} 219 onclick={closeDrawer}
219 - class="w-full flex items-center gap-3 px-3 py-2.5 rounded-lg transition-colors text-left" 220 + class="w-full flex items-center px-3 py-2 rounded-lg transition-colors text-left"
220 onmouseenter={(e) => e.currentTarget.style.backgroundColor = 'var(--theme-fill)'} 221 onmouseenter={(e) => e.currentTarget.style.backgroundColor = 'var(--theme-fill)'}
221 onmouseleave={(e) => e.currentTarget.style.backgroundColor = 'transparent'} 222 onmouseleave={(e) => e.currentTarget.style.backgroundColor = 'transparent'}
222 > 223 >
223 - <svg class="w-4 h-4 flex-shrink-0" style="color: var(--theme-texto);" fill="none" stroke="currentColor" viewBox="0 0 24 24" stroke-width="1.5">
224 - <path stroke-linecap="round" stroke-linejoin="round" d="M11.25 11.25l.041-.02a.75.75 0 011.063.852l-.708 2.836a.75.75 0 001.063.853l.041-.021M21 12a9 9 0 11-18 0 9 9 0 0118 0zm-9-3.75h.008v.008H12V8.25z"/>
225 - </svg>
226 <span class="text-sm" style="color: var(--theme-titulo);">Sobre el proyecto</span> 224 <span class="text-sm" style="color: var(--theme-titulo);">Sobre el proyecto</span>
227 </a> 225 </a>
228 - </div>
229 -
230 - <!-- Separador -->
231 - <div class="border-t my-4" style="border-color: var(--theme-borde);"></div>
232 -
233 - <!-- Descargas -->
234 - <a
235 - href="/descargas"
236 - onclick={closeDrawer}
237 - class="w-full flex items-center gap-3 px-3 py-3 rounded-lg transition-colors text-left"
238 - style="background-color: {$page.url.pathname === '/descargas' ? 'var(--theme-fill)' : 'transparent'};"
239 - onmouseenter={(e) => e.currentTarget.style.backgroundColor = 'var(--theme-fill)'}
240 - onmouseleave={(e) => e.currentTarget.style.backgroundColor = $page.url.pathname === '/descargas' ? 'var(--theme-fill)' : 'transparent'}
241 - >
242 - <svg class="w-4 h-4 flex-shrink-0" style="color: var(--theme-accent);" fill="none" stroke="currentColor" viewBox="0 0 24 24" stroke-width="1.5">
243 - <path stroke-linecap="round" stroke-linejoin="round" d="M3 16.5v2.25A2.25 2.25 0 005.25 21h13.5A2.25 2.25 0 0021 18.75V16.5M16.5 12L12 16.5m0 0L7.5 12m4.5 4.5V3"/>
244 - </svg>
245 - <span class="text-sm font-medium" style="color: var(--theme-accent);">Descargas</span>
246 - </a>
247 -
248 - <!-- Créditos -->
249 <a 226 <a
250 href="/creditos" 227 href="/creditos"
251 onclick={closeDrawer} 228 onclick={closeDrawer}
252 - class="w-full flex items-center gap-3 px-3 py-2.5 rounded-lg transition-colors text-left mt-2" 229 + class="w-full flex items-center px-3 py-2 rounded-lg transition-colors text-left"
253 onmouseenter={(e) => e.currentTarget.style.backgroundColor = 'var(--theme-fill)'} 230 onmouseenter={(e) => e.currentTarget.style.backgroundColor = 'var(--theme-fill)'}
254 onmouseleave={(e) => e.currentTarget.style.backgroundColor = 'transparent'} 231 onmouseleave={(e) => e.currentTarget.style.backgroundColor = 'transparent'}
255 > 232 >
256 - <svg class="w-4 h-4 flex-shrink-0" style="color: var(--theme-texto);" fill="none" stroke="currentColor" viewBox="0 0 24 24" stroke-width="1.5">
257 - <path stroke-linecap="round" stroke-linejoin="round" d="M15 19.128a9.38 9.38 0 002.625.372 9.337 9.337 0 004.121-.952 4.125 4.125 0 00-7.533-2.493M15 19.128v-.003c0-1.113-.285-2.16-.786-3.07M15 19.128v.106A12.318 12.318 0 018.624 21c-2.331 0-4.512-.645-6.374-1.766l-.001-.109a6.375 6.375 0 0111.964-3.07M12 6.375a3.375 3.375 0 11-6.75 0 3.375 3.375 0 016.75 0zm8.25 2.25a2.625 2.625 0 11-5.25 0 2.625 2.625 0 015.25 0z"/>
258 - </svg>
259 <span class="text-sm" style="color: var(--theme-texto);">Créditos institucionales</span> 233 <span class="text-sm" style="color: var(--theme-texto);">Créditos institucionales</span>
260 </a> 234 </a>
235 + </div>
261 </nav> 236 </nav>
262 237
263 <!-- Footer --> 238 <!-- Footer -->
......
...@@ -220,7 +220,7 @@ ...@@ -220,7 +220,7 @@
220 const url = `${base}${item.codigo}`; 220 const url = `${base}${item.codigo}`;
221 console.log('[SEARCH] goToResult:', item.tipo, item.codigo, '→', url); 221 console.log('[SEARCH] goToResult:', item.tipo, item.codigo, '→', url);
222 open = false; 222 open = false;
223 - window.location.href = url; 223 + goto(url);
224 } 224 }
225 } 225 }
226 226
......
1 <script> 1 <script>
2 import '../app.css'; 2 import '../app.css';
3 import { page, navigating } from '$app/stores'; 3 import { page, navigating } from '$app/stores';
4 - import favicon from '$lib/assets/favicon.svg'; 4 + import favicon from '$lib/assets/favicon.ico';
5 import Navbar from '$lib/components/ui/Navbar.svelte'; 5 import Navbar from '$lib/components/ui/Navbar.svelte';
6 import NavigationDrawer from '$lib/components/layout/NavigationDrawer.svelte'; 6 import NavigationDrawer from '$lib/components/layout/NavigationDrawer.svelte';
7 import SearchModal from '$lib/components/ui/SearchModal.svelte'; 7 import SearchModal from '$lib/components/ui/SearchModal.svelte';
......
1 <script> 1 <script>
2 import { onMount } from 'svelte'; 2 import { onMount } from 'svelte';
3 + import { goto } from '$app/navigation';
3 import { landingSearchMode, landingSelectedClassifiers, landingSearchQuery } from '$lib/stores/landingSearchState'; 4 import { landingSearchMode, landingSelectedClassifiers, landingSearchQuery } from '$lib/stores/landingSearchState';
4 import { openDrawer } from '$lib/stores/drawer.js'; 5 import { openDrawer } from '$lib/stores/drawer.js';
5 6
...@@ -811,7 +812,7 @@ ...@@ -811,7 +812,7 @@
811 url = `/programa/${generateCodigo(hit)}`; 812 url = `/programa/${generateCodigo(hit)}`;
812 } 813 }
813 814
814 - window.location.href = url; 815 + goto(url);
815 } 816 }
816 817
817 function clearSearch() { 818 function clearSearch() {
...@@ -1123,7 +1124,7 @@ ...@@ -1123,7 +1124,7 @@
1123 {#each EXAMPLES_PROGRAMAS as ex} 1124 {#each EXAMPLES_PROGRAMAS as ex}
1124 <span 1125 <span
1125 class="mode-pill" 1126 class="mode-pill"
1126 - onclick={() => searchFromPill(ex.label)} 1127 + onclick={(e) => { e.stopPropagation(); searchFromPill(ex.label); }}
1127 onkeydown={(e) => e.key === 'Enter' && searchFromPill(ex.label)} 1128 onkeydown={(e) => e.key === 'Enter' && searchFromPill(ex.label)}
1128 role="button" 1129 role="button"
1129 tabindex="0" 1130 tabindex="0"
...@@ -1165,7 +1166,7 @@ ...@@ -1165,7 +1166,7 @@
1165 class="clf-chip" 1166 class="clf-chip"
1166 class:clf-chip-active={selectedClassifiers.includes(clf.id)} 1167 class:clf-chip-active={selectedClassifiers.includes(clf.id)}
1167 class:clf-chip-disabled={clf.disabled} 1168 class:clf-chip-disabled={clf.disabled}
1168 - onclick={() => { if (!clf.disabled) toggleClassifier(clf.id); }} 1169 + onclick={(e) => { e.stopPropagation(); if (!clf.disabled) toggleClassifier(clf.id); }}
1169 disabled={clf.disabled} 1170 disabled={clf.disabled}
1170 > 1171 >
1171 <span class="clf-dot"></span> 1172 <span class="clf-dot"></span>
...@@ -1176,11 +1177,11 @@ ...@@ -1176,11 +1177,11 @@
1176 <div class="mode-card-pills"> 1177 <div class="mode-card-pills">
1177 {#each EXAMPLES_CLASIFICADORES as ex} 1178 {#each EXAMPLES_CLASIFICADORES as ex}
1178 {#if ex.href} 1179 {#if ex.href}
1179 - <a href={ex.href} class="mode-pill">{ex.label}</a> 1180 + <a href={ex.href} class="mode-pill" onclick={(e) => e.stopPropagation()}>{ex.label}</a>
1180 {:else} 1181 {:else}
1181 <span 1182 <span
1182 class="mode-pill" 1183 class="mode-pill"
1183 - onclick={() => searchFromPill(ex.label, ex.classifier)} 1184 + onclick={(e) => { e.stopPropagation(); searchFromPill(ex.label, ex.classifier); }}
1184 onkeydown={(e) => e.key === 'Enter' && searchFromPill(ex.label, ex.classifier)} 1185 onkeydown={(e) => e.key === 'Enter' && searchFromPill(ex.label, ex.classifier)}
1185 role="button" 1186 role="button"
1186 tabindex="0" 1187 tabindex="0"
...@@ -2240,8 +2241,8 @@ ...@@ -2240,8 +2241,8 @@
2240 .pills-hint{font-family:var(--sans);font-size:10px;color:#7B7870;font-weight:500} 2241 .pills-hint{font-family:var(--sans);font-size:10px;color:#7B7870;font-weight:500}
2241 .hint-desktop{display:inline} 2242 .hint-desktop{display:inline}
2242 .hint-mobile{display:none} 2243 .hint-mobile{display:none}
2243 - .mode-pill{font-family:var(--sans);font-size:11px;font-weight:500;padding:5px 10px;border-radius:8px;cursor:pointer;transition:all 0.2s;border:1px solid rgba(255,255,255,0.15);background:rgba(255,255,255,0.06);color:#F5F0E8} 2244 + .mode-pill{font-family:var(--sans);font-size:11px;font-weight:500;padding:5px 10px;border-radius:8px;cursor:pointer;transition:all 0.2s;border:1px solid rgba(255,255,255,0.15);background:rgba(255,255,255,0.06);color:#F5F0E8 !important;text-decoration:none}
2244 - .mode-pill:hover{background:rgba(255,255,255,0.12);border-color:rgba(255,255,255,0.25);color:#F5F0E8} 2245 + .mode-pill:hover{background:rgba(255,255,255,0.12);border-color:rgba(255,255,255,0.25);color:#FFFFFF !important}
2245 2246
2246 .mode-card-radio{position:absolute;top:16px;right:16px} 2247 .mode-card-radio{position:absolute;top:16px;right:16px}
2247 .radio-dot{width:18px;height:18px;border-radius:50%;border:2px solid rgba(255,255,255,0.2);display:block;transition:all 0.2s;position:relative} 2248 .radio-dot{width:18px;height:18px;border-radius:50%;border:2px solid rgba(255,255,255,0.2);display:block;transition:all 0.2s;position:relative}
...@@ -2635,8 +2636,8 @@ ...@@ -2635,8 +2636,8 @@
2635 :global(html:not(.dark)) .radio-dot-active{border-color:#D4A017} 2636 :global(html:not(.dark)) .radio-dot-active{border-color:#D4A017}
2636 2637
2637 /* Mode pills */ 2638 /* Mode pills */
2638 - :global(html:not(.dark)) .mode-pill{border-color:rgba(0,0,0,0.12);background:rgba(0,0,0,0.04);color:#555} 2639 + :global(html:not(.dark)) .mode-pill{border-color:rgba(0,0,0,0.12);background:rgba(0,0,0,0.04);color:#555 !important}
2639 - :global(html:not(.dark)) .mode-pill:hover{background:rgba(0,0,0,0.08);border-color:rgba(0,0,0,0.2);color:#1d1d1f} 2640 + :global(html:not(.dark)) .mode-pill:hover{background:rgba(0,0,0,0.08);border-color:rgba(0,0,0,0.2);color:#1d1d1f !important}
2640 :global(html:not(.dark)) .pills-hint{color:#999} 2641 :global(html:not(.dark)) .pills-hint{color:#999}
2641 2642
2642 /* Gear / settings */ 2643 /* Gear / settings */
......
1 +export const ssr = false;
2 +
1 import { error } from '@sveltejs/kit'; 3 import { error } from '@sveltejs/kit';
2 4
3 import { API_HOST } from '$lib/api.js'; 5 import { API_HOST } from '$lib/api.js';
......
...@@ -1217,18 +1217,19 @@ ...@@ -1217,18 +1217,19 @@
1217 .slice(0, 20); 1217 .slice(0, 20);
1218 } 1218 }
1219 1219
1220 - function parseDescripciones(descripcionesStr) { 1220 + function parseDescripciones(descs) {
1221 - if (!descripcionesStr) return []; 1221 + if (!descs) return [];
1222 - try { 1222 + let arr;
1223 - const parsed = JSON.parse(descripcionesStr); 1223 + if (typeof descs === 'string') {
1224 - return parsed.sort((a, b) => { 1224 + try { arr = JSON.parse(descs); } catch { return []; }
1225 - const maxYearA = getMaxYear(a.rangos); 1225 + } else {
1226 - const maxYearB = getMaxYear(b.rangos); 1226 + arr = Array.isArray(descs) ? descs : [];
1227 + }
1228 + return [...arr].sort((a, b) => {
1229 + const maxYearA = getMaxYear(a.gestion || a.rangos);
1230 + const maxYearB = getMaxYear(b.gestion || b.rangos);
1227 return maxYearB - maxYearA; 1231 return maxYearB - maxYearA;
1228 }); 1232 });
1229 - } catch {
1230 - return [];
1231 - }
1232 } 1233 }
1233 1234
1234 function getMaxYear(rangos) { 1235 function getMaxYear(rangos) {
......
...@@ -1364,19 +1364,19 @@ ...@@ -1364,19 +1364,19 @@
1364 .slice(0, 20); 1364 .slice(0, 20);
1365 } 1365 }
1366 1366
1367 - function parseDescripciones(descripcionesStr) { 1367 + function parseDescripciones(descs) {
1368 - if (!descripcionesStr) return []; 1368 + if (!descs) return [];
1369 - try { 1369 + let arr;
1370 - const parsed = JSON.parse(descripcionesStr); 1370 + if (typeof descs === 'string') {
1371 - // Ordenar por año más reciente (extraer el máximo año de cada rango) 1371 + try { arr = JSON.parse(descs); } catch { return []; }
1372 - return parsed.sort((a, b) => { 1372 + } else {
1373 - const maxYearA = getMaxYear(a.rangos); 1373 + arr = Array.isArray(descs) ? descs : [];
1374 - const maxYearB = getMaxYear(b.rangos);
1375 - return maxYearB - maxYearA; // Descendente, más reciente primero
1376 - });
1377 - } catch {
1378 - return [];
1379 } 1374 }
1375 + return [...arr].sort((a, b) => {
1376 + const maxYearA = getMaxYear(a.gestion || a.rangos);
1377 + const maxYearB = getMaxYear(b.gestion || b.rangos);
1378 + return maxYearB - maxYearA;
1379 + });
1380 } 1380 }
1381 1381
1382 function getMaxYear(rangos) { 1382 function getMaxYear(rangos) {
......
...@@ -881,18 +881,19 @@ ...@@ -881,18 +881,19 @@
881 .slice(0, 20); 881 .slice(0, 20);
882 } 882 }
883 883
884 - function parseDescripciones(descripcionesStr) { 884 + function parseDescripciones(descs) {
885 - if (!descripcionesStr) return []; 885 + if (!descs) return [];
886 - try { 886 + let arr;
887 - const parsed = typeof descripcionesStr === 'string' ? JSON.parse(descripcionesStr) : descripcionesStr; 887 + if (typeof descs === 'string') {
888 - return parsed.sort((a, b) => { 888 + try { arr = JSON.parse(descs); } catch { return []; }
889 - const maxYearA = getMaxYear(a.rangos); 889 + } else {
890 - const maxYearB = getMaxYear(b.rangos); 890 + arr = Array.isArray(descs) ? descs : [];
891 + }
892 + return [...arr].sort((a, b) => {
893 + const maxYearA = getMaxYear(a.gestion || a.rangos);
894 + const maxYearB = getMaxYear(b.gestion || b.rangos);
891 return maxYearB - maxYearA; 895 return maxYearB - maxYearA;
892 }); 896 });
893 - } catch {
894 - return [];
895 - }
896 } 897 }
897 898
898 function getMaxYear(rangos) { 899 function getMaxYear(rangos) {
......
...@@ -722,6 +722,7 @@ ...@@ -722,6 +722,7 @@
722 }); 722 });
723 723
724 onMount(async () => { 724 onMount(async () => {
725 + console.log('[SECTORES] onMount started');
725 isMobile = 'ontouchstart' in window || navigator.maxTouchPoints > 0; 726 isMobile = 'ontouchstart' in window || navigator.maxTouchPoints > 0;
726 727
727 requestAnimationFrame(() => { 728 requestAnimationFrame(() => {
...@@ -735,10 +736,10 @@ ...@@ -735,10 +736,10 @@
735 const data = await res.json(); 736 const data = await res.json();
736 737
737 if (Array.isArray(data)) { 738 if (Array.isArray(data)) {
738 - allItems = data; 739 + allItems = data.filter(item => String(item.acteco) !== '0' && !String(item.acteco).startsWith('0.') && !/desconocido/i.test(item.desc_acteco || ''));
739 740
740 // Sectores = items de profundidad 1 741 // Sectores = items de profundidad 1
741 - sectores = data 742 + sectores = allItems
742 .filter(item => getDepth(item.acteco) === 1) 743 .filter(item => getDepth(item.acteco) === 1)
743 .sort((a, b) => String(a.acteco).localeCompare(String(b.acteco), undefined, { numeric: true })); 744 .sort((a, b) => String(a.acteco).localeCompare(String(b.acteco), undefined, { numeric: true }));
744 745
...@@ -766,6 +767,7 @@ ...@@ -766,6 +767,7 @@
766 selectedYear = 2025; 767 selectedYear = 2025;
767 } 768 }
768 769
770 + console.log('[SECTORES] loading done, sectores:', sectores.length, 'allItems:', allItems.length, 'selectedYear:', selectedYear, 'layoutMounted:', layoutMounted, 'viewMode:', viewMode);
769 loading = false; 771 loading = false;
770 }); 772 });
771 773
...@@ -1223,18 +1225,19 @@ ...@@ -1223,18 +1225,19 @@
1223 .slice(0, 20); 1225 .slice(0, 20);
1224 } 1226 }
1225 1227
1226 - function parseDescripciones(descripcionesStr) { 1228 + function parseDescripciones(descs) {
1227 - if (!descripcionesStr) return []; 1229 + if (!descs) return [];
1228 - try { 1230 + let arr;
1229 - const parsed = JSON.parse(descripcionesStr); 1231 + if (typeof descs === 'string') {
1230 - return parsed.sort((a, b) => { 1232 + try { arr = JSON.parse(descs); } catch { return []; }
1231 - const maxYearA = getMaxYear(a.rangos); 1233 + } else {
1232 - const maxYearB = getMaxYear(b.rangos); 1234 + arr = Array.isArray(descs) ? descs : [];
1235 + }
1236 + return [...arr].sort((a, b) => {
1237 + const maxYearA = getMaxYear(a.gestion || a.rangos);
1238 + const maxYearB = getMaxYear(b.gestion || b.rangos);
1233 return maxYearB - maxYearA; 1239 return maxYearB - maxYearA;
1234 }); 1240 });
1235 - } catch {
1236 - return [];
1237 - }
1238 } 1241 }
1239 1242
1240 function getMaxYear(rangos) { 1243 function getMaxYear(rangos) {
......
This diff is collapsed. Click to expand it.
1 <script> 1 <script>
2 import { onMount, tick } from 'svelte'; 2 import { onMount, tick } from 'svelte';
3 + import { goto } from '$app/navigation';
3 import { page } from '$app/stores'; 4 import { page } from '$app/stores';
4 import * as d3 from 'd3'; 5 import * as d3 from 'd3';
5 6
...@@ -142,7 +143,7 @@ ...@@ -142,7 +143,7 @@
142 } 143 }
143 144
144 function navigateToEntity(item) { 145 function navigateToEntity(item) {
145 - window.location.href = `/entidad/${item.codigo}`; 146 + goto(`/entidad/${item.codigo}`);
146 } 147 }
147 148
148 function onSearchKeydown(e) { 149 function onSearchKeydown(e) {
......
1 +export const ssr = false;
2 +
1 import { error } from '@sveltejs/kit'; 3 import { error } from '@sveltejs/kit';
2 4
3 import { API_HOST } from '$lib/api.js'; 5 import { API_HOST } from '$lib/api.js';
......
1 +export const ssr = false;
2 +
1 import { error } from '@sveltejs/kit'; 3 import { error } from '@sveltejs/kit';
2 4
3 import { API_HOST } from '$lib/api.js'; 5 import { API_HOST } from '$lib/api.js';
...@@ -17,7 +19,7 @@ export async function load({ params }) { ...@@ -17,7 +19,7 @@ export async function load({ params }) {
17 const clasRes = await fetch(`${API_BASE}/clasificador`); 19 const clasRes = await fetch(`${API_BASE}/clasificador`);
18 if (clasRes.ok) { 20 if (clasRes.ok) {
19 const clasificador = await clasRes.json(); 21 const clasificador = await clasRes.json();
20 - const current = clasificador.find(c => c.organismo === parseInt(codigo)); 22 + const current = clasificador.find(c => String(c.organismo) === codigo);
21 if (current) { 23 if (current) {
22 // Padres: grupo y subgrupo (como objetos virtuales para navegación) 24 // Padres: grupo y subgrupo (como objetos virtuales para navegación)
23 padres = [ 25 padres = [
......
1 +export const ssr = false;
2 +
1 import { error } from '@sveltejs/kit'; 3 import { error } from '@sveltejs/kit';
2 4
3 import { API_HOST } from '$lib/api.js'; 5 import { API_HOST } from '$lib/api.js';
......
...@@ -19,10 +19,9 @@ ...@@ -19,10 +19,9 @@
19 </p> 19 </p>
20 20
21 <p class="p3"> 21 <p class="p3">
22 - La plataforma reúne más de veinte años de información sobre ingresos y gastos 22 + La plataforma reúne 10 años de información sobre ingresos y gastos
23 públicos, organizada mediante los clasificadores presupuestarios oficiales y a 23 públicos, organizada mediante los clasificadores presupuestarios oficiales y a
24 - través de los programas y proyectos de inversión pública. Los datos se actualizan 24 + través de los programas y proyectos de inversión pública.
25 - semanalmente y abarcan a todas las entidades del sector público.
26 </p> 25 </p>
27 26
28 <p class="p3"> 27 <p class="p3">
......
1 <script> 1 <script>
2 import { onMount, tick } from 'svelte'; 2 import { onMount, tick } from 'svelte';
3 + import { goto } from '$app/navigation';
3 import { page } from '$app/stores'; 4 import { page } from '$app/stores';
4 import { get } from 'svelte/store'; 5 import { get } from 'svelte/store';
5 import * as d3 from 'd3'; 6 import * as d3 from 'd3';
...@@ -224,7 +225,7 @@ ...@@ -224,7 +225,7 @@
224 } 225 }
225 226
226 function navigateToEntity(item) { 227 function navigateToEntity(item) {
227 - window.location.href = `/ubicacion/${item.codigo}`; 228 + goto(`/ubicacion/${item.codigo}`);
228 } 229 }
229 230
230 function onSearchKeydown(e) { 231 function onSearchKeydown(e) {
......
This diff is collapsed. Click to expand it.
No preview for this file type
No preview for this file type
No preview for this file type
1 -import adapter from '@sveltejs/adapter-auto'; 1 +import adapter from '@sveltejs/adapter-node';
2 2
3 /** @type {import('@sveltejs/kit').Config} */ 3 /** @type {import('@sveltejs/kit').Config} */
4 const config = { 4 const config = {
5 kit: { 5 kit: {
6 - // adapter-auto only supports some environments, see https://svelte.dev/docs/kit/adapter-auto for a list.
7 - // If your environment is not supported, or you settled on a specific environment, switch out the adapter.
8 - // See https://svelte.dev/docs/kit/adapters for more information about adapters.
9 adapter: adapter() 6 adapter: adapter()
10 } 7 }
11 }; 8 };
......
...@@ -377,7 +377,7 @@ Sector → Subsector → Área → Subárea → Entidad ...@@ -377,7 +377,7 @@ Sector → Subsector → Área → Subárea → Entidad
377 377
378 --- 378 ---
379 379
380 -## Tablas de Vista de Entidad 380 +## Tablas de Vista de Entidad"
381 381
382 ### 13. `entidad_resumen` - Resumen histórico por entidad/DA 382 ### 13. `entidad_resumen` - Resumen histórico por entidad/DA
383 383
......