<template>
  <div class="search-box">
    <input
      aria-label="Search"
      :value="query"
      autocomplete="off"
      spellcheck="false"
      placeholder="请查询"
      @input="query = $event.target.value"
      @focus="focused = true"
      @blur="focused = false"
      @keyup.enter="go(focusIndex)"
      @keyup.up="onUp"
      @keyup.down="onDown"
    >
    <ul v-if="showSuggestions"
        class="suggestions"
        :class="{ 'align-right': alignRight }"
        @mouseleave="unfocus"
    >
      <li v-for="(s, i) in suggestions" :key="i" class="suggestion"
          :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">&gt; {{ 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 () {
      /**
       * 查询
       * 数据源（菜单可见内容，是懒加载的，所以页面搜索后端处理会好点）：
       * 1. # title
       * 2. ## headers
       */
      const query = this.query.trim().toLowerCase()
      if (!query) {
        return
      }

      const { pages, themeConfig } = this.$site
      const max = themeConfig.searchMaxSuggestions || 5
      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]
        // 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 4px
    font-size 0.9rem
    line-height 1.9rem
    padding 0 2rem 0 0.5rem
    outline none
    transition all .2s ease
    background #fff url(../assets/search.svg) right 0.6rem center no-repeat
    background-size 1rem
    &:focus
      cursor auto
      border-color $accentColor
  .suggestions
    background #f1f0f3
    width 20rem
    position absolute
    top 1.5rem
    border 1px solid $borderColor
    border-radius 4px
    padding 0.4rem 0
    list-style-type none
    box-shadow 0 2px 10px 0 rgba(0,0,0,0.15)
    &.align-right
      right 0
  .suggestion
    line-height 1.4
    padding 0.4rem 0.8rem
    cursor pointer
    a
      color #737f8c
      .page-title
        font-weight 600
      .header
        font-size 0.9em
        margin-left 0.25em
    &.focused
      background-color rgba(181,174,206,0.2)
      a
        color $accentColor

@media screen and (prefers-color-scheme: dark)
  body:not(.theme-light)
    .search-box
      input
        color darken($textColorDark, 25%)
        border-color lighten($borderColorDark, 10%)
        background-color $bgColorDark
      .suggestions
        border-color $borderColorDark
        background #282829
      .suggestion
        a
          color darken($textColorDark, 14%)
        &.focused
          background-color lighten(#282829, 10%)
          a
            color $accentColor
@media screen
  body.theme-dark
    .search-box
      input
        color darken($textColorDark, 25%)
        border-color lighten($borderColorDark, 10%)
        background-color $bgColorDark
      .suggestions
        border-color $borderColorDark
        background #282829
      .suggestion
        a
          color darken($textColorDark, 14%)
        &.focused
          background-color lighten(#282829, 10%)
          a
            color $accentColor
@media (max-width: $MQNarrow)
  .search-box
    input
      cursor pointer
      width 0
      border-color transparent
      background-color unset
      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>
