mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-04-21 23:09:39 +00:00
feat: right side panel (#6952)
<img width="1183" height="809" alt="CleanShot 2025-11-26 at 16 01 15" src="https://github.com/user-attachments/assets/c14dc5c3-a672-4dcd-917d-14f16310188e" /> ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-6952-feat-right-side-panel-2b76d73d36508112b121c283a479f42a) by [Unito](https://www.unito.io) --------- Co-authored-by: github-actions <github-actions@github.com>
This commit is contained in:
@@ -17,17 +17,19 @@
|
||||
'text-center text-xs font-normal',
|
||||
{
|
||||
'bg-interface-menu-component-surface-selected':
|
||||
isSelected(option) && !disabled,
|
||||
'hover:bg-interface-menu-component-surface-hovered':
|
||||
!isSelected(option) && !disabled,
|
||||
isSelected(index) && !disabled,
|
||||
'hover:bg-interface-menu-component-surface-selected/50':
|
||||
!isSelected(index) && !disabled,
|
||||
'opacity-50 cursor-not-allowed': disabled,
|
||||
'cursor-pointer': !disabled
|
||||
},
|
||||
isSelected(option) && !disabled ? 'text-primary' : 'text-secondary'
|
||||
isSelected(index) && !disabled
|
||||
? 'text-text-primary'
|
||||
: 'text-text-secondary'
|
||||
)
|
||||
"
|
||||
:disabled="disabled"
|
||||
@click="handleSelect(option)"
|
||||
@click="handleSelect(index)"
|
||||
>
|
||||
{{ getOptionLabel(option) }}
|
||||
</button>
|
||||
@@ -37,14 +39,18 @@
|
||||
<script
|
||||
setup
|
||||
lang="ts"
|
||||
generic="T extends string | number | { label: string; value: any }"
|
||||
generic="
|
||||
T extends string | number | { label: string; value: string | number }
|
||||
"
|
||||
>
|
||||
import { cn } from '@/utils/tailwindUtil'
|
||||
|
||||
import { WidgetInputBaseClass } from '../layout'
|
||||
|
||||
type ModelValue = T extends object ? T['value'] : T
|
||||
|
||||
interface Props {
|
||||
modelValue: string | null | undefined
|
||||
modelValue: ModelValue | null | undefined
|
||||
options: T[]
|
||||
optionLabel?: string // PrimeVue compatible prop
|
||||
optionValue?: string // PrimeVue compatible prop
|
||||
@@ -52,7 +58,7 @@ interface Props {
|
||||
}
|
||||
|
||||
interface Emits {
|
||||
'update:modelValue': [value: string]
|
||||
'update:modelValue': [value: ModelValue]
|
||||
}
|
||||
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
@@ -64,18 +70,19 @@ const props = withDefaults(defineProps<Props>(), {
|
||||
const emit = defineEmits<Emits>()
|
||||
|
||||
// handle both string/number arrays and object arrays with PrimeVue compatibility
|
||||
const getOptionValue = (option: T, index: number): string => {
|
||||
if (typeof option === 'object' && option !== null) {
|
||||
const valueField = props.optionValue
|
||||
const value =
|
||||
(option as any)[valueField] ??
|
||||
(option as any).value ??
|
||||
(option as any).name ??
|
||||
(option as any).label ??
|
||||
index
|
||||
return String(value)
|
||||
const getOptionValue = (option: T, index: number): ModelValue => {
|
||||
if (typeof option !== 'object') {
|
||||
return option as ModelValue
|
||||
}
|
||||
return String(option)
|
||||
|
||||
const valueField = props.optionValue
|
||||
const value =
|
||||
(option as any)[valueField] ??
|
||||
option.value ??
|
||||
(option as any).name ??
|
||||
option.label ??
|
||||
index
|
||||
return value
|
||||
}
|
||||
|
||||
// for display with PrimeVue compatibility
|
||||
@@ -84,24 +91,24 @@ const getOptionLabel = (option: T): string => {
|
||||
const labelField = props.optionLabel
|
||||
return (
|
||||
(option as any)[labelField] ??
|
||||
(option as any).label ??
|
||||
option.label ??
|
||||
(option as any).name ??
|
||||
(option as any).value ??
|
||||
option.value ??
|
||||
String(option)
|
||||
)
|
||||
}
|
||||
return String(option)
|
||||
}
|
||||
|
||||
const isSelected = (option: T): boolean => {
|
||||
const optionValue = getOptionValue(option, props.options.indexOf(option))
|
||||
return optionValue === String(props.modelValue ?? '')
|
||||
const isSelected = (index: number): boolean => {
|
||||
const optionValue = getOptionValue(props.options[index], index)
|
||||
return String(optionValue) === String(props.modelValue ?? '')
|
||||
}
|
||||
|
||||
const handleSelect = (option: T) => {
|
||||
const handleSelect = (index: number) => {
|
||||
if (props.disabled) return
|
||||
|
||||
const optionValue = getOptionValue(option, props.options.indexOf(option))
|
||||
const optionValue = getOptionValue(props.options[index], index)
|
||||
emit('update:modelValue', optionValue)
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -1,18 +1,24 @@
|
||||
<script setup lang="ts">
|
||||
import { noop } from 'es-toolkit'
|
||||
import { inject } from 'vue'
|
||||
|
||||
import type { SimplifiedWidget } from '@/types/simplifiedWidget'
|
||||
|
||||
defineProps<{
|
||||
widget: Pick<SimplifiedWidget<string | number | undefined>, 'name' | 'label'>
|
||||
}>()
|
||||
|
||||
const hideLayoutField = inject<boolean>('hideLayoutField', false)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div
|
||||
class="grid grid-cols-subgrid h-7.5 min-w-0 items-center justify-between gap-1"
|
||||
>
|
||||
<div class="relative flex h-full min-w-0 items-center">
|
||||
<div
|
||||
v-if="!hideLayoutField"
|
||||
class="relative flex h-full min-w-0 items-center"
|
||||
>
|
||||
<p
|
||||
v-if="widget.name"
|
||||
class="flex-1 truncate text-xs font-normal text-node-component-slot-text"
|
||||
|
||||
Reference in New Issue
Block a user