mirror of
https://github.com/thangisme/notes.git
synced 2024-11-18 01:56:02 -05:00
Updated lunr.js, added search navigation and preview/highlighting
This commit is contained in:
parent
e9f016ac0f
commit
e64a6aa239
@ -179,7 +179,6 @@ body {
|
|||||||
bottom: 0;
|
bottom: 0;
|
||||||
padding-top: $sp-4;
|
padding-top: $sp-4;
|
||||||
padding-bottom: $sp-4;
|
padding-bottom: $sp-4;
|
||||||
background-color: $sidebar-color;
|
|
||||||
|
|
||||||
@include mq(md) {
|
@include mq(md) {
|
||||||
position: static;
|
position: static;
|
||||||
|
@ -79,6 +79,10 @@
|
|||||||
&.active {
|
&.active {
|
||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@include mq(md) {
|
||||||
|
width: $search-results-width;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.search-results-list {
|
.search-results-list {
|
||||||
@ -98,15 +102,57 @@
|
|||||||
margin: 0;
|
margin: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.search-results-link {
|
.search-result {
|
||||||
display: block;
|
display: block;
|
||||||
padding-top: $sp-1;
|
padding-top: $sp-1;
|
||||||
padding-right: $sp-3;
|
|
||||||
padding-bottom: $sp-1;
|
padding-bottom: $sp-1;
|
||||||
padding-left: $sp-3;
|
padding-left: $sp-3;
|
||||||
|
padding-right: $sp-3;
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
color: $body-heading-color;
|
background-color: darken($body-background-color, 5%);
|
||||||
background-color: darken($body-background-color, 2%);
|
}
|
||||||
|
|
||||||
|
@include mq(md) {
|
||||||
|
padding-left: $sp-4;
|
||||||
|
padding-right: $sp-4;
|
||||||
|
|
||||||
|
&.active {
|
||||||
|
background-color: darken($body-background-color, 5%);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-result-title {
|
||||||
|
display: block;
|
||||||
|
padding-top: $sp-2;
|
||||||
|
padding-bottom: $sp-2;
|
||||||
|
padding-right: $sp-4;
|
||||||
|
|
||||||
|
@include mq(sm) {
|
||||||
|
display: inline-block;
|
||||||
|
width: 40%;
|
||||||
|
vertical-align: top;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-result-preview {
|
||||||
|
display: block;
|
||||||
|
padding-top: $sp-2;
|
||||||
|
padding-bottom: $sp-2;
|
||||||
|
padding-left: $sp-4;
|
||||||
|
border-left: $border;
|
||||||
|
border-left-color: $border-color;
|
||||||
|
color: $search-result-preview-color;
|
||||||
|
@include fs-2;
|
||||||
|
|
||||||
|
@include mq(sm) {
|
||||||
|
display: inline-block;
|
||||||
|
width: 60%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-result-highlight {
|
||||||
|
color: $link-color;
|
||||||
|
font-weight: bold;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -56,6 +56,7 @@ $code-background-color: $grey-lt-000 !default;
|
|||||||
|
|
||||||
$body-text-color: $grey-dk-100 !default;
|
$body-text-color: $grey-dk-100 !default;
|
||||||
$body-heading-color: $grey-dk-300 !default;
|
$body-heading-color: $grey-dk-300 !default;
|
||||||
|
$search-result-preview-color: $grey-dk-100 !default;
|
||||||
$nav-child-link-color: $grey-dk-100 !default;
|
$nav-child-link-color: $grey-dk-100 !default;
|
||||||
$link-color: $purple-000 !default;
|
$link-color: $purple-000 !default;
|
||||||
$btn-primary-color: $purple-100 !default;
|
$btn-primary-color: $purple-100 !default;
|
||||||
@ -110,6 +111,7 @@ $nav-width: 264px !default;
|
|||||||
$nav-width-md: 248px !default;
|
$nav-width-md: 248px !default;
|
||||||
$content-width: 800px !default;
|
$content-width: 800px !default;
|
||||||
$header-height: 60px !default;
|
$header-height: 60px !default;
|
||||||
|
$search-results-width: 488px !default;
|
||||||
|
|
||||||
//
|
//
|
||||||
// Media queries in pixels
|
// Media queries in pixels
|
||||||
|
@ -31,13 +31,6 @@ function toggleNav(){
|
|||||||
// Site search
|
// Site search
|
||||||
|
|
||||||
function initSearch() {
|
function initSearch() {
|
||||||
var index = lunr(function () {
|
|
||||||
this.ref('id');
|
|
||||||
this.field('title', { boost: 20 });
|
|
||||||
this.field('content', { boost: 10 });
|
|
||||||
this.field('url');
|
|
||||||
});
|
|
||||||
|
|
||||||
// Get the generated search_data.json file so lunr.js can search it locally.
|
// Get the generated search_data.json file so lunr.js can search it locally.
|
||||||
|
|
||||||
sc = document.getElementsByTagName("script");
|
sc = document.getElementsByTagName("script");
|
||||||
@ -62,17 +55,25 @@ function initSearch() {
|
|||||||
if (request.status >= 200 && request.status < 400) {
|
if (request.status >= 200 && request.status < 400) {
|
||||||
// Success!
|
// Success!
|
||||||
var data = JSON.parse(request.responseText);
|
var data = JSON.parse(request.responseText);
|
||||||
var keys = Object.keys(data);
|
|
||||||
|
var index = lunr(function () {
|
||||||
|
this.ref('id');
|
||||||
|
this.field('title', { boost: 200 });
|
||||||
|
this.field('content', { boost: 2 });
|
||||||
|
this.field('url');
|
||||||
|
this.metadataWhitelist = ['position']
|
||||||
|
|
||||||
for (var i in data) {
|
for (var i in data) {
|
||||||
index.add({
|
this.add({
|
||||||
id: data[i].id,
|
id: data[i].id,
|
||||||
title: data[i].title,
|
title: data[i].title,
|
||||||
content: data[i].content,
|
content: data[i].content,
|
||||||
url: data[i].url
|
url: data[i].url
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
searchResults(data);
|
});
|
||||||
|
|
||||||
|
searchResults(index, data);
|
||||||
} else {
|
} else {
|
||||||
// We reached our target server, but it returned an error
|
// We reached our target server, but it returned an error
|
||||||
console.log('Error loading ajax request. Request status:' + request.status);
|
console.log('Error loading ajax request. Request status:' + request.status);
|
||||||
@ -86,66 +87,168 @@ function initSearch() {
|
|||||||
|
|
||||||
request.send();
|
request.send();
|
||||||
|
|
||||||
function searchResults(dataStore) {
|
function searchResults(index, data) {
|
||||||
|
var index = index;
|
||||||
|
var docs = data;
|
||||||
var searchInput = document.querySelector('.js-search-input');
|
var searchInput = document.querySelector('.js-search-input');
|
||||||
var searchResults = document.querySelector('.js-search-results');
|
var searchResults = document.querySelector('.js-search-results');
|
||||||
var store = dataStore;
|
|
||||||
|
|
||||||
function hideResults() {
|
function hideResults() {
|
||||||
searchResults.innerHTML = '';
|
searchResults.innerHTML = '';
|
||||||
searchResults.classList.remove('active');
|
searchResults.classList.remove('active');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
addEvent(searchInput, 'keydown', function(e){
|
||||||
|
switch (e.keyCode) {
|
||||||
|
case 38: // arrow up
|
||||||
|
var active = document.querySelector('.search-result.active');
|
||||||
|
if (active.parentElement.previousSibling) {
|
||||||
|
var previous = active.parentElement.previousSibling.querySelector('.search-result');
|
||||||
|
active.classList.remove('active');
|
||||||
|
previous.classList.add('active');
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
case 40: // arrow down
|
||||||
|
var active = document.querySelector('.search-result.active');
|
||||||
|
if (active.parentElement.nextSibling) {
|
||||||
|
var next = active.parentElement.nextSibling.querySelector('.search-result');
|
||||||
|
active.classList.remove('active');
|
||||||
|
next.classList.add('active');
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
case 13: // enter
|
||||||
|
var active = document.querySelector('.search-result.active');
|
||||||
|
active.click();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
addEvent(searchInput, 'keyup', function(e){
|
addEvent(searchInput, 'keyup', function(e){
|
||||||
var query = this.value;
|
switch (e.keyCode) {
|
||||||
|
case 27: // When esc key is pressed, hide the results and clear the field
|
||||||
searchResults.innerHTML = '';
|
|
||||||
searchResults.classList.remove('active');
|
|
||||||
|
|
||||||
if (query === '') {
|
|
||||||
hideResults();
|
hideResults();
|
||||||
} else {
|
searchInput.value = '';
|
||||||
var results = index.search(query);
|
return;
|
||||||
|
case 38: // arrow up
|
||||||
|
case 40: // arrow down
|
||||||
|
case 13: // enter
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
hideResults();
|
||||||
|
|
||||||
|
var input = this.value;
|
||||||
|
if (input === '') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var results = index.query(function (query) {
|
||||||
|
var tokens = lunr.tokenizer(input)
|
||||||
|
query.term(tokens, {
|
||||||
|
boost: 10
|
||||||
|
});
|
||||||
|
query.term(tokens, {
|
||||||
|
wildcard: lunr.Query.wildcard.TRAILING
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
if (results.length > 0) {
|
if (results.length > 0) {
|
||||||
searchResults.classList.add('active');
|
searchResults.classList.add('active');
|
||||||
var resultsList = document.createElement('ul');
|
var resultsList = document.createElement('ul');
|
||||||
|
resultsList.classList.add('search-results-list');
|
||||||
searchResults.appendChild(resultsList);
|
searchResults.appendChild(resultsList);
|
||||||
|
|
||||||
for (var i in results) {
|
for (var i in results) {
|
||||||
|
var result = results[i];
|
||||||
|
var doc = docs[result.ref];
|
||||||
|
|
||||||
var resultsListItem = document.createElement('li');
|
var resultsListItem = document.createElement('li');
|
||||||
var resultsLink = document.createElement('a');
|
|
||||||
var resultsUrlDesc = document.createElement('span');
|
|
||||||
var resultsUrl = store[results[i].ref].url;
|
|
||||||
var resultsRelUrl = store[results[i].ref].relUrl;
|
|
||||||
var resultsTitle = store[results[i].ref].title;
|
|
||||||
|
|
||||||
resultsLink.setAttribute('href', resultsUrl);
|
|
||||||
resultsLink.innerText = resultsTitle;
|
|
||||||
resultsUrlDesc.innerText = resultsRelUrl;
|
|
||||||
|
|
||||||
resultsList.classList.add('search-results-list');
|
|
||||||
resultsListItem.classList.add('search-results-list-item');
|
resultsListItem.classList.add('search-results-list-item');
|
||||||
resultsLink.classList.add('search-results-link');
|
|
||||||
resultsUrlDesc.classList.add('fs-2','text-grey-dk-000','d-block');
|
|
||||||
|
|
||||||
resultsList.appendChild(resultsListItem);
|
resultsList.appendChild(resultsListItem);
|
||||||
resultsListItem.appendChild(resultsLink);
|
|
||||||
resultsLink.appendChild(resultsUrlDesc);
|
var resultLink = document.createElement('a');
|
||||||
|
resultLink.classList.add('search-result');
|
||||||
|
if (i == 0) {
|
||||||
|
resultLink.classList.add('active');
|
||||||
}
|
}
|
||||||
|
resultLink.setAttribute('href', doc.url);
|
||||||
|
resultsListItem.appendChild(resultLink);
|
||||||
|
|
||||||
|
var resultTitle = document.createElement('div');
|
||||||
|
resultTitle.classList.add('search-result-title');
|
||||||
|
resultTitle.innerText = doc.title;
|
||||||
|
resultLink.appendChild(resultTitle);
|
||||||
|
|
||||||
|
var metadata = result.matchData.metadata;
|
||||||
|
var contentFound = false;
|
||||||
|
for (var j in metadata) {
|
||||||
|
if (metadata[j].title) {
|
||||||
|
var position = metadata[j].title.position[0];
|
||||||
|
var start = position[0];
|
||||||
|
var end = position[0] + position[1];
|
||||||
|
resultTitle.innerHTML = doc.title.substring(0, start) + '<span class="search-result-highlight">' + doc.title.substring(start, end) + '</span>' + doc.title.substring(end, doc.title.length);
|
||||||
|
|
||||||
|
} else if (metadata[j].content && !contentFound) {
|
||||||
|
contentFound = true;
|
||||||
|
|
||||||
|
var position = metadata[j].content.position[0];
|
||||||
|
var start = position[0];
|
||||||
|
var end = position[0] + position[1];
|
||||||
|
var previewStart = start;
|
||||||
|
var previewEnd = end;
|
||||||
|
var ellipsesBefore = true;
|
||||||
|
var ellipsesAfter = true;
|
||||||
|
for (var k = 0; k < 3; k++) {
|
||||||
|
var nextSpace = doc.content.lastIndexOf(' ', previewStart - 2);
|
||||||
|
var nextDot = doc.content.lastIndexOf('.', previewStart - 2);
|
||||||
|
if ((nextDot > 0) && (nextDot > nextSpace)) {
|
||||||
|
previewStart = nextDot + 1;
|
||||||
|
ellipsesBefore = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (nextSpace < 0) {
|
||||||
|
previewStart = 0;
|
||||||
|
ellipsesBefore = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
previewStart = nextSpace + 1;
|
||||||
|
}
|
||||||
|
for (var k = 0; k < 10; k++) {
|
||||||
|
var nextSpace = doc.content.indexOf(' ', previewEnd + 1);
|
||||||
|
var nextDot = doc.content.indexOf('.', previewEnd + 1);
|
||||||
|
if ((nextDot > 0) && (nextDot < nextSpace)) {
|
||||||
|
previewEnd = nextDot + 1;
|
||||||
|
ellipsesAfter = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (nextSpace < 0) {
|
||||||
|
previewEnd = doc.content.length;
|
||||||
|
ellipsesAfter = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
previewEnd = nextSpace;
|
||||||
|
}
|
||||||
|
var preview = doc.content.substring(previewStart, start);
|
||||||
|
if (ellipsesBefore) {
|
||||||
|
preview = '... ' + preview;
|
||||||
|
}
|
||||||
|
preview += '<span class="search-result-highlight">' + doc.content.substring(start, end) + '</span>';
|
||||||
|
preview += doc.content.substring(end, previewEnd);
|
||||||
|
if (ellipsesAfter) {
|
||||||
|
preview += '...';
|
||||||
}
|
}
|
||||||
|
|
||||||
// When esc key is pressed, hide the results and clear the field
|
var resultPreview = document.createElement('div');
|
||||||
if (e.keyCode == 27) {
|
resultPreview.classList.add('search-result-preview');
|
||||||
hideResults();
|
resultPreview.innerHTML = preview;
|
||||||
searchInput.value = '';
|
resultLink.appendChild(resultPreview);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
addEvent(searchInput, 'blur', function(){
|
addEvent(searchInput, 'blur', hideResults);
|
||||||
setTimeout(function(){ hideResults() }, 300);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
6
assets/js/vendor/lunr.min.js
vendored
6
assets/js/vendor/lunr.min.js
vendored
File diff suppressed because one or more lines are too long
Loading…
Reference in New Issue
Block a user