Skip to content

Commit

Permalink
Add support for Lunr and Algolia search (#48)
Browse files Browse the repository at this point in the history
* Add basic support for Lunr and Algolia search
* Fix skip links
* Fix URL paths
* Add toggle for Algolia "powered by" badge
* Improve placement of search toggle
* Fix search icon fill color
* Add search documentation
* Update CHANGELOG
* Enable search on demo site
* Update TOC
  • Loading branch information
mmistakes authored Feb 16, 2018
1 parent 6d43c0f commit e94ea30
Show file tree
Hide file tree
Showing 42 changed files with 826 additions and 44 deletions.
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,16 @@ and this project adheres to [Semantic Versioning](http://semver.org/).

## Unreleased

### Added
- Add site-wide search toggle.
- Add support for Lunr search. [#48](https://github.com/mmistakes/jekyll-theme-basically-basic/pull/48)
- Add support for Algolia search. [#48](https://github.com/mmistakes/jekyll-theme-basically-basic/pull/48)

### Changed
- New installation and upgrade instructions.
- Absolutely position navigation menu instead of sticking it to the top.
- Visually hide "Menu" label.
- Improve alignment of menu toggle when search is enabled.

### Fixed
- Fix `border-bottom` for Gist line numbers.
Expand Down
75 changes: 68 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,10 +42,13 @@ with a few enhancements thrown in for good measure:
3. [Text](#text)
4. [Navigation](#navigation)
5. [Pagination](#pagination)
6. [Author](#author)
7. [Reading Time](#reading-time)
8. [Comments (via Disqus)](#comments-via-disqus)
9. [Google Analytics](#google-analytics)
6. [Search](#search)
1. [Lunr (default)](#lunr-default)
2. [Algolia](#algolia)
7. [Author](#author)
8. [Reading Time](#reading-time)
9. [Comments (via Disqus)](#comments-via-disqus)
10. [Google Analytics](#google-analytics)
5. [Layouts](#layouts)
1. [`layout: default`](#layout-default)
2. [`layout: post`](#layout-post)
Expand All @@ -63,9 +66,6 @@ with a few enhancements thrown in for good measure:
8. [Contributing](#contributing)
1. [Pull Requests](#pull-requests)
9. [Credits](#credits)
1. [Creator](#creator)
2. [Icons + Demo Images:](#icons--demo-images)
3. [Other:](#other)
10. [License](#license)

## Installation
Expand Down Expand Up @@ -402,6 +402,67 @@ add the following front matter:
paginate: true
```

### Search

To enable site-wide search add `search: true` to your `_config.yml`.

#### Lunr (default)

The default search uses [**Lunr**](https://lunrjs.com/) to build a search index of all your documents. This method is 100% compatible with sites hosted on GitHub Pages.

**Note:** Only the first 50 words of a post or page's body content is added to the Lunr search index. Setting `search_full_content` to `true` in your `_config.yml` will override this and could impact page load performance.

#### Algolia

For faster and more relevant search:

1. Add the [`jekyll-algolia`](https://github.com/algolia/jekyll-algolia) gem to your `Gemfile`, in the `:jekyll_plugins` section.

```ruby
group :jekyll_plugins do
gem "jekyll-feed"
gem "jekyll-seo-tag"
gem "jekyll-sitemap"
gem "jekyll-paginate"
gem "jekyll-algolia"
end
```

Once this is done, download all dependencies by running `bundle install`.

2. Switch search providers from `lunr` to `algolia` in your `_config.yml` file:

```yaml
search_provider: algolia
```

3. Add the following Algolia credentials to your `_config.yml` file. *If you don't have an Algolia account, you can open a free [Community plan](https://www.algolia.com/users/sign_up/hacker). Once signed in, you can grab your credentials from [your dashboard](https://www.algolia.com/licensing).*

```yaml
algolia:
application_id: # YOUR_APPLICATION_ID
index_name: # YOUR_INDEX_NAME
search_only_api_key: # YOUR_SEARCH_ONLY_API_KEY
powered_by: # true (default), false
```

4. Once your credentials are setup, you can run the indexing with the following command:

```
ALGOLIA_API_KEY=your_admin_api_key bundle exec jekyll algolia
```

For Windows users you will have to use `set` to assigned the `ALGOLIA_API_KEY` environment variable.

```
set ALGOLIA_API_KEY=your_admin_api_key
bundle exec jekyll algolia
```

Note that `ALGOLIA_API_KEY` should be set to your admin API key.

To use the Algolia search with GitHub Pages hosted sites follow [this deployment guide](https://community.algolia.com/jekyll-algolia/github-pages.html). Or this guide for [deploying on Netlify](https://community.algolia.com/jekyll-algolia/netlify.html).

### Author

Author information is used as meta data for post "by lines" and propagates the
Expand Down
8 changes: 8 additions & 0 deletions _config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,14 @@ author:
twitter_username:
github_username:
logo: # path of site logo, e.g. "/assets/images/logo.png"
search: # true, false (default)
search_full_content: false # true, false (default)
search_provider: # lunr (default), algolia
algolia:
application_id: # YOUR_APPLICATION_ID
index_name: # YOUR_INDEX_NAME
search_only_api_key: # YOUR_SEARCH_ONLY_API_KEY
powered_by: # true (default), false

# Build settings
markdown: kramdown
Expand Down
3 changes: 3 additions & 0 deletions _data/theme.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ t:
skip_content: "Skip to content"
skip_footer: "Skip to footer"
menu: "Menu"
search: "Search"
results_found: "Result(s) found"
search_placeholder_text: "Enter your search term..."
home: "Home"
newer: "Newer"
older: "Older"
Expand Down
13 changes: 12 additions & 1 deletion _includes/scripts.html
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,15 @@
{% include google-analytics.html %}
{% endif %}

<script async src="{{ '/assets/javascripts/main.js' | relative_url }}"></script>
<script src="https://code.jquery.com/jquery-3.3.1.min.js" integrity="sha256-FgpCb/KJQlLNfOu91ta32o/NMZxltwRo8QtmkMRdAu8=" crossorigin="anonymous"></script>
<script async src="{{ '/assets/javascripts/main.js' | relative_url }}"></script>

{% if site.search %}
{%- assign search_provider = site.search_provider | default: "lunr" -%}
{%- case search_provider -%}
{%- when "lunr" -%}
{% include search/lunr-search-scripts.html %}
{%- when "algolia" -%}
{% include search/algolia-search-scripts.html %}
{%- endcase -%}
{% endif %}
13 changes: 13 additions & 0 deletions _includes/search-form.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<div class="inner">
{% if site.search %}
{%- assign search_provider = site.search_provider | default: "lunr" -%}
{%- case search_provider -%}
{%- when "lunr" -%}
<input type="text" id="search" class="search-input" tabindex="-1" placeholder="{{ site.data.theme.t.menu.search_placeholder_text | default: 'Enter your search term...' }}" />
<div id="results" class="results"></div>
{%- when "algolia" -%}
<div tabindex="-1" class="search-searchbar"></div>
<div class="search-hits"></div>
{%- endcase -%}
{% endif %}
</div>
52 changes: 52 additions & 0 deletions _includes/search/algolia-search-scripts.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
<!-- Including InstantSearch.js library and styling -->
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/instantsearch.min.js"></script>
<link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/npm/[email protected]/dist/instantsearch.min.css">
<link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/npm/[email protected]/dist/instantsearch-theme-algolia.min.css">

<script>
// Instanciating InstantSearch.js with Algolia credentials
const search = instantsearch({
appId: '{{ site.algolia.application_id }}',
apiKey: '{{ site.algolia.search_only_api_key }}',
indexName: '{{ site.algolia.index_name }}',
searchParameters: {
restrictSearchableAttributes: [
'title',
'content'
]
}
});

const hitTemplate = function(hit) {
const url = hit.url;
const title = hit._highlightResult.title.value;
const content = hit._highlightResult.html.value;

return `
<article class="entry">
<h3 class="entry-title"><a href="{{ site.baseurl }}${url}">${title}</a></h3>
<div class="entry-excerpt">${content}</div>
</article>
`;
}

// Adding searchbar and results widgets
search.addWidget(
instantsearch.widgets.searchBox({
container: '.search-searchbar',
{% unless site.algolia.powered_by == false %}poweredBy: true,{% endunless %}
placeholder: '{{ site.data.theme.t.menu.search_placeholder_text | default: "Enter your search term..." }}'
})
);
search.addWidget(
instantsearch.widgets.hits({
container: '.search-hits',
templates: {
item: hitTemplate
}
})
);

// Starting the search
search.start();
</script>
106 changes: 106 additions & 0 deletions _includes/search/lunr-search-scripts.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
{%- assign lang = site.lang | slice: 0, 2 | default: "en" -%}
{%- case lang -%}
{%- when "da" -%}
{%- assign lang = "da" -%}
{%- when "de" -%}
{%- assign lang = "de" -%}
{%- when "du" -%}
{%- assign lang = "du" -%}
{-% when "es" -%}
{%- assign lang = "es" -%}
{%- when "fi" -%}
{%- assign lang = "fi" -%}
{%- when "fr" -%}
{%- assign lang = "fr" -%}
{%- when "hu" -%}
{%- assign lang = "hu" -%}
{%- when "it" -%}
{%- assign lang = "it" -%}
{%- when "ja" -%}
{%- assign lang = "ja" -%}
{%- when "jp" -%}
{%- assign lang = "jp" -%}
{%- when "no" -%}
{%- assign lang = "no" -%}
{%- when "pt" -%}
{%- assign lang = "pt" -%}
{%- when "ro" -%}
{%- assign lang = "ro" -%}
{%- when "ru" -%}
{%- assign lang = "ru" -%}
{%- when "sv" -%}
{%- assign lang = "sv" -%}
{%- when "tr" -%}
{%- assign lang = "tr" -%}
{%- else -%}
{%- assign lang = "en" -%}
{%- endcase -%}
<script src="{{ '/assets/javascripts/lunr/lunr.min.js' | absolute_url }}"></script>
<script src="{{ '/assets/javascripts/search-data.json' | absolute_url }}"></script>
{%- unless lang == "en" -%}
<script src="{{ '/assets/javascripts/lunr/lunr.stemmer.support.min.js' | absolute_url }}"></script>
<script src="{{ '/assets/javascripts/lunr/lunr.' | append: lang | append: '.min.js' | absolute_url }}"></script>
{%- endunless %}
<script>
var idx = lunr(function () {
{% unless lang == "en" %}
// use the language
this.use(lunr.{{ lang }});
{% endunless %}
// the, the normal lunr index initialization
this.field('title')
this.field('excerpt')
this.field('categories')
this.field('tags')
this.ref('id')

this.pipeline.remove(lunr.trimmer)

// add documents to index
for (var item in store) {
this.add({
title: store[item].title,
excerpt: store[item].excerpt,
categories: store[item].categories,
tags: store[item].tags,
id: item
})
}
});

console.log(jQuery.type(idx));

$(document).ready(function () {
$('input#search').on('keyup', function () {
var resultdiv = $('#results');
var query = $(this).val().toLowerCase();
var result =
idx.query(function (q) {
query.split(lunr.tokenizer.separator).forEach(function (term) {
q.term(term, { boost: 100 })
if (query.lastIndexOf(" ") != query.length - 1) {
q.term(term, { usePipeline: false, wildcard: lunr.Query.wildcard.TRAILING, boost: 10 })
}
if (term != "") {
q.term(term, { usePipeline: false, editDistance: 1, boost: 1 })
}
})
});
resultdiv.empty();
resultdiv.prepend('<p class="results-found">' + result.length + ' {{ site.data.theme.t.menu.results_found | default: "Result(s) found" }}</p>');
for (var item in result) {
var ref = result[item].ref;
var searchitem =
'<article class="entry">' +
'<h3 class="entry-title">' +
'<a href="' + store[ref].url + '">' + store[ref].title + '</a>' +
'</h3>' +
'<div class="entry-excerpt">' +
'<p>' + store[ref].excerpt.split(" ").splice(0, 20).join(" ") + '...</p>' +
'</div>' +
'</article>';
resultdiv.append(searchitem);
}
});
});
</script>
19 changes: 17 additions & 2 deletions _layouts/default.html
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,18 @@
{% include skip-links.html %}

<div class="sidebar-toggle-wrapper">
{% if site.search %}
<button class="search-toggle" type="button">
<svg class="icon" width="16" height="16" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 15.99 16">
<title>{{ site.data.theme.t.search | default: 'Search' }}</title>
<path d="M15.5,13.12L13.19,10.8a1.69,1.69,0,0,0-1.28-.55l-0.06-.06A6.5,6.5,0,0,0,5.77,0,6.5,6.5,0,0,0,2.46,11.59a6.47,6.47,0,0,0,7.74.26l0.05,0.05a1.65,1.65,0,0,0,.5,1.24l2.38,2.38A1.68,1.68,0,0,0,15.5,13.12ZM6.4,2A4.41,4.41,0,1,1,2,6.4,4.43,4.43,0,0,1,6.4,2Z" transform="translate(-.01)"></path>
</svg>
</button>
{% endif %}

<button class="toggle navicon-button larr" type="button">
<span class="toggle-inner">
<span class="sidebar-toggle-label">{{ site.data.theme.t.menu | default: 'Menu' }}</span>
<span class="sidebar-toggle-label visually-hidden">{{ site.data.theme.t.menu | default: 'Menu' }}</span>
<span class="navicon"></span>
</span>
</button>
Expand All @@ -31,7 +40,13 @@
<div class="canvas">
<div class="wrapper">
{% include masthead.html %}
{{ content }}
<div class="initial-content">
{{ content }}
</div>

<div class="search-content">
{% include search-form.html %}
</div>
</div>
</div>

Expand Down
1 change: 1 addition & 0 deletions _sass/basically-basic.scss
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
@import "basically-basic/global";
@import "basically-basic/sidebar";
@import "basically-basic/navigation";
@import "basically-basic/search";
@import "basically-basic/footer";
@import "basically-basic/entries";
@import "basically-basic/buttons";
Expand Down
10 changes: 5 additions & 5 deletions _sass/basically-basic/_base.scss
Original file line number Diff line number Diff line change
Expand Up @@ -111,8 +111,8 @@ a {
}
}

*:focus {
border-color: $accent-color;
outline: none;
box-shadow: 0 0 10px $accent-color;
}
// *:focus {
// border-color: $accent-color;
// outline: none;
// box-shadow: 0 0 10px $accent-color;
// }
Loading

0 comments on commit e94ea30

Please sign in to comment.