Remove search overlay

- Fixes #88
- Replace overlay with dedicated search page (see /search/index.md)
- Replace simpleJekyllSearch.js
- Include pages in search.json index
This commit is contained in:
Michael Rose 2015-01-21 16:24:43 -05:00
parent 281a67f07c
commit 461d7c8199
21 changed files with 295 additions and 257 deletions

1
404.md
View file

@ -3,6 +3,7 @@ layout: page
title: "Page Not Found" title: "Page Not Found"
description: "Page not found. Your pixels are in another canvas." description: "Page not found. Your pixels are in another canvas."
sitemap: false sitemap: false
search_omit: true
--- ---
Sorry, but the page you were trying to view does not exist --- perhaps you can try searching for it below. Sorry, but the page you were trying to view does not exist --- perhaps you can try searching for it below.

View file

@ -11,7 +11,7 @@ Looking for a simple, responsive, theme for your Jekyll powered blog? Well look
* Minimal embellishments and subtle animations. * Minimal embellishments and subtle animations.
* Optional large feature images for posts and pages. * Optional large feature images for posts and pages.
* [Custom 404 page](http://mmistakes.github.io/so-simple-theme/404.html) to get you started. * [Custom 404 page](http://mmistakes.github.io/so-simple-theme/404.html) to get you started.
* [Simple site search](https://github.com/christian-fei/Simple-Jekyll-Search) * Basic [search capabilities](https://github.com/mathaywarduk/jekyll-search)
* Support for Disqus Comments * Support for Disqus Comments
![screenshot of So Simple Theme](http://mmistakes.github.io/so-simple-theme/images/so-simple-theme-preview.jpg) ![screenshot of So Simple Theme](http://mmistakes.github.io/so-simple-theme/images/so-simple-theme-preview.jpg)

View file

@ -4,7 +4,6 @@ title: So Simple Theme
locale: en_US locale: en_US
description: A simple and clean responsive Jekyll theme for words and photos. description: A simple and clean responsive Jekyll theme for words and photos.
logo: site-logo.png logo: site-logo.png
search: true
url: //mmistakes.github.io/so-simple-theme url: //mmistakes.github.io/so-simple-theme

View file

@ -14,3 +14,6 @@
- title: Made Mistakes - title: Made Mistakes
url: http://mademistakes.com url: http://mademistakes.com
- title: Search
url: /search/

View file

@ -9,15 +9,12 @@
{% endif %} {% endif %}
<li><a href="{{ domain }}{{ link.url }}" {% if link.url contains 'http' %}target="_blank"{% endif %}>{{ link.title }}</a></li> <li><a href="{{ domain }}{{ link.url }}" {% if link.url contains 'http' %}target="_blank"{% endif %}>{{ link.title }}</a></li>
{% endfor %} {% endfor %}
{% if site.search %}<li class="dosearch"><span><i class="fa fa-search"></i> Search</span></li>{% endif %}
</ul> </ul>
</nav> </nav>
</div><!-- /.navigation-wrapper --> </div><!-- /.navigation-wrapper -->
{% include browser-upgrade.html %} {% include browser-upgrade.html %}
{% if site.search %}{% include site-search.html %}{% endif %}
{% if page.image.feature %}<header class="masthead"> {% if page.image.feature %}<header class="masthead">
{% if site.logo != null %} {% if site.logo != null %}
<div class="wrap"> <div class="wrap">

View file

@ -1,45 +1,7 @@
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script> <script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<script>window.jQuery || document.write('<script src="{{ site.url }}/assets/js/vendor/jquery-1.9.1.min.js"><\/script>')</script> <script>window.jQuery || document.write('<script src="{{ site.url }}/assets/js/vendor/jquery-1.9.1.min.js"><\/script>')</script>
<script src="{{ site.url }}/assets/js/scripts.min.js"></script> <script src="{{ site.url }}/assets/js/scripts.min.js"></script>
{% if site.search %}
<!-- Jekyll Simple Search option -->
<script>
$(document).ready(function() {
$('.search-field').jekyllSearch({
jsonFile: '{{ site.url }}/search.json',
searchResults: '.search-results',
template: '<li><article><a href="{url}">{title} <span class="entry-date"><time datetime="{date}">{shortdate}</time></span></a></article></li>',
fuzzy: true,
noResults: '<p>Nothing found.</p>'
});
});
(function( $, window, undefined ) {
var bs = {
close: $(".close-btn"),
searchform: $(".search-form"),
canvas: $(".js-menu-screen"),
dothis: $('.dosearch')
};
bs.dothis.on('click', function() {
$('.search-wrapper').css({ display: "block" });
$('body').toggleClass('no-scroll');
bs.searchform.toggleClass('active');
bs.searchform.find('input').focus();
bs.canvas.toggleClass('is-visible');
});
bs.close.on('click', function() {
$('.search-wrapper').removeAttr( 'style' );
$('body').toggleClass('no-scroll');
bs.searchform.toggleClass('active');
bs.canvas.removeClass('is-visible');
});
})( jQuery, window );
</script>
{% endif %}
{% if site.owner.google.analytics %} {% if site.owner.google.analytics %}
<!-- Asynchronous Google Analytics snippet --> <!-- Asynchronous Google Analytics snippet -->
<script> <script>

View file

@ -1,7 +0,0 @@
<div class="search-wrapper">
<div class="search-form">
<input type="text" class="search-field" placeholder="Search...">
<button class="close-btn"><i class="fa fa-times-circle fa-2x"></i></button>
<ul class="search-results post-list"></ul><!-- /.search-results -->
</div><!-- /.search-form -->
</div><!-- ./search-wrapper -->

View file

@ -230,3 +230,24 @@ select:focus {
float : left; float : left;
margin-left : 0; margin-left : 0;
margin-right : 3px; } margin-right : 3px; }
// Search
// --------------------------------------------------
.simple-search {
text-align: center;
label {
display: none;
}
/* input field */
#goog-wm-qt {
@include media($medium) {
width: 80%;
}
}
/* submit button */
#goog-wm-sb {}
}

View file

@ -344,6 +344,12 @@ span + .entry-title {
display: inline; display: inline;
} }
} }
/* post excerpt */
.excerpt {
display: block;
float: none;
@include font-size(14, no, 16);
}
} }
// Tag index // Tag index
.tag-box { .tag-box {

View file

@ -1,78 +0,0 @@
// Jekyll Simple Search
// -------------------------------------------------
.search-form {
width: 100%;
position: relative;
opacity: 0;
transition: all 200ms 100ms cubic-bezier(0, 0.6, 0.4, 1);
top: 0;
left: -200px;
z-index: 9002;
.search-field {
-webkit-appearance: none;
border: none;
width: 100%;
color: $white;
border: none;
border-bottom: 1px solid lighten($white, 20);
background-color: transparent;
box-shadow: none;
border-radius: 0;
background-clip: padding-box;
@include font-size(32);
&:focus {
box-shadow: none;
outline: none;
}
}
&.active {
opacity: 1;
top: 0;
left: 0;
}
&.hidden {
display: none;
}
::-webkit-input-placeholder {
@include font-size(32);
}
.search-field::-webkit-search-decoration,
.search-field::-webkit-search-cancel-button,
.search-field::-webkit-search-results-button,
.search-field::-webkit-search-results-decoration {
display: none;
}
.post-list {
position: absolute;
width: 100%;
h4, li, p, a {
color: $white;
}
li {
border-bottom: 1px solid lighten($white,20);
}
}
}
// search button in navigation
.no-js .dosearch {
display: none;
}
.dosearch {
span {
display: block;
margin-bottom: 10px;
padding: 12px 20px;
@include media($medium) {
margin-bottom: 0;
padding: 6px 10px;
}
cursor: pointer;
@include rounded(4px);
background-color: transparent;
color: $white;
&:hover {
@include box-shadow($shadow: inset 0 0 1px $white);
background-color: lighten($black, 10);
}
}
}

View file

@ -2,6 +2,7 @@
layout: page layout: page
title: Sample Articles title: Sample Articles
excerpt: "An archive of articles sorted by date." excerpt: "An archive of articles sorted by date."
search_omit: true
--- ---
<ul class="post-list"> <ul class="post-list">

View file

@ -26,4 +26,3 @@ sitemap: false
@import "layout"; @import "layout";
@import "vendor/font-awesome/font-awesome"; @import "vendor/font-awesome/font-awesome";
@import "vendor/magnific-popup/magnific-popup"; @import "vendor/magnific-popup/magnific-popup";
@import "simple-search";

200
assets/js/plugins/search.js Normal file
View file

@ -0,0 +1,200 @@
/**
* A simple JSON search
* Requires jQuery (v 1.7+)
*
* @author Mat Hayward - Erskine Design
* @version 0.1
*/
/* ==========================================================================
Initialisation
========================================================================== */
var q, jsonFeedUrl = "/search.json",
$searchForm = $("[data-search-form]"),
$searchInput = $("[data-search-input]"),
$resultTemplate = $("#search-result"),
$resultsPlaceholder = $("[data-search-results]"),
$foundContainer = $("[data-search-found]"),
$foundTerm = $("[data-search-found-term]"),
$foundCount = $("[data-search-found-count]"),
allowEmpty = true,
showLoader = true,
loadingClass = "is--loading";
$(document).ready( function() {
// hide items found string
$foundContainer.hide();
// initiate search functionality
initSearch();
});
/* ==========================================================================
Search functions
========================================================================== */
/**
* Initiate search functionality.
* Shows results based on querystring if present.
* Binds search function to form submission.
*/
function initSearch() {
// Get search results if q parameter is set in querystring
if (getParameterByName('q')) {
q = decodeURIComponent(getParameterByName('q'));
$searchInput.val(q);
execSearch(q);
}
// Get search results on submission of form
$(document).on("submit", $searchForm, function(e) {
e.preventDefault();
q = $searchInput.val();
execSearch(q);
});
}
/**
* Executes search
* @param {String} q
* @return null
*/
function execSearch(q) {
if (q != '' || allowEmpty) {
if (showLoader) {
toggleLoadingClass();
}
getSearchResults(processData());
}
}
/**
* Toggles loading class on results and found string
* @return null
*/
function toggleLoadingClass() {
$resultsPlaceholder.toggleClass(loadingClass);
$foundContainer.toggleClass(loadingClass);
}
/**
* Get Search results from JSON
* @param {Function} callbackFunction
* @return null
*/
function getSearchResults(callbackFunction) {
$.get(jsonFeedUrl, callbackFunction, 'json');
}
/**
* Process search result data
* @return null
*/
function processData() {
$results = [];
return function(data) {
var resultsCount = 0,
results = "";
$.each(data, function(index, item) {
// check if search term is in content or title
if (item.excerpt.toLowerCase().indexOf(q.toLowerCase()) > -1 || item.title.toLowerCase().indexOf(q.toLowerCase()) > -1) {
var result = populateResultContent($resultTemplate.html(), item);
resultsCount++;
results += result;
}
});
if (showLoader) {
toggleLoadingClass();
}
populateResultsString(resultsCount);
showSearchResults(results);
}
}
/**
* Add search results to placeholder
* @param {String} results
* @return null
*/
function showSearchResults(results) {
// Add results HTML to placeholder
$resultsPlaceholder.html(results);
}
/**
* Add results content to item template
* @param {String} html
* @param {object} item
* @return {String} Populated HTML
*/
function populateResultContent(html, item) {
html = injectContent(html, item.title, '##Title##');
html = injectContent(html, item.link, '##Url##');
html = injectContent(html, item.excerpt, '##Excerpt##');
html = injectContent(html, item.date, '##Date##');
return html;
}
/**
* Populates results string
* @param {String} count
* @return null
*/
function populateResultsString(count) {
$foundTerm.text(q);
$foundCount.text(count);
$foundContainer.show();
}
/* ==========================================================================
Helper functions
========================================================================== */
/**
* Gets query string parameter - taken from http://stackoverflow.com/questions/901115/how-can-i-get-query-string-values-in-javascript
* @param {String} name
* @return {String} parameter value
*/
function getParameterByName(name) {
var match = RegExp('[?&]' + name + '=([^&]*)').exec(window.location.search);
return match && decodeURIComponent(match[1].replace(/\+/g, ' '));
}
/**
* Injects content into template using placeholder
* @param {String} originalContent
* @param {String} injection
* @param {String} placeholder
* @return {String} injected content
*/
function injectContent(originalContent, injection, placeholder) {
var regex = new RegExp(placeholder, 'g');
return originalContent.replace(regex, injection);
}

View file

@ -1,108 +0,0 @@
/*global jQuery */
/*!
* Simple Jekyll Search
* Christian Fei - https://github.com/christian-fei/Simple-Jekyll-Search *
*
*/
(function($) {
$.fn.jekyllSearch = function(options) {
var settings = $.extend({
jsonFile : '/search.json',
template : '<a href="{url}" title="{desc}">{title}</a>',
searchResults : '.results',
searchResultsTitle : '<h4>Search results</h4>',
limit : '10',
noResults : '<p>Oh shucks<br/><small>Nothing found :(</small></p>'
}, options);
var jsonData = [],
origThis = this,
searchResults = $(settings.searchResults);
var matches = [];
if(settings.jsonFile.length && searchResults.length){
$.ajax({
type: "GET",
url: settings.jsonFile,
dataType: 'json',
success: function(data, textStatus, jqXHR) {
jsonData = data;
registerEvent();
},
error: function(x,y,z) {
console.log("***ERROR in jekyllSearch.js***");
console.log(x);
console.log(y);
console.log(z);
// x.responseText should have what's wrong
}
});
}
function registerEvent(){
origThis.keyup(function(e){
if(e.which === 13){
if(matches)
window.location = matches[0].url;
//follow the first link
// if(searchResults.children().length)
}
if($(this).val().length){
writeMatches( performSearch($(this).val()) );
}else{
clearSearchResults();
}
});
}
function performSearch(str){
matches = [];
for (var i = 0; i < jsonData.length; i++) {
var obj = jsonData[i];
for (key in obj) {
if(obj.hasOwnProperty(key)){
if (obj[key] instanceof Array){
var seen = false;
for (var j = 0; j < obj[key].length; j++){
if(obj[key][j].toLowerCase().indexOf(str.toLowerCase()) >= 0){
matches.push(obj);
break;
}
}
}else if (obj[key].toLowerCase().indexOf(str.toLowerCase()) >= 0){
matches.push(obj);
break;
}
}
}
}
return matches;
}
function writeMatches(m){
clearSearchResults();
searchResults.append( $(settings.searchResultsTitle) );
if(m && m.length){
for (var i = 0; i < m.length && i < settings.limit; i++) {
var obj = m[i];
output = settings.template;
output = output.replace(/\{(.*?)\}/g, function(match, property) {
return obj[property];
});
searchResults.append($(output));
}
}else{
searchResults.append( settings.noResults );
}
}
function clearSearchResults(){
searchResults.children().remove();
}
}
}(jQuery));

File diff suppressed because one or more lines are too long

View file

@ -2,6 +2,7 @@
layout: page layout: page
title: Blog title: Blog
excerpt: "An archive of blog posts sorted by date." excerpt: "An archive of blog posts sorted by date."
search_omit: true
--- ---
<ul class="post-list"> <ul class="post-list">

View file

@ -2,6 +2,7 @@
layout: page layout: page
title: Latest Posts title: Latest Posts
excerpt: "A simple and clean responsive Jekyll theme for words and photos." excerpt: "A simple and clean responsive Jekyll theme for words and photos."
search_omit: true
--- ---
<ul class="post-list"> <ul class="post-list">

View file

@ -1,15 +1,25 @@
--- ---
sitemap: false sitemap: false
--- ---
[ [
{% for post in site.posts %} {% for post in site.posts %}
{ {% if post.title != null and post.title != empty and post.search_omit != true %}
"title" : "{{ post.title | escape }}", {% if forloop.index > 1 %},{% endif %}{
"category" : "{{ post.category }}", "title" : {{ post.title | jsonify }},
"tags" : "{{ post.tags | array_to_sentence_string }}", "link" : "{{ site.url }}{{ post.url }}",
"url" : "{{ site.url }}{{ post.url }}", "excerpt" : "{{ post.excerpt }}"
"date" : "{{ post.date }}", }
"shortdate" : "{{ post.date | date: '%B %d, %Y' }}" {% endif %}
} {% unless forloop.last %},{% endunless %} {% endfor %}
{% for page in site.pages %}
{% if page.layout != 'none' and page.layout != 'none' and page.title != null and page.title != empty and page.search_omit != true %}
{% if forloop.index > 1 %},{% endif %}{
"title" : {{ page.title | jsonify }},
"link" : "{{ site.url }}{{ page.url | replace: 'index.html', '' }}",
"excerpt" : "{{ page.excerpt }}"
}
{%endif%}
{% endfor %} {% endfor %}
] ]

32
search/index.md Normal file
View file

@ -0,0 +1,32 @@
---
layout: page
title: "Search"
date:
modified:
excerpt:
image:
feature:
search_omit: true
sitemap: false
---
<!-- Search form -->
<form method="get" action="{{ site.url }}/search/" data-search-form class="simple-search">
<label for="q">Search {{ site.title }} for:</label>
<input type="search" name="q" id="q" placeholder="What are you looking for?" data-search-input id="goog-wm-qt" />
<input type="submit" value="Search" id="goog-wm-sb" />
</form>
<!-- Search results placeholder -->
<h6 data-search-found>
<span data-search-found-count></span> result(s) found for &ldquo;<span data-search-found-term></span>&rdquo;.
</h6>
<ul class="post-list" data-search-results></ul>
<!-- Search result template -->
<script type="text/x-template" id="search-result">
<li>
<article>
<a href="##Url##">##Title## <span class="excerpt">##Excerpt##</span></a>
</article></li>
</script>

View file

@ -2,6 +2,7 @@
layout: page layout: page
title: Tag Index title: Tag Index
excerpt: "An archive of posts sorted by tag." excerpt: "An archive of posts sorted by tag."
search_omit: true
--- ---
{% capture site_tags %}{% for tag in site.tags %}{{ tag | first }}{% unless forloop.last %},{% endunless %}{% endfor %}{% endcapture %} {% capture site_tags %}{% for tag in site.tags %}{{ tag | first }}{% unless forloop.last %},{% endunless %}{% endfor %}{% endcapture %}

View file

@ -323,14 +323,11 @@ Here's an example of a tweet with Twitter Cards enabled.
--- ---
## Simple Search ## Jekyll search
Adding `search: true` to your `_config.yml` enables search using Christian Fei's [Simple Jekyll jQuery plugin](https://github.com/christian-fei/Simple-Jekyll-Search). Clicking the search link in the navigation bar will overlay a Search box that searches on post titles using an auto generated JSON file. This is a very basic attempt at [indexing a Jekyll site](https://github.com/mathaywarduk/jekyll-search) and returning search results with JSON --- Google this is not.
<figure> To exclude posts/pages from search results add `search_omit: true` to their YAML Front Matter.
<img src="{{ site.url }}/images/simple-search-screenshot.jpg" alt="search screenshot">
<figcaption>Search your site by post title</figcaption>
</figure>
--- ---