ff-operation/src/components/admin/EquipmentSelect.vue

138 lines
4.3 KiB
Vue

<template>
<div class="w-full">
<Combobox v-model="selected" :disabled="!enabled">
<ComboboxLabel v-if="!usePlaceholder">{{ title }}</ComboboxLabel>
<div class="relative">
<div
class="rounded-md shadow-sm relative block w-full border border-gray-300 focus:border-primary placeholder-gray-500 text-gray-900 focus:outline-none focus:ring-0 focus:z-10 sm:text-sm resize-none"
>
<ComboboxInput
class="w-full border-none py-2 pl-3 pr-10 text-sm leading-5 text-gray-900 focus:ring-0"
:displayValue="(equipment) => selectedEquipment?.name ?? ''"
@input="query = $event.target.value"
:placeholder="usePlaceholder ? title : ''"
/>
<ComboboxButton class="absolute inset-y-0 right-0 flex items-center pr-2">
<ChevronUpDownIcon class="h-5 w-5 text-gray-400" aria-hidden="true" />
</ComboboxButton>
</div>
<TransitionRoot
leave="transition ease-in duration-100"
leaveFrom="opacity-100"
leaveTo="opacity-0"
@after-leave="query = ''"
>
<ComboboxOptions
class="absolute z-20 mt-1 max-h-60 w-full overflow-auto rounded-md border border-gray-300 bg-white py-1 text-base shadow-md ring-1 ring-black/5 focus:outline-none sm:text-sm"
>
<div
v-if="availableEquipment.length === 0"
class="relative cursor-default select-none px-4 py-2 text-gray-700"
>
Keine Auswahl verfügbar
</div>
<div
v-if="filtered.length === 0 && query !== ''"
class="relative cursor-default select-none px-4 py-2 text-gray-700"
>
Keine Treffer
</div>
<ComboboxOption
v-for="person in filtered"
as="template"
:key="person.id"
:value="person.id"
v-slot="{ selected, active }"
>
<li
class="relative cursor-default select-none py-2 pl-10 pr-4"
:class="{
'bg-primary text-white': active,
'text-gray-900': !active,
}"
>
<span class="block truncate" :class="{ 'font-medium': selected, 'font-normal': !selected }">
{{ person.name }}
</span>
<span
v-if="selected"
class="absolute inset-y-0 left-0 flex items-center pl-3"
:class="{ 'text-white': active, 'text-primary': !active }"
>
<CheckIcon class="h-5 w-5" aria-hidden="true" />
</span>
</li>
</ComboboxOption>
</ComboboxOptions>
</TransitionRoot>
</div>
</Combobox>
</div>
</template>
<script setup lang="ts">
import { defineComponent, type PropType } from "vue";
import {
Combobox,
ComboboxInput,
ComboboxButton,
ComboboxOptions,
ComboboxOption,
TransitionRoot,
ComboboxLabel,
} from "@headlessui/vue";
import { CheckIcon, ChevronUpDownIcon } from "@heroicons/vue/20/solid";
import type { EquipmentViewModel } from "@/viewmodels/admin/configuration/equipment.models";
</script>
<script lang="ts">
export default defineComponent({
props: {
title: String,
usePlaceholder: {
type: Boolean,
default: false,
},
enabled: {
type: Boolean,
default: true,
},
modelValue: {
type: String,
default: "",
},
availableEquipment: {
type: Array as PropType<Array<EquipmentViewModel>>,
default: [],
},
},
data() {
return {
query: "" as string,
};
},
computed: {
selected: {
get() {
return this.modelValue;
},
set(val: Array<string>) {
this.$emit("update:model-value", val);
},
},
selectedEquipment() {
return this.availableEquipment.find((ae) => ae.id == this.selected);
},
filtered() {
return this.query == ""
? this.availableEquipment
: this.availableEquipment.filter((e) => {
const arr = this.query.toLocaleLowerCase().split(" ");
return arr.some((q) => e.name.toLocaleLowerCase().includes(q) || e.code?.toLocaleLowerCase().includes(q));
});
},
},
});
</script>