pp-planer/resources/js/Components/LabelPicker.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>