Move search bar into dedicated component
This commit is contained in:
		
							
								
								
									
										94
									
								
								pvc-vue/src/components/general/VMSearchBar.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										94
									
								
								pvc-vue/src/components/general/VMSearchBar.vue
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,94 @@ | ||||
| <template> | ||||
|   <div class="search-box"> | ||||
|     <i class="fas fa-search search-icon"></i> | ||||
|     <input  | ||||
|       type="text"  | ||||
|       placeholder="Search VMs..."  | ||||
|       :value="modelValue" | ||||
|       @input="handleSearch" | ||||
|       @focus="handleFocus" | ||||
|       @blur="handleBlur" | ||||
|       class="form-control search-input" | ||||
|     > | ||||
|     <button  | ||||
|       v-if="modelValue && showList && showClearButton"  | ||||
|       class="btn-clear"  | ||||
|       @click="clearSearch" | ||||
|     > | ||||
|       <i class="fas fa-times"></i> | ||||
|     </button> | ||||
|   </div> | ||||
| </template> | ||||
|  | ||||
| <script setup> | ||||
| import { defineProps, defineEmits } from 'vue'; | ||||
|  | ||||
| const props = defineProps({ | ||||
|   modelValue: { | ||||
|     type: String, | ||||
|     required: true | ||||
|   }, | ||||
|   showList: { | ||||
|     type: Boolean, | ||||
|     required: true | ||||
|   }, | ||||
|   showClearButton: { | ||||
|     type: Boolean, | ||||
|     default: true | ||||
|   } | ||||
| }); | ||||
|  | ||||
| const emit = defineEmits(['update:modelValue', 'search', 'focus', 'blur', 'clear']); | ||||
|  | ||||
| const handleSearch = (event) => { | ||||
|   emit('update:modelValue', event.target.value); | ||||
|   emit('search', event.target.value); | ||||
| }; | ||||
|  | ||||
| const handleFocus = (event) => { | ||||
|   emit('focus', event); | ||||
| }; | ||||
|  | ||||
| const handleBlur = (event) => { | ||||
|   emit('blur', event); | ||||
| }; | ||||
|  | ||||
| const clearSearch = () => { | ||||
|   emit('update:modelValue', ''); | ||||
|   emit('clear'); | ||||
| }; | ||||
| </script> | ||||
|  | ||||
| <style scoped> | ||||
| .search-box { | ||||
|   position: relative; | ||||
|   flex: 1; | ||||
|   min-width: 200px; | ||||
| } | ||||
|  | ||||
| .search-icon { | ||||
|   position: absolute; | ||||
|   left: 10px; | ||||
|   top: 50%; | ||||
|   transform: translateY(-50%); | ||||
|   color: #6c757d; | ||||
| } | ||||
|  | ||||
| .search-input { | ||||
|   padding-left: 30px; | ||||
|   padding-right: 30px; | ||||
| } | ||||
|  | ||||
| .btn-clear { | ||||
|   position: absolute; | ||||
|   right: 10px; | ||||
|   top: 50%; | ||||
|   transform: translateY(-50%); | ||||
|   background: none; | ||||
|   border: none; | ||||
|   color: #6c757d; | ||||
|   cursor: pointer; | ||||
|   padding: 0; | ||||
|   font-size: 0.875rem; | ||||
| } | ||||
| </style>  | ||||
| @@ -11,25 +11,15 @@ | ||||
|           <i class="fas fa-list"></i> List VMs | ||||
|         </button> | ||||
|          | ||||
|         <div class="search-box"> | ||||
|           <i class="fas fa-search search-icon"></i> | ||||
|           <input  | ||||
|             type="text"  | ||||
|             placeholder="Search VMs..."  | ||||
|             :value="showVMList ? searchQuery : (selectedVMData?.name || '')" | ||||
|             @input="handleSearch" | ||||
|         <VMSearchBar | ||||
|           :model-value="showVMList ? searchQuery : selectedVMData?.name || ''" | ||||
|           :show-list="showVMList" | ||||
|           :show-clear-button="showVMList" | ||||
|           @search="handleSearch" | ||||
|           @focus="handleSearchFocus" | ||||
|           @blur="handleSearchBlur" | ||||
|             class="form-control search-input" | ||||
|           > | ||||
|           <button  | ||||
|             v-if="searchQuery && showVMList"  | ||||
|             class="btn-clear"  | ||||
|             @click="clearSearch" | ||||
|           > | ||||
|             <i class="fas fa-times"></i> | ||||
|           </button> | ||||
|         </div> | ||||
|           @clear="clearSearch" | ||||
|         /> | ||||
|          | ||||
|         <div class="filter-dropdown"> | ||||
|           <button  | ||||
| @@ -217,6 +207,7 @@ import { ref, computed, onMounted, onUnmounted, watch, nextTick } from 'vue'; | ||||
| import { useRouter, useRoute } from 'vue-router'; | ||||
| import CollapsibleSection from '../../general/CollapsibleSection.vue'; | ||||
| import ValueCard from '../../general/ValueCard.vue'; | ||||
| import VMSearchBar from '../../general/VMSearchBar.vue'; | ||||
|  | ||||
| const router = useRouter(); | ||||
| const route = useRoute(); | ||||
| @@ -428,8 +419,8 @@ const getStatusClass = (state) => { | ||||
| }; | ||||
|  | ||||
| // Handle search input | ||||
| const handleSearch = (event) => { | ||||
|   searchQuery.value = event.target.value; | ||||
| const handleSearch = (value) => { | ||||
|   searchQuery.value = value; | ||||
|   searchActive.value = true; | ||||
|   filterVMs(); | ||||
| }; | ||||
| @@ -637,6 +628,13 @@ const formatStorage = (sizeGB) => { | ||||
|   if (sizeGB < 1024) return sizeGB + ' GB'; | ||||
|   return (sizeGB / 1024).toFixed(1) + ' TB'; | ||||
| }; | ||||
|  | ||||
| // Clear search | ||||
| const clearSearch = () => { | ||||
|   searchQuery.value = ''; | ||||
|   searchActive.value = false; | ||||
|   filterVMs(); | ||||
| }; | ||||
| </script>  | ||||
|  | ||||
| <style scoped> | ||||
| @@ -687,39 +685,6 @@ const formatStorage = (sizeGB) => { | ||||
|   margin-left: 0.5rem; | ||||
| } | ||||
|  | ||||
| /* Search box styles */ | ||||
| .search-box { | ||||
|   position: relative; | ||||
|   flex: 1; | ||||
|   min-width: 200px; | ||||
| } | ||||
|  | ||||
| .search-icon { | ||||
|   position: absolute; | ||||
|   left: 10px; | ||||
|   top: 50%; | ||||
|   transform: translateY(-50%); | ||||
|   color: #6c757d; | ||||
| } | ||||
|  | ||||
| .search-input { | ||||
|   padding-left: 30px; | ||||
|   padding-right: 30px; | ||||
| } | ||||
|  | ||||
| .btn-clear { | ||||
|   position: absolute; | ||||
|   right: 10px; | ||||
|   top: 50%; | ||||
|   transform: translateY(-50%); | ||||
|   background: none; | ||||
|   border: none; | ||||
|   color: #6c757d; | ||||
|   cursor: pointer; | ||||
|   padding: 0; | ||||
|   font-size: 0.875rem; | ||||
| } | ||||
|  | ||||
| /* VM List styles */ | ||||
| .vm-list-container { | ||||
|   background-color: white; | ||||
|   | ||||
		Reference in New Issue
	
	Block a user