Files
ComfyUI_frontend/src/components/dialog/content/SettingDialogContent.vue
Chenlei Hu 637f5b501e Add about panel in settings dialog (#799)
* basic about page

* Remove frontend version from setting dialog header

* Style about page

* basic system stats

* Basic styling

* Reword

* Format memory amount
2024-09-12 17:31:19 +09:00

219 lines
5.5 KiB
Vue

<template>
<div class="settings-container">
<div class="settings-sidebar">
<SearchBox
class="settings-search-box"
v-model:modelValue="searchQuery"
@search="handleSearch"
:placeholder="$t('searchSettings') + '...'"
/>
<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">
<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, i) in sortedGroups(category)"
:key="group.label"
:divider="i !== 0"
:group="{
label: group.label,
settings: flattenTree<SettingParams>(group)
}"
/>
</TabPanel>
<TabPanel key="about" value="About">
<AboutPanel />
</TabPanel>
</TabPanels>
</Tabs>
</div>
</div>
</template>
<script setup lang="ts">
import { ref, computed, onMounted, watch } from 'vue'
import Listbox from 'primevue/listbox'
import Tabs from 'primevue/tabs'
import TabPanels from 'primevue/tabpanels'
import TabPanel from 'primevue/tabpanel'
import Divider from 'primevue/divider'
import { SettingTreeNode, useSettingStore } from '@/stores/settingStore'
import { SettingParams } from '@/types/settingTypes'
import SettingGroup from './setting/SettingGroup.vue'
import SearchBox from '@/components/common/SearchBox.vue'
import NoResultsPlaceholder from '@/components/common/NoResultsPlaceholder.vue'
import { flattenTree } from '@/utils/treeUtil'
import AboutPanel from './setting/AboutPanel.vue'
interface ISettingGroup {
label: string
settings: SettingParams[]
}
const aboutPanelNode: SettingTreeNode = {
key: 'about',
label: 'About',
children: []
}
const settingStore = useSettingStore()
const settingRoot = computed<SettingTreeNode>(() => settingStore.settingTree)
const categories = computed<SettingTreeNode[]>(() => [
...(settingRoot.value.children || []),
aboutPanelNode
])
const activeCategory = ref<SettingTreeNode | null>(null)
const searchResults = ref<ISettingGroup[]>([])
watch(activeCategory, (newCategory, oldCategory) => {
if (newCategory === null) {
activeCategory.value = oldCategory
}
})
onMounted(() => {
activeCategory.value = categories.value[0]
})
const sortedGroups = (category: SettingTreeNode) => {
return [...(category.children || [])].sort((a, b) =>
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>
.settings-tab-panels {
padding-top: 0px !important;
}
</style>
<style scoped>
.settings-container {
display: flex;
height: 70vh;
width: 60vw;
max-width: 1000px;
overflow: hidden;
/* Prevents container from scrolling */
}
.settings-sidebar {
width: 250px;
flex-shrink: 0;
/* Prevents sidebar from shrinking */
overflow-y: auto;
padding: 10px;
}
.settings-search-box {
width: 100%;
margin-bottom: 10px;
}
.settings-content {
flex-grow: 1;
overflow-y: auto;
/* Allows vertical scrolling */
}
/* Ensure the Listbox takes full width of the sidebar */
.settings-sidebar :deep(.p-listbox) {
width: 100%;
}
/* Optional: Style scrollbars for webkit browsers */
.settings-sidebar::-webkit-scrollbar,
.settings-content::-webkit-scrollbar {
width: 1px;
}
.settings-sidebar::-webkit-scrollbar-thumb,
.settings-content::-webkit-scrollbar-thumb {
background-color: transparent;
}
@media (max-width: 768px) {
.settings-container {
flex-direction: column;
height: auto;
}
.settings-sidebar {
width: 100%;
}
}
</style>