diff --git a/static/script.js b/static/script.js index 9d96ab93..affa6609 100644 --- a/static/script.js +++ b/static/script.js @@ -613,11 +613,8 @@ if (clearFiltersBtn) { resultsEmptyEl.style.display = "block"; resultsGrid.style.display = "none"; resultsEmptyEl.style.display = "block"; + showSearchInput(false); // Hide search when no results if (message && emptyMessageEl) emptyMessageEl.textContent = message; - if (!projects || projects.length === 0) { //if no projects returned from api, show the "no results" message and hide the grid - resultsGrid.style.display = "none"; - resultsEmptyEl.style.display = "block"; - if (message && emptyMessageEl) emptyMessageEl.textContent = message; //if api sent back a message (e.g. "no projects found matching your criteria"), show that resultsSection.scrollIntoView({ behavior: "smooth" }); return; } @@ -630,6 +627,10 @@ if (clearFiltersBtn) { resultsGrid.appendChild(buildProjectCard(project)); }); + // Show search input and setup filter (only once) + showSearchInput(true); + if (!searchInput) setupFilter(); + resultsSection.scrollIntoView({ behavior: "smooth" }); } @@ -703,6 +704,62 @@ if (clearFiltersBtn) { return text.length > maxLength ? text.slice(0, maxLength) + "..." : text; } + // ---------------------------------------------------------- + // Filter projects based on search input (title, description, AND skills) + // ---------------------------------------------------------- + var searchInput = null; + var currentProjects = []; + + function setupFilter() { + searchInput = document.getElementById("results-search"); + if (!searchInput) return; + + searchInput.addEventListener("input", function (e) { + var searchTerm = e.target.value.trim().toLowerCase(); + var cards = resultsGrid.querySelectorAll(".project-card"); + + cards.forEach(function (card) { + // Get title and description + var title = card.querySelector(".project-card-title")?.textContent.toLowerCase() || ""; + var desc = card.querySelector(".project-card-desc")?.textContent.toLowerCase() || ""; + + // Get all skill/tag text from project-tag elements + var tags = card.querySelectorAll(".project-tag"); + var tagTexts = ""; + tags.forEach(function(tag) { + tagTexts += tag.textContent.toLowerCase() + " "; + }); + + // Combine all searchable text + var searchableText = title + " " + desc + " " + tagTexts; + + // Check if search term matches ANY content + if (searchTerm === "" || searchableText.includes(searchTerm)) { + card.style.display = ""; + } else { + card.style.display = "none"; + } + }); + }); + } + + function showSearchInput(show) { + var wrap = document.getElementById("results-search-wrap"); + if (wrap) { + wrap.style.display = show ? "block" : "none"; + if (show && searchInput) { + searchInput.value = ""; + // Reset any hidden cards when showing search + if (resultsGrid) { + var cards = resultsGrid.querySelectorAll(".project-card"); + cards.forEach(function(card) { + card.style.display = ""; + }); + } + } + } + } + } // end isIndexPage @@ -954,4 +1011,4 @@ function scrollToTop() { if (scrollTopBtn) { window.addEventListener('scroll', handleScroll); scrollTopBtn.addEventListener('click', scrollToTop); -} +} \ No newline at end of file diff --git a/static/style.css b/static/style.css index 13cd1c94..c3a04ff8 100644 --- a/static/style.css +++ b/static/style.css @@ -2845,4 +2845,43 @@ select:focus { flex: 1; white-space: pre; color: #e6edf3; +} +/* ---- Results Search Input --------------------------------- */ +.results-search-wrap { + max-width: 480px; + margin: 0 auto 32px auto; +} + +.results-search-input { + width: 100%; + padding: 12px 18px; + font-family: var(--font-body); + font-size: 0.95rem; + border: 1.5px solid var(--border); + border-radius: var(--r-full); + background: var(--white); + transition: border-color var(--t), box-shadow var(--t); +} + +.results-search-input:focus { + outline: none; + border-color: var(--indigo-500); + box-shadow: 0 0 0 3px rgba(79, 110, 247, 0.12); +} + +.results-search-input::placeholder { + color: var(--gray-400); +} + +/* ---- Accessibility ----------------------------------------- */ +.visually-hidden { + position: absolute; + width: 1px; + height: 1px; + padding: 0; + margin: -1px; + overflow: hidden; + clip: rect(0, 0, 0, 0); + white-space: nowrap; + border-width: 0; } \ No newline at end of file diff --git a/templates/index.html b/templates/index.html index 18537b94..7f9b7c2d 100644 --- a/templates/index.html +++ b/templates/index.html @@ -75,7 +75,6 @@
Every recommendation comes with practical resources — not just a project name.
Projects are scored against your exact skills, level, and interest — not pulled from a generic list.
@@ -343,13 +289,6 @@Each project includes a numbered roadmap so you always know what to build next, without guessing.
@@ -363,20 +302,9 @@Download a working template for every project. Skip the blank-page problem and start - building immediately.
- -Download a working template for every project. Skip the blank-page problem and start building immediately. -
+Download a working template for every project. Skip the blank-page problem and start building immediately.
Get starter code - @@ -413,18 +341,11 @@