<template> <div class="container"> <slot name="header"> <PageHeader v-if="title" :document="{ title }" /> </slot> <div class="md:flex justify-between mb-8"> <div class="w-full"> <div class="md:flex"> <TInputIcon v-model="query" type="search" :placeholder="searchPlaceholder || $t('search')" input-class="rounded-full" icon="search" icon-class="text-2xl text-blue-100 dark:text-gray-600" icon-wrapper-class="top-0.5" class="flex-1" has-focus /> <slot name="search" /> </div> <slot name="items" :items="computedResults"> <section v-if="computedResults.length" class="mt-8"> <transition-group name="list"> <nuxt-link v-for="(item, index) of computedResults" :id=" (index === 0 || computedResults[index - 1].firstLetter !== item.firstLetter) && item.firstLetter " :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 " > <slot name="item" :item="item"> <h1 class="text-xl" v-html="item.title" /> <div class="font-light text-gray-600 dark:text-gray-400" v-html="item.description" /> </slot> </nuxt-link> </transition-group> </section> </slot> <SearchNoResult v-if="query.length && hasNoResult"> <slot name="noResult" :query="query"> <ul class="list-disc list-inside mt-3"> <li> <nuxt-link :to="`/recherche?q=${query}`" class="hover:underline" > {{ $t('noResult.searchWholeSite', { query }) }} </nuxt-link> </li> <li> <a :href="`https://forum.monnaie-libre.fr/search?q=${query}`" class="hover:underline" target="_blank" rel="noopener noreferrer" > {{ $t('noResult.searchOnForum', { query }) }} </a> </li> </ul> </slot> </SearchNoResult> </div> <aside class="sticky h-full top-24 ml-12 bottom-12"> <slot name="sidebar" :query="query" :computedResults="computedResults" /> </aside> </div> <slot name="footer" :query="query" :computedResults="computedResults" /> </div> </template> <script> import { debounce, highlight } from '~/libs/helpers' export default { name: 'SearchContainer', props: { results: { type: Array, required: true, }, title: { type: String, default: null, }, searchPlaceholder: { type: String, default: null, }, searchFunction: { type: Function, required: true, }, getQueryUrl: { type: Function, default(q) { return new URLSearchParams({ q, }) }, }, }, data() { return { query: '', searchResults: [], hasNoResult: false, } }, computed: { computedResults() { return this.searchResults.map((item) => ({ ...item, firstLetter: item.title.replace(/^<mark>/, '')[0].toUpperCase(), // ! remove <mark> if title start by highlighten query })) }, }, watch: { query: debounce(function () { this.search() }, 500), }, mounted() { this.searchResults = this.results this.query = this.$route.query.q || '' }, methods: { async search(force) { const query = this.query.trim() if (query.length || force) { const results = await this.searchFunction(this.query) if (results.length) { this.hasNoResult = false this.searchResults = highlight(this.query, results) } else { this.hasNoResult = true this.searchResults = [] } } else { this.searchResults = this.results this.hasNoResult = false } // Replace url with query string const queryUrl = this.getQueryUrl(query).toString() history.replaceState( {}, null, this.$route.path + (queryUrl.length ? `?${queryUrl}` : '') ) }, }, } // @ManUtopiK: Test avec composition-api // import { // defineComponent, // ref, // useContext, // useAsync, // useFetch, // onBeforeMount, // watch, // } from '@nuxtjs/composition-api' // export default defineComponent({ // name: 'FaqPage', // setup() { // const { route, query, $content } = useContext() // const query = ref(query.value.q) // const results = useAsync(() => $content('faq').fetch()) // const documentFAQ = useAsync(() => $content('ui/faq').fetch()) // onBeforeMount(async () => { // results.value = await $content('faq').search(query.value).fetch() // }) // watch(query, async (val) => { // val = val.trim() // results.value = await $content('faq').search(val).fetch() // const queryPath = val.length ? `?s=${encodeURIComponent(val)}` : '' // history.pushState({}, null, route.value.path + queryPath) // }) // console.log(documentFAQ.value) // return { query, results, documentFAQ } // }, // }) </script>