Move search bar into dedicated component
This commit is contained in:
parent
037ea7fe8e
commit
c467b92384
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"
|
||||
@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>
|
||||
<VMSearchBar
|
||||
:model-value="showVMList ? searchQuery : selectedVMData?.name || ''"
|
||||
:show-list="showVMList"
|
||||
:show-clear-button="showVMList"
|
||||
@search="handleSearch"
|
||||
@focus="handleSearchFocus"
|
||||
@blur="handleSearchBlur"
|
||||
@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;
|
||||
|
Loading…
x
Reference in New Issue
Block a user