Add search settings feature (#362)

* Add setting searchbox ui

* Basic search

* Remove first divider

* Keep group label on search result

* No result placeholder

* Prevent no result flash

* i18n

* Disable category nav when searching
This commit is contained in:
Chenlei Hu
2024-08-10 17:26:57 -04:00
committed by GitHub
parent 3e7b0a4907
commit 7ce7490bc3
5 changed files with 194 additions and 6 deletions

View File

@@ -1,26 +1,49 @@
<template>
<div class="settings-container">
<div class="settings-sidebar">
<SettingSearchBox
class="settings-search-box"
v-model:modelValue="searchQuery"
@search="handleSearch"
/>
<Listbox
v-model="activeCategory"
:options="categories"
optionLabel="label"
scrollHeight="100%"
:disabled="inSearch"
:pt="{ root: { class: 'border-none' } }"
/>
</div>
<Divider layout="vertical" />
<div class="settings-content" v-if="activeCategory">
<Tabs :value="activeCategory.label">
<TabPanels>
<div class="settings-content">
<Tabs :value="tabValue">
<TabPanels class="settings-tab-panels">
<TabPanel key="search-results" value="Search Results">
<div v-if="searchResults.length > 0">
<SettingGroup
v-for="(group, i) in searchResults"
:key="group.label"
:divider="i !== 0"
:group="group"
/>
</div>
<NoResultsPlaceholder
v-else
icon="pi pi-search"
:title="$t('noResultsFound')"
:message="$t('searchFailedMessage')"
/>
</TabPanel>
<TabPanel
v-for="category in categories"
:key="category.key"
:value="category.label"
>
<SettingGroup
v-for="group in sortedGroups(category)"
v-for="(group, i) in sortedGroups(category)"
:key="group.label"
:divider="i !== 0"
:group="{
label: group.label,
settings: flattenTree<SettingParams>(group)
@@ -43,15 +66,22 @@ import Divider from 'primevue/divider'
import { SettingTreeNode, useSettingStore } from '@/stores/settingStore'
import { SettingParams } from '@/types/settingTypes'
import SettingGroup from './setting/SettingGroup.vue'
import SettingSearchBox from './setting/SettingSearchBox.vue'
import NoResultsPlaceholder from '@/components/common/NoResultsPlaceholder.vue'
import { flattenTree } from '@/utils/treeUtil'
interface ISettingGroup {
label: string
settings: SettingParams[]
}
const settingStore = useSettingStore()
const settingRoot = computed<SettingTreeNode>(() => settingStore.settingTree)
const categories = computed<SettingTreeNode[]>(
() => settingRoot.value.children || []
)
const activeCategory = ref<SettingTreeNode | null>(null)
const searchResults = ref<ISettingGroup[]>([])
watch(activeCategory, (newCategory, oldCategory) => {
if (newCategory === null) {
@@ -68,6 +98,48 @@ const sortedGroups = (category: SettingTreeNode) => {
a.label.localeCompare(b.label)
)
}
const searchQuery = ref<string>('')
const searchInProgress = ref<boolean>(false)
watch(searchQuery, () => (searchInProgress.value = true))
const handleSearch = (query: string) => {
if (!query) {
searchResults.value = []
return
}
const allSettings = flattenTree<SettingParams>(settingRoot.value)
const filteredSettings = allSettings.filter(
(setting) =>
setting.id.toLowerCase().includes(query.toLowerCase()) ||
setting.name.toLowerCase().includes(query.toLowerCase())
)
const groupedSettings: { [key: string]: SettingParams[] } = {}
filteredSettings.forEach((setting) => {
const groupLabel = setting.id.split('.')[1]
if (!groupedSettings[groupLabel]) {
groupedSettings[groupLabel] = []
}
groupedSettings[groupLabel].push(setting)
})
searchResults.value = Object.entries(groupedSettings).map(
([label, settings]) => ({
label,
settings
})
)
searchInProgress.value = false
}
const inSearch = computed(
() => searchQuery.value.length > 0 && !searchInProgress.value
)
const tabValue = computed(() =>
inSearch.value ? 'Search Results' : activeCategory.value?.label
)
</script>
<style>
@@ -75,6 +147,10 @@ const sortedGroups = (category: SettingTreeNode) => {
.border-none {
border: none !important;
}
.settings-tab-panels {
padding-top: 0px !important;
}
</style>
<style scoped>
@@ -95,6 +171,11 @@ const sortedGroups = (category: SettingTreeNode) => {
padding: 10px;
}
.settings-search-box {
width: 100%;
margin-bottom: 10px;
}
.settings-content {
flex-grow: 1;
overflow-y: auto;