limpieza de codigo

This commit is contained in:
2026-10-07 11:37:16 -03:00
parent f818a01003
commit 6ee037ec20
13 changed files with 618 additions and 1198 deletions
+165
View File
@@ -17,6 +17,7 @@ async function initApp() {
initInsightsFeed();
initContactForm();
initCareersForm();
initSearchPage();
}
/* ==========================================================================
@@ -1177,3 +1178,167 @@ function initHeroVideoSpeed() {
video.playbackRate = targetSpeed;
});
}
/* ==========================================================================
12. BÚSQUEDA EN EL SITIO — Página buscar.html
========================================================================== */
const SEARCH_INDEX_URL = 'data/search-index.json';
async function initSearchPage() {
const form = document.getElementById('search-page-form');
const input = document.getElementById('search-page-input');
const results = document.getElementById('search-results');
const status = document.getElementById('search-status');
const suggestions = document.getElementById('search-suggestions');
// Si no estamos en buscar.html, salir silenciosamente
if (!form || !input || !results) return;
let index = [];
// Cargar índice
try {
const res = await fetch(SEARCH_INDEX_URL, { cache: 'no-store' });
if (res.ok) {
index = await res.json();
} else {
console.warn('No se pudo cargar search-index.json:', res.status);
}
} catch (e) {
console.warn('Error cargando search-index.json:', e);
}
// Normalizar texto (sin acentos, minúsculas)
const normalize = (str) =>
(str || '')
.toString()
.toLowerCase()
.normalize('NFD')
.replace(/[\u0300-\u036f]/g, '');
// Escapar HTML
const escapeHtml = (str) =>
(str || '').replace(/[&<>"']/g, (c) => ({
'&': '&amp;',
'<': '&lt;',
'>': '&gt;',
'"': '&quot;',
"'": '&#39;'
}[c]));
// Scoring por relevancia
function scoreItem(item, terms) {
const title = normalize(item.titulo);
const desc = normalize(item.descripcion);
const kw = normalize(item.keywords);
let score = 0;
terms.forEach(term => {
if (!term) return;
if (title.includes(term)) score += 10;
if (kw.includes(term)) score += 6;
if (desc.includes(term)) score += 3;
});
// Bonus si la frase completa aparece en el título
const fullPhrase = terms.join(' ');
if (fullPhrase && title.includes(fullPhrase)) score += 5;
return score;
}
// Resaltar coincidencias
function highlight(text, terms) {
let safe = escapeHtml(text);
terms.forEach(term => {
if (term.length < 2) return;
const escaped = term.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
const regex = new RegExp(`(${escaped})`, 'gi');
safe = safe.replace(regex, '<mark>$1</mark>');
});
return safe;
}
// Render de resultados
function render(term) {
results.innerHTML = '';
const cleanTerm = (term || '').trim();
if (!cleanTerm) {
if (status) status.textContent = '';
if (suggestions) suggestions.hidden = false;
return;
}
if (suggestions) suggestions.hidden = true;
const terms = normalize(cleanTerm).split(/\s+/).filter(Boolean);
const scored = index
.map(item => ({ item, score: scoreItem(item, terms) }))
.filter(r => r.score > 0)
.sort((a, b) => b.score - a.score);
if (scored.length === 0) {
if (status) status.textContent = '';
results.innerHTML = `
<div class="search-empty">
<svg width="48" height="48" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
<circle cx="11" cy="11" r="8"></circle>
<line x1="21" y1="21" x2="16.65" y2="16.65"></line>
<line x1="8" y1="11" x2="14" y2="11"></line>
</svg>
<p>No encontramos resultados para <strong>${escapeHtml(cleanTerm)}</strong>.</p>
<p class="search-hint">
Probá con otros términos o <a href="contacto.html">contactanos directamente</a>.
</p>
</div>
`;
return;
}
if (status) {
status.textContent = `${scored.length} resultado${scored.length !== 1 ? 's' : ''} para "${cleanTerm}"`;
}
results.innerHTML = scored.map(({ item }) => `
<article class="search-result-item">
<div class="result-category">${escapeHtml(item.categoria)}</div>
<h3><a href="${escapeHtml(item.url)}">${highlight(item.titulo, terms)}</a></h3>
<p>${highlight(item.descripcion, terms)}</p>
</article>
`).join('');
}
// Leer ?q= de la URL al cargar
const params = new URLSearchParams(window.location.search);
const initialQuery = params.get('q') || '';
if (initialQuery) {
input.value = initialQuery;
render(initialQuery);
} else {
if (suggestions) suggestions.hidden = false;
// Foco automático al llegar sin query
setTimeout(() => input.focus(), 100);
}
// Submit del form
form.addEventListener('submit', (e) => {
e.preventDefault();
const q = input.value.trim();
const newUrl = q
? `?q=${encodeURIComponent(q)}`
: window.location.pathname;
window.history.replaceState({}, '', newUrl);
render(q);
});
// Búsqueda en vivo con debounce
let debounceTimer;
input.addEventListener('input', () => {
clearTimeout(debounceTimer);
debounceTimer = setTimeout(() => {
render(input.value);
}, 220);
});
}