mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-02-03 14:54:37 +00:00
This pull request introduces improvements to the workflow template selector and search box components, focusing on better user experience and more accurate terminology. The most significant changes include adding debounced search input handling, updating sorting option labels, and refining UI styling for consistency. **Search functionality improvements:** * Refactored `SearchBox.vue` to use an internal search query state and a debounced update mechanism, reducing unnecessary parent updates and improving responsiveness. The parent model is updated only after the user stops typing for 300ms. (`src/components/input/SearchBox.vue`) [[1]](diffhunk://#diff-08f3b0c51fbfe63171509b9944bf7558228f6c2596a1ef5338e88ab64585791bL6-R6) [[2]](diffhunk://#diff-08f3b0c51fbfe63171509b9944bf7558228f6c2596a1ef5338e88ab64585791bR39-R62) * Updated the search box in `WorkflowTemplateSelectorDialog.vue` to use the new debounced search model and increased its size for better visibility. (`src/components/custom/widget/WorkflowTemplateSelectorDialog.vue`) **Sorting and terminology updates:** * Changed sorting option labels to use more precise terminology, such as "VRAM Usage (Low to High)" and added new locale strings for sorting options. (`src/components/custom/widget/WorkflowTemplateSelectorDialog.vue`, `src/locales/en/main.json`) [[1]](diffhunk://#diff-2c860bdc48e907b1b85dbef846599d8376dd02cff90f49e490eebe61371fecedL623-R623) [[2]](diffhunk://#diff-bbf3da78aeff5b4d868a17a6960d109cb0627316cda2f9b5fa7c08e9abd93be6L1032-R1035) **UI and styling adjustments:** * Adjusted the width of the sorting dropdown for better alignment and consistency. (`src/components/custom/widget/WorkflowTemplateSelectorDialog.vue`) * Updated active navigation item background color for improved visual clarity. (`src/components/widget/nav/NavItem.vue`) ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-5975-Workflow-templates-review-2866d73d365081419257f9df2bab9c5b) by [Unito](https://www.unito.io) https://github.com/user-attachments/assets/4f72d515-f114-4cd4-8a76-6abbe906e5bb
113 lines
2.8 KiB
Vue
113 lines
2.8 KiB
Vue
<template>
|
|
<div :class="wrapperStyle" @click="focusInput">
|
|
<i class="icon-[lucide--search]" :class="iconColorStyle" />
|
|
<InputText
|
|
ref="input"
|
|
v-model="internalSearchQuery"
|
|
:aria-label="
|
|
placeholder || t('templateWidgets.sort.searchPlaceholder', 'Search...')
|
|
"
|
|
:placeholder="
|
|
placeholder || t('templateWidgets.sort.searchPlaceholder', 'Search...')
|
|
"
|
|
type="text"
|
|
unstyled
|
|
:class="inputStyle"
|
|
/>
|
|
</div>
|
|
</template>
|
|
|
|
<script setup lang="ts">
|
|
import { useDebounceFn } from '@vueuse/core'
|
|
import InputText from 'primevue/inputtext'
|
|
import { computed, onMounted, ref, watch } from 'vue'
|
|
|
|
import { t } from '@/i18n'
|
|
import { cn } from '@/utils/tailwindUtil'
|
|
|
|
const SEARCH_DEBOUNCE_DELAY_MS = 300
|
|
|
|
const {
|
|
autofocus = false,
|
|
placeholder,
|
|
showBorder = false,
|
|
size = 'md'
|
|
} = defineProps<{
|
|
autofocus?: boolean
|
|
placeholder?: string
|
|
showBorder?: boolean
|
|
size?: 'md' | 'lg'
|
|
}>()
|
|
|
|
// defineModel without arguments uses 'modelValue' as the prop name
|
|
const searchQuery = defineModel<string>()
|
|
|
|
// Internal search query state for immediate UI updates
|
|
const internalSearchQuery = ref<string>(searchQuery.value ?? '')
|
|
|
|
// Create debounced function to update the parent model
|
|
const updateSearchQuery = useDebounceFn((value: string) => {
|
|
searchQuery.value = value
|
|
}, SEARCH_DEBOUNCE_DELAY_MS)
|
|
|
|
// Watch internal query changes and trigger debounced update
|
|
watch(internalSearchQuery, (newValue) => {
|
|
void updateSearchQuery(newValue)
|
|
})
|
|
|
|
// Sync external changes back to internal state
|
|
watch(searchQuery, (newValue) => {
|
|
if (newValue !== internalSearchQuery.value) {
|
|
internalSearchQuery.value = newValue || ''
|
|
}
|
|
})
|
|
|
|
const input = ref<{ $el: HTMLElement } | null>()
|
|
const focusInput = () => {
|
|
if (input.value && input.value.$el) {
|
|
input.value.$el.focus()
|
|
}
|
|
}
|
|
|
|
onMounted(() => autofocus && focusInput())
|
|
|
|
const wrapperStyle = computed(() => {
|
|
const baseClasses = [
|
|
'relative flex w-full items-center gap-2',
|
|
'bg-white dark-theme:bg-zinc-800',
|
|
'cursor-text'
|
|
]
|
|
|
|
if (showBorder) {
|
|
return cn(
|
|
...baseClasses,
|
|
'rounded p-2',
|
|
'border border-solid',
|
|
'border-zinc-200 dark-theme:border-zinc-700'
|
|
)
|
|
}
|
|
|
|
// Size-specific classes matching button sizes for consistency
|
|
const sizeClasses = {
|
|
md: 'h-8 px-2 py-1.5', // Matches button sm size
|
|
lg: 'h-10 px-4 py-2' // Matches button md size
|
|
}[size]
|
|
|
|
return cn(...baseClasses, 'rounded-lg', sizeClasses)
|
|
})
|
|
|
|
const inputStyle = computed(() => {
|
|
return cn(
|
|
'absolute inset-0 w-full h-full pl-11',
|
|
'border-none outline-none bg-transparent',
|
|
'text-sm text-neutral dark-theme:text-white'
|
|
)
|
|
})
|
|
|
|
const iconColorStyle = computed(() => {
|
|
return cn(
|
|
!showBorder ? 'text-neutral' : ['text-zinc-300', 'dark-theme:text-zinc-700']
|
|
)
|
|
})
|
|
</script>
|