|
| 1 | +<template> |
| 2 | + <div class="flex flex-col space-y-2 w-96"> |
| 3 | + <div |
| 4 | + class="relative flex justify-between items-start flex-col sm:flex-row sm:h-16 h-20 w-full" |
| 5 | + > |
| 6 | + <div class="px-5 sm:px-2"> |
| 7 | + <h1 class="font-normal poppins text-2xl text-[#6C6C6C]">Tags</h1> |
| 8 | + </div> |
| 9 | + <div class="relative h-[36px] w-[251px] mb-1 sm:mb-0"> |
| 10 | + <!-- Input field for adding new tags --> |
| 11 | + <input |
| 12 | + type="text" |
| 13 | + v-model="input" |
| 14 | + @keydown.enter.prevent="handleEnter" |
| 15 | + @focus="isFocused = true" |
| 16 | + @blur="isFocused = false" |
| 17 | + placeholder="search for tags here" |
| 18 | + class="h-[36px] w-[251px] poppins text-sm font-normal px-5 rounded-full searchbar focus:outline-none focus:ring-2 focus:ring-blue-500" |
| 19 | + /> |
| 20 | + <img |
| 21 | + src="../assets/searchicon.svg" |
| 22 | + class="absolute top-[25%] right-[10%]" |
| 23 | + alt="searchicon" |
| 24 | + /> |
| 25 | + |
| 26 | + <!-- Suggestions dropdown --> |
| 27 | + <ul |
| 28 | + v-if="suggestions.length && isFocused" |
| 29 | + class="absolute mt-1 border-2 border-[#808080] rounded-b-3xl bg-white max-h-48 overflow-y-auto w-[251px] z-1 mt-5 py-2 px-4 poppins" |
| 30 | + > |
| 31 | + <li |
| 32 | + v-for="(suggestion, index) in suggestions" |
| 33 | + :key="index" |
| 34 | + @mousedown.prevent="selectSuggestion(suggestion)" |
| 35 | + class="py-1 px-2 cursor-pointer hover:bg-gray-100 text-black rounded-md" |
| 36 | + > |
| 37 | + {{ suggestion }} |
| 38 | + </li> |
| 39 | + </ul> |
| 40 | + </div> |
| 41 | + </div> |
| 42 | + |
| 43 | + <!-- Display selected tags --> |
| 44 | + <div class="flex flex-wrap gap-3 mb-2 poppins"> |
| 45 | + <span |
| 46 | + v-for="(tag, index) in selectedTags" |
| 47 | + :key="index" |
| 48 | + class="text-[#808080] h-[36px] px-3 ml-1 flex items-center bg-transparent border-[2.5px] border-[#808080] rounded-full text-xs shadow" |
| 49 | + > |
| 50 | + {{ tag }} |
| 51 | + <button |
| 52 | + @click="removeTag(index)" |
| 53 | + class="ml-7 hover:text-red-800 h-4 w-4 flex justify-end items-center" |
| 54 | + > |
| 55 | + <img src="../assets/cross.svg" alt="removetag" /> |
| 56 | + </button> |
| 57 | + </span> |
| 58 | + </div> |
| 59 | + </div> |
| 60 | +</template> |
| 61 | + |
| 62 | +<script setup> |
| 63 | +import { ref, computed } from "vue"; |
| 64 | +
|
| 65 | +const props = defineProps({ |
| 66 | + availableTags: { |
| 67 | + type: Array, |
| 68 | + default: () => [], |
| 69 | + }, |
| 70 | + initialTags: { |
| 71 | + type: Array, |
| 72 | + default: () => [], |
| 73 | + }, |
| 74 | +}); |
| 75 | +
|
| 76 | +const emit = defineEmits(["update:tags"]); |
| 77 | +
|
| 78 | +const input = ref(""); |
| 79 | +const isFocused = ref(false); |
| 80 | +const selectedTags = ref([...props.initialTags]); |
| 81 | +
|
| 82 | +const suggestions = computed(() => { |
| 83 | + if (!input.value) return []; |
| 84 | + const lowercaseInput = input.value.toLowerCase(); |
| 85 | + return props.availableTags |
| 86 | + .filter( |
| 87 | + (tag) => |
| 88 | + tag.toLowerCase().includes(lowercaseInput) && |
| 89 | + !selectedTags.value.includes(tag) |
| 90 | + ) |
| 91 | + .slice(0, 3); |
| 92 | +}); |
| 93 | +
|
| 94 | +const handleEnter = () => { |
| 95 | + const tag = input.value.trim(); |
| 96 | + if (tag) { |
| 97 | + addTag(tag); |
| 98 | + input.value = ""; |
| 99 | + } |
| 100 | +}; |
| 101 | +
|
| 102 | +const addTag = (tag) => { |
| 103 | + if (!selectedTags.value.includes(tag)) { |
| 104 | + selectedTags.value.push(tag); |
| 105 | + emit("update:tags", selectedTags.value); |
| 106 | + } |
| 107 | +}; |
| 108 | +
|
| 109 | +const removeTag = (index) => { |
| 110 | + selectedTags.value.splice(index, 1); |
| 111 | + emit("update:tags", selectedTags.value); |
| 112 | +}; |
| 113 | +
|
| 114 | +const selectSuggestion = (suggestion) => { |
| 115 | + addTag(suggestion); |
| 116 | + input.value = ""; |
| 117 | +}; |
| 118 | +</script> |
| 119 | + |
| 120 | +<style scoped> |
| 121 | +.searchbar { |
| 122 | + box-shadow: 0px 0px 8px 1.5px rgb(0 0 0 / 0.1); |
| 123 | +} |
| 124 | +.poppins { |
| 125 | + font-family: "Poppins", sans-serif; |
| 126 | + font-smooth: always; |
| 127 | +} |
| 128 | +</style> |
0 commit comments