improve the comparison search feature
All checks were successful
Build and Push Docker Image / build-and-push (push) Successful in 56s
All checks were successful
Build and Push Docker Image / build-and-push (push) Successful in 56s
This commit is contained in:
@@ -771,6 +771,58 @@ function setupEventListeners() {
|
|||||||
|
|
||||||
// Compare search
|
// Compare search
|
||||||
let compareSearchTimeout;
|
let compareSearchTimeout;
|
||||||
|
let lastCompareSearchData = null;
|
||||||
|
|
||||||
|
function renderCompareResults(data) {
|
||||||
|
if (!data) return;
|
||||||
|
lastCompareSearchData = data;
|
||||||
|
|
||||||
|
const results = data.schools.filter(s => !selectedSchools.some(sel => sel.urn === s.urn));
|
||||||
|
|
||||||
|
const headerHtml = `
|
||||||
|
<div class="compare-results-header">
|
||||||
|
<span>${results.length} school${results.length !== 1 ? 's' : ''} found</span>
|
||||||
|
<button class="compare-results-close" title="Close (Esc)">
|
||||||
|
<svg viewBox="0 0 16 16" width="14" height="14" fill="none" stroke="currentColor" stroke-width="2">
|
||||||
|
<path d="M12 4L4 12M4 4l8 8"/>
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
|
||||||
|
if (results.length === 0) {
|
||||||
|
elements.compareResults.innerHTML = headerHtml + '<div class="compare-result-item"><span class="name">No more schools to add</span></div>';
|
||||||
|
} else {
|
||||||
|
elements.compareResults.innerHTML = headerHtml + results.slice(0, 10).map(school => `
|
||||||
|
<div class="compare-result-item" data-urn="${school.urn}" data-name="${escapeHtml(school.school_name)}">
|
||||||
|
<div class="name">${escapeHtml(school.school_name)}</div>
|
||||||
|
<div class="location">${escapeHtml(school.local_authority || '')}${school.postcode ? ' • ' + escapeHtml(school.postcode) : ''}</div>
|
||||||
|
</div>
|
||||||
|
`).join('');
|
||||||
|
|
||||||
|
elements.compareResults.querySelectorAll('.compare-result-item').forEach(item => {
|
||||||
|
item.addEventListener('click', () => {
|
||||||
|
const urn = parseInt(item.dataset.urn);
|
||||||
|
const school = data.schools.find(s => s.urn === urn);
|
||||||
|
if (school) {
|
||||||
|
addToComparison(school);
|
||||||
|
// Re-render results without closing (filter out newly added school)
|
||||||
|
renderCompareResults(data);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add close button handler
|
||||||
|
const closeBtn = elements.compareResults.querySelector('.compare-results-close');
|
||||||
|
if (closeBtn) {
|
||||||
|
closeBtn.addEventListener('click', () => {
|
||||||
|
elements.compareResults.classList.remove('active');
|
||||||
|
elements.compareSearch.value = '';
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
elements.compareSearch.addEventListener('input', async () => {
|
elements.compareSearch.addEventListener('input', async () => {
|
||||||
clearTimeout(compareSearchTimeout);
|
clearTimeout(compareSearchTimeout);
|
||||||
const query = elements.compareSearch.value.trim();
|
const query = elements.compareSearch.value.trim();
|
||||||
@@ -784,41 +836,14 @@ function setupEventListeners() {
|
|||||||
const data = await fetchAPI(`/api/schools?search=${encodeURIComponent(query)}`);
|
const data = await fetchAPI(`/api/schools?search=${encodeURIComponent(query)}`);
|
||||||
if (!data) return;
|
if (!data) return;
|
||||||
|
|
||||||
const results = data.schools.filter(s => !selectedSchools.some(sel => sel.urn === s.urn));
|
renderCompareResults(data);
|
||||||
|
|
||||||
if (results.length === 0) {
|
|
||||||
elements.compareResults.innerHTML = '<div class="compare-result-item"><span class="name">No schools found</span></div>';
|
|
||||||
} else {
|
|
||||||
elements.compareResults.innerHTML = results.slice(0, 10).map(school => `
|
|
||||||
<div class="compare-result-item" data-urn="${school.urn}" data-name="${escapeHtml(school.school_name)}">
|
|
||||||
<div class="name">${escapeHtml(school.school_name)}</div>
|
|
||||||
<div class="location">${escapeHtml(school.local_authority || '')}${school.postcode ? ' • ' + escapeHtml(school.postcode) : ''}</div>
|
|
||||||
</div>
|
|
||||||
`).join('');
|
|
||||||
|
|
||||||
elements.compareResults.querySelectorAll('.compare-result-item').forEach(item => {
|
|
||||||
item.addEventListener('click', () => {
|
|
||||||
const urn = parseInt(item.dataset.urn);
|
|
||||||
const school = data.schools.find(s => s.urn === urn);
|
|
||||||
if (school) {
|
|
||||||
addToComparison(school);
|
|
||||||
elements.compareSearch.value = '';
|
|
||||||
elements.compareResults.classList.remove('active');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
elements.compareResults.classList.add('active');
|
elements.compareResults.classList.add('active');
|
||||||
}, 300);
|
}, 300);
|
||||||
});
|
});
|
||||||
|
|
||||||
elements.compareSearch.addEventListener('blur', () => {
|
|
||||||
setTimeout(() => elements.compareResults.classList.remove('active'), 200);
|
|
||||||
});
|
|
||||||
|
|
||||||
elements.compareSearch.addEventListener('focus', () => {
|
elements.compareSearch.addEventListener('focus', () => {
|
||||||
if (elements.compareSearch.value.trim().length >= 2) {
|
if (elements.compareSearch.value.trim().length >= 2 && lastCompareSearchData) {
|
||||||
|
renderCompareResults(lastCompareSearchData);
|
||||||
elements.compareResults.classList.add('active');
|
elements.compareResults.classList.add('active');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -852,6 +877,13 @@ function setupEventListeners() {
|
|||||||
// Keyboard
|
// Keyboard
|
||||||
document.addEventListener('keydown', (e) => {
|
document.addEventListener('keydown', (e) => {
|
||||||
if (e.key === 'Escape') {
|
if (e.key === 'Escape') {
|
||||||
|
// Close compare results if open
|
||||||
|
if (elements.compareResults.classList.contains('active')) {
|
||||||
|
elements.compareResults.classList.remove('active');
|
||||||
|
elements.compareSearch.value = '';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Close modal if open
|
||||||
closeModal();
|
closeModal();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -476,6 +476,38 @@ body {
|
|||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.compare-results-header {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
padding: 0.6rem 1rem;
|
||||||
|
background: var(--bg-secondary);
|
||||||
|
border-bottom: 1px solid var(--border-color);
|
||||||
|
font-size: 0.8rem;
|
||||||
|
color: var(--text-muted);
|
||||||
|
position: sticky;
|
||||||
|
top: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.compare-results-close {
|
||||||
|
width: 24px;
|
||||||
|
height: 24px;
|
||||||
|
border: none;
|
||||||
|
background: transparent;
|
||||||
|
border-radius: var(--radius-sm);
|
||||||
|
cursor: pointer;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
color: var(--text-muted);
|
||||||
|
transition: var(--transition);
|
||||||
|
}
|
||||||
|
|
||||||
|
.compare-results-close:hover {
|
||||||
|
background: var(--accent-coral);
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
.compare-result-item {
|
.compare-result-item {
|
||||||
padding: 0.75rem 1rem;
|
padding: 0.75rem 1rem;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
|||||||
Reference in New Issue
Block a user