static/js/projects.js (83 lines of code) (raw):

/** * Copyright 2018 Twitter, Inc. * SPDX-License-Identifier: Apache-2.0 */ const projectCards = Array.from(document.getElementsByClassName("project-card")) const searchBox = document.getElementById("search-box") // parse cards to build project list const projects = [] projectCards.forEach(card => { projects.push({ id: card.id, name: card.getElementsByClassName("project-name")[0].innerText, description: card.getElementsByClassName("project-description")[0].innerText, language: card.getElementsByClassName("project-language")[0].innerText, }) }) // import fuse and initialize let fuse; import("https://cdnjs.cloudflare.com/ajax/libs/fuse.js/6.4.6/fuse.esm.min.js") .then(module => { Fuse = module.default fuse = new Fuse(projects, { findAllMatches: true, isCaseSensitive: false, threshold: 0.1, ignoreLocation: true, useExtendedSearch: true, keys: [ "name", "description", "language", ], }) // perform initial search with query parameter if present if (q = new URL(window.location).searchParams.get("q")) { search(q) } // respond to browser history navigation window.addEventListener("popstate", () => { q = new URL(window.location).searchParams.get("q") search(q) }) }) // perform search on search-box keyup and store in browser history. searchBox.addEventListener('keyup', function(event) { const query = this.value search(query) // push new query onto history stack const url = new URL(window.location) if (url.searchParams.get('q') != query) { if (query) { url.searchParams.set('q', query) } else { url.searchParams.delete('q') } pushState(query, url) } }) // debounce wraps a function so that calls will be delayed to prevent repeated // calls within the specified time window. const debounce = (fn, timeout = 500) => { let timer return (...args) => { clearTimeout(timer) timer = setTimeout(() => { fn.apply(this, args); }, timeout); } } // pushState pushes the new search query onto the browser history on a slight // delay. This is to prevent every individual keystroke from being pushed onto // the history stack. const pushState = debounce((query, url) => { window.history.pushState({}, `Projects search: ${query}`, url) }) // search the project list for the query string and display ranked results. const search = (query) => { searchBox.value = query const resultsBox = document.getElementById('results') if (!query) { // reset all project cards projectCards.forEach(card => { card.classList.remove("hide") card.style.removeProperty("order") }) resultsBox.classList.add("hide") return } const results = fuse.search(query) // first, hide all the projects projectCards.forEach(card => { card.classList.add("hide") }) // show results in ranked order let order = 1 results.forEach(r => { const card = document.getElementById(r.item.id) card.classList.remove("hide") card.style.setProperty("order", order++) }) resultsBox.getElementsByClassName("count")[0].innerText = results.length resultsBox.getElementsByClassName("query")[0].innerText = query resultsBox.classList.remove("hide") }