diff --git a/components/home/HomeSearch.vue b/components/home/HomeSearch.vue index dd2412db31b1de5da934585c4a8f5bc2657a3e9c..75f3188cccb2520d4e2be18dfae0eccc1c119d5f 100644 --- a/components/home/HomeSearch.vue +++ b/components/home/HomeSearch.vue @@ -1,33 +1,23 @@ <template> - <section class="bg-blue-100"> - <div class="container py-12 relative"> - <h1 - class="font-bold mb-8 text-3xl text-center text-gray-700 dark:text-white dark:text-opacity-50" - > - Chercher... - </h1> - + <section class="bg-gray-100"> + <div class="container py-12 relative prose"> <div class="flex justify-evenly"> <TInputIcon - v-model="querySite" + ref="search" + v-model="query" type="search" - :placeholder="$t('home.searchSitePlaceholder')" + :placeholder="placeholder" class="w-full" - input-class="text-xl rounded-full" + input-class="text-2xl rounded-full" icon="search" icon-class="text-2xl text-blue-100 dark:text-gray-600" - @keyup.enter="$router.push(`/recherche?q=${querySite}`)" + @keyup.enter="search()" /> - <TInputIcon - v-model="queryRessources" - type="search" - :placeholder="$t('home.searchRessourcesPlaceholder')" - class="w-full mx-8" - input-class="text-xl rounded-full" - icon="search" - icon-class="text-2xl text-blue-100 dark:text-gray-600" - @keyup.enter="$router.push(`/ressources?q=${queryRessources}`)" + <t-button + class="ml-6 rounded-full text-xl" + :text="$t('search')" + @click="search()" /> </div> </div> @@ -38,13 +28,146 @@ export default { data() { return { - querySite: null, - queryRessources: null, + 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, } }, + mounted() { + this.typewrite(this.strings[this.arrayPos], this.strPos) + }, methods: { - searchOnSite() { - this.$router.push(`/recherche?q=${this.querySite}`) + search() { + if (this.query) { + this.$router.push(`/recherche?q=${this.query}`) + } else { + this.$refs.search.$children[0].$el.focus() + } + }, + 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 }, }, } diff --git a/components/ressources/RessourcesItem.vue b/components/ressources/RessourcesItem.vue index 5a485ff7e257c53c8ce21c14d0fc6f2d26ab3b60..cd5a554dc96f435a68ac7882c436700df496e0b7 100644 --- a/components/ressources/RessourcesItem.vue +++ b/components/ressources/RessourcesItem.vue @@ -1,5 +1,5 @@ <template> - <div class="flex cursor-pointer mb-8 w-1/2 p-0.5 pr-4 overflow-hidden"> + <div class="flex cursor-pointer mb-8 p-0.5 pr-4 overflow-hidden"> <a class="flex-none mr-4 shadow rounded bg-gray-100" style="width: 200px; height: 150px" diff --git a/locales/fr.js b/locales/fr.js index 4ac86ed116d9ef88e62e2ca096ebf1655515f2c3..20d0d76bd3096128d07eafbcd3552803131492e5 100644 --- a/locales/fr.js +++ b/locales/fr.js @@ -1,6 +1,6 @@ export default { cancel: 'Annuler', - search: 'Rechercher', + search: 'Chercher', goBack: 'Retour', noResult: { diff --git a/pages/recherche.vue b/pages/recherche.vue index c090ee0aa7d4bf5186c987947fee47e2335b3c3b..564b1c1e4a3bd76e796da9348b8c875093d7c7c9 100644 --- a/pages/recherche.vue +++ b/pages/recherche.vue @@ -5,15 +5,45 @@ :search-placeholder="$t('recherche.searchPlaceholder')" :search-function="searchFunction" > - <template #item="{ item }"> - <div class="rounded text-gray-400 text-xs uppercase font-semibold"> - {{ item.path.replace(/\/[^\/]*$/, '').substr(1) }} + <template #items="{ items }"> + <div class="flex"> + <section class="mt-8 w-1/2"> + <transition-group name="list"> + <nuxt-link + v-for="item of items.filter( + (page) => !page.path.startsWith('/ressources') + )" + :key="item.path" + :to="item.path.replace(/^\/pages\//, '/')" + class="block cursor-pointer dark-hover:bg-gray-700 hover:bg-gray-100 mb-2 p-2 rounded-lg transition-colors" + > + <div + class="rounded text-gray-400 text-xs uppercase font-semibold" + > + {{ item.path.replace(/\/[^\/]*$/, '').substr(1) }} + </div> + <h1 class="text-xl" v-html="item.title" /> + <div + class="font-light text-gray-600 dark:text-gray-400" + v-html="item.description" + /> + </nuxt-link> + </transition-group> + </section> + + <section class="mt-8 w-1/2"> + <transition-group name="list" class="flex flex-wrap"> + <RessourcesItem + v-for="item of items + .filter((page) => page.path.startsWith('/ressources')) + .slice(0, 3)" + :key="item.path" + :item="item" + @select-category="$router.push(`/ressources?filters=${$event}`)" + /> + </transition-group> + </section> </div> - <h1 class="text-xl" v-html="item.title" /> - <div - class="font-light text-gray-600 dark:text-gray-400" - v-html="item.description" - /> </template> <div slot="noResult"> @@ -49,26 +79,29 @@ </template> <script> -import { debounce, highlight, reduceResults } from '~/libs/helpers' +import { debounce, highlight } from '~/libs/helpers' -const fields = ['title', 'description', 'path'] +// const fields = ['title', 'description', 'path'] export default { name: 'RecherchePage', data() { return { forumResults: [], + ressourcesResults: [], } }, methods: { async searchFunction(query) { let results = await this.$content({ deep: true }) .search(query) - .only(fields) + // .only(fields) .fetch() if (results.length) { - results = reduceResults(results) + results = results.filter( + (page) => !page.path.startsWith('/ui') && page.title + ) results.length < 6 ? this.searchOnForum(query) : (this.forumResults = []) diff --git a/pages/ressources.vue b/pages/ressources.vue index 1766caa3bffb9392d95cd70d74d826e4e1431880..d69e0a1e5d178b8758df2e2e9b43dd9132e6a97d 100644 --- a/pages/ressources.vue +++ b/pages/ressources.vue @@ -22,6 +22,7 @@ v-for="item in items" :key="item.path" :item="item" + class="w-1/2" @select-category="selectedCategories = $event" /> </transition-group>