diff --git a/frontend/app.js b/frontend/app.js index 3fb6ff2..bc53bf4 100644 --- a/frontend/app.js +++ b/frontend/app.js @@ -17,6 +17,7 @@ const state = { metrics: null, // Cached metric definitions pagination: { page: 1, pageSize: 50, total: 0, totalPages: 0 }, isShowingFeatured: true, // Whether showing featured schools vs search results + searchMode: "name", // "name" or "location" locationSearch: { active: false, postcode: null, @@ -52,13 +53,21 @@ const CHART_COLORS = [ // ============================================================================= const elements = { + // Search mode toggle + searchModeToggle: document.querySelector(".search-mode-toggle"), + searchModeBtns: document.querySelectorAll(".search-mode-btn"), + nameSearchPanel: document.getElementById("name-search-panel"), + locationSearchPanel: document.getElementById("location-search-panel"), + // Name search schoolSearch: document.getElementById("school-search"), localAuthorityFilter: document.getElementById("local-authority-filter"), typeFilter: document.getElementById("type-filter"), + // Location search postcodeSearch: document.getElementById("postcode-search"), radiusSelect: document.getElementById("radius-select"), locationSearchBtn: document.getElementById("location-search-btn"), - clearLocationBtn: document.getElementById("clear-location-btn"), + typeFilterLocation: document.getElementById("type-filter-location"), + // Schools grid schoolsGrid: document.getElementById("schools-grid"), compareSearch: document.getElementById("compare-search"), compareResults: document.getElementById("compare-results"), @@ -265,12 +274,18 @@ function populateFilters(data) { elements.localAuthorityFilter.appendChild(option); }); - // Populate school type filter + // Populate school type filter (both name and location panels) data.school_types.forEach((type) => { const option = document.createElement("option"); option.value = type; option.textContent = type; elements.typeFilter.appendChild(option); + + // Also add to location panel's type filter + const optionLocation = document.createElement("option"); + optionLocation.value = type; + optionLocation.textContent = type; + elements.typeFilterLocation.appendChild(optionLocation); }); // Populate ranking area dropdown @@ -298,27 +313,37 @@ function populateFilters(data) { // ============================================================================= async function loadSchools() { - const search = elements.schoolSearch.value.trim(); - const localAuthority = elements.localAuthorityFilter.value; - const type = elements.typeFilter.value; - const { active: locationActive, postcode, radius } = state.locationSearch; - - // If no search query (or less than 2 chars) and no filters and no location search, show featured schools - if (search.length < 2 && !localAuthority && !type && !locationActive) { - await loadFeaturedSchools(); - return; - } - const params = new URLSearchParams(); - if (search.length >= 2) params.append("search", search); - if (localAuthority) params.append("local_authority", localAuthority); - if (type) params.append("school_type", type); + if (state.searchMode === "name") { + // Name search mode + const search = elements.schoolSearch.value.trim(); + const localAuthority = elements.localAuthorityFilter.value; + const type = elements.typeFilter.value; + + // If no search query (or less than 2 chars) and no filters, show featured schools + if (search.length < 2 && !localAuthority && !type) { + await loadFeaturedSchools(); + return; + } + + if (search.length >= 2) params.append("search", search); + if (localAuthority) params.append("local_authority", localAuthority); + if (type) params.append("school_type", type); + } else { + // Location search mode + const { active: locationActive, postcode, radius } = state.locationSearch; + const type = elements.typeFilterLocation.value; + + // If no location search active, show featured schools + if (!locationActive) { + await loadFeaturedSchools(); + return; + } - // Add location search params - if (locationActive && postcode) { params.append("postcode", postcode); params.append("radius", radius); + if (type) params.append("school_type", type); } params.append("page", state.pagination.page); @@ -421,32 +446,10 @@ async function searchByLocation() { }; state.pagination.page = 1; - // Show clear button - elements.clearLocationBtn.style.display = "inline-flex"; - // Load schools with location filter await loadSchools(); } -function clearLocationSearch() { - state.locationSearch = { - active: false, - postcode: null, - radius: 5, - }; - state.pagination.page = 1; - - // Clear input - elements.postcodeSearch.value = ""; - elements.radiusSelect.value = "5"; - - // Hide clear button - elements.clearLocationBtn.style.display = "none"; - - // Reload schools (will show featured if no other filters) - loadSchools(); -} - function renderFeaturedSchools(schools) { elements.schoolsGrid.innerHTML = `
-
- -
- +
+ + +
+ +
+
+ +
+ + + + +
+
+
+ +
- diff --git a/frontend/styles.css b/frontend/styles.css index 6105c41..c83f7dd 100644 --- a/frontend/styles.css +++ b/frontend/styles.css @@ -198,6 +198,62 @@ body { margin: 2rem auto 3rem; } +/* Search Mode Toggle */ +.search-mode-toggle { + display: flex; + justify-content: center; + gap: 0; + margin-bottom: 1.5rem; + background: var(--bg-card); + border: 2px solid var(--border-color); + border-radius: var(--radius-lg); + padding: 4px; + max-width: 400px; + margin-left: auto; + margin-right: auto; +} + +.search-mode-btn { + flex: 1; + display: flex; + align-items: center; + justify-content: center; + gap: 0.5rem; + padding: 0.75rem 1.25rem; + font-size: 0.95rem; + font-family: inherit; + font-weight: 500; + border: none; + border-radius: var(--radius-md); + background: transparent; + color: var(--text-muted); + cursor: pointer; + transition: var(--transition); +} + +.search-mode-btn:hover { + color: var(--text-primary); +} + +.search-mode-btn.active { + background: var(--accent-coral); + color: white; + box-shadow: 0 2px 8px rgba(224, 114, 86, 0.3); +} + +.search-mode-btn svg { + flex-shrink: 0; +} + +/* Search Panels */ +.search-panel { + display: none; +} + +.search-panel.active { + display: block; +} + .search-container { position: relative; margin-bottom: 1rem; @@ -258,11 +314,8 @@ body { } /* Location Search */ -.location-search { - margin-bottom: 1rem; -} - .location-input-group { + margin-bottom: 1rem; display: flex; gap: 0.75rem; align-items: center;