91 lines
3 KiB
Vue
91 lines
3 KiB
Vue
<script setup>
|
|
import { computed, ref } from 'vue'
|
|
|
|
const props = defineProps({
|
|
labels: { type: Array, default: () => [] },
|
|
disabled: { type: Boolean, default: false },
|
|
})
|
|
|
|
const model = defineModel({ type: Number, default: null })
|
|
const search = ref('')
|
|
const isOpen = ref(false)
|
|
|
|
const filtered = computed(() =>
|
|
props.labels.filter((l) => l.name.toLowerCase().includes(search.value.toLowerCase())),
|
|
)
|
|
|
|
const selected = computed(() => props.labels.find((l) => l.id === model.value))
|
|
|
|
function select(label) {
|
|
model.value = label.id
|
|
search.value = ''
|
|
isOpen.value = false
|
|
}
|
|
|
|
function open() {
|
|
if (!props.disabled) isOpen.value = true
|
|
}
|
|
|
|
function close() {
|
|
setTimeout(() => {
|
|
isOpen.value = false
|
|
}, 150)
|
|
}
|
|
</script>
|
|
|
|
<template>
|
|
<div class="relative">
|
|
<div
|
|
class="flex cursor-pointer items-center gap-2 rounded-lg border border-gray-300 bg-white px-3 py-2 text-sm shadow-sm"
|
|
:class="{ 'cursor-not-allowed opacity-50': disabled }"
|
|
@click="open"
|
|
data-testid="label-picker-trigger"
|
|
>
|
|
<span
|
|
v-if="selected?.color"
|
|
class="h-4 w-4 shrink-0 rounded"
|
|
:style="{ backgroundColor: selected.color }"
|
|
/>
|
|
<span class="flex-1 truncate text-gray-700">
|
|
{{ selected ? selected.name : 'Label auswählen...' }}
|
|
</span>
|
|
</div>
|
|
|
|
<div
|
|
v-if="isOpen"
|
|
class="absolute z-50 mt-1 w-full rounded-lg border border-gray-200 bg-white shadow-lg"
|
|
data-testid="label-picker-dropdown"
|
|
>
|
|
<div class="border-b border-gray-100 p-2">
|
|
<input
|
|
v-model="search"
|
|
type="text"
|
|
placeholder="Label suchen..."
|
|
class="w-full rounded border-gray-300 text-sm"
|
|
autofocus
|
|
@blur="close"
|
|
/>
|
|
</div>
|
|
<div class="max-h-48 overflow-y-auto">
|
|
<button
|
|
v-for="label in filtered"
|
|
:key="label.id"
|
|
class="flex w-full items-center gap-2 px-3 py-2 text-sm transition-colors hover:bg-amber-50"
|
|
:class="label.hidden_at ? 'text-gray-400' : 'text-gray-700'"
|
|
:data-testid="'label-option-' + label.id"
|
|
@click="select(label)"
|
|
>
|
|
<span
|
|
class="h-3 w-3 shrink-0 rounded"
|
|
:style="label.color ? { backgroundColor: label.color } : { backgroundColor: '#ccc' }"
|
|
/>
|
|
<span class="truncate">{{ label.name }}{{ label.hidden_at ? ' (deaktiviert)' : '' }}</span>
|
|
</button>
|
|
<div v-if="filtered.length === 0" class="px-3 py-4 text-center text-sm text-gray-400">
|
|
Kein Label gefunden
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</template>
|