7 changed files with 259 additions and 7 deletions
@ -0,0 +1,198 @@ |
|||||
|
{{ define "main" }} |
||||
|
<!-- The "search/index.html" layout renders the search engine --> |
||||
|
<article class="search article-list"> |
||||
|
<header> |
||||
|
<h1>{{ .Title }}</h1> |
||||
|
{{- with .Description }} |
||||
|
<h4>{{ . }}</h4> |
||||
|
{{- end }} |
||||
|
</header> |
||||
|
{{ .Content }} |
||||
|
<input id="searchInput" tabindex="0" placeholder="{{ i18n "search_here" }}" autofocus> |
||||
|
<div id="searchResults"> |
||||
|
</div> |
||||
|
<script type="text/javascript"> |
||||
|
var searchResults = document.getElementById('searchResults'); // targets the <div> above |
||||
|
var searchInput = document.getElementById('searchInput'); // input box for search |
||||
|
var lastSearch = ""; |
||||
|
|
||||
|
// Helper function to create an element with attributes |
||||
|
function tag(name, attrs) { |
||||
|
var el = document.createElement(name.toString()); |
||||
|
|
||||
|
!!attrs && Object.keys(attrs).forEach(function(key) { |
||||
|
el.setAttribute(key, attrs[key]); |
||||
|
}); |
||||
|
|
||||
|
return el; |
||||
|
} |
||||
|
|
||||
|
function printSearchResult(result) { |
||||
|
var section = tag("section"); |
||||
|
|
||||
|
// |
||||
|
// Article headline |
||||
|
// |
||||
|
var a = tag("a", { href: result.item.permalink }); |
||||
|
a.textContent = result.item.title; |
||||
|
if (result.item.hasEnFlag) { |
||||
|
var img = tag("img", { src: "/icons/en.svg", 'class': "tiny-flag", alt: "en flag" }); |
||||
|
a.appendChild(img); |
||||
|
} |
||||
|
var h4 = tag("h4"); |
||||
|
h4.textContent = result.item.type_label + " >> "; |
||||
|
h4.appendChild(a); |
||||
|
section.appendChild(h4); |
||||
|
|
||||
|
// |
||||
|
// Metadata |
||||
|
// |
||||
|
if (result.item.type != "page") { |
||||
|
var div = tag("div", { 'class': 'post-metadata'}); |
||||
|
var span_date = tag("span", { 'class': 'publication-date' }); |
||||
|
span_date.textContent = {{ i18n "published_on" }} + " " + result.item.date; |
||||
|
div.appendChild(span_date); |
||||
|
if (result.item.topics != null) { |
||||
|
result.item.topics.forEach(function (v) { |
||||
|
var topic_detail = taxonomies.topics[v]; |
||||
|
if (topic_detail == null) { |
||||
|
return; |
||||
|
} |
||||
|
var span = tag("span", { 'class': 'topic' }); |
||||
|
var i = tag("i", { 'class': 'material-icons', 'aria-hidden': 'true'}); |
||||
|
i.textContent = "link"; |
||||
|
span.appendChild(i); |
||||
|
var a = tag("a", { href: topic_detail.href }); |
||||
|
a.textContent = topic_detail.title; |
||||
|
span.appendChild(a); |
||||
|
div.appendChild(span); |
||||
|
}); |
||||
|
} |
||||
|
if (result.item.opensource != null) { |
||||
|
result.item.opensource.forEach(function (v) { |
||||
|
var opensource_detail = taxonomies.opensource[v]; |
||||
|
if (opensource_detail == null) { |
||||
|
return; |
||||
|
} |
||||
|
var span = tag("span", { 'class': 'opensource' }); |
||||
|
var i = tag("i", { 'class': 'material-icons', 'aria-hidden': 'true'}); |
||||
|
i.textContent = "label"; |
||||
|
span.appendChild(i); |
||||
|
var a = tag("a", { href: opensource_detail.href }); |
||||
|
a.textContent = opensource_detail.title; |
||||
|
span.appendChild(a); |
||||
|
div.appendChild(span); |
||||
|
}); |
||||
|
} |
||||
|
if (result.item.reading_time != null) { |
||||
|
var span = tag("span", { 'class': 'reading-time' }); |
||||
|
var i = tag("i", { 'class': "material-icons", 'aria-hidden': "true" }); |
||||
|
i.textContent = "schedule"; |
||||
|
span.appendChild(i); |
||||
|
var readingTime = document.createTextNode(result.item.reading_time); |
||||
|
span.appendChild(readingTime); |
||||
|
div.appendChild(span); |
||||
|
} |
||||
|
section.appendChild(div); |
||||
|
} |
||||
|
|
||||
|
var p = tag("p", {}); |
||||
|
p.textContent = result.item.summary; |
||||
|
var a = tag("a", { href: result.item.permalink, 'class': 'continue-reading' }); |
||||
|
a.textContent = {{ i18n "continue_reading" }}; |
||||
|
p.appendChild(a); |
||||
|
section.appendChild(p); |
||||
|
|
||||
|
searchResults.appendChild(section); |
||||
|
} |
||||
|
|
||||
|
function clearSearchResults() { |
||||
|
var child = searchResults.lastElementChild; |
||||
|
while (child) { |
||||
|
searchResults.removeChild(child); |
||||
|
child = searchResults.lastElementChild; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// |
||||
|
// load the search index |
||||
|
// |
||||
|
function fuseInit(searchDb) { |
||||
|
var options = { // fuse.js options; check fuse.js website for details |
||||
|
shouldSort: true, |
||||
|
ignoreLocation: true, |
||||
|
threshold: 0.4, |
||||
|
minMatchCharLength: 3, |
||||
|
keys: [ |
||||
|
'title', |
||||
|
'permalink', |
||||
|
'summary', |
||||
|
'topics', |
||||
|
'opensource' |
||||
|
] |
||||
|
}; |
||||
|
fuse = new Fuse(searchDb, options); // build the index from the json file |
||||
|
} |
||||
|
|
||||
|
// |
||||
|
// using the index loaded previously, run a search query (for "term") |
||||
|
// every time a letter is typed in the search box |
||||
|
// |
||||
|
function executeSearch(term) { |
||||
|
if (lastSearch == term) { |
||||
|
// Don't query Fuse if the search terms have not changed |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
clearSearchResults(); |
||||
|
let results = fuse.search(term); |
||||
|
results.slice(0, 20).forEach(printSearchResult); |
||||
|
lastSearch = term; |
||||
|
} |
||||
|
|
||||
|
// Fill-in details about taxonomies |
||||
|
{{- $.Scratch.Set "taxonomies" dict -}} |
||||
|
{{- range $name, $taxonomy := .Site.Taxonomies -}} |
||||
|
{{- $.Scratch.Set "taxonomy" dict -}} |
||||
|
{{- range (index $.Site.Taxonomies $name) -}} |
||||
|
{{- $.Scratch.SetInMap "taxonomy" .Page.Title (dict "href" .Page.RelPermalink "title" .Page.Title) -}} |
||||
|
{{- end -}} |
||||
|
{{- $.Scratch.SetInMap "taxonomies" $name ($.Scratch.Get "taxonomy") -}} |
||||
|
{{- end }} |
||||
|
var taxonomies = {{- $.Scratch.Get "taxonomies" | jsonify | safeJS -}}; |
||||
|
|
||||
|
// Fill-in the Search DB with site's content |
||||
|
{{- $.Scratch.Add "index" slice -}} |
||||
|
{{- range .Site.RegularPages -}} |
||||
|
{{- $.Scratch.Set "reading_time" nil -}} |
||||
|
{{- if eq .Type "blog" -}} |
||||
|
{{- $minutes := .ReadingTime -}} |
||||
|
{{- if gt $minutes 0 -}} |
||||
|
{{- $.Scratch.Set "reading_time" (i18n "minutes" $minutes) -}} |
||||
|
{{- end -}} |
||||
|
{{- end -}} |
||||
|
|
||||
|
{{- $.Scratch.Set "date" nil -}} |
||||
|
{{- if ne .Type "page" -}} |
||||
|
{{- $.Scratch.Set "date" (.Date.Format (i18n "date_format")) -}} |
||||
|
{{- end -}} |
||||
|
|
||||
|
{{ .Scratch.Set "en_article_in_fr_site" false }} |
||||
|
{{- partial "lang-detection.html" . -}} |
||||
|
{{- $.Scratch.Add "index" (dict "title" .Title "opensource" .Params.opensource "topics" .Params.topics "permalink" .Permalink "hasEnFlag" (.Scratch.Get "en_article_in_fr_site") "type" .Type "type_label" (i18n (print "type_" .Type)) "date" ($.Scratch.Get "date") "reading_time" ($.Scratch.Get "reading_time") "summary" (.Summary | plainify | htmlUnescape)) -}} |
||||
|
{{- end }} |
||||
|
var searchDb = {{- $.Scratch.Get "index" | jsonify | safeJS -}}; |
||||
|
|
||||
|
// Initialize the Fuse.io framework with the Search DB |
||||
|
fuseInit(searchDb); |
||||
|
|
||||
|
// |
||||
|
// execute search as each character is typed |
||||
|
// |
||||
|
searchInput.onkeyup = function(e) { |
||||
|
executeSearch(this.value); |
||||
|
} |
||||
|
|
||||
|
</script> |
||||
|
</article> |
||||
|
{{ end }} |
||||
File diff suppressed because one or more lines are too long
Loading…
Reference in new issue