Spaces:
Running
Running
| <script setup lang="ts"> | |
| import { ref, defineProps, defineEmits } from 'vue'; | |
| import useSnackbar from "@plugin/composables/snackbar.ts"; | |
| const props = defineProps({ | |
| showButtonText: { | |
| type: Boolean, | |
| default: false, | |
| }, | |
| modelValue: { | |
| type: String, | |
| default: '', | |
| }, | |
| }); | |
| const emit = defineEmits(['update:modelValue', 'on-submit']); | |
| const { createNotification } = useSnackbar(); | |
| const textInput = ref<HTMLInputElement | null>(null); | |
| function updateValue(event: Event) { | |
| const value = (event.target as HTMLInputElement)?.value; | |
| validateTextLength(value); | |
| validateTextIsNotUrl(value); | |
| emit('update:modelValue', value); | |
| } | |
| const validateTextIsNotUrl = (value: string): Boolean => { | |
| const urlPattern = /^(https?:\/\/)?([\w\-]+\.)+[\w\-]{2,}(\/[\w\-._~:/?#[\]@!$&'()*+,;=%]*)?$/i; | |
| if (urlPattern.test(value)) { | |
| createNotification({ | |
| message: 'Please use only keywords for text search. URLs are not allowed.', | |
| type: 'error', | |
| }); | |
| return false; | |
| } | |
| return true; | |
| } | |
| function validateTextLength(value: string): boolean { | |
| if (value.length >= 256) { | |
| createNotification({ | |
| message: 'You have reached the maximum number of allowed characters for text search (256).', | |
| type: 'info', | |
| }) | |
| return false; | |
| } | |
| return true; | |
| } | |
| function validateTextNotEmpty(value: string): boolean { | |
| if (value.length === 0) { | |
| createNotification({ | |
| message: 'Please type in the text search prompt to proceed', | |
| type: 'warning', | |
| }); | |
| return false; | |
| } | |
| return true; | |
| } | |
| const onEnter = (e: Event): void => { | |
| if (!validateTextIsNotUrl(props.modelValue)) { | |
| return; | |
| } | |
| if (!validateTextNotEmpty(props.modelValue)) { | |
| return; | |
| } | |
| emit('on-submit'); | |
| } | |
| </script> | |
| <template> | |
| <div class="search-input" > | |
| <input | |
| ref="textInput" | |
| :value="modelValue" | |
| @input="updateValue" | |
| v-bind="$attrs" | |
| @keydown.enter="onEnter" | |
| placeholder="or type to search" | |
| maxlength="256" | |
| /> | |
| <button @click="onEnter" :with-text="showButtonText"> | |
| <svg class="app-svg-icon" width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg"> | |
| <path d="M17.5 17.5L13.875 13.875M15.8333 9.16667C15.8333 12.8486 12.8486 15.8333 9.16667 15.8333C5.48477 15.8333 2.5 12.8486 2.5 9.16667C2.5 5.48477 5.48477 2.5 9.16667 2.5C12.8486 2.5 15.8333 5.48477 15.8333 9.16667Z" stroke="#8586AD" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/> | |
| </svg> | |
| <span v-if="showButtonText"> Search </span> | |
| </button> | |
| </div> | |
| </template> | |
| <style scoped lang="scss"> | |
| @import "@/assets/mixins"; | |
| @import '@plugin/assets/main.scss'; | |
| @import '@plugin/assets/_variables_override.scss'; | |
| .search-input { | |
| display: flex; | |
| height: 48px; | |
| width: 100%; | |
| color: $primary-400; | |
| button { | |
| padding: 0px; | |
| @include tertiary-icon-only; | |
| border: unset; | |
| border-radius: 0px 6px 6px 0px; | |
| border: 1px solid $main-50; | |
| color: inherit; | |
| &[with-text="true"] { | |
| padding:12px 24px; | |
| span { | |
| color: inherit; | |
| } | |
| } | |
| } | |
| input { | |
| @include input; | |
| border: 1px solid $main-50; | |
| border-radius: 6px 0px 0px 6px; | |
| padding: 12px 16px; | |
| &:disabled { | |
| background-color: dimgrey; | |
| color: linen; | |
| opacity: 1; | |
| } | |
| } | |
| } | |
| </style> |