Rafael Lopez

fix nav teclado

This diff is collapsed. Click to expand it.
......@@ -21,6 +21,7 @@
"dependencies": {
"@observablehq/plot": "^0.6.17",
"@supabase/supabase-js": "^2.98.0",
"@sveltejs/adapter-node": "^5.5.4",
"d3": "^7.9.0",
"fuse.js": "^7.1.0",
"hyparquet": "^1.25.1",
......
No preview for this file type
......@@ -133,22 +133,31 @@
<a
href="/"
onclick={closeDrawer}
class="w-full flex items-center gap-3 px-3 py-3 rounded-lg transition-colors text-left mb-4"
class="w-full flex items-center px-3 py-2.5 rounded-lg transition-colors text-left"
style="background-color: {$page.url.pathname === '/' ? 'var(--theme-fill)' : 'transparent'};"
onmouseenter={(e) => e.currentTarget.style.backgroundColor = 'var(--theme-fill)'}
onmouseleave={(e) => e.currentTarget.style.backgroundColor = $page.url.pathname === '/' ? 'var(--theme-fill)' : 'transparent'}
>
<svg class="w-4 h-4 flex-shrink-0" style="color: var(--theme-texto);" fill="currentColor" viewBox="0 0 20 20">
<rect x="2" y="2" width="7" height="7" rx="1.5"/>
<rect x="11" y="2" width="7" height="7" rx="1.5"/>
<rect x="2" y="11" width="7" height="7" rx="1.5"/>
<rect x="11" y="11" width="7" height="7" rx="1.5"/>
</svg>
<span class="font-medium text-sm" style="color: var(--theme-titulo);">Inicio / Buscador</span>
<span class="text-sm" style="color: var(--theme-titulo);">Inicio / Buscador</span>
</a>
<!-- Descargas -->
<a
href="/descargas"
onclick={closeDrawer}
class="w-full flex items-center px-3 py-2.5 rounded-lg transition-colors text-left mb-4"
style="background-color: {$page.url.pathname === '/descargas' ? 'var(--theme-fill)' : 'transparent'};"
onmouseenter={(e) => e.currentTarget.style.backgroundColor = 'var(--theme-fill)'}
onmouseleave={(e) => e.currentTarget.style.backgroundColor = $page.url.pathname === '/descargas' ? 'var(--theme-fill)' : 'transparent'}
>
<span class="text-sm" style="color: var(--theme-titulo);">Descargas</span>
</a>
<!-- Separador -->
<div class="border-t mb-4" style="border-color: var(--theme-borde);"></div>
<!-- Clasificadores -->
<div class="mb-6">
<div class="mb-4">
<h3 class="text-xs font-semibold uppercase tracking-wider mb-3 px-2" style="color: var(--theme-texto);">
Navegar por clasificadores
</h3>
......@@ -157,13 +166,13 @@
<a
href={c.href}
onclick={closeDrawer}
class="w-full flex items-center justify-between px-3 py-2.5 rounded-lg transition-colors text-left group"
class="w-full flex items-center justify-between px-3 py-2 rounded-lg transition-colors text-left group"
style="background-color: {isActive(c.href) ? 'var(--theme-fill)' : 'transparent'};"
onmouseenter={(e) => e.currentTarget.style.backgroundColor = 'var(--theme-fill)'}
onmouseleave={(e) => e.currentTarget.style.backgroundColor = isActive(c.href) ? 'var(--theme-fill)' : 'transparent'}
>
<div class="flex-1 min-w-0">
<span class="text-sm font-medium block" style="color: var(--theme-titulo);">{c.nombre}</span>
<span class="text-sm block" style="color: var(--theme-titulo);">{c.nombre}</span>
<span class="text-xs" style="color: var(--theme-texto);">{c.desc}</span>
</div>
<svg
......@@ -178,86 +187,52 @@
</svg>
</a>
{/each}
</div>
</div>
<!-- Ver todos los clasificadores -->
<a
href="/clasificadores"
onclick={closeDrawer}
class="w-full flex items-center gap-3 px-3 py-3 rounded-lg transition-colors text-left mb-6"
class="w-full flex items-center px-3 py-2 rounded-lg transition-colors text-left mt-1"
style="background-color: {$page.url.pathname === '/clasificadores' ? 'var(--theme-fill)' : 'transparent'};"
onmouseenter={(e) => e.currentTarget.style.backgroundColor = 'var(--theme-fill)'}
onmouseleave={(e) => e.currentTarget.style.backgroundColor = $page.url.pathname === '/clasificadores' ? 'var(--theme-fill)' : 'transparent'}
>
<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">
<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"/>
</svg>
<span class="text-sm" style="color: var(--theme-accent);">Ver todos los clasificadores</span>
<span class="text-xs" style="color: var(--theme-texto);">Ver todos los clasificadores</span>
</a>
</div>
</div>
<!-- Separador -->
<div class="border-t my-4" style="border-color: var(--theme-borde);"></div>
<div class="border-t mb-4" style="border-color: var(--theme-borde);"></div>
<!-- Enlaces -->
<div class="space-y-1">
<a
href="/documentacion"
onclick={closeDrawer}
class="w-full flex items-center gap-3 px-3 py-2.5 rounded-lg transition-colors text-left"
class="w-full flex items-center px-3 py-2 rounded-lg transition-colors text-left"
onmouseenter={(e) => e.currentTarget.style.backgroundColor = 'var(--theme-fill)'}
onmouseleave={(e) => e.currentTarget.style.backgroundColor = 'transparent'}
>
<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">
<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"/>
</svg>
<span class="text-sm" style="color: var(--theme-titulo);">Documentación</span>
</a>
<a
href="/sobre"
onclick={closeDrawer}
class="w-full flex items-center gap-3 px-3 py-2.5 rounded-lg transition-colors text-left"
class="w-full flex items-center px-3 py-2 rounded-lg transition-colors text-left"
onmouseenter={(e) => e.currentTarget.style.backgroundColor = 'var(--theme-fill)'}
onmouseleave={(e) => e.currentTarget.style.backgroundColor = 'transparent'}
>
<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">
<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"/>
</svg>
<span class="text-sm" style="color: var(--theme-titulo);">Sobre el proyecto</span>
</a>
</div>
<!-- Separador -->
<div class="border-t my-4" style="border-color: var(--theme-borde);"></div>
<!-- Descargas -->
<a
href="/descargas"
onclick={closeDrawer}
class="w-full flex items-center gap-3 px-3 py-3 rounded-lg transition-colors text-left"
style="background-color: {$page.url.pathname === '/descargas' ? 'var(--theme-fill)' : 'transparent'};"
onmouseenter={(e) => e.currentTarget.style.backgroundColor = 'var(--theme-fill)'}
onmouseleave={(e) => e.currentTarget.style.backgroundColor = $page.url.pathname === '/descargas' ? 'var(--theme-fill)' : 'transparent'}
>
<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">
<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"/>
</svg>
<span class="text-sm font-medium" style="color: var(--theme-accent);">Descargas</span>
</a>
<!-- Créditos -->
<a
href="/creditos"
onclick={closeDrawer}
class="w-full flex items-center gap-3 px-3 py-2.5 rounded-lg transition-colors text-left mt-2"
class="w-full flex items-center px-3 py-2 rounded-lg transition-colors text-left"
onmouseenter={(e) => e.currentTarget.style.backgroundColor = 'var(--theme-fill)'}
onmouseleave={(e) => e.currentTarget.style.backgroundColor = 'transparent'}
>
<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">
<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"/>
</svg>
<span class="text-sm" style="color: var(--theme-texto);">Créditos institucionales</span>
</a>
</div>
</nav>
<!-- Footer -->
......
......@@ -220,7 +220,7 @@
const url = `${base}${item.codigo}`;
console.log('[SEARCH] goToResult:', item.tipo, item.codigo, '→', url);
open = false;
window.location.href = url;
goto(url);
}
}
......
<script>
import '../app.css';
import { page, navigating } from '$app/stores';
import favicon from '$lib/assets/favicon.svg';
import favicon from '$lib/assets/favicon.ico';
import Navbar from '$lib/components/ui/Navbar.svelte';
import NavigationDrawer from '$lib/components/layout/NavigationDrawer.svelte';
import SearchModal from '$lib/components/ui/SearchModal.svelte';
......
<script>
import { onMount } from 'svelte';
import { goto } from '$app/navigation';
import { landingSearchMode, landingSelectedClassifiers, landingSearchQuery } from '$lib/stores/landingSearchState';
import { openDrawer } from '$lib/stores/drawer.js';
......@@ -811,7 +812,7 @@
url = `/programa/${generateCodigo(hit)}`;
}
window.location.href = url;
goto(url);
}
function clearSearch() {
......@@ -1123,7 +1124,7 @@
{#each EXAMPLES_PROGRAMAS as ex}
<span
class="mode-pill"
onclick={() => searchFromPill(ex.label)}
onclick={(e) => { e.stopPropagation(); searchFromPill(ex.label); }}
onkeydown={(e) => e.key === 'Enter' && searchFromPill(ex.label)}
role="button"
tabindex="0"
......@@ -1165,7 +1166,7 @@
class="clf-chip"
class:clf-chip-active={selectedClassifiers.includes(clf.id)}
class:clf-chip-disabled={clf.disabled}
onclick={() => { if (!clf.disabled) toggleClassifier(clf.id); }}
onclick={(e) => { e.stopPropagation(); if (!clf.disabled) toggleClassifier(clf.id); }}
disabled={clf.disabled}
>
<span class="clf-dot"></span>
......@@ -1176,11 +1177,11 @@
<div class="mode-card-pills">
{#each EXAMPLES_CLASIFICADORES as ex}
{#if ex.href}
<a href={ex.href} class="mode-pill">{ex.label}</a>
<a href={ex.href} class="mode-pill" onclick={(e) => e.stopPropagation()}>{ex.label}</a>
{:else}
<span
class="mode-pill"
onclick={() => searchFromPill(ex.label, ex.classifier)}
onclick={(e) => { e.stopPropagation(); searchFromPill(ex.label, ex.classifier); }}
onkeydown={(e) => e.key === 'Enter' && searchFromPill(ex.label, ex.classifier)}
role="button"
tabindex="0"
......@@ -2240,8 +2241,8 @@
.pills-hint{font-family:var(--sans);font-size:10px;color:#7B7870;font-weight:500}
.hint-desktop{display:inline}
.hint-mobile{display:none}
.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}
.mode-pill:hover{background:rgba(255,255,255,0.12);border-color:rgba(255,255,255,0.25);color:#F5F0E8}
.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}
.mode-pill:hover{background:rgba(255,255,255,0.12);border-color:rgba(255,255,255,0.25);color:#FFFFFF !important}
.mode-card-radio{position:absolute;top:16px;right:16px}
.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 @@
:global(html:not(.dark)) .radio-dot-active{border-color:#D4A017}
/* Mode pills */
:global(html:not(.dark)) .mode-pill{border-color:rgba(0,0,0,0.12);background:rgba(0,0,0,0.04);color:#555}
:global(html:not(.dark)) .mode-pill:hover{background:rgba(0,0,0,0.08);border-color:rgba(0,0,0,0.2);color:#1d1d1f}
:global(html:not(.dark)) .mode-pill{border-color:rgba(0,0,0,0.12);background:rgba(0,0,0,0.04);color:#555 !important}
: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}
:global(html:not(.dark)) .pills-hint{color:#999}
/* Gear / settings */
......
export const ssr = false;
import { error } from '@sveltejs/kit';
import { API_HOST } from '$lib/api.js';
......
......@@ -1217,18 +1217,19 @@
.slice(0, 20);
}
function parseDescripciones(descripcionesStr) {
if (!descripcionesStr) return [];
try {
const parsed = JSON.parse(descripcionesStr);
return parsed.sort((a, b) => {
const maxYearA = getMaxYear(a.rangos);
const maxYearB = getMaxYear(b.rangos);
function parseDescripciones(descs) {
if (!descs) return [];
let arr;
if (typeof descs === 'string') {
try { arr = JSON.parse(descs); } catch { return []; }
} else {
arr = Array.isArray(descs) ? descs : [];
}
return [...arr].sort((a, b) => {
const maxYearA = getMaxYear(a.gestion || a.rangos);
const maxYearB = getMaxYear(b.gestion || b.rangos);
return maxYearB - maxYearA;
});
} catch {
return [];
}
}
function getMaxYear(rangos) {
......
......@@ -1364,19 +1364,19 @@
.slice(0, 20);
}
function parseDescripciones(descripcionesStr) {
if (!descripcionesStr) return [];
try {
const parsed = JSON.parse(descripcionesStr);
// Ordenar por año más reciente (extraer el máximo año de cada rango)
return parsed.sort((a, b) => {
const maxYearA = getMaxYear(a.rangos);
const maxYearB = getMaxYear(b.rangos);
return maxYearB - maxYearA; // Descendente, más reciente primero
});
} catch {
return [];
function parseDescripciones(descs) {
if (!descs) return [];
let arr;
if (typeof descs === 'string') {
try { arr = JSON.parse(descs); } catch { return []; }
} else {
arr = Array.isArray(descs) ? descs : [];
}
return [...arr].sort((a, b) => {
const maxYearA = getMaxYear(a.gestion || a.rangos);
const maxYearB = getMaxYear(b.gestion || b.rangos);
return maxYearB - maxYearA;
});
}
function getMaxYear(rangos) {
......
......@@ -881,18 +881,19 @@
.slice(0, 20);
}
function parseDescripciones(descripcionesStr) {
if (!descripcionesStr) return [];
try {
const parsed = typeof descripcionesStr === 'string' ? JSON.parse(descripcionesStr) : descripcionesStr;
return parsed.sort((a, b) => {
const maxYearA = getMaxYear(a.rangos);
const maxYearB = getMaxYear(b.rangos);
function parseDescripciones(descs) {
if (!descs) return [];
let arr;
if (typeof descs === 'string') {
try { arr = JSON.parse(descs); } catch { return []; }
} else {
arr = Array.isArray(descs) ? descs : [];
}
return [...arr].sort((a, b) => {
const maxYearA = getMaxYear(a.gestion || a.rangos);
const maxYearB = getMaxYear(b.gestion || b.rangos);
return maxYearB - maxYearA;
});
} catch {
return [];
}
}
function getMaxYear(rangos) {
......
......@@ -722,6 +722,7 @@
});
onMount(async () => {
console.log('[SECTORES] onMount started');
isMobile = 'ontouchstart' in window || navigator.maxTouchPoints > 0;
requestAnimationFrame(() => {
......@@ -735,10 +736,10 @@
const data = await res.json();
if (Array.isArray(data)) {
allItems = data;
allItems = data.filter(item => String(item.acteco) !== '0' && !String(item.acteco).startsWith('0.') && !/desconocido/i.test(item.desc_acteco || ''));
// Sectores = items de profundidad 1
sectores = data
sectores = allItems
.filter(item => getDepth(item.acteco) === 1)
.sort((a, b) => String(a.acteco).localeCompare(String(b.acteco), undefined, { numeric: true }));
......@@ -766,6 +767,7 @@
selectedYear = 2025;
}
console.log('[SECTORES] loading done, sectores:', sectores.length, 'allItems:', allItems.length, 'selectedYear:', selectedYear, 'layoutMounted:', layoutMounted, 'viewMode:', viewMode);
loading = false;
});
......@@ -1223,18 +1225,19 @@
.slice(0, 20);
}
function parseDescripciones(descripcionesStr) {
if (!descripcionesStr) return [];
try {
const parsed = JSON.parse(descripcionesStr);
return parsed.sort((a, b) => {
const maxYearA = getMaxYear(a.rangos);
const maxYearB = getMaxYear(b.rangos);
function parseDescripciones(descs) {
if (!descs) return [];
let arr;
if (typeof descs === 'string') {
try { arr = JSON.parse(descs); } catch { return []; }
} else {
arr = Array.isArray(descs) ? descs : [];
}
return [...arr].sort((a, b) => {
const maxYearA = getMaxYear(a.gestion || a.rangos);
const maxYearB = getMaxYear(b.gestion || b.rangos);
return maxYearB - maxYearA;
});
} catch {
return [];
}
}
function getMaxYear(rangos) {
......
This diff is collapsed. Click to expand it.
<script>
import { onMount, tick } from 'svelte';
import { goto } from '$app/navigation';
import { page } from '$app/stores';
import * as d3 from 'd3';
......@@ -142,7 +143,7 @@
}
function navigateToEntity(item) {
window.location.href = `/entidad/${item.codigo}`;
goto(`/entidad/${item.codigo}`);
}
function onSearchKeydown(e) {
......
export const ssr = false;
import { error } from '@sveltejs/kit';
import { API_HOST } from '$lib/api.js';
......
export const ssr = false;
import { error } from '@sveltejs/kit';
import { API_HOST } from '$lib/api.js';
......@@ -17,7 +19,7 @@ export async function load({ params }) {
const clasRes = await fetch(`${API_BASE}/clasificador`);
if (clasRes.ok) {
const clasificador = await clasRes.json();
const current = clasificador.find(c => c.organismo === parseInt(codigo));
const current = clasificador.find(c => String(c.organismo) === codigo);
if (current) {
// Padres: grupo y subgrupo (como objetos virtuales para navegación)
padres = [
......
export const ssr = false;
import { error } from '@sveltejs/kit';
import { API_HOST } from '$lib/api.js';
......
......@@ -19,10 +19,9 @@
</p>
<p class="p3">
La plataforma reúne más de veinte años de información sobre ingresos y gastos
La plataforma reúne 10 años de información sobre ingresos y gastos
públicos, organizada mediante los clasificadores presupuestarios oficiales y a
través de los programas y proyectos de inversión pública. Los datos se actualizan
semanalmente y abarcan a todas las entidades del sector público.
través de los programas y proyectos de inversión pública.
</p>
<p class="p3">
......
<script>
import { onMount, tick } from 'svelte';
import { goto } from '$app/navigation';
import { page } from '$app/stores';
import { get } from 'svelte/store';
import * as d3 from 'd3';
......@@ -224,7 +225,7 @@
}
function navigateToEntity(item) {
window.location.href = `/ubicacion/${item.codigo}`;
goto(`/ubicacion/${item.codigo}`);
}
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
import adapter from '@sveltejs/adapter-auto';
import adapter from '@sveltejs/adapter-node';
/** @type {import('@sveltejs/kit').Config} */
const config = {
kit: {
// adapter-auto only supports some environments, see https://svelte.dev/docs/kit/adapter-auto for a list.
// If your environment is not supported, or you settled on a specific environment, switch out the adapter.
// See https://svelte.dev/docs/kit/adapters for more information about adapters.
adapter: adapter()
}
};
......
......@@ -377,7 +377,7 @@ Sector → Subsector → Área → Subárea → Entidad
---
## Tablas de Vista de Entidad
## Tablas de Vista de Entidad"
### 13. `entidad_resumen` - Resumen histórico por entidad/DA
......