Skip to content
Snippets Groups Projects
Select Git revision
  • c070e18bcefaa0871acce45afde11cd0213bb8e4
  • master default protected
  • dev
3 results

AdvancedSearch.vue

Blame
  • AdvancedSearch.vue 5.14 KiB
    <template>
      <div class="advanced-search">
        <div class="active-filters">
          <div
            v-for="filter in allFilters"
            :key="filter.join('-')"
            class="filter-chip"
          >
            <span>{{ filter[1] }}</span>
            <button
              class="remove-button"
              type="button"
              @click="removeFilter(filter)"
            >
              &#10006;
            </button>
          </div>
        </div>
    
        <button
          class="advanced-search-button"
          type="button"
          @click="displayAdvancedSearch"
        >
          ADVANCED SEARCH
        </button>
      </div>
    
      <AppDialog
        v-model="advancedSearchVisible"
        class="advanced-search-dialog"
        @close="updateFilters"
      >
        <header>
          <h2>ADVANCED SEARCH</h2>
        </header>
    
        <div class="options-group">
          <h3>ORGANISM</h3>
          <div class="checkbox-list">
            <div
              v-for="spe in speciesList"
              :key="spe"
              class="checkbox"
            >
              <input
                :id="spe.replace(' ', '-') + '-checkbox'"
                v-model="filters.species"
                :value="spe"
                type="checkbox"
              >
              <label :for="spe.replace(' ', '-') + '-checkbox'">
                {{ spe }}
              </label>
            </div>
          </div>
        </div>
    
        <div class="options-group">
          <h3>SOURCES</h3>
          <div class="checkbox-list">
            <div
              v-for="source in sourcesList"
              :key="source"
              class="checkbox"
            >
              <input
                :id="source + '-checkbox'"
                v-model="filters.sources"
                :value="source"
                type="checkbox"
              >
              <label :for="source + '-checkbox'">
                {{ source }}
              </label>
            </div>
          </div>
        </div>
    
        <footer>
          <button
            class="search-button"
            type="button"
            @click="closeAdvancedSearch"
          >
            SEARCH
          </button>
        </footer>
      </AppDialog>
    </template>
    
    <script setup lang="ts">
    import { Ref, computed, onMounted, ref } from "vue"
    import AppDialog from "./AppDialog.vue"
    import { useStore } from "../store"
    import { AdvancedFilters, FilterChip } from "../types"
    
    onMounted(() => {
      if (store.antibodiesSources.length === 0) {
        store.getAntibodiesSources()
        store.getAntibodiesSpecies()
      }
    })
    
    const emit = defineEmits<{
      filtersUpdate: [filters: AdvancedFilters]
    }>()
    
    const store = useStore()
    const advancedSearchVisible: Ref<boolean> = ref(false)
    const filters: Ref<AdvancedFilters> = ref({
      species: [],
      sources: []
    })
    const sourcesList = computed(() => store.antibodiesSources)
    const speciesList = computed(() => store.antibodiesSpecies)
    const allFilters = computed(() => {
      const filterChips: FilterChip[] = []
    
      filters.value.species.forEach(value => {
        filterChips.push(['species', value])
      })
    
      filters.value.sources.forEach(value => {
        filterChips.push(['sources', value])
      })
    
      return filterChips
    })
    
    /**
     * Open the dialog box.
     */
    function displayAdvancedSearch(): void {
      advancedSearchVisible.value = true
    }
    
    /**
     * Close the dialog box.
     */
    function closeAdvancedSearch(): void {
      advancedSearchVisible.value = false
    }
    
    /**
     * On dialog close, emit the new filters to
     * the parent component.
     */
    function updateFilters(): void {
      emit('filtersUpdate', filters.value)
    }
    
    /**
     * Remove one of the filter chips and re-emit
     * the filters immediately.
     * @param filterChip - The data of the filter chip to remove
     */
    function removeFilter(filterChip: FilterChip): void {
      const valueIndex: number = filters.value[filterChip[0]].indexOf(filterChip[1])
      filters.value[filterChip[0]].splice(valueIndex, 1)
      emit('filtersUpdate', filters.value)
    }
    </script>
    
    <style scoped>
    .active-filters {
      display: flex;
      gap: calc((var(--spacing)) / 2);
      padding-top: calc((var(--spacing)) / 2);
    }
    
    .filter-chip {
      border: 1px solid var(--primary);
      border-radius: 16px;
      color: var(--primary);
      display: flex;
      align-items: center;
      padding-left: 6px;
    }
    
    .filter-chip .remove-button {
      color: inherit;
      padding: 6px;
      background: none;
      border: none;
      cursor: pointer;
    }
    
    .advanced-search {
      display: flex;
      margin-bottom: calc(var(--spacing) * 3);
      width: 700px;
      text-align: end;
    }
    
    .advanced-search-button {
      color: var(--white);
      background: none;
      border: none;
      cursor: pointer;
      padding-top: calc(var(--spacing) / 2);
      margin-left: auto;
    }
    
    .advanced-search-button:hover {
      color: var(--primary);
    }
    
    .advanced-search-dialog h2 {
      margin-bottom: calc(var(--spacing) * 2);
      margin-top: 0;
    }
    
    .options-group .checkbox-list {
      display: flex;
      flex-flow: row wrap;
      gap: var(--spacing);
      padding-left: var(--spacing);
    }
    
    .checkbox {
      display: flex;
      gap: calc(var(--spacing) / 2);
    }
    
    .checkbox:hover {
      color: var(--primary);
    }
    
    .checkbox input,
    .checkbox label {
      cursor: pointer;
    }
    
    .checkbox input:checked+label {
      color: var(--primary);
    }
    
    .advanced-search-dialog footer {
      display: flex;
      align-items: center;
      justify-content: flex-end;
      margin-top: var(--spacing);
    }
    
    .search-button {
      background-color: var(--primary);
      border-radius: var(--radius);
      border: none;
      color: var(--white);
      cursor: pointer;
      font-weight: 700;
      height: 40px;
      padding: 7px var(--spacing);
    }
    </style>