Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add local search, closes #5 #31

Merged
merged 17 commits into from
Sep 9, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 8 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,21 +12,26 @@ Then, in your Saber config file:

```yml
theme: tailsaw
plugins:
- saber-plugin-query-posts
- saber-plugin-prismjs
- saber-plugin-critical
# If you want to enable local search:
- saber-plugin-search
```

This starter template includes samples of common page types, and comes pre-configured with:

- A fully responsive theme
- [Tailwind CSS](https://tailwindcss.com/), a utility CSS framework that allows you to customize your design without touching a line of CSS
- Syntax highlighting using [Prism](https://prismjs.com)
- A search bar which indexes your content automatically (when `saber-plugin-search` is used)
- Progress bar and page transition
- A custom 404 page
- A component for accepting newsletter signups
- A sample contact form

Coming soon:

- A search bar which indexes your content automatically and requires zero configuration
- RSS feed and sitemap generator
- Config options

Expand Down Expand Up @@ -57,7 +62,7 @@ featured: true

### Adding Assets

You can easily include assets in your posts, just by [linking to their relative location](https://saber.land/docs/images-fonts-and-files.html).
You can easily include assets in your posts, just by [linking to their relative location](https://saber.land/docs/images-fonts-and-files.html).

---

Expand Down
3 changes: 2 additions & 1 deletion example/pages/index.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
---
injectAllPosts: true
layout: home
title: Home
---

foo
Welcome to our site!
3 changes: 3 additions & 0 deletions example/saber-config.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,9 @@ module.exports = {
},
{
resolve: 'saber-plugin-critical'
},
{
resolve: 'saber-plugin-search'
}
]
}
11 changes: 8 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -59,8 +59,14 @@
"bracketSpacing": true
},
"dependencies": {
"fuse.js": "^3.4.5",
"lodash.debounce": "^4.0.8",
"nprogress": "^0.2.0",
"typeface-nunito-sans": "^0.0.72"
"typeface-nunito-sans": "^0.0.72",
"saber-plugin-critical": "^1.0.2",
"saber-plugin-prismjs": "^0.2.1",
"saber-plugin-query-posts": "^0.4.0",
"saber-plugin-search": "^0.1.0"
},
"devDependencies": {
"@fullhuman/postcss-purgecss": "^1.2.0",
Expand All @@ -79,7 +85,6 @@
"xo": "^0.24.0"
},
"peerDependencies": {
"saber": ">=0.7.0",
"saber-plugin-query-posts": ">=0.4.0"
"saber": ">=0.8.0"
}
}
11 changes: 7 additions & 4 deletions src/components/SiteHeader.vue
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
class="flex items-center shadow bg-white border-b h-24 py-4"
role="banner"
>
<div class="container flex items-center max-w-8xl mx-auto px-4 lg:px-8">
<div class="container flex items-center max-w-4xl mx-auto px-4 lg:px-8">
<div class="flex items-center">
<saber-link
to="/"
Expand All @@ -18,14 +18,16 @@
/>

<h1
class="text-lg md:text-2xl text-blue-800 font-semibold hover:text-blue-600 my-0"
class="text-lg md:text-2xl text-blue-darkest font-semibold hover:text-blue-dark my-0"
>
{{ $siteConfig.title }}
</h1>
</saber-link>
</div>

<div class="flex flex-1 justify-end items-center">
<SiteSearch v-if="$fetchSearchDatabase" />

<nav class="hidden lg:flex items-center justify-end text-lg">
<NavLink
class="ml-6 text-grey-darker hover:text-blue-dark"
Expand Down Expand Up @@ -72,7 +74,7 @@
'lg:block': nav
}"
>
<ul class="list-none p0 my-0">
<ul class="list-reset my-0">
<li class="pl-4">
<NavLink
class="nav-menu__item hover:text-blue"
Expand All @@ -88,9 +90,10 @@

<script>
import NavLink from './NavLink'
import SiteSearch from './SiteSearch'

export default {
components: { NavLink },
components: { NavLink, SiteSearch },
data() {
return {
nav: false
Expand Down
175 changes: 175 additions & 0 deletions src/components/SiteSearch.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,175 @@
<template>
<div class="flex flex-1 justify-end items-center text-right px-4">
<div
class="absolute md:relative w-full justify-end bg-white left-0 top-0 z-10 mt-7 md:mt-0 px-4 md:px-0"
:class="{ 'hidden md:flex': !searching }"
>
<label for="search" class="hidden">Search</label>

<input
class="transition-fast relative block h-10 w-full lg:w-1/2 lg:focus:w-3/4 bg-gray-100 border border-gray-500 focus:border-blue-400 outline-none cursor-pointer text-gray-700 px-4 pb-0 pt-px"
:class="{ 'transition-border': query, 'lg:w-3/4': query }"
autocomplete="off"
name="search"
placeholder="Search"
type="search"
ref="search"
@keyup="query = $refs.search.value"
@keyup.esc="reset()"
@keyup.enter="goTo()"
@blur="!results && reset()"
/>

<button
v-if="query || searching"
class="absolute top-0 right-0 leading-snug font-400 text-3xl text-blue-500 hover:text-blue-600 focus:outline-none pr-7 md:pr-3"
@click="reset()"
>
&times;
</button>

<transition name="fade">
<div
v-if="query"
class="absolute left-0 right-0 md:inset-auto w-full lg:w-3/4 text-left mb-4 md:mt-10"
>
<div
class="flex flex-col bg-white border border-b-0 border-t-0 border-blue-400 rounded-b-lg shadow-lg mx-4 md:mx-0"
>
<a
v-for="(result, index) in results"
class="bg-white hover:bg-blue-100 border-b border-blue-400 text-xl cursor-pointer p-4"
:class="{ 'rounded-b-lg': index === results.length - 1 }"
:title="result.title"
:key="result.permalink"
@click.prevent="goTo(result.permalink)"
>
{{ result.title }}

<span class="block font-normal text-gray-700 text-sm my-1">
{{ result.excerpt }}
</span>
</a>

<div
v-if="!results.length"
class="bg-white w-full hover:bg-blue-100 border-b border-blue-400 rounded-b-lg shadow cursor-pointer p-4"
>
<p class="my-0">
No results for <strong>{{ query }}</strong>
</p>
</div>
</div>
</div>
</transition>
</div>

<button
title="Start searching"
type="button"
class="flex md:hidden bg-gray-100 hover:bg-blue-100 justify-center items-center border border-gray-500 rounded-full focus:outline-none h-10 px-3"
@click.prevent="showInput()"
>
<img
src="../assets/img/magnifying-glass.svg"
alt="search icon"
class="h-4 w-4 max-w-none"
/>
</button>
</div>
</template>

<script>
import Fuse from 'fuse.js'
import debounce from 'lodash.debounce'

export default {
data() {
return {
searching: false,
query: '',
results: []
}
},
methods: {
showInput() {
this.searching = true
this.$nextTick(() => {
this.$refs.search.focus()
})
},
reset() {
this.$refs.search.value = ''
this.searching = false
this.results = []
this.query = ''
this.$refs.search.blur()
},
goTo(to) {
if (!to) to = this.results[0] && this.results[0].permalink
if (!to) return
this.$router.push(to)
this.reset()
},
search() {
if (window.__FUSE__) this.results = window.__FUSE__.search(this.query)
}
},
watch: {
query: debounce(
function() {
this.search()
},
50,
{
leading: true,
trailing: true
}
)
},
async mounted() {
if (!window.__FUSE__) {
const database = await this.$fetchSearchDatabase()
window.__FUSE__ = new Fuse(database, {
shouldSort: true,
keys: Object.keys(database[0])
})
}
}
}
</script>

<style scoped>
input[name='search'] {
background-image: url('../assets/img/magnifying-glass.svg');
background-position: 0.8em;
background-repeat: no-repeat;
border-radius: 25px;
text-indent: 1.2em;
}

input[name='search'].transition-border {
border-bottom-left-radius: 0;
border-bottom-right-radius: 0;
border-top-left-radius: 0.5rem;
border-top-right-radius: 0.5rem;
}

input[type='search']::-webkit-search-decoration,
input[type='search']::-webkit-search-cancel-button,
input[type='search']::-webkit-search-results-button,
input[type='search']::-webkit-search-results-decoration {
-webkit-appearance: none;
}

.fade-enter-active {
transition: opacity 0.5s;
}
.fade-leave-active {
transition: opacity 0s;
}
.fade-enter,
.fade-leave-to {
opacity: 0;
}
</style>
15 changes: 15 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -4039,6 +4039,11 @@ functional-red-black-tree@^1.0.1:
resolved "https://registry.yarnpkg.com/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz#1b0ab3bd553b2a0d6399d29c0e3ea0b252078327"
integrity sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=

fuse.js@^3.4.5:
version "3.4.5"
resolved "https://registry.yarnpkg.com/fuse.js/-/fuse.js-3.4.5.tgz#8954fb43f9729bd5dbcb8c08f251db552595a7a6"
integrity sha512-s9PGTaQIkT69HaeoTVjwGsLfb8V8ScJLx5XGFcKHg0MqLUH/UZ4EKOtqtXX9k7AFqCGxD1aJmYb8Q5VYDibVRQ==

gauge@~2.7.3:
version "2.7.4"
resolved "https://registry.yarnpkg.com/gauge/-/gauge-2.7.4.tgz#2c03405c7538c39d7eb37b317022e325fb018bf7"
Expand Down Expand Up @@ -5426,6 +5431,11 @@ lodash.camelcase@^4.1.1:
resolved "https://registry.yarnpkg.com/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz#b28aa6288a2b9fc651035c7711f65ab6190331a6"
integrity sha1-soqmKIorn8ZRA1x3EfZathkDMaY=

lodash.debounce@^4.0.8:
version "4.0.8"
resolved "https://registry.yarnpkg.com/lodash.debounce/-/lodash.debounce-4.0.8.tgz#82d79bff30a67c4005ffd5e2515300ad9ca4d7af"
integrity sha1-gteb/zCmfEAF/9XiUVMArZyk168=

lodash.defaults@4.2.0, lodash.defaults@^4.0.1:
version "4.2.0"
resolved "https://registry.yarnpkg.com/lodash.defaults/-/lodash.defaults-4.2.0.tgz#d09178716ffea4dde9e5fb7b37f6f0802274580c"
Expand Down Expand Up @@ -7933,6 +7943,11 @@ saber-plugin-query-posts@^0.4.0:
slugo "^0.2.3"
url-join "^4.0.0"

saber-plugin-search@^0.1.0:
version "0.1.0"
resolved "https://registry.yarnpkg.com/saber-plugin-search/-/saber-plugin-search-0.1.0.tgz#5d249c1c58dd33a47dfda3ed4f37ff40aef2f099"
integrity sha512-D9P5bxo0PnEXcrLJKdxpyfyIeZs2yb5YSJywjz1H4L5t79Qil9xx9MhYTU7x1dupurNAZZ+N4F63RTnez44Dqg==

saber-utils@^0.2.1:
version "0.2.1"
resolved "https://registry.yarnpkg.com/saber-utils/-/saber-utils-0.2.1.tgz#20d4942cb5a3c61b7da97119c5aaae69b5c8b356"
Expand Down