OptionsFilter.vue 1.5 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677
  1. <template>
  2. <div class="flex min-h-57 flex-col justify-between gap-2">
  3. <Listbox
  4. v-model="model"
  5. :options="options"
  6. multiple
  7. scrollHeight="12rem"
  8. @change="emit('filterCallback')"
  9. >
  10. <!--suppress VueUnrecognizedSlot -->
  11. <template #option="{ option, selected, index }">
  12. <div
  13. :id="`filter_${index}`"
  14. class="flex w-full flex-row items-center gap-1"
  15. :class="
  16. !isFilteredOption(option) &&
  17. 'text-surface-400! dark:text-surface-500!'
  18. "
  19. >
  20. <div class="min-w-[0.875em]">
  21. <Icon
  22. v-if="selected"
  23. name="ph:check-bold"
  24. size="0.875em"
  25. />
  26. </div>
  27. <div class="truncate">
  28. {{ option }}
  29. </div>
  30. </div>
  31. </template>
  32. </Listbox>
  33. <Button
  34. class="py-0.5!"
  35. variant="outlined"
  36. size="small"
  37. fluid
  38. :disabled="!hasFilterFor(props.field)"
  39. @click="resetFilterFor(props.field)"
  40. >
  41. Reset
  42. </Button>
  43. </div>
  44. </template>
  45. <script setup>
  46. const model = defineModel()
  47. const props = defineProps({
  48. field: {
  49. type: String,
  50. required: true
  51. },
  52. options: {
  53. type: Array,
  54. required: true
  55. },
  56. filteredOptions: {
  57. type: Array,
  58. required: true
  59. }
  60. })
  61. const emit = defineEmits(["filterCallback"])
  62. const { hasFilterFor, resetFilterFor } = useFiltersStore()
  63. function isFilteredOption(option) {
  64. return _includes(props.filteredOptions, option)
  65. }
  66. </script>
  67. <style scoped></style>