Last active
August 7, 2025 09:16
-
Star
(177)
You must be signed in to star a gist -
Fork
(18)
You must be signed in to fork a gist
-
-
Save eddiewebb/735feb48f50f0ddd65ae5606a1cb41ae to your computer and use it in GitHub Desktop.
Revisions
-
eddiewebb revised this gist
Feb 7, 2022 . 1 changed file with 17 additions and 1 deletion.There are no files selected for viewing
This file contains hidden or 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 charactersOriginal file line number Diff line number Diff line change @@ -267,4 +267,20 @@ outputs: - json ``` See https://gohugo.io/templates/output-formats#output-formats-for-pages ## MIT License Copyright 2022 Edward A. Webbinaro Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -
eddiewebb revised this gist
Mar 8, 2018 . 1 changed file with 12 additions and 1 deletion.There are no files selected for viewing
This file contains hidden or 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 charactersOriginal file line number Diff line number Diff line change @@ -256,4 +256,15 @@ Add this snippet to your config file to instruct Hugo to create the index file i ... [outputs] home = ["HTML", "RSS", "JSON"] ``` Alternately if using a custom _index.md for home page, you can just add the output formats to front matter. ``` outputs: - html - rss - json ``` See https://gohugo.io/templates/output-formats#output-formats-for-pages -
eddiewebb revised this gist
Mar 8, 2018 . 1 changed file with 2 additions and 2 deletions.There are no files selected for viewing
This file contains hidden or 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 charactersOriginal file line number Diff line number Diff line change @@ -251,9 +251,9 @@ The result is a newly created JSON index at `/index.json` ``` ## Config.toml Add this snippet to your config file to instruct Hugo to create the index file in JSON format. (RSS and HTML are default outputs, what's important is to add JSON. ``` ... [outputs] home = ["HTML", "RSS", "JSON"] ``` -
eddiewebb revised this gist
Mar 8, 2018 . 1 changed file with 17 additions and 2 deletions.There are no files selected for viewing
This file contains hidden or 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 charactersOriginal file line number Diff line number Diff line change @@ -113,8 +113,8 @@ This is the page rendered when viewing `/search` in your browser. THis example <div id="summary-${key}"> <h4><a href="${link}">${title}</a></h4> <p>${snippet}</p> ${ isset tags }<p>Tags: ${tags}</p>${ end } ${ isset categories }<p>Categories: ${categories}</p>${ end } </div> </script> {{ end }} @@ -210,6 +210,21 @@ function param(name) { } function render(templateString, data) { var conditionalMatches,conditionalPattern,copy; conditionalPattern = /\$\{\s*isset ([a-zA-Z]*) \s*\}(.*)\$\{\s*end\s*}/g; //since loop below depends on re.lastInxdex, we use a copy to capture any manipulations whilst inside the loop copy = templateString; while ((conditionalMatches = conditionalPattern.exec(templateString)) !== null) { if(data[conditionalMatches[1]]){ //valid key, remove conditionals, leave contents. copy = copy.replace(conditionalMatches[0],conditionalMatches[2]); }else{ //not valid, remove entire section copy = copy.replace(conditionalMatches[0],''); } } templateString = copy; //now any conditionals removed we can do simple substitution var key, find, re; for (key in data) { find = '\\$\\{\\s*' + key + '\\s*\\}'; -
eddiewebb revised this gist
Mar 8, 2018 . 1 changed file with 1 addition and 0 deletions.There are no files selected for viewing
This file contains hidden or 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 charactersOriginal file line number Diff line number Diff line change @@ -92,6 +92,7 @@ keys: [ This is the page rendered when viewing `/search` in your browser. THis example uses the template functionality of "base" and "blocks", to add my required JS files right above `</body>` but only on this page. You can use any template, as long as you include the 3rd part libs (jquery, fuse, mark.js) before search.js, it will work. ``` {{ define "footerfiles" }} <script src="https://code.jquery.com/jquery-3.3.1.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/fuse.js/3.2.0/fuse.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/mark.js/8.11.1/jquery.mark.min.js"></script> <script src="{{ "js/search.js" | absURL }}"></script> -
eddiewebb revised this gist
Mar 8, 2018 . 1 changed file with 2 additions and 1 deletion.There are no files selected for viewing
This file contains hidden or 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 charactersOriginal file line number Diff line number Diff line change @@ -113,6 +113,7 @@ This is the page rendered when viewing `/search` in your browser. THis example <h4><a href="${link}">${title}</a></h4> <p>${snippet}</p> <p>Tags: ${tags}</p> <p>Tags: ${categories}</p> </div> </script> {{ end }} @@ -176,7 +177,7 @@ function populateResults(result){ snippetHighlights.push(searchQuery); }else{ $.each(value.matches,function(matchKey,mvalue){ if(mvalue.key == "tags" || mvalue.key == "categories" ){ snippetHighlights.push(mvalue.value); }else if(mvalue.key == "contents"){ start = mvalue.indices[0][0]-summaryInclude>0?mvalue.indices[0][0]-summaryInclude:0; -
eddiewebb revised this gist
Mar 8, 2018 . 1 changed file with 8 additions and 15 deletions.There are no files selected for viewing
This file contains hidden or 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 charactersOriginal file line number Diff line number Diff line change @@ -136,7 +136,8 @@ var fuseOptions = { keys: [ {name:"title",weight:0.8}, {name:"contents",weight:0.5}, {name:"tags",weight:0.3}, {name:"categories",weight:0.3} ] }; @@ -192,7 +193,7 @@ function populateResults(result){ //pull template from hugo templarte definition var templateDefinition = $('#search-result-template').html(); //replace values var output = render(templateDefinition,{key:key,title:value.item.title,link:value.item.permalink,tags:value.item.tags,categories:value.item.categories,snippet:snippet}); $('#search-results').append(output); $.each(snippetHighlights,function(snipkey,snipvalue){ @@ -224,19 +225,11 @@ function render(templateString, data) { Hugo already builds indexes of all pages, we can cherry-pick which aspects should be searchable. The result is a newly created JSON index at `/index.json` ``` {{- $.Scratch.Add "index" slice -}} {{- range .Site.RegularPages -}} {{- $.Scratch.Add "index" (dict "title" .Title "tags" .Params.tags "categories" .Params.categories "contents" .Plain "permalink" .Permalink) -}} {{- end -}} {{- $.Scratch.Get "index" | jsonify -}} ``` -
eddiewebb revised this gist
Mar 8, 2018 . 1 changed file with 17 additions and 0 deletions.There are no files selected for viewing
This file contains hidden or 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 charactersOriginal file line number Diff line number Diff line change @@ -1,10 +1,27 @@ # Client side searching for Hugo.io with Fuse.js - [WHY](#why) - [Sample](#sample) - [Setup](#setup) - [Files](#files) * [content/search.md](#content-searchmd) * [layouts/\_default/search.html](#layouts---default-searchhtml) * [static/js/search.js](#static-js-searchjs) * [layouts/\_default/index.json](#layouts---default-indexjson) * [Config.toml](#configtoml) # WHY This gist shows how to implement client side searching with nothing but Hugo and a few common JS tools. - No NPM, grunt, etc - No additional build time steps, just `hugo` as you would normally. - Easy to swap out choice of client side search tools, anything that can use a json index - Highlights matching keywords in results # Sample You can visit the [Hugo Resume Theme](https://github.com/eddiewebb/hugo-resume) with example site to quickly explore this feature, or visit [live site](https://www.edwardawebb.com/search/) (try "devops", "atlassian developer", or "rest api" as good sample searches). # Setup 1. Add the file shown here in root directory or under `themes/<themeName>` 1. Add JSON as additional output format in `config.toml` -
eddiewebb revised this gist
Mar 8, 2018 . 1 changed file with 21 additions and 14 deletions.There are no files selected for viewing
This file contains hidden or 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 charactersOriginal file line number Diff line number Diff line change @@ -110,15 +110,16 @@ summaryInclude=60; var fuseOptions = { shouldSort: true, includeMatches: true, threshold: 0.0, tokenize:true, location: 0, distance: 100, maxPatternLength: 32, minMatchCharLength: 1, keys: [ {name:"title",weight:0.8}, {name:"contents",weight:0.5}, {name:"tags",weight:0.3} ] }; @@ -153,16 +154,21 @@ function populateResults(result){ var snippet = ""; var snippetHighlights=[]; var tags =[]; if( fuseOptions.tokenize ){ snippetHighlights.push(searchQuery); }else{ $.each(value.matches,function(matchKey,mvalue){ if(mvalue.key == "tags"){ snippetHighlights.push(mvalue.value); }else if(mvalue.key == "contents"){ start = mvalue.indices[0][0]-summaryInclude>0?mvalue.indices[0][0]-summaryInclude:0; end = mvalue.indices[0][1]+summaryInclude<contents.length?mvalue.indices[0][1]+summaryInclude:contents.length; snippet += contents.substring(start,end); snippetHighlights.push(mvalue.value.substring(mvalue.indices[0][0],mvalue.indices[0][1]-mvalue.indices[0][0]+1)); } }); } if(snippet.length<1){ snippet += contents.substring(0,summaryInclude*2); } @@ -194,6 +200,7 @@ function render(templateString, data) { } ``` ## layouts/_default/index.json -
eddiewebb revised this gist
Mar 8, 2018 . 1 changed file with 2 additions and 2 deletions.There are no files selected for viewing
This file contains hidden or 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 charactersOriginal file line number Diff line number Diff line change @@ -48,14 +48,14 @@ To search additional fields defined in front matter, you must add it in 2 places ### Edit layouts/_default/index.JSON This exposes the values in /index.json i.e. add `category` \``` ... "contents":{{ .Content | plainify | jsonify }} {{ if .Params.tags }}, "tags":{{ .Params.tags | jsonify }}{{end}}, "categories" : {{ .Params.categories | jsonify }}, ... \``` ### Edit fuse.js options to Search `static/js/search.js` -
eddiewebb revised this gist
Mar 8, 2018 . 1 changed file with 2 additions and 2 deletions.There are no files selected for viewing
This file contains hidden or 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 charactersOriginal file line number Diff line number Diff line change @@ -36,10 +36,10 @@ This implementation uses Fusejs, jquery and mark.js ## Initial setup Search depends on additional output content type of JSON in config.toml \``` [outputs] home = ["HTML", "JSON"] \``` ## Searching additional fileds -
eddiewebb revised this gist
Mar 8, 2018 . 1 changed file with 48 additions and 6 deletions.There are no files selected for viewing
This file contains hidden or 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 charactersOriginal file line number Diff line number Diff line change @@ -18,9 +18,8 @@ This gist shows how to implement client side searching with nothing but Hugo and ``` --- title: "Search Results" sitemap: priority : 0.1 layout: "search" --- @@ -29,10 +28,50 @@ This file exists solely to respond to /search URL with the related `search` layo No content shown here is rendered, all content is based in the template layouts/page/search.html Setting a very low sitemap priority will tell search engines this is not important content. This implementation uses Fusejs, jquery and mark.js ## Initial setup Search depends on additional output content type of JSON in config.toml ``` [outputs] home = ["HTML", "JSON"] ``` ## Searching additional fileds To search additional fields defined in front matter, you must add it in 2 places. ### Edit layouts/_default/index.JSON This exposes the values in /index.json i.e. add `category` ``` ... "contents":{{ .Content | plainify | jsonify }} {{ if .Params.tags }}, "tags":{{ .Params.tags | jsonify }}{{end}}, "categories" : {{ .Params.categories | jsonify }}, ... ``` ### Edit fuse.js options to Search `static/js/search.js` \``` keys: [ "title", "contents", "tags", "categories" ] \``` ``` ## layouts/_default/search.html This is the page rendered when viewing `/search` in your browser. THis example uses the template functionality of "base" and "blocks", to add my required JS files right above `</body>` but only on this page. You can use any template, as long as you include the 3rd part libs (jquery, fuse, mark.js) before search.js, it will work. ``` {{ define "footerfiles" }} @@ -66,9 +105,8 @@ This is the page rendered when viewing `/search` in your browser. THis example ## static/js/search.js This file uses jquery, fuse.js, mark.js to search the hugo created index, and return matching content, with highlighting. ``` summaryInclude=60; var fuseOptions = { shouldSort: true, includeMatches: true, @@ -84,6 +122,7 @@ var fuseOptions = { ] }; var searchQuery = param("s"); if(searchQuery){ $("#search-query").val(searchQuery); @@ -92,6 +131,8 @@ if(searchQuery){ $('#search-results').append("<p>Please enter a word or phrase above</p>"); } function executeSearch(searchQuery){ $.getJSON( "/index.json", function( data ) { var pages = data; @@ -139,7 +180,7 @@ function populateResults(result){ } function param(name) { return decodeURIComponent((location.search.split(name + '=')[1] || '').split('&')[0]).replace(/\+/g, ' '); } function render(templateString, data) { @@ -152,6 +193,7 @@ function render(templateString, data) { return templateString; } ``` ## layouts/_default/index.json -
eddiewebb revised this gist
Mar 5, 2018 . 1 changed file with 9 additions and 0 deletions.There are no files selected for viewing
This file contains hidden or 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 charactersOriginal file line number Diff line number Diff line change @@ -7,6 +7,7 @@ This gist shows how to implement client side searching with nothing but Hugo and # Setup 1. Add the file shown here in root directory or under `themes/<themeName>` 1. Add JSON as additional output format in `config.toml` 1. `hugo` 1. Visit `localhost:1313/search` @@ -171,4 +172,12 @@ The result is a newly created JSON index at `/index.json` {{ end }} ] ``` ## Config.toml Add this snippet to your config file to instruct Hugo to create the index file in JSON format. ``` ... [outputs] home = ["HTML", "JSON"] ``` -
eddiewebb revised this gist
Mar 5, 2018 . 1 changed file with 22 additions and 0 deletions.There are no files selected for viewing
This file contains hidden or 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 charactersOriginal file line number Diff line number Diff line change @@ -3,6 +3,7 @@ This gist shows how to implement client side searching with nothing but Hugo and - No NPM, grunt, etc - No additional build time steps, just `hugo` as you would normally. - Easy to swap out choice of client side search tools, anything that can use a json index - Highlights matching keywords in results # Setup 1. Add the file shown here in root directory or under `themes/<themeName>` @@ -62,6 +63,7 @@ This is the page rendered when viewing `/search` in your browser. THis example ``` ## static/js/search.js This file uses jquery, fuse.js, mark.js to search the hugo created index, and return matching content, with highlighting. ``` // how many characters to include on either side of match keyword summaryInclude=60; @@ -149,4 +151,24 @@ function render(templateString, data) { return templateString; } ``` ## layouts/_default/index.json Hugo already builds indexes of all pages, we can cherry-pick which aspects should be searchable. The result is a newly created JSON index at `/index.json` ``` [ {{ $pages := .Pages }} {{ $len := (len $pages) }} {{ range $index, $element := $pages }} { "title":{{ .Title | jsonify }}, "contents":{{ .Content | plainify | jsonify }} {{ if .Params.tags }}, "tags":{{ .Params.tags | jsonify }}{{end}}, "permalink": {{ .Permalink | jsonify }} }{{ if lt (add $index 1) $len }},{{ end }} {{ end }} ] ``` -
eddiewebb revised this gist
Mar 5, 2018 . 2 changed files with 122 additions and 15 deletions.There are no files selected for viewing
This file contains hidden or 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 charactersOriginal file line number Diff line number Diff line change @@ -1,14 +0,0 @@ This file contains hidden or 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 charactersOriginal file line number Diff line number Diff line change @@ -5,13 +5,13 @@ This gist shows how to implement client side searching with nothing but Hugo and - Easy to swap out choice of client side search tools, anything that can use a json index # Setup 1. Add the file shown here in root directory or under `themes/<themeName>` 1. `hugo` 1. Visit `localhost:1313/search` # Files ## content/search.md ``` --- @@ -28,4 +28,125 @@ This file exists solely to respond to /search URL with the related `search` layo No content shown here is rendered, all content is based in the template layouts/page/search.html This implementation uses Fusejs, jquery and mark.js ``` ## layouts/page/search.html This is the page rendered when viewing `/search` in your browser. THis example uses the template functionality of "base" and "blocks", to add my required JS files right above `</body>` but only on this page. You can use any template, as long as you include the 3rd part libs (jquery, fuse, mark.js) before search.js, it will work. ``` {{ define "footerfiles" }} <script src="https://cdnjs.cloudflare.com/ajax/libs/fuse.js/3.2.0/fuse.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/mark.js/8.11.1/jquery.mark.min.js"></script> <script src="{{ "js/search.js" | absURL }}"></script> {{ end }} {{ define "main" }} <section class="resume-section p-3 p-lg-5 d-flex flex-column"> <div class="my-auto" > <form action="{{ "search" | absURL }}"> <input id="search-query" name="s"/> </form> <div id="search-results"> <h3>Matching pages</h3> </div> </div> </section> <!-- this template is sucked in by search.js and appended to the search-results div above. So editing here will adjust style --> <script id="search-result-template" type="text/x-js-template"> <div id="summary-${key}"> <h4><a href="${link}">${title}</a></h4> <p>${snippet}</p> <p>Tags: ${tags}</p> </div> </script> {{ end }} ``` ## static/js/search.js ``` // how many characters to include on either side of match keyword summaryInclude=60; //options for fuse.js var fuseOptions = { shouldSort: true, includeMatches: true, threshold: 0.1, location: 0, distance: 100, maxPatternLength: 32, minMatchCharLength: 1, keys: [ "title", "contents", "tags" ] }; var searchQuery = param("s"); if(searchQuery){ $("#search-query").val(searchQuery); executeSearch(searchQuery); }else { $('#search-results').append("<p>Please enter a word or phrase above</p>"); } function executeSearch(searchQuery){ $.getJSON( "/index.json", function( data ) { var pages = data; var fuse = new Fuse(pages, fuseOptions); var result = fuse.search(searchQuery); console.log({"matches":result}); if(result.length > 0){ populateResults(result); }else{ $('#search-results').append("<p>No matches found</p>"); } }); } function populateResults(result){ $.each(result,function(key,value){ var contents= value.item.contents; var snippet = ""; var snippetHighlights=[]; var tags =[]; $.each(value.matches,function(matchKey,mvalue){ if(mvalue.key == "tags"){ snippetHighlights.push(mvalue.value); }else if(mvalue.key == "contents"){ start = mvalue.indices[0][0]-summaryInclude>0?mvalue.indices[0][0]-summaryInclude:0; end = mvalue.indices[0][1]+summaryInclude<contents.length?mvalue.indices[0][1]+summaryInclude:contents.length; snippet += contents.substring(start,end); snippetHighlights.push(mvalue.value.substring(mvalue.indices[0][0],mvalue.indices[0][1]-mvalue.indices[0][0]+1)); } }); if(snippet.length<1){ snippet += contents.substring(0,summaryInclude*2); } //pull template from hugo templarte definition var templateDefinition = $('#search-result-template').html(); //replace values var output = render(templateDefinition,{key:key,title:value.item.title,link:value.item.permalink,tags:value.item.tags,snippet:snippet}); $('#search-results').append(output); $.each(snippetHighlights,function(snipkey,snipvalue){ $("#summary-"+key).mark(snipvalue); }); }); } function param(name) { return (location.search.split(name + '=')[1] || '').split('&')[0]; } function render(templateString, data) { var key, find, re; for (key in data) { find = '\\$\\{\\s*' + key + '\\s*\\}'; re = new RegExp(find, 'g'); templateString = templateString.replace(re, data[key]); } return templateString; } ``` -
eddiewebb created this gist
Mar 5, 2018 .There are no files selected for viewing
This file contains hidden or 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 charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,14 @@ --- title: "Search Results" date: 2018-02-10T18:56:13-05:00 sitemap: priority : 1.0 layout: "search" --- This file exists solely to respond to /search URL with the related `search` layout template. No content shown here is rendered, all content is based in the template layouts/page/search.html This implementation uses Fusejs, jquery and mark.js This file contains hidden or 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 charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,31 @@ # WHY This gist shows how to implement client side searching with nothing but Hugo and a few common JS tools. - No NPM, grunt, etc - No additional build time steps, just `hugo` as you would normally. - Easy to swap out choice of client side search tools, anything that can use a json index # Setup 1. Add JSON output for index on `config.toml` 1. Add the file shown here in root directory or under `themes/<themeName>` 1. `hugo` 1. Visit `localhost:1313/search` # Files ## content/search.md ``` --- title: "Search Results" date: 2018-02-10T18:56:13-05:00 sitemap: priority : 1.0 layout: "search" --- This file exists solely to respond to /search URL with the related `search` layout template. No content shown here is rendered, all content is based in the template layouts/page/search.html This implementation uses Fusejs, jquery and mark.js ```