1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
|
<section class="search-modal mb-10 hidden">
<input class="bg-gray-100 w-full px-3 py-2 rounded outline-none" type="search" placeholder="Search here...">
<section class="results bg-white border border-gray-200 shadow-md p-2 flex flex-col gap-2 rounded mt-4 hidden"></section>
</section>
<script src="https://unpkg.com/lunr/lunr.js"></script>
<script>
(async function() {
const debounceDelay = 700;
// Fetch search index generated by Hugo.
const req = await fetch('/index.json');
window.searchDocuments = await req.json();
window.searchIndex = lunr(function() {
this.ref('permalink');
this.field('title', { boost: 20 });
this.field('tags', { boost: 10 });
this.field('summary', { boost: 1 });
window.searchDocuments.forEach(function(doc) {
this.add(doc);
}, this);
console.log('Search index processed...');
})
// Connect DOM and search the index.
let cachedSearchTerm = null;
const searchModal = document.querySelector('.search-modal');
const searchInput = document.querySelector('.search-modal input');
const searchResults = document.querySelector('.search-modal .results');
// Display search modal.
window.showSearchModal = function() {
searchModal.classList.remove('hidden');
searchInput.focus();
}
// Detect OS and sets proper search button text.
const searchButtonElement = document.querySelector('.search-button');
const searchButtonTextElement = document.querySelector('.search-button-text');
if (searchButtonElement) {
let searchButtonText = 'ctrl+k';
if (navigator.platform.toUpperCase().indexOf('MAC') >= 0) {
searchButtonText = 'cmd+k';
}
searchButtonTextElement.innerText = searchButtonText;
searchButtonElement.classList.remove('hidden');
}
// On keyboard shortcut shows search modal.
document.addEventListener('keydown', function(event) {
// Handles macOS CMD+k.
if ((event.ctrlKey || event.metaKey) && event.key === 'k') {
event.preventDefault();
showSearchModal();
}
// Handles Windows/Linux Ctrl+k.
if (event.ctrlKey && event.key === 'k') {
event.preventDefault();
showSearchModal();
}
});
// Debounce magic.
function debounce(func, delay) {
let timerId;
return function (...args) {
clearTimeout(timerId);
timerId = setTimeout(() => {
func.apply(this, args);
}, delay);
};
}
// Do the actual search.
searchInput.addEventListener('keyup', debounce((evt)=> {
const query = evt.target.value.trim().toLowerCase();
if (query.length && query != cachedSearchTerm) {
const results = searchIndex.search(query);
if (results.length == 0) {
searchResults.classList.add('hidden');
} else {
searchResults.innerText = '';
searchResults.classList.remove('hidden');
cachedSearchTerm = query;
results.forEach(resultItem => {
const item = window.searchDocuments.find(doc => doc.permalink === resultItem.ref);
const link = document.createElement('a');
link.href = item.permalink;
link.classList.add('hover:bg-gray-100', 'cursor-pointer', 'py-2', 'px-3', 'rounded');
const title = document.createElement('div');
title.classList.add('text-gray-800', 'font-medium');
title.innerHTML = item.title;
link.appendChild(title);
const meta = document.createElement('div');
meta.classList.add('text-gray-500', 'flex', 'items-center', 'gap-2');
const section = document.createElement('span');
section.classList.add('uppercase', 'text-xs', 'font-medium', 'bg-gray-200', 'px-1', 'rounded')
section.innerText = item.type;
meta.appendChild(section);
const summary = document.createElement('span');
const summaryText = item.summary.length > 80 ? `${item.summary.substring(0, 80)}...` : item.summary;
summary.innerHTML = summaryText;
meta.appendChild(summary);
link.appendChild(meta);
searchResults.appendChild(link);
});
}
}
}, debounceDelay));
})();
</script>
|