on master help sign in
Merge pull request #139 from francescanarea/search-bar-release

Search bar release

commitd943c204fff7feea9f08aab3d59c5546dd02a6d5 authorfrancescanarea <francesca@Narea.com> dateFri 19 Jul 2019, 15:10 (7 years ago) parentb345f06c49eed2
4 files changed+89−176
sass/_main.scss+35−107 static/scripts.js+43−62 templates/partials/navigation-docs.html+4−2 templates/partials/search-overlay.html+7−5
sass/_main.scss+35−107
@@ -91,6 +91,7 @@ iframe {
9191 .content-nav {
9292 &__search-bar {
9393 width: 100%;
94+ padding-left: 0rem;
9495 }
9596 &__index {
9697 height: calc(100% - 48px);
@@ -238,6 +239,9 @@ iframe {
238239 transform: translate(0, 7px);
239240 }
240241 }
242+ &__search-icon {
243+ -webkit-transform: rotate(-45deg);
244+ }
241245}
242246
243247.has-active-main-nav {
@@ -287,101 +291,42 @@ iframe {
287291 max-width: 320px;
288292}
289293
290−.search-overlay {
291− position: fixed;
292− height: 100%;
293− width: 100%;
294+.padding-none {
295+ padding: 0 !important;
296+}
297+
298+.border-none {
299+ border: none !important;
300+}
301+
302+.b-transparent {
294303 background: rgba(0,0,0,0.4);
304+}
305+
306+.top0 {
295307 top: 0;
296− left: 0;
297− z-index: 10;
298− display: none;
308+}
309+
310+.float-right {
311+ float: right;
312+}
313+
314+.search-overlay {
299315 .search-bar {
300− padding: 0;
301− border: none;
302316 &__input {
303317 padding-left: 40px;
304− border-left: none;
305− border-top: none;
306− border-right: none;
307− }
308− &:before {
309− z-index: 1;
310− }
311− &:hover, &:active, &:focus {
312− border: none;
313− }
314− input[type="search"] {
315− &:hover, &:active, &:focus {
316− border-left: none;
317− border-top: none;
318− border-right: none;
319− }
320− }
321− &__input {
322− line-height: (6rem / 4);
323318 }
324319 }
325320}
326321
327322.search-results {
328323 max-height: 400px;
329− //&__item, &__item a,
330− &__header {
331− color: #B1B2B3;
332− }
333− &__item {
334− a {
335− text-decoration: none;
336− display: block;
337− padding: (3rem /4) (4rem / 4);
338− &:hover {
339− background: #F9F9F9;
340− &:before, &:after {
341− content: '';
342− position: absolute;
343− right: 40px;
344− }
345− &:before {
346− content: '';
347− height: 10px;
348− width: 10px;
349− border-top: 2px solid #000;
350− border-right: 2px solid #000;
351− transform: rotate(45deg);
352− top: 17px;
353− }
354− &:after {
355− content: '';
356− width: 17px;
357− height: 2px;
358− background: #000;
359− top: 22px;
360− right: 39px;
361− }
362− }
363− }
364− position: relative;
365− transition: all 0.1s linear;
366− &:last-child {
367− margin-bottom: (2rem / 4);
368− }
369− b {
370− color: #000;
371− }
372− &__title {
373− font-size: (6rem / 4);
374− text-transform: capitalize;
375− &__slug-end {
376− color: #000;
377− font-weight: 700;
378− padding-right: (8rem / 4);
379− }
324+ &__item a:hover {
325+ background: #F9F9F9;
326+ span {
327+ display:inline-block;
380328 }
381329 }
382− &__header {
383− padding: 0 (7rem / 4);
384− }
385330}
386331
387332.has-active-search-window {
@@ -394,6 +339,14 @@ iframe {
394339 * styling
395340 */
396341
342+ // remove default x icon
343+ input[type="search"]::-webkit-search-decoration,
344+ input[type="search"]::-webkit-search-cancel-button,
345+ input[type="search"]::-webkit-search-results-button,
346+ input[type="search"]::-webkit-search-results-decoration {
347+ display: none;
348+ }
349+
397350textarea, input[type="text"], input[type="email"], input[type="number"], input[type="search"] {
398351 border: 1px solid #B1B2B3;
399352 font-size: (4rem / 4);
@@ -432,7 +385,6 @@ button, .btn {
432385 border: 1px solid #B1B2B3;
433386 background: #fff;
434387 font-size: (4rem / 4);
435− line-height: (6rem / 4);
436388 transition: all 0.1s linear;
437389 padding: 12px 12px 12px 40px;
438390 position: relative;
@@ -440,30 +392,6 @@ button, .btn {
440392 text-align: left;
441393 box-shadow: none !important;
442394 color: #B1B2B3;
443− &:after {
444− content: '';
445− position: absolute;
446− left: 10px;
447− top: 20px;
448− width: 10px;
449− height: 10px;
450− border-radius: 50%;
451− border: 2px solid #000;
452− margin-top: -4px;
453− }
454− &:before {
455− content: '';
456− position: absolute;
457− left: 23px;
458− top: 25px;
459− transform: rotate(-45deg);
460− background: #000;
461− width: 2px;
462− height: 9px;
463− }
464− &:hover {
465− border: 1px solid #000000;
466− }
467395}
468396
469397.has-valid-input {
static/scripts.js+43−62
@@ -1,39 +1,4 @@
1−//
2− // styling of input fields
3−//
4−
5−var inputElements = document.querySelectorAll('input.tlon-input');
6−for (var i = 0; i < inputElements.length; i++) {
7− //listen for changes in input
8− inputElements[i].addEventListener('input', function() {
9− // if input has a value do this
10− if (this.value) {
11− var inputContainer = this.parentNode;
12− var validInputs = inputContainer.querySelectorAll('input.tlon-input:valid');
13− var inputs = inputContainer.querySelectorAll('input.tlon-input');
14− if (validInputs.length !== 0) {
15− // has valid input
16− for (var i = 0; i < validInputs.length; i++) {
17− if (this.classList.contains('is-valid') == false ) {
18− validInputs[i].parentNode.classList.add('has-valid-input');
19− }
20− }
21− } else {
22− // doesn't have valid input
23− for (var i = 0; i < inputs.length; i++) {
24− inputs[i].parentNode.classList.remove('has-valid-input');
25− }
26− }
27− } else {
28− this.parentNode.classList.remove('has-valid-input');
29− }
30− });
31−}
32−
33−//
34− // toggling of navigation menus
35−//
36−
1+// toggling of navigation menus
372var toggleMainNav = document.getElementById('js-main-nav-toggle');
383if (toggleMainNav !== null) {
394 toggleMainNav.onclick = function() {
@@ -84,10 +49,8 @@ function initHotKeys() {
8449 });
8550};
8651
87−//
88− // search functionality
89−//
9052
53+// search functionality
9154function debounce(func, wait) {
9255 var timeout;
9356
@@ -122,6 +85,7 @@ function makeTeaser(body, terms) {
12285 var stemmedTerms = terms.map(function (w) {
12386 return elasticlunr.stemmer(w.toLowerCase());
12487 });
88+
12589 var termFound = false;
12690 var index = 0;
12791 var weighted = []; // contains elements of ["word", weight, index_in_document]
@@ -206,48 +170,49 @@ function makeTeaser(body, terms) {
206170 startIndex = word[2];
207171 }
208172
209− // add <em/> around search terms
210− if (word[1] === TERM_WEIGHT) {
211− teaser.push("<b>");
212− }
213173 startIndex = word[2] + word[0].length;
214174 teaser.push(body.substring(word[2], startIndex));
215175
216− if (word[1] === TERM_WEIGHT) {
217− teaser.push("</b>");
218− }
219176 }
220177 teaser.push("…");
221178 return teaser.join("");
222179}
223180
224−function formatSearchResultTitle(path) {
225− var pathArray = path.split( 'docs/' );
226− var slug = pathArray[1];
227− var slugArray = slug.split( '/' );
228− var lastPartTitle = slugArray.splice(slugArray.length - 2, slugArray.length).join('');
229− var firstPartTitle = slugArray.join(' / ');
181+function formatSearchResultTitle(item) {
182+ var pathArray = item.ref.split( '/' );
183+
184+ // first directory is in 4th element of split path array
185+ var firstPartTitle = pathArray[3];
186+
187+ // last directory is in 2nd to last element of array
188+ var lastPartTitle = item.doc.title;
230189
231− var fullTitle = firstPartTitle + ' / ' + '<span class="search-results__item__title__slug-end">' + lastPartTitle + '</span>';
190+ var fullTitle = firstPartTitle + '<span class="gray90 inline-block pl2">' + ' / ' + lastPartTitle + '</span>';
232191
233192 return fullTitle;
234193}
235194
236195function formatSearchResultItem(item, terms) {
196+ console.log(item);
237197 var li = document.createElement("li");
238198 var createA = document.createElement("a");
239199 li.appendChild(createA);
240− var teaserTitle = formatSearchResultTitle(item.ref);
200+ var teaserTitle = formatSearchResultTitle(item);
241201 li.classList.add("search-results__item");
202+ li.classList.add("ph3");
242203 var hrefA = item.ref;
243204 createA.setAttribute('href', hrefA);
244− createA.innerHTML = `<span class="search-results__item__title">${teaserTitle}</span>`;
245− createA.innerHTML += `<div class="search-results__teaser">${makeTeaser(item.doc.body, terms)}</div>`;
205+ createA.setAttribute('class','no-underline block pl6 pv3');
206+ createA.innerHTML = `<span class="fs45 capitalize">${teaserTitle}</span>`;
207+ createA.innerHTML += `<span class='pr7 fs5 none float-right'>→</span>`;
208+ createA.innerHTML += `<div class="fs35 truncate mr10">${makeTeaser(item.doc.body, terms)}</div>`;
246209 return li;
247210}
248211
249212function initSearch() {
250213 var searchInput = document.getElementById("search");
214+ var searchForm = document.getElementById("search-form");
215+ var inputReset = searchForm.nextElementSibling;
251216
252217 if (!searchInput) {
253218 return;
@@ -257,9 +222,9 @@ function initSearch() {
257222 var searchResultsHeader = document.querySelector(".search-results__header");
258223 var searchResultsItems = document.querySelector(".search-results__items");
259224 var MAX_ITEMS = 200;
260−
261225 var options = {
262226 bool: "AND",
227+ expand: true, // turn on partial word search
263228 fields: {
264229 title: {boost: 2},
265230 body: {boost: 1},
@@ -267,19 +232,22 @@ function initSearch() {
267232 };
268233 var currentTerm = "";
269234 var index = elasticlunr.Index.load(window.searchIndex);
270−
271235 // toggle search window
272236 var toggleSearchWindow = document.getElementById('js-search-window-toggle');
273237 var bodyEl = document.body;
274238 var searchOverlay = document.getElementById('search-overlay');
275239 var searchWindow = document.getElementById('search-window');
276240 var searchActive = bodyEl.classList.contains('has-active-search-window');
241+
277242 if (toggleSearchWindow !== null) {
278243 toggleSearchWindow.onclick = function() {
244+ inputReset.style.display="none";
245+
279246 //activate search
280247 bodyEl.classList.toggle('has-active-search-window');
281248 //put input in focus when activating search
282249 searchInput.focus();
250+
283251 searchInput.value = "";
284252 searchResultsHeader.value = "";
285253 searchResults.style.display = searchInput.value.trim() === "" ? "none" : "block";
@@ -291,12 +259,12 @@ function initSearch() {
291259 })
292260 }
293261
294− // when typing
262+
295263 searchInput.addEventListener("keyup", debounce(function() {
296− searchResultsHeader.value = "";
264+ inputReset.style.display="block";
297265
266+ searchResultsHeader.value = "";
298267 var term = searchInput.value.trim();
299−
300268 /*
301269 //removed to fix: a state where there’s a valid search term, but no results
302270
@@ -308,19 +276,21 @@ function initSearch() {
308276 searchResults.style.overflowY = term === "" ? "hidden" : "scroll";
309277 searchResultsItems.innerHTML = "";
310278 if (term === "") {
279+ inputReset.style.display="none";
311280 return;
312281 }
313282
314283 var results = index.search(term, options).filter(function (r) {
315284 return r.doc.body !== "";
316285 });
286+
317287 if (results.length === 0) {
318288 searchResultsHeader.innerText = `No search results for '${term}'.`;
319289 return;
320290 }
321291
322292 currentTerm = term;
323− searchResultsHeader.innerText = `${results.length} search results for '${term}':`;
293+ searchResultsHeader.innerText = `${results.length} search results for '${term}':`;
324294 for (var i = 0; i < Math.min(results.length, MAX_ITEMS); i++) {
325295 if (!results[i].doc.body) {
326296 continue;
@@ -328,6 +298,17 @@ function initSearch() {
328298 searchResultsItems.appendChild(formatSearchResultItem(results[i], term.split(" ")));
329299 }
330300 }, 150));
301+
302+ // reset input button
303+ inputReset.onclick=function(){
304+ document.getElementById('search-form').reset();
305+ }
306+ searchForm.addEventListener("reset", function(event){
307+ var e = document.createEvent('KeyboardEvent');
308+ e.initEvent("keyup", false, true);
309+ searchInput.dispatchEvent(e);
310+ });
311+
331312}
332313
333314if (document.readyState === "complete" ||
templates/partials/navigation-docs.html+4−2
@@ -1,13 +1,15 @@
11{% block content %}
22<div id="js-content-nav-toggle" class="content-nav-icon"></div>
33<nav class="content-nav">
4− <button id="js-search-window-toggle" type="button" class="search-bar content-nav__search-bar mb2">Search</button>
4+ <button id="js-search-window-toggle" type="button" class="search-bar content-nav__search-bar inline align-center" style="outline:none">
5+ <div class="inline-block"><span class="header__search-icon mh3 inline-block fs6">⚲</span></div><span class="gray50">Search</span>
6+ </button>
57 <ul class="list content-nav__index">
68 {% block menu %}
79 {% set index = get_section(path="docs/_index.md") %}
810 {% for s in index.subsections %}
911 {% set subsection = get_section(path=s) %}
10− <li class="list__item content-nav__index__item">
12+ <li class="list__item content-nav__index__item mt5">
1113 <a class="text-600" href="{{ subsection.permalink }}">
1214 {{ subsection.title }}
1315 </a>
templates/partials/search-overlay.html+7−5
@@ -1,12 +1,14 @@
11{% block content %}
2−<div id="search-overlay" class="search-overlay">
2+<div id="search-overlay" class="search-overlay fix vh100 w-full b-transparent z10 none top0">
33 <div class="wrapper">
44 <div id="search-window" class="pop-up">
5− <div class="search-bar">
6− <input id="search" autocomplete="off" type="search" class="search-bar__input" placeholder="Go to...">
5+ <div class="search-bar padding-none border-none z1 inline align-center w-full">
6+ <span class="header__search-icon ml3 abs z1 fs6 gray50">⚲</span>
7+ <form id="search-form" class="w-full"><input id="search" autocomplete="off" type="search" class="search-bar__input border-none" placeholder="Go to..."></form>
8+ <a id="search-reset" class="fs6 pr3 gray50 no-underline pointer:hover">&#57503;</a>
79 </div>
8− <div class="search-results">
9− <div class="search-results__header mb2"></div>
10+ <div id="search-results" class="search-results bt1 b-gray40">
11+ <div class="search-results__header ml9 mv2 gray60 fs3"></div>
1012 <ul class="list search-results__items"></ul>
1113 </div>
1214 </div>