diff --git a/src/assets/styles/tailwind.css b/src/assets/styles/tailwind.css index ca2aebef253b0d81eed9aacf33f0f7f2bac87aa3..c410a57e26a81e1dd568fca9f63264533781a72a 100644 --- a/src/assets/styles/tailwind.css +++ b/src/assets/styles/tailwind.css @@ -176,4 +176,12 @@ thead .fc-day-selected:hover { @apply tw-pr-6; } } + + .form-control:focus-within { + color: #495057; + background-color: #fff; + border-color: #80bdff; + outline: 0; + box-shadow: 0 0 0 0.2rem rgba(0, 123, 255, 0.25); + } } diff --git a/src/components/generic/TagInput.vue b/src/components/generic/TagInput.vue new file mode 100644 index 0000000000000000000000000000000000000000..e4f87c871e2721c4b481f6cf8d5301fdb7c96844 --- /dev/null +++ b/src/components/generic/TagInput.vue @@ -0,0 +1,62 @@ +<template> + <div + class="form-control tw-flex tw-flex-wrap tw-gap-2 tw-h-auto tw-min-h-[46px] tw-cursor-text" + @click="inputEl?.focus?.()" + > + <span + v-for="(tag, index) in modelValue" + :key="index" + class="tw-py-1 tw-px-2 tw-flex tw-items-center tw-bg-gray-100 tw-flex-none tw-rounded tw-max-w-full" + > + <span class="tw-min-w-0 tw-truncate">{{ tag }}</span> + <button type="button" class="btn tw-text-xs tw-p-0" @click="removeTag(index)"> + <icon-system-uicons-cross /> + </button> + </span> + + <input + ref="inputEl" + v-model="tagInputValue" + type="text" + class="tw-flex-1 tw-border-none focus:tw-outline-none tw-p-0 tw-m-0 tw-min-w-[150px]" + @keyup.enter.prevent="addTag" + @keyup.delete="maybeRemoveLastTag" + @click.stop + /> + </div> +</template> + +<script lang="ts" setup> +import { computed, ref } from 'vue' +import { useUpdatableState } from '@/util' + +defineOptions({ compatConfig: { MODE: 3 } }) + +const props = defineProps<{ + modelValue: string[] +}>() +const emit = defineEmits<{ + 'update:modelValue': [string[]] +}>() +const value = useUpdatableState( + computed(() => props.modelValue), + (newValue) => emit('update:modelValue', newValue), +) +const tagInputValue = ref('') +const inputEl = ref<HTMLInputElement>() + +function addTag() { + value.value.push(tagInputValue.value) + tagInputValue.value = '' +} + +function removeTag(index: number) { + value.value.splice(index, 1) +} + +function maybeRemoveLastTag() { + if (tagInputValue.value === '' && value.value.length > 0) { + value.value.splice(value.value.length - 1, 1) + } +} +</script>