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>
|
</div>
|
||||||
|
|
||||||
<!-- Filters -->
|
<!-- 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 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="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="funcional" onclick="filterExperts('funcional')">Consultores funcionales</button>
|
||||||
<button class="filter-chip" data-filter="developer" onclick="filterExperts('developer')">Desarrolladores</button>
|
<button class="filter-chip" data-filter="developer" onclick="filterExperts('developer')">Desarrolladores</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Expert grid (mock data) -->
|
<!-- Expert grid -->
|
||||||
<div class="grid md:grid-cols-2 lg:grid-cols-3 gap-6" id="expertGrid">
|
<div class="grid md:grid-cols-2 lg:grid-cols-3 gap-6" id="expertGrid">
|
||||||
<!-- Dynamically loaded from GET endpoint -->
|
<!-- Dynamically loaded from GET endpoint -->
|
||||||
<div id="expertGridLoading" style="grid-column:1/-1;text-align:center;padding:60px 0;color:#64748b;">
|
<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) {
|
function filterExperts(filter) {
|
||||||
|
currentFilter = filter;
|
||||||
document.querySelectorAll('.filter-chip').forEach(chip => {
|
document.querySelectorAll('.filter-chip').forEach(chip => {
|
||||||
chip.classList.toggle('active', chip.dataset.filter === filter);
|
chip.classList.toggle('active', chip.dataset.filter === filter);
|
||||||
});
|
});
|
||||||
if (filter === 'all') {
|
const searchInput = document.getElementById('expertSearch');
|
||||||
renderExperts(allExperts);
|
if (searchInput) searchExperts(searchInput.value);
|
||||||
} 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;
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load experts on page load
|
// Load experts on page load
|
||||||
@@ -755,23 +780,6 @@
|
|||||||
setTimeout(() => toast.classList.remove('show'), 4000);
|
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 =====
|
// ===== SCROLL ANIMATIONS =====
|
||||||
const observer = new IntersectionObserver((entries) => {
|
const observer = new IntersectionObserver((entries) => {
|
||||||
entries.forEach(entry => {
|
entries.forEach(entry => {
|
||||||
|
|||||||
Reference in New Issue
Block a user