| 
									
										
										
										
											2018-09-28 10:19:11 +02:00
										 |  |  | <template> | 
					
						
							|  |  |  |   <div class="search-box"> | 
					
						
							|  |  |  |     <input | 
					
						
							|  |  |  |       @input="query = $event.target.value" | 
					
						
							|  |  |  |       aria-label="Search" | 
					
						
							|  |  |  |       :value="query" | 
					
						
							|  |  |  |       autocomplete="off" | 
					
						
							|  |  |  |       spellcheck="false" | 
					
						
							|  |  |  |       @focus="focused = true" | 
					
						
							|  |  |  |       @blur="focused = false" | 
					
						
							|  |  |  |       @keyup.enter="go(focusIndex)" | 
					
						
							|  |  |  |       @keyup.up="onUp" | 
					
						
							| 
									
										
										
										
											2018-10-28 08:15:31 +01:00
										 |  |  |       @keyup.down="onDown" | 
					
						
							|  |  |  |       placeholder="Search" | 
					
						
							|  |  |  |     > | 
					
						
							| 
									
										
										
										
											2018-09-28 10:19:11 +02:00
										 |  |  |     <ul class="suggestions" | 
					
						
							|  |  |  |       v-if="showSuggestions" | 
					
						
							|  |  |  |       :class="{ 'align-right': alignRight }" | 
					
						
							|  |  |  |       @mouseleave="unfocus"> | 
					
						
							|  |  |  |       <li class="suggestion" v-for="(s, i) in suggestions"
 | 
					
						
							|  |  |  |         :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> | 
					
						
							|  |  |  |           <span v-if="s.header" class="header">> {{ s.header.title }}</span> | 
					
						
							|  |  |  |         </a> | 
					
						
							|  |  |  |       </li> | 
					
						
							|  |  |  |     </ul> | 
					
						
							|  |  |  |   </div> | 
					
						
							|  |  |  | </template> | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | <script> | 
					
						
							|  |  |  | export default { | 
					
						
							|  |  |  |   data () { | 
					
						
							|  |  |  |     return { | 
					
						
							|  |  |  |       query: '', | 
					
						
							|  |  |  |       focused: false, | 
					
						
							|  |  |  |       focusIndex: 0 | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   }, | 
					
						
							|  |  |  |   computed: { | 
					
						
							|  |  |  |     showSuggestions () { | 
					
						
							|  |  |  |       return ( | 
					
						
							|  |  |  |         this.focused && | 
					
						
							|  |  |  |         this.suggestions && | 
					
						
							|  |  |  |         this.suggestions.length | 
					
						
							|  |  |  |       ) | 
					
						
							|  |  |  |     }, | 
					
						
							|  |  |  |     suggestions () { | 
					
						
							|  |  |  |       const query = this.query.trim().toLowerCase() | 
					
						
							|  |  |  |       if (!query) { | 
					
						
							|  |  |  |         return | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       const { pages, themeConfig } = this.$site | 
					
						
							|  |  |  |       const max = themeConfig.searchMaxSuggestions || 5 | 
					
						
							|  |  |  |       const searchContext = this.$route.path.split('/').slice(1)[0] | 
					
						
							|  |  |  |       const localePath = this.$localePath | 
					
						
							|  |  |  |       const matches = item => ( | 
					
						
							|  |  |  |         item.title && | 
					
						
							|  |  |  |         item.title.toLowerCase().indexOf(query) > -1 | 
					
						
							|  |  |  |       ) | 
					
						
							|  |  |  |       const res = [] | 
					
						
							|  |  |  |       for (let i = 0; i < pages.length; i++) { | 
					
						
							|  |  |  |         if (res.length >= max) break | 
					
						
							|  |  |  |         const p = pages[i] | 
					
						
							| 
									
										
										
										
											2018-10-25 20:59:49 +02:00
										 |  |  |         // filter out results that do not match current version context
 | 
					
						
							| 
									
										
										
										
											2018-10-26 14:19:04 +02:00
										 |  |  |         if ( ! p.path.startsWith(searchContext, 1)) { | 
					
						
							|  |  |  |           continue; | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2018-09-28 10:19:11 +02:00
										 |  |  |         // filter out results that do not match current locale
 | 
					
						
							|  |  |  |         if (this.getPageLocalePath(p) !== localePath) continue | 
					
						
							|  |  |  |         if (matches(p)) { | 
					
						
							|  |  |  |           res.push(p) | 
					
						
							|  |  |  |         } else if (p.headers) { | 
					
						
							|  |  |  |           for (let j = 0; j < p.headers.length; j++) { | 
					
						
							|  |  |  |             if (res.length >= max) break | 
					
						
							|  |  |  |             const h = p.headers[j] | 
					
						
							|  |  |  |             if (matches(h)) { | 
					
						
							|  |  |  |               res.push(Object.assign({}, p, { | 
					
						
							|  |  |  |                 path: p.path + '#' + h.slug, | 
					
						
							|  |  |  |                 header: h | 
					
						
							|  |  |  |               })) | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |           } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       return res | 
					
						
							|  |  |  |     }, | 
					
						
							|  |  |  |     // 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 '/' | 
					
						
							|  |  |  |     }, | 
					
						
							|  |  |  |     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 | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       this.$router.push(this.suggestions[i].path) | 
					
						
							|  |  |  |       this.query = '' | 
					
						
							|  |  |  |       this.focusIndex = 0 | 
					
						
							|  |  |  |     }, | 
					
						
							|  |  |  |     focus (i) { | 
					
						
							|  |  |  |       this.focusIndex = i | 
					
						
							|  |  |  |     }, | 
					
						
							|  |  |  |     unfocus () { | 
					
						
							|  |  |  |       this.focusIndex = -1 | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | </script> | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | <style lang="stylus"> | 
					
						
							|  |  |  | @import './styles/config.styl' | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | .search-box | 
					
						
							|  |  |  |   display inline-block | 
					
						
							|  |  |  |   position relative | 
					
						
							|  |  |  |   margin-right 0.5rem | 
					
						
							|  |  |  |   input | 
					
						
							|  |  |  |     cursor text | 
					
						
							|  |  |  |     width 10rem | 
					
						
							|  |  |  |     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 .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 | 
					
						
							|  |  |  |       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 | 
					
						
							|  |  |  |       left 1rem | 
					
						
							|  |  |  |       &:focus | 
					
						
							|  |  |  |         cursor text | 
					
						
							|  |  |  |         left 0 | 
					
						
							|  |  |  |         width 10rem | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | @media (max-width: $MQNarrow) and (min-width: $MQMobile) | 
					
						
							|  |  |  |   .search-box | 
					
						
							|  |  |  |     .suggestions | 
					
						
							|  |  |  |       left 0 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | @media (max-width: $MQMobile) | 
					
						
							|  |  |  |   .search-box | 
					
						
							|  |  |  |     margin-right 0 | 
					
						
							|  |  |  |     .suggestions | 
					
						
							|  |  |  |       right 0 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | @media (max-width: $MQMobileNarrow) | 
					
						
							|  |  |  |   .search-box | 
					
						
							|  |  |  |     .suggestions | 
					
						
							|  |  |  |       width calc(100vw - 4rem) | 
					
						
							|  |  |  |     input:focus | 
					
						
							|  |  |  |       width 8rem | 
					
						
							|  |  |  | </style> |