All files / src/components SearchFilterHeader.vue

100% Statements 10/10
100% Branches 2/2
100% Functions 2/2
100% Lines 9/9

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119  88x 3x 3x                                       3x                                             84x       84x     2x 2x       1x                                                                                                                        
<template>
  <div class="row mb-3">
    <div class="col-12">
      <div class="search-filter-group">
        <span class="search-filter-icon" aria-hidden="true">
          <font-awesome-icon icon="fa-solid fa-search" class="search-filter-icon-glyph" />
        </span>
        <input
          :value="modelValue"
          type="text"
          class="form-control search-filter-input"
          :placeholder="placeholder"
          @input="onInput"
        />
        <button
          v-if="modelValue"
          class="btn btn-outline-secondary search-filter-clear"
          type="button"
          @click="clearSearch"
        >
          {{ t('common.clear') }}
        </button>
      </div>
      <small class="text-muted d-block mt-2">
        {{
          t('common.filteredResults')
            .replace('{filtered}', String(filteredCount))
            .replace('{total}', String(totalCount))
        }}
      </small>
    </div>
  </div>
</template>
 
<script setup lang="ts">
import { useUILanguage } from '@/composables/useUILanguage'
 
interface Props {
  modelValue: string
  placeholder: string
  filteredCount: number
  totalCount: number
}
 
defineProps<Props>()
 
const emit = defineEmits<{
  'update:modelValue': [value: string]
}>()
 
const { t } = useUILanguage()
 
function onInput(event: Event) {
  const target = event.target as HTMLInputElement
  emit('update:modelValue', target.value)
}
 
function clearSearch() {
  emit('update:modelValue', '')
}
</script>
 
<style scoped>
.search-filter-group {
  display: flex;
  align-items: stretch;
  width: 100%;
}
 
.search-filter-icon,
.search-filter-input,
.search-filter-clear {
  height: 42px;
}
 
.search-filter-icon {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 42px;
  border: 1px solid var(--bw-border);
  border-right: 0;
  border-radius: 0.375rem 0 0 0.375rem;
  background: var(--bw-surface-muted);
  color: var(--bw-text-muted);
}
 
.search-filter-input {
  border-radius: 0;
  border-left: 0;
  min-width: 0;
  background-color: var(--bw-surface);
  color: var(--bw-text);
  border-color: var(--bw-border);
}
 
.search-filter-input:focus {
  z-index: 2;
}
 
.search-filter-clear {
  border-radius: 0 0.375rem 0.375rem 0;
}
 
.search-filter-clear,
.search-filter-icon {
  display: flex;
  align-items: center;
}
 
.search-filter-icon-glyph {
  font-size: 0.95rem;
}
 
[data-bs-theme='dark'] .search-filter-clear {
  border-color: var(--bw-border);
}
</style>