-
Notifications
You must be signed in to change notification settings - Fork 168
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #1 from apvarun/add-search
Add search UI
- Loading branch information
Showing
18 changed files
with
296 additions
and
14 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
# Changelog | ||
|
||
All the changes made to Showcase theme for Hugo. | ||
|
||
## v1.1.0 - 2021-07-17 | ||
|
||
### Added | ||
|
||
- Add support for text search | ||
|
||
## v1.0.0 - 2021-07-16 | ||
|
||
- Initial Release |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,170 @@ | ||
// Credits to search implementation: https://gist.github.com/cmod/5410eae147e4318164258742dd053993 | ||
|
||
var fuse; // holds our search engine | ||
var searchVisible = false; | ||
var firstRun = true; // allow us to delay loading json data unless search activated | ||
var list = document.querySelector('.search-list'); // targets the <ul> | ||
var first = list.firstChild; // first child of search list | ||
var last = list.lastChild; // last child of search list | ||
var maininput = document.querySelector('.search-ui input'); // input box for search | ||
var searchResultsHeading = document.querySelector('.search-results'); // input box for search | ||
var noResults = document.querySelector('.no-results'); // input box for search | ||
var resultsAvailable = false; // Did we get any search results? | ||
|
||
// ========================================== | ||
// The main keyboard event listener running the show | ||
// | ||
document.querySelector('.open-search').addEventListener('click', openSearch); | ||
document.querySelector('.close-search').addEventListener('click', closeSearch); | ||
|
||
function closeSearch() { | ||
document.querySelector('.search-ui').classList.add("hidden"); | ||
document.activeElement.blur(); // remove focus from search box | ||
searchVisible = false; // search not visible | ||
searchResultsHeading.classList.add('hidden'); | ||
} | ||
|
||
function openSearch() { | ||
// Load json search index if first time invoking search | ||
// Means we don't load json unless searches are going to happen; keep user payload small unless needed | ||
if (firstRun) { | ||
loadSearch(); // loads our json data and builds fuse.js search index | ||
firstRun = false; // let's never do this again | ||
} | ||
|
||
// Toggle visibility of search box | ||
if (!searchVisible) { | ||
document.querySelector('.search-ui').classList.remove("hidden"); | ||
document.querySelector('.search-ui input').focus(); // put focus in input box so you can just start typing | ||
searchVisible = true; // search visible | ||
} | ||
} | ||
|
||
document.addEventListener('keydown', function (event) { | ||
|
||
if (event.metaKey && event.which === 191) { | ||
openSearch() | ||
} | ||
|
||
// Allow ESC (27) to close search box | ||
if (event.keyCode == 27) { | ||
if (searchVisible) { | ||
document.querySelector('.search-ui').classList.add("hidden"); | ||
document.activeElement.blur(); | ||
searchVisible = false; | ||
searchResultsHeading.classList.add('hidden'); | ||
} | ||
} | ||
|
||
// DOWN (40) arrow | ||
if (event.keyCode == 40) { | ||
if (searchVisible && resultsAvailable) { | ||
console.log("down"); | ||
event.preventDefault(); // stop window from scrolling | ||
if (document.activeElement == maininput) { first.focus(); } // if the currently focused element is the main input --> focus the first <li> | ||
else if (document.activeElement == last) { last.focus(); } // if we're at the bottom, stay there | ||
else { document.activeElement.parentElement.nextSibling.firstElementChild.focus(); } // otherwise select the next search result | ||
} | ||
} | ||
|
||
// UP (38) arrow | ||
if (event.keyCode == 38) { | ||
if (searchVisible && resultsAvailable) { | ||
event.preventDefault(); // stop window from scrolling | ||
if (document.activeElement == maininput) { maininput.focus(); } // If we're in the input box, do nothing | ||
else if (document.activeElement == first) { maininput.focus(); } // If we're at the first item, go to input box | ||
else { document.activeElement.parentElement.previousSibling.firstElementChild.focus(); } // Otherwise, select the search result above the current active one | ||
} | ||
} | ||
}) | ||
|
||
|
||
// ========================================== | ||
// execute search as each character is typed | ||
// | ||
document.querySelector('.search-ui input').onkeyup = function (e) { | ||
executeSearch(this.value); | ||
} | ||
|
||
|
||
// ========================================== | ||
// fetch some json without jquery | ||
// | ||
function fetchJSONFile(path, callback) { | ||
var httpRequest = new XMLHttpRequest(); | ||
httpRequest.onreadystatechange = function () { | ||
if (httpRequest.readyState === 4) { | ||
if (httpRequest.status === 200) { | ||
var data = JSON.parse(httpRequest.responseText); | ||
if (callback) callback(data); | ||
} | ||
} | ||
}; | ||
httpRequest.open('GET', path); | ||
httpRequest.send(); | ||
} | ||
|
||
|
||
// ========================================== | ||
// load our search index, only executed once | ||
// on first call of search box (CMD-/) | ||
// | ||
function loadSearch() { | ||
fetchJSONFile('/index.json', function (data) { | ||
|
||
var options = { // fuse.js options; check fuse.js website for details | ||
shouldSort: true, | ||
location: 0, | ||
distance: 100, | ||
threshold: 0.4, | ||
minMatchCharLength: 2, | ||
keys: [ | ||
'title', | ||
'permalink', | ||
'contents' | ||
] | ||
}; | ||
fuse = new Fuse(data, options); // build the index from the json file | ||
}); | ||
} | ||
|
||
|
||
// ========================================== | ||
// using the index we loaded on CMD-/, run | ||
// a search query (for "term") every time a letter is typed | ||
// in the search box | ||
// | ||
function executeSearch(term) { | ||
let results = fuse.search(term); // the actual query being run using fuse.js | ||
let searchitems = ''; // our results bucket | ||
|
||
if (results.length === 0) { // no results based on what was typed into the input box | ||
resultsAvailable = false; | ||
searchitems = ''; | ||
if (term !== "") { | ||
noResults.classList.remove('hidden') | ||
} else { | ||
noResults.classList.add('hidden') | ||
} | ||
} else { // build our html | ||
noResults.classList.add('hidden') | ||
if (term !== "") { | ||
searchResultsHeading.classList.remove('hidden'); | ||
} | ||
|
||
for (let item in results.slice(0, 5)) { // only show first 5 results | ||
const title = '<div class="text-2xl mb-2 font-bold">' + results[item].item.title + '</div>'; | ||
const date = results[item].item.date ? '<div><em class="">' + new Date(results[item].item.date).toDateString() + '</em></div>' : ''; | ||
const contents = '<div>' + results[item].item.contents + '</div>'; | ||
|
||
searchitems = searchitems + '<li><a class="block mb-2 px-4 py-2 rounded pb-2 border-b border-gray-200 dark:border-gray-600 focus:bg-gray-100 dark:focus:bg-gray-700 focus:outline-none" href="' + results[item].item.permalink + '" tabindex="0">' + title + date + contents + '</a></li>'; | ||
} | ||
resultsAvailable = true; | ||
} | ||
|
||
list.innerHTML = searchitems; | ||
if (results.length > 0) { | ||
first = list.firstChild.firstElementChild; // first result container — used for checking against keyboard up/down location | ||
last = list.lastChild.firstElementChild; // last result container — used for checking against keyboard up/down location | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
{{- $.Scratch.Add "index" slice -}} | ||
{{- range .Site.RegularPages -}} | ||
{{- $.Scratch.Add "index" (dict "title" .Title "tags" .Params.tags "date" .Params.Lastmod "categories" .Params.categories "contents" .Summary "permalink" .Permalink) -}} | ||
{{- end -}} | ||
{{- $.Scratch.Get "index" | jsonify -}} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.