Browse Source

added search type dropdown with vue-select

Bachir Soussi Chiadmi 3 years ago
parent
commit
0f48e600b9
5 changed files with 223 additions and 62 deletions
  1. 96 28
      assets/css/app.scss
  2. 10 0
      package-lock.json
  3. 2 0
      package.json
  4. 112 33
      src/components/nav/Search.vue
  5. 3 1
      src/index.js

+ 96 - 28
assets/css/app.scss

@@ -552,35 +552,90 @@ footer[role="tools"]{
       background-color: $bleuroi;
       form{
         padding: 0.7em;
-        label[for="keys"]{
-          display: none;
-        }
-        input[type="text"]{
-          padding:0.3em;
-          font-size: 0.756em;
-          line-height: 1;
-          height:1em;
-          border:none;
-          border-radius: 2px;
+        fieldset{
+          padding:1em;
+          border: none;
+          &:not(:first-of-type){
+            border-left: 1px solid $grisclair;
+          }
         }
-        // input[type="submit"]{
-        //   #submit-search{
-        //     border:none;
-        //
-        //   }
-        // }
-        span.mdi{
-          display: inline-block;
-          font-size: 1.2em;
-          line-height:1.1;
-          vertical-align:middle;
-          width:1.2em; height:1.2em;
-          border-radius: 0.6em;
-          background-color: #fff;
-          color: $bleuroi;
-          text-align: center;
-          font-weight: 700;
-          cursor: pointer;
+        fieldset.search{
+          >div{
+            display: inline-block;
+            width:80%;
+            vertical-align: middle;
+          }
+          label[for="keys"]{
+            display: none;
+          }
+          input[type="text"]{
+            padding:0.3em;
+            box-sizing: border-box;
+            font-size: 0.756em;
+            line-height: 1;
+            width:100%;
+            height:1.2em;
+            border:none;
+            border-radius: 2px;
+          }
+          #search-type{
+            padding:0.2em 0 0 0;
+            div[role="combobox"]{
+              background-color: #fff;
+              padding:0;
+              border-radius: 2px;
+              border: none;
+            }
+            input[type="search"]{
+              margin:0;
+              padding:0;
+            }
+            .vs__search{
+              &, &:focus{
+                font-size: 0.756em;
+                line-height: 1;
+                height:1.2em;
+                border:none;
+                box-sizing: border-box;
+              }
+            }
+            .vs__actions{
+              padding:1px 3px;
+              svg[role="presentation"]{
+                transform: scale(0.8);
+                path{
+                  fill: $bleuroi;
+                }
+              }
+            }
+            .vs__selected{
+              margin:0;
+              padding:0;
+              line-height:1;
+              font-size: 0.756em;
+            }
+            // border-radius: 2px;
+            // border: none;
+          }
+          // input[type="submit"]{
+          //   #submit-search{
+          //     border:none;
+          //
+          //   }
+          // }
+          span.mdi{
+            display: inline-block;
+            font-size: 1.2em;
+            line-height:1.1;
+            vertical-align:middle;
+            width:1.2em; height:1.2em;
+            border-radius: 0.6em;
+            background-color: #fff;
+            color: $bleuroi;
+            text-align: center;
+            font-weight: 700;
+            cursor: pointer;
+          }
         }
       }
     }
@@ -594,6 +649,19 @@ footer[role="tools"]{
   }
 }
 
+// vue-select
+ul[role="listbox"]{
+  @include fontsans;
+  padding:0;
+  margin:0;
+  border:none;
+  li{
+    padding:0.3em;
+    margin:0;
+    font-size: 0.756em;
+    line-height: 1;
+  }
+}
 
 //  ___
 // |_ _|__ ___ _ _  ___

+ 10 - 0
package-lock.json

@@ -1063,6 +1063,11 @@
         "@types/yargs": "^13.0.0"
       }
     },
+    "@popperjs/core": {
+      "version": "2.4.4",
+      "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.4.4.tgz",
+      "integrity": "sha512-1oO6+dN5kdIA3sKPZhRGJTfGVP4SWV6KqlMOwry4J3HfyD68sl/3KmG7DeYUzvN+RbhXDnv/D8vNNB8168tAMg=="
+    },
     "@types/babel__core": {
       "version": "7.1.3",
       "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.3.tgz",
@@ -12066,6 +12071,11 @@
         "bezier-easing": "2.1.0"
       }
     },
+    "vue-select": {
+      "version": "3.10.7",
+      "resolved": "https://registry.npmjs.org/vue-select/-/vue-select-3.10.7.tgz",
+      "integrity": "sha512-6rvIYBNEp9y0xK/sq2ZzDCxKA2BoVNliyctOeMtzarQzvpLlab7l8zvqr2jhGZOxozp7jd2AvZxpF3Ivems2wQ=="
+    },
     "vue-server-renderer": {
       "version": "2.6.10",
       "resolved": "https://registry.npmjs.org/vue-server-renderer/-/vue-server-renderer-2.6.10.tgz",

+ 2 - 0
package.json

@@ -18,12 +18,14 @@
   "author": "Daniel Cook",
   "license": "MIT",
   "dependencies": {
+    "@popperjs/core": "^2.4.4",
     "axios": "^0.18.1",
     "vue": "^2.6.10",
     "vue-infinite-loading": "^2.4.5",
     "vue-meta": "^1.6.0",
     "vue-router": "^3.1.3",
     "vue-scrollto": "^2.18.1",
+    "vue-select": "^3.10.7",
     "vuex": "^3.1.1",
     "vuex-router-sync": "^5.0.0"
   },

+ 112 - 33
src/components/nav/Search.vue

@@ -1,48 +1,81 @@
 <template>
   <div id="search" class="col-11">
-    <form class="search-form">
-      <label for="keys">Search</label>
-      <input
-        id="keys"
-        v-model="keys"
-        type="text"
-        placeholder="search"
-        @keydown.enter.prevent="submit"
-      >
-      <span
-        v-if="!isloading"
-        class="mdi mdi-magnify"
-        title="rechercher"
-        @click.prevent="submit"
-        @keydown.enter.prevent="submit"
-      />
-      <span
-        v-else
-        class="mdi mdi-loading"
-        title="chargement"
-      />
-      <!-- <input
-        id="submit-search"
-        type="submit"
-        name="search"
-        value="Search"
-        class="mdi mdi-magnify"
-        @click.prevent="submit"
-        @keyup.enter="submit"
-      > -->
+    <form class="search-form row">
+      <fieldset class="search col-3">
+        <div>
+          <label for="keys">Search</label>
+          <input
+            id="keys"
+            v-model="keys"
+            type="text"
+            placeholder="search"
+            @keydown.enter.prevent="submit"
+          >
+          <v-select
+            id="search-type"
+            type="select"
+            placeholder="dans ..."
+            append-to-body
+            :calculate-position="withPopper"
+            :options="searchTypeOptions"
+            :clearable="false"
+            :value="searchTypeValue"
+            @input="onSearchTypeSelected"
+          />
+        </div>
+
+        <span
+          v-if="!isloading"
+          class="mdi mdi-magnify"
+          title="rechercher"
+          @click.prevent="submit"
+          @keydown.enter.prevent="submit"
+        />
+        <span
+          v-else
+          class="mdi mdi-loading"
+          title="chargement"
+        />
+        <!-- <input
+          id="submit-search"
+          type="submit"
+          name="search"
+          value="Search"
+          class="mdi mdi-magnify"
+          @click.prevent="submit"
+          @keyup.enter="submit"
+        > -->
+      </fieldset>
+      <fieldset class="filters-nominum col-3">
+        <span>Filters Nominum</span>
+      </fieldset>
+      <fieldset class="filters-locorum col-3">
+        <span>Filters Nominum</span>
+      </fieldset>
+      <fieldset class="filters-operum col-3">
+        <span>Filters Nominum</span>
+      </fieldset>
     </form>
   </div>
 </template>
 
 <script>
 
+import { createPopper } from '@popperjs/core'
+
 import { mapActions, mapState } from 'vuex'
 
 export default {
   name: 'Search',
-  // data: () => ({
-  //   typed: ''
-  // }),
+  data: () => ({
+    searchTypeOptions: [
+      { 'code': 'text', 'label': 'Dans les textes' },
+      { 'code': 'nominum', 'label': 'Dans les personnes' },
+      { 'code': 'locorum', 'label': 'Dans les lieux' },
+      { 'code': 'operum', 'label': 'Dans les objets' }
+    ],
+    searchTypeValue: { 'code': 'text', 'label': 'Dans les textes' }
+  }),
   computed: {
     keys: {
       get () { return this.$store.state.Search.keys },
@@ -59,6 +92,52 @@ export default {
     submit () {
       console.log('submited', this.keys)
       this.getResults()
+    },
+    withPopper (dropdownList, component, { width }) {
+      /**
+       * We need to explicitly define the dropdown width since
+       * it is usually inherited from the parent with CSS.
+       */
+      dropdownList.style.width = width
+
+      /**
+       * Here we position the dropdownList relative to the $refs.toggle Element.
+       *
+       * The 'offset' modifier aligns the dropdown so that the $refs.toggle and
+       * the dropdownList overlap by 1 pixel.
+       *
+       * The 'toggleClass' modifier adds a 'drop-up' class to the Vue Select
+       * wrapper so that we can set some styles for when the dropdown is placed
+       * above.
+       */
+      const popper = createPopper(component.$refs.toggle, dropdownList, {
+        placement: 'top',
+        modifiers: [
+          {
+            name: 'offset',
+            options: {
+              offset: [0, -1]
+            }
+          },
+          {
+            name: 'toggleClass',
+            enabled: true,
+            phase: 'write',
+            fn ({ state }) {
+              component.$el.classList.toggle('drop-up', state.placement === 'top')
+            }
+          }]
+      })
+
+      /**
+       * To prevent memory leaks Popper needs to be destroyed.
+       * If you return function, it will be called just before dropdown is removed from DOM.
+       */
+      return () => popper.destroy()
+    },
+    onSearchTypeSelected (e) {
+      console.log('onSearchTypeSelected', e)
+      this.searchTypeValue = e
     }
   }
 }

+ 3 - 1
src/index.js

@@ -5,11 +5,13 @@ import store from './store'
 import Meta from 'vue-meta'
 import InfiniteLoading from 'vue-infinite-loading'
 import VueScrollTo from 'vue-scrollto'
+import VueSelect from 'vue-select'
 
 import App from './App'
 
 import 'assets/css/mdi/css/materialdesignicons.css'
 // import 'mdi/font'
+import 'vue-select/src/scss/vue-select.scss'
 import 'assets/css/app.scss'
 
 Vue.use(Meta)
@@ -30,7 +32,7 @@ Vue.use(InfiniteLoading, {
 
 Vue.use(VueScrollTo)
 
-// window.env = process.env
+Vue.component('v-select', VueSelect)
 
 window.apipath = process.env === 'prod' ? `http://${window.location.hostname}/api` : 'http://localhost:8984'