mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-03-05 13:10:24 +00:00
Style: Larger Node Text, More Sidebar Alignment (#7223)
## Summary See what it looks like. How it feels. What do you think? - Also was able to unify down to a single SearchBox component. ## Changes - Bigger widget / slot labels - Smaller header text - Unified Searchboxes across sidebar tabs ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-7223-Style-prototype-with-larger-node-text-2c36d73d365081f8a371c86f178fa1ff) by [Unito](https://www.unito.io) --------- Co-authored-by: github-actions <github-actions@github.com>
This commit is contained in:
@@ -1,84 +1,93 @@
|
||||
<template>
|
||||
<div>
|
||||
<IconField>
|
||||
<Button
|
||||
v-if="filterIcon"
|
||||
class="p-inputicon filter-button"
|
||||
:icon="filterIcon"
|
||||
text
|
||||
severity="contrast"
|
||||
@click="$emit('showFilter', $event)"
|
||||
/>
|
||||
<InputText
|
||||
ref="inputRef"
|
||||
class="search-box-input w-full"
|
||||
:model-value="modelValue"
|
||||
:placeholder="placeholder"
|
||||
:autofocus="autofocus"
|
||||
@input="handleInput"
|
||||
/>
|
||||
<InputIcon v-if="!modelValue" :class="icon" />
|
||||
<Button
|
||||
v-if="modelValue"
|
||||
class="p-inputicon clear-button"
|
||||
icon="pi pi-times"
|
||||
text
|
||||
severity="contrast"
|
||||
@click="clearSearch"
|
||||
/>
|
||||
</IconField>
|
||||
<div
|
||||
v-if="filters?.length"
|
||||
class="search-filters flex flex-wrap gap-2 pt-2"
|
||||
>
|
||||
<SearchFilterChip
|
||||
v-for="filter in filters"
|
||||
:key="filter.id"
|
||||
:text="filter.text"
|
||||
:badge="filter.badge"
|
||||
:badge-class="filter.badgeClass"
|
||||
@remove="$emit('removeFilter', filter)"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
:class="
|
||||
cn(
|
||||
'relative flex w-full items-center gap-2 bg-comfy-input cursor-text text-comfy-input-foreground',
|
||||
customClass,
|
||||
wrapperStyle
|
||||
)
|
||||
"
|
||||
>
|
||||
<InputText
|
||||
ref="inputRef"
|
||||
v-model="modelValue"
|
||||
:placeholder
|
||||
:autofocus
|
||||
unstyled
|
||||
class="absolute inset-0 size-full pl-11 border-none outline-none bg-transparent text-sm"
|
||||
:aria-label="placeholder"
|
||||
/>
|
||||
<IconButton
|
||||
v-if="filterIcon"
|
||||
class="p-inputicon filter-button absolute right-0 inset-y-0 h-full m-0 p-0"
|
||||
:icon="filterIcon"
|
||||
severity="contrast"
|
||||
@click="$emit('showFilter', $event)"
|
||||
/>
|
||||
<InputIcon v-if="!modelValue" :class="icon" />
|
||||
<Button
|
||||
v-if="modelValue"
|
||||
class="p-inputicon clear-button"
|
||||
icon="pi pi-times"
|
||||
text
|
||||
severity="contrast"
|
||||
@click="modelValue = ''"
|
||||
/>
|
||||
</div>
|
||||
<div v-if="filters?.length" class="search-filters flex flex-wrap gap-2 pt-2">
|
||||
<SearchFilterChip
|
||||
v-for="filter in filters"
|
||||
:key="filter.id"
|
||||
:text="filter.text"
|
||||
:badge="filter.badge"
|
||||
:badge-class="filter.badgeClass"
|
||||
@remove="$emit('removeFilter', filter)"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts" generic="TFilter extends SearchFilter">
|
||||
import { debounce } from 'es-toolkit/compat'
|
||||
import { cn } from '@comfyorg/tailwind-utils'
|
||||
import { watchDebounced } from '@vueuse/core'
|
||||
import Button from 'primevue/button'
|
||||
import IconField from 'primevue/iconfield'
|
||||
import InputIcon from 'primevue/inputicon'
|
||||
import InputText from 'primevue/inputtext'
|
||||
import { ref } from 'vue'
|
||||
import { computed, ref } from 'vue'
|
||||
|
||||
import IconButton from '../button/IconButton.vue'
|
||||
import type { SearchFilter } from './SearchFilterChip.vue'
|
||||
import SearchFilterChip from './SearchFilterChip.vue'
|
||||
|
||||
const {
|
||||
modelValue,
|
||||
placeholder = 'Search...',
|
||||
icon = 'pi pi-search',
|
||||
debounceTime = 300,
|
||||
filterIcon,
|
||||
filters = [],
|
||||
autofocus = false
|
||||
autofocus = false,
|
||||
showBorder = false,
|
||||
size = 'md',
|
||||
class: customClass
|
||||
} = defineProps<{
|
||||
modelValue: string
|
||||
placeholder?: string
|
||||
icon?: string
|
||||
debounceTime?: number
|
||||
filterIcon?: string
|
||||
filters?: TFilter[]
|
||||
autofocus?: boolean
|
||||
showBorder?: boolean
|
||||
size?: 'md' | 'lg'
|
||||
class?: string
|
||||
}>()
|
||||
|
||||
const emit = defineEmits<{
|
||||
(e: 'update:modelValue', value: string): void
|
||||
(e: 'search', value: string, filters: TFilter[]): void
|
||||
(e: 'showFilter', event: Event): void
|
||||
(e: 'removeFilter', filter: TFilter): void
|
||||
}>()
|
||||
|
||||
const modelValue = defineModel<string>({ required: true })
|
||||
|
||||
const inputRef = ref()
|
||||
|
||||
defineExpose({
|
||||
@@ -87,20 +96,27 @@ defineExpose({
|
||||
}
|
||||
})
|
||||
|
||||
const emitSearch = debounce((value: string) => {
|
||||
emit('search', value, filters)
|
||||
}, debounceTime)
|
||||
watchDebounced(
|
||||
modelValue,
|
||||
(value: string) => {
|
||||
emit('search', value, filters)
|
||||
},
|
||||
{ debounce: debounceTime }
|
||||
)
|
||||
|
||||
const handleInput = (event: Event) => {
|
||||
const target = event.target as HTMLInputElement
|
||||
emit('update:modelValue', target.value)
|
||||
emitSearch(target.value)
|
||||
}
|
||||
const wrapperStyle = computed(() => {
|
||||
if (showBorder) {
|
||||
return cn('rounded p-2 border border-solid border-border-default')
|
||||
}
|
||||
|
||||
const clearSearch = () => {
|
||||
emit('update:modelValue', '')
|
||||
emitSearch('')
|
||||
}
|
||||
// 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('rounded-lg', sizeClasses)
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
Reference in New Issue
Block a user