diff options
Diffstat (limited to 'themes/simple/layouts/partials/search.html')
| -rw-r--r-- | themes/simple/layouts/partials/search.html | 191 |
1 files changed, 0 insertions, 191 deletions
diff --git a/themes/simple/layouts/partials/search.html b/themes/simple/layouts/partials/search.html deleted file mode 100644 index f157f03..0000000 --- a/themes/simple/layouts/partials/search.html +++ /dev/null | |||
| @@ -1,191 +0,0 @@ | |||
| 1 | {{ $cachebuster := delimit (shuffle (split (md5 "6fab11c6669976d759d2992eff1dd5be") "" )) "" }} | ||
| 2 | |||
| 3 | <section class="search-modal mb-10 hidden"> | ||
| 4 | <input class="bg-gray-100 w-full px-3 py-2 rounded outline-none" type="search" placeholder="Search here..."> | ||
| 5 | <section class="results bg-white border border-gray-200 shadow-md p-2 flex flex-col gap-2 rounded mt-4 hidden"></section> | ||
| 6 | </section> | ||
| 7 | |||
| 8 | <script src="https://unpkg.com/lunr/lunr.js"></script> | ||
| 9 | <script> | ||
| 10 | (async function() { | ||
| 11 | const debounceDelay = 700; | ||
| 12 | const maxSearchResults = 10; | ||
| 13 | |||
| 14 | // Fetch search index generated by Hugo. | ||
| 15 | const req = await fetch('/index.json?v={{ $cachebuster }}'); | ||
| 16 | window.searchDocuments = await req.json(); | ||
| 17 | |||
| 18 | window.searchIndex = lunr(function() { | ||
| 19 | this.ref('permalink'); | ||
| 20 | this.field('title', { boost: 20 }); | ||
| 21 | this.field('tags', { boost: 10 }); | ||
| 22 | this.field('summary', { boost: 1 }); | ||
| 23 | |||
| 24 | window.searchDocuments.forEach(function(doc) { | ||
| 25 | this.add(doc); | ||
| 26 | }, this); | ||
| 27 | |||
| 28 | console.log('Search index processed...'); | ||
| 29 | }) | ||
| 30 | |||
| 31 | // Connect DOM and search the index. | ||
| 32 | let cachedSearchTerm = null; | ||
| 33 | const searchModal = document.querySelector('.search-modal'); | ||
| 34 | const searchInput = document.querySelector('.search-modal input'); | ||
| 35 | const searchResults = document.querySelector('.search-modal .results'); | ||
| 36 | |||
| 37 | // Display search modal. | ||
| 38 | window.showSearchModal = function() { | ||
| 39 | searchModal.classList.remove('hidden'); | ||
| 40 | searchInput.focus(); | ||
| 41 | } | ||
| 42 | |||
| 43 | // Detect OS and sets proper search button text. | ||
| 44 | const searchButtonElement = document.querySelector('.search-button'); | ||
| 45 | const searchButtonTextElement = document.querySelector('.search-button-text'); | ||
| 46 | if (searchButtonElement) { | ||
| 47 | let searchButtonText = 'Ctrl+K'; | ||
| 48 | if (navigator.platform.toUpperCase().indexOf('MAC') >= 0) { | ||
| 49 | searchButtonText = '⌘+K'; | ||
| 50 | } | ||
| 51 | searchButtonTextElement.innerText = searchButtonText; | ||
| 52 | searchButtonElement.classList.remove('hidden'); | ||
| 53 | } | ||
| 54 | |||
| 55 | // On keyboard shortcut shows search modal. | ||
| 56 | let currentSearchResultsSectionIndex = -1; | ||
| 57 | const itemHoverClass = 'bg-gray-100'; | ||
| 58 | document.addEventListener('keydown', function(event) { | ||
| 59 | // Handles macOS CMD+k. | ||
| 60 | if ((event.ctrlKey || event.metaKey) && event.key === 'k') { | ||
| 61 | event.preventDefault(); | ||
| 62 | showSearchModal(); | ||
| 63 | } | ||
| 64 | |||
| 65 | // Handles Windows/Linux Ctrl+k. | ||
| 66 | if (event.ctrlKey && event.key === 'k') { | ||
| 67 | event.preventDefault(); | ||
| 68 | showSearchModal(); | ||
| 69 | } | ||
| 70 | |||
| 71 | |||
| 72 | // If ESC is pressed when the input is empty close the search modal. | ||
| 73 | if (event.key === 'Escape' || event.key === 'Esc') { | ||
| 74 | if (searchInput.value.length == 0) { | ||
| 75 | if (!searchModal.classList.contains('hidden')) { | ||
| 76 | cachedSearchTerm = null; | ||
| 77 | searchModal.classList.add('hidden'); | ||
| 78 | searchResults.innerText = ''; | ||
| 79 | if (!searchResults.classList.contains('hidden')) { | ||
| 80 | searchResults.classList.add('hidden'); | ||
| 81 | } | ||
| 82 | } | ||
| 83 | } else { | ||
| 84 | const listItems = searchResults.querySelectorAll('a'); | ||
| 85 | listItems.forEach(el => el.classList.remove(itemHoverClass)); | ||
| 86 | currentSearchResultsSectionIndex = -1; | ||
| 87 | searchInput.focus(); | ||
| 88 | } | ||
| 89 | } | ||
| 90 | |||
| 91 | |||
| 92 | // Arrow UP/DOWN movement through search results. | ||
| 93 | if (event.key === 'ArrowUp') { | ||
| 94 | if (!searchResults.classList.contains('hidden')) { | ||
| 95 | event.preventDefault(); | ||
| 96 | |||
| 97 | const listItems = searchResults.querySelectorAll('a'); | ||
| 98 | listItems.forEach(el => el.classList.remove(itemHoverClass)); | ||
| 99 | currentSearchResultsSectionIndex--; | ||
| 100 | |||
| 101 | if (!listItems[currentSearchResultsSectionIndex]) { | ||
| 102 | currentSearchResultsSectionIndex = -1; | ||
| 103 | searchInput.focus(); | ||
| 104 | } | ||
| 105 | |||
| 106 | if (currentSearchResultsSectionIndex != -1) { | ||
| 107 | listItems[currentSearchResultsSectionIndex].classList.add(itemHoverClass); | ||
| 108 | listItems[currentSearchResultsSectionIndex].focus(); | ||
| 109 | } | ||
| 110 | } | ||
| 111 | } | ||
| 112 | if (event.key === 'ArrowDown') { | ||
| 113 | if (!searchResults.classList.contains('hidden')) { | ||
| 114 | event.preventDefault(); | ||
| 115 | |||
| 116 | const listItems = searchResults.querySelectorAll('a'); | ||
| 117 | listItems.forEach(el => el.classList.remove(itemHoverClass)); | ||
| 118 | currentSearchResultsSectionIndex++; | ||
| 119 | |||
| 120 | if (!listItems[currentSearchResultsSectionIndex]) { | ||
| 121 | currentSearchResultsSectionIndex = 0; | ||
| 122 | } | ||
| 123 | |||
| 124 | if (currentSearchResultsSectionIndex != -1) { | ||
| 125 | listItems[currentSearchResultsSectionIndex].classList.add(itemHoverClass); | ||
| 126 | listItems[currentSearchResultsSectionIndex].focus(); | ||
| 127 | } | ||
| 128 | } | ||
| 129 | } | ||
| 130 | |||
| 131 | }); | ||
| 132 | |||
| 133 | // Debounce magic. | ||
| 134 | function debounce(func, delay) { | ||
| 135 | let timerId; | ||
| 136 | return function (...args) { | ||
| 137 | clearTimeout(timerId); | ||
| 138 | timerId = setTimeout(() => { | ||
| 139 | func.apply(this, args); | ||
| 140 | }, delay); | ||
| 141 | }; | ||
| 142 | } | ||
| 143 | |||
| 144 | // Do the actual search. | ||
| 145 | searchInput.addEventListener('keyup', debounce((evt)=> { | ||
| 146 | const query = evt.target.value.trim().toLowerCase(); | ||
| 147 | if (query.length && query != cachedSearchTerm) { | ||
| 148 | const results = searchIndex.search(`*${query}*`); | ||
| 149 | |||
| 150 | if (results.length == 0) { | ||
| 151 | if (!searchResults.classList.contains('hidden')) { | ||
| 152 | searchResults.classList.add('hidden'); | ||
| 153 | } | ||
| 154 | } else { | ||
| 155 | searchResults.innerText = ''; | ||
| 156 | searchResults.classList.remove('hidden'); | ||
| 157 | cachedSearchTerm = query; | ||
| 158 | |||
| 159 | results.slice(0, maxSearchResults).forEach(resultItem => { | ||
| 160 | const item = window.searchDocuments.find(doc => doc.permalink === resultItem.ref); | ||
| 161 | |||
| 162 | const link = document.createElement('a'); | ||
| 163 | link.href = item.permalink; | ||
| 164 | link.classList.add('hover:bg-gray-100', 'cursor-pointer', 'py-2', 'px-3', 'rounded'); | ||
| 165 | |||
| 166 | const title = document.createElement('div'); | ||
| 167 | title.classList.add('text-gray-800', 'font-medium'); | ||
| 168 | title.innerHTML = item.title; | ||
| 169 | link.appendChild(title); | ||
| 170 | |||
| 171 | const meta = document.createElement('div'); | ||
| 172 | meta.classList.add('text-gray-500', 'flex', 'items-center', 'gap-2'); | ||
| 173 | |||
| 174 | const section = document.createElement('span'); | ||
| 175 | section.classList.add('uppercase', 'text-xs', 'font-medium', 'bg-gray-200', 'px-1', 'rounded') | ||
| 176 | section.innerText = item.type; | ||
| 177 | meta.appendChild(section); | ||
| 178 | |||
| 179 | const summary = document.createElement('span'); | ||
| 180 | const summaryText = item.summary.length > 80 ? `${item.summary.substring(0, 80)}...` : item.summary; | ||
| 181 | summary.innerHTML = summaryText; | ||
| 182 | meta.appendChild(summary); | ||
| 183 | |||
| 184 | link.appendChild(meta); | ||
| 185 | searchResults.appendChild(link); | ||
| 186 | }); | ||
| 187 | } | ||
| 188 | } | ||
| 189 | }, debounceDelay)); | ||
| 190 | })(); | ||
| 191 | </script> | ||
