Move search bar into dedicated component

This commit is contained in:
Joshua Boniface 2025-03-02 11:16:32 -05:00
parent 037ea7fe8e
commit c467b92384
2 changed files with 113 additions and 54 deletions

View 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>

View File

@ -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;