Add real-time search: filter experts by name, skills, modules, languages, summary. Works with filters.
This commit is contained in:
+43
-35
@@ -224,14 +224,21 @@
|
||||
</div>
|
||||
|
||||
<!-- Filters -->
|
||||
<div class="flex flex-wrap gap-3 mb-10" id="filters">
|
||||
<div class="flex flex-wrap items-center justify-between gap-6 mb-12">
|
||||
<div class="flex-1 max-w-lg">
|
||||
<div style="position:relative;">
|
||||
<svg style="position:absolute;left:16px;top:50%;transform:translateY(-50%);" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="#94a3b8" stroke-width="2.5" stroke-linecap="round"><circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/></svg>
|
||||
<input type="text" id="expertSearch" placeholder="Buscar por nombre, habilidades, módulos..." oninput="searchExperts(this.value)" style="width:100%;padding:12px 16px 12px 46px;background:#fff;border:1px solid #e2e8f0;border-radius:12px;font-family:'Inter',sans-serif;font-size:0.9375rem;color:#0f172a;outline:none;transition:border-color 0.2s;" onfocus="this.style.borderColor='#4338ca'" onblur="this.style.borderColor='#e2e8f0'">
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex flex-wrap gap-3" id="filters">
|
||||
<button class="filter-chip active" data-filter="all" onclick="filterExperts('all')">Todos</button>
|
||||
<button class="filter-chip" data-filter="certified" onclick="filterExperts('certified')">Certificados</button>
|
||||
<button class="filter-chip" data-filter="funcional" onclick="filterExperts('funcional')">Consultores funcionales</button>
|
||||
<button class="filter-chip" data-filter="developer" onclick="filterExperts('developer')">Desarrolladores</button>
|
||||
</div>
|
||||
|
||||
<!-- Expert grid (mock data) -->
|
||||
<!-- Expert grid -->
|
||||
<div class="grid md:grid-cols-2 lg:grid-cols-3 gap-6" id="expertGrid">
|
||||
<!-- Dynamically loaded from GET endpoint -->
|
||||
<div id="expertGridLoading" style="grid-column:1/-1;text-align:center;padding:60px 0;color:#64748b;">
|
||||
@@ -664,26 +671,44 @@
|
||||
}
|
||||
});
|
||||
|
||||
// ===== EXPERT FILTERS =====
|
||||
// ===== EXPERT SEARCH =====
|
||||
let currentFilter = 'all';
|
||||
|
||||
function searchExperts(query) {
|
||||
const q = query.toLowerCase().trim();
|
||||
let filtered = allExperts;
|
||||
|
||||
// Apply current filter
|
||||
if (currentFilter === 'certified') {
|
||||
filtered = filtered.filter(ex => ex.certified === 'yes' || ex.certified === true);
|
||||
}
|
||||
|
||||
// Apply search query
|
||||
if (q.length > 0) {
|
||||
filtered = filtered.filter(ex => {
|
||||
const name = (ex.name || '').toLowerCase();
|
||||
const skills = (ex.skills || '').toLowerCase();
|
||||
const modules = (ex.modules || '').toLowerCase();
|
||||
const extra = (ex.extra || '').toLowerCase();
|
||||
const summary = (ex.summary || '').toLowerCase();
|
||||
const languages = (ex.languages || '').toLowerCase();
|
||||
return name.includes(q) || skills.includes(q) || modules.includes(q) ||
|
||||
extra.includes(q) || summary.includes(q) || languages.includes(q) ||
|
||||
(ex.certified === 'yes' && 'certificado'.includes(q));
|
||||
});
|
||||
}
|
||||
|
||||
renderExperts(filtered);
|
||||
}
|
||||
|
||||
// Update filterExperts to store current filter and search together
|
||||
function filterExperts(filter) {
|
||||
currentFilter = filter;
|
||||
document.querySelectorAll('.filter-chip').forEach(chip => {
|
||||
chip.classList.toggle('active', chip.dataset.filter === filter);
|
||||
});
|
||||
if (filter === 'all') {
|
||||
renderExperts(allExperts);
|
||||
} else if (filter === 'certified') {
|
||||
renderExperts(allExperts.filter(ex => ex.certified === 'yes' || ex.certified === true));
|
||||
} else {
|
||||
// Filter by skills/modules containing the filter term
|
||||
renderExperts(allExperts.filter(ex => {
|
||||
const skills = (ex.skills || '').toLowerCase();
|
||||
const modules = (ex.modules || '').toLowerCase();
|
||||
const combined = skills + ' ' + modules;
|
||||
// No way to programmatically determine funcional vs developer from API data
|
||||
// Show all for now
|
||||
return true;
|
||||
}));
|
||||
}
|
||||
const searchInput = document.getElementById('expertSearch');
|
||||
if (searchInput) searchExperts(searchInput.value);
|
||||
}
|
||||
|
||||
// Load experts on page load
|
||||
@@ -755,23 +780,6 @@
|
||||
setTimeout(() => toast.classList.remove('show'), 4000);
|
||||
}
|
||||
|
||||
// ===== EXPERT FILTERS =====
|
||||
function filterExperts(filter) {
|
||||
document.querySelectorAll('.filter-chip').forEach(chip => {
|
||||
chip.classList.toggle('active', chip.dataset.filter === filter);
|
||||
});
|
||||
|
||||
document.querySelectorAll('#expertGrid .expert-card').forEach(card => {
|
||||
const role = card.dataset.role;
|
||||
const certified = card.dataset.certified === 'true';
|
||||
let show = true;
|
||||
if (filter === 'certified') show = certified;
|
||||
if (filter === 'funcional') show = role === 'funcional';
|
||||
if (filter === 'developer') show = role === 'developer';
|
||||
card.style.display = show ? '' : 'none';
|
||||
});
|
||||
}
|
||||
|
||||
// ===== SCROLL ANIMATIONS =====
|
||||
const observer = new IntersectionObserver((entries) => {
|
||||
entries.forEach(entry => {
|
||||
|
||||
Reference in New Issue
Block a user