diff --git a/src/components/dialog/content/SettingDialogContent.vue b/src/components/dialog/content/SettingDialogContent.vue index 13afc222f..f3dead47c 100644 --- a/src/components/dialog/content/SettingDialogContent.vue +++ b/src/components/dialog/content/SettingDialogContent.vue @@ -9,10 +9,10 @@ /> @@ -21,7 +21,7 @@ - + (() => const activeCategory = ref(null) const searchResults = ref([]) +const displayedCategories = ref([]) watch(activeCategory, (newCategory, oldCategory) => { - if (newCategory === null) { + if (!inSearch.value && newCategory === null) { activeCategory.value = oldCategory } }) @@ -166,6 +167,8 @@ onMounted(() => { ? categories.value.find((x) => x.key === props.defaultPanel) ?? categories.value[0] : categories.value[0] + + displayedCategories.value = categories.value }) const sortedGroups = (category: SettingTreeNode): ISettingGroup[] => { @@ -179,15 +182,36 @@ const sortedGroups = (category: SettingTreeNode): ISettingGroup[] => { const searchQuery = ref('') const searchInProgress = ref(false) -watch(searchQuery, () => (searchInProgress.value = true)) +const inSearch = computed( + () => searchQuery.value.length > 0 && !searchInProgress.value +) + +const clearSearchResults = () => { + searchResults.value = [] + displayedCategories.value = categories.value + displayedCategories.value.forEach((cat) => { + cat.disabled = false + }) +} + +const restoreDefaultCategory = () => { + const fallback = props.defaultPanel + ? categories.value.find((x) => x.key === props.defaultPanel) + : categories.value[0] + activeCategory.value = fallback +} const handleSearch = (query: string) => { if (!query) { - searchResults.value = [] + clearSearchResults() + restoreDefaultCategory() return } + activeCategory.value = null + const queryLower = query.toLocaleLowerCase() + searchInProgress.value = true const allSettings = flattenTree(settingRoot.value) const filteredSettings = allSettings.filter((setting) => { const idLower = setting.id.toLowerCase() @@ -203,27 +227,77 @@ const handleSearch = (query: string) => { ) }) - const groupedSettings: { [key: string]: SettingParams[] } = {} + const groupedSettingsByCategory: Record = {} filteredSettings.forEach((setting) => { - const groupLabel = setting.id.split('.')[1] - if (!groupedSettings[groupLabel]) { - groupedSettings[groupLabel] = [] + const secondLevel = setting.category?.[1] || setting.id.split('.')[1] // e.g. "Comfy", "Appearance", ... + if (!groupedSettingsByCategory[secondLevel]) { + groupedSettingsByCategory[secondLevel] = [] } - groupedSettings[groupLabel].push(setting) + + groupedSettingsByCategory[secondLevel].push(setting) }) - searchResults.value = Object.entries(groupedSettings).map( + searchResults.value = Object.entries(groupedSettingsByCategory).map( ([label, settings]) => ({ label, settings }) ) + + const matchedTopCategories = new Set( + filteredSettings.map((s) => { + const topCat = s.category?.[0] || s.id.split('.')[0] || '' + return topCat.toLowerCase() + }) + ) + + displayedCategories.value = categories.value.map((cat) => { + const splitted = cat.key.split('/') + const lastPart = splitted[splitted.length - 1] // "Comfy", "Appearance", ... + const isMatched = matchedTopCategories.has(lastPart.toLowerCase()) + return { + ...cat, + disabled: !isMatched + } + }) + searchInProgress.value = false } -const inSearch = computed( - () => searchQuery.value.length > 0 && !searchInProgress.value -) +watch(searchQuery, () => { + searchInProgress.value = true +}) + +/** + * Further filter the search results by the currently active category. + * → For example, if the user clicks on "Comfy" in the sidebar, + * show only the search results for "Comfy" + */ +const filteredSearchResults = computed(() => { + if (!inSearch.value) { + return searchResults.value + } + + if (!activeCategory.value) { + return searchResults.value + } + + // e.g. "root/Comfy" -> "Comfy" (strip the prefix) + const splitted = activeCategory.value.key.split('/') + const lastPart = splitted[splitted.length - 1] // e.g. "Comfy" + const activeCatName = lastPart.toLowerCase() + + return searchResults.value + .map((group) => { + const filtered = group.settings.filter((setting) => { + const topCat = setting.category?.[0] || setting.id.split('.')[0] || '' + return topCat.toLowerCase() === activeCatName + }) + return { label: group.label, settings: filtered } + }) + .filter((g) => g.settings.length > 0) +}) + const tabValue = computed(() => inSearch.value ? 'Search Results' : activeCategory.value?.label )