Skip to content

Commit

Permalink
add flex search
Browse files Browse the repository at this point in the history
  • Loading branch information
z3by committed Jan 22, 2020
1 parent 14f2a6a commit 4722e8a
Show file tree
Hide file tree
Showing 20 changed files with 15,131 additions and 3 deletions.
325 changes: 325 additions & 0 deletions SearchBox.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,325 @@
<template>
<div class="search-box">
<input
@input="query = $event.target.value"
aria-label="Search"
:value="query"
:class="{ 'focused': focused }"
:placeholder="placeholder"
autocomplete="off"
spellcheck="false"
@focus="focused = true"
@blur="focused = false"
@keyup.enter="go(focusIndex)"
@keyup.up="onUp"
@keyup.down="onDown"
ref="input"
>
<ul
class="suggestions"
v-if="showSuggestions"
:class="{ 'align-right': alignRight }"
@mouseleave="unfocus"
>
<li
class="suggestion"
v-for="(s, i) in suggestions"
:key="i"
:class="{ focused: i === focusIndex }"
@mousedown="go(i)"
@mouseenter="focus(i)"
>
<a
:href="s.path"
@click.prevent
>
<span class="page-title">{{ s.title || s.path }}</span>
</a>
</li>
</ul>
</div>
</template>

<script>
import Flexsearch from "flexsearch";
/* global SEARCH_MAX_SUGGESTIONS, SEARCH_PATHS, SEARCH_HOTKEYS */
export default {
data () {
return {
query: '',
focused: false,
focusIndex: 0,
placeholder: undefined,
index: null
}
},
mounted () {
this.placeholder = this.$site.themeConfig.searchPlaceholder || ''
document.addEventListener('keydown', this.onHotkey)
this.setupFlexSearch()
},
beforeDestroy () {
document.removeEventListener('keydown', this.onHotkey)
},
computed: {
showSuggestions () {
return (
this.focused
&& this.suggestions
&& this.suggestions.length
)
},
suggestions () {
const query = this.query.trim().toLowerCase()
if (!query) {
return
}
const result = this.index.search(query)
return result
},
// make suggestions align right when there are not enough items
alignRight () {
const navCount = (this.$site.themeConfig.nav || []).length
const repo = this.$site.repo ? 1 : 0
return navCount + repo <= 2
}
},
methods: {
getPageLocalePath (page) {
for (const localePath in this.$site.locales || {}) {
if (localePath !== '/' && page.path.indexOf(localePath) === 0) {
return localePath
}
}
return '/'
},
isSearchable (page) {
let searchPaths = SEARCH_PATHS
// all paths searchables
if (searchPaths === null) { return true }
searchPaths = Array.isArray(searchPaths) ? searchPaths : new Array(searchPaths)
return searchPaths.filter(path => {
return page.path.match(path)
}).length > 0
},
onHotkey (event) {
if (event.srcElement === document.body && SEARCH_HOTKEYS.includes(event.key)) {
this.$refs.input.focus()
event.preventDefault()
}
},
onUp () {
if (this.showSuggestions) {
if (this.focusIndex > 0) {
this.focusIndex--
} else {
this.focusIndex = this.suggestions.length - 1
}
}
},
onDown () {
if (this.showSuggestions) {
if (this.focusIndex < this.suggestions.length - 1) {
this.focusIndex++
} else {
this.focusIndex = 0
}
}
},
go (i) {
if (!this.showSuggestions) {
return
}
const path = this.suggestions[i].path
if (this.$route.path !== path) {
this.$router.push(this.suggestions[i].path)
};
this.query = ''
this.focusIndex = 0
},
focus (i) {
this.focusIndex = i
},
unfocus () {
this.focusIndex = -1
},
setupFlexSearch () {
let defaultOptions = {
encode: "balance",
tokenize: "forward",
threshold: 0,
async: false,
worker: false,
cache: false
}
let options = this.$site.themeConfig.flexSearchOptions || defaultOptions
options = {
...options,
doc: {
id: "key",
field: ["title", "content"]
}
}
this.index = new Flexsearch(options);
const { pages } = this.$site;
this.index.add(pages);
}
}
}
</script>

<style lang="stylus">
.search-box {
display: inline-block;
position: relative;
margin-right: 1rem;
input {
cursor: text;
width: 10rem;
height: 2rem;
color: lighten($textColor, 25%);
display: inline-block;
border: 1px solid darken($borderColor, 10%);
border-radius: 2rem;
font-size: 0.9rem;
line-height: 2rem;
padding: 0 0.5rem 0 2rem;
outline: none;
transition: all 0.2s ease;
background: #fff url('search.svg') 0.6rem 0.5rem no-repeat;
background-size: 1rem;
&:focus {
cursor: auto;
border-color: $accentColor;
}
}
.suggestions {
background: #fff;
width: 20rem;
position: absolute;
top: 1.5rem;
border: 1px solid darken($borderColor, 10%);
border-radius: 6px;
padding: 0.4rem;
list-style-type: none;
&.align-right {
right: 0;
}
}
.suggestion {
line-height: 1.4;
padding: 0.4rem 0.6rem;
border-radius: 4px;
cursor: pointer;
a {
white-space: normal;
color: lighten($textColor, 35%);
.page-title {
font-weight: 600;
}
.header {
font-size: 0.9em;
margin-left: 0.25em;
}
}
&.focused {
background-color: #f3f4f5;
a {
color: $accentColor;
}
}
}
}
@media (max-width: $MQNarrow) {
.search-box {
input {
cursor: pointer;
width: 0;
border-color: transparent;
position: relative;
&:focus {
cursor: text;
left: 0;
width: 10rem;
}
}
}
}
// Match IE11
@media all and (-ms-high-contrast: none) {
.search-box input {
height: 2rem;
}
}
@media (max-width: $MQNarrow) and (min-width: $MQMobile) {
.search-box {
.suggestions {
left: 0;
}
}
}
@media (max-width: $MQMobile) {
.search-box {
margin-right: 0;
input {
left: 1rem;
}
.suggestions {
right: 0;
}
}
}
@media (max-width: $MQMobileNarrow) {
.search-box {
.suggestions {
width: calc(100vw - 4rem);
}
input:focus {
width: 8rem;
}
}
}
</style>
13 changes: 13 additions & 0 deletions example/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
pids
logs
node_modules
npm-debug.log
coverage/
run
dist
public
.DS_Store
.nyc_output
.basement
config.local.js
basement_dist
13 changes: 13 additions & 0 deletions example/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# example

>
## Development

```bash
yarn dev
yarn build
```

For more details, please head VuePress's [documentation](https://v1.vuepress.vuejs.org/).

15 changes: 15 additions & 0 deletions example/docs/.vuepress/components/Foo/Bar.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<template>
<p class="demo">
{{ msg }}
</p>
</template>

<script>
export default {
data () {
return {
msg: 'Hello this is <Foo-Bar>'
}
}
}
</script>
3 changes: 3 additions & 0 deletions example/docs/.vuepress/components/OtherComponent.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<template>
<p class="demo">This is another component</p>
</template>
15 changes: 15 additions & 0 deletions example/docs/.vuepress/components/demo-component.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<template>
<p class="demo">
{{ msg }}
</p>
</template>

<script>
export default {
data() {
return {
msg: 'Hello this is <demo-component>'
}
}
}
</script>
Loading

0 comments on commit 4722e8a

Please sign in to comment.