Skip to content
Snippets Groups Projects
HomeSearchInput.vue 5.31 KiB
Newer Older
Emmanuel Salomon's avatar
Emmanuel Salomon committed
<template>
  <section class="bg-gray-100 dark:bg-gray-800">
    <div class="container py-12 relative prose">
      <div class="flex justify-evenly">
          ref="search"
          v-model="query"
          type="search"
          :placeholder="placeholder"
          class="w-full"
          :input-class="inputClass"
          icon="search"
          :icon-class="iconClass"
          icon-wrapper-class="top-0.5"
          @keyup.enter="search()"
        />
        <t-button :class="buttonClass" :text="$t('search')" @click="search()" />
      </div>
    </div>
  </section>
Emmanuel Salomon's avatar
Emmanuel Salomon committed
</template>

<script>
export default {
  props: {
    inputClass: {
      type: String,
      default: 'text-2xl rounded-full',
    },
    iconClass: {
      type: String,
      default: 'text-2xl text-blue-100 dark:text-gray-600',
    },
    buttonClass: {
      type: String,
      default: 'text-xl ml-6 rounded-full',
    },
  },
Emmanuel Salomon's avatar
Emmanuel Salomon committed
  data() {
    return {
Emmanuel Salomon's avatar
Emmanuel Salomon committed
      query: null,
      placeholder: '',

      timeout: null,
      typeSpeed: 50,
      backDelay: 1000,
      backSpeed: 5,
      strPos: 0,
      arrayPos: 0,
      curString: null,
      curStrPos: null,
      strings: [
        'Chercher sur le site...',
        'Chercher un site sur la monnaie libre...',
        'Chercher un groupe local, une asso...',
        "Besoin d'aide ? Une question ? (FAQ)",
        "Besoin d'un tutoriel ? Une vidéo ?",
        'Un terme à expliquer ? (Lexique)',
      ],
      smartBackspace: true,
Emmanuel Salomon's avatar
Emmanuel Salomon committed
  mounted() {
    this.typewrite(this.strings[this.arrayPos], this.strPos)
  },
Emmanuel Salomon's avatar
Emmanuel Salomon committed
  methods: {
Emmanuel Salomon's avatar
Emmanuel Salomon committed
    search() {
      if (this.query) {
        this.$router.push(`/recherche?q=${this.query}`)
      } else {
        this.$refs.search.focus()
Emmanuel Salomon's avatar
Emmanuel Salomon committed
      }
    },
    typewrite(curString, curStrPos) {
      const numChars = 1
      // skip over any HTML chars
      curStrPos = this.typeHtmlChars(curString, curStrPos)

      this.timeout = setTimeout(() => {
        // We're done with this sentence!
        if (curStrPos >= curString.length) {
          this.doneTyping(curString, curStrPos)
        } else {
          this.keepTyping(curString, curStrPos, numChars)
        }
      }, this.typeSpeed)
    },
    keepTyping(curString, curStrPos, numChars) {
      // start typing each new char into existing string
      // curString: arg, this.el.html: original text inside element
      curStrPos += numChars
      const nextString = curString.substr(0, curStrPos)
      this.placeholder = nextString
      // loop the function
      this.typewrite(curString, curStrPos)
    },
    doneTyping(curString, curStrPos) {
      this.timeout = setTimeout(() => {
        this.backspace(curString, curStrPos)
      }, this.backDelay)
    },
    typeHtmlChars(curString, curStrPos) {
      const curChar = curString.substr(curStrPos).charAt(0)
      if (curChar === '<' || curChar === '&') {
        let endTag = ''
        if (curChar === '<') {
          endTag = '>'
        } else {
          endTag = ';'
        }
        while (curString.substr(curStrPos + 1).charAt(0) !== endTag) {
          curStrPos++
          if (curStrPos + 1 > curString.length) {
            break
          }
        }
        curStrPos++
      }
      return curStrPos
    },
    backspace(curString, curStrPos) {
      this.timeout = setTimeout(() => {
        curStrPos = this.backSpaceHtmlChars(curString, curStrPos, this)
        // replace text with base text + typed characters
        const curStringAtPosition = curString.substr(0, curStrPos)
        this.placeholder = curStringAtPosition

        // if smartBack is enabled
        if (this.smartBackspace) {
          // the remaining part of the current string is equal of the same part of the new string
          const nextString = this.strings[this.arrayPos + 1]
          if (
            nextString &&
            curStringAtPosition === nextString.substr(0, curStrPos)
          ) {
            this.stopNum = curStrPos
          } else {
            this.stopNum = 0
          }
        }

        // if the number (id of character in current string) is
        // less than the stop number, keep going
        if (curStrPos > this.stopNum) {
          // subtract characters one by one
          curStrPos--
          // loop the function
          this.backspace(curString, curStrPos)
        } else if (curStrPos <= this.stopNum) {
          // if the stop number has been reached, increase
          // array position to next string
          this.arrayPos++
          // When looping, begin at the beginning after backspace complete
          if (this.arrayPos === this.strings.length) {
            this.arrayPos = 0
            this.typewrite(this.strings[this.arrayPos], this.strPos)
          } else {
            this.typewrite(this.strings[this.arrayPos], curStrPos)
          }
        }
      }, this.backSpeed)
    },
    backSpaceHtmlChars(curString, curStrPos) {
      const curChar = curString.substr(curStrPos).charAt(0)
      if (curChar === '>' || curChar === ';') {
        let endTag = ''
        if (curChar === '>') {
          endTag = '<'
        } else {
          endTag = '&'
        }
        while (curString.substr(curStrPos - 1).charAt(0) !== endTag) {
          curStrPos--
          if (curStrPos < 0) {
            break
          }
        }
        curStrPos--
      }
      return curStrPos
Emmanuel Salomon's avatar
Emmanuel Salomon committed
    },
  },
}
</script>

<style lang="scss" scoped></style>