mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-02-04 15:10:06 +00:00
feat(V3 UI style): color picker + file upload + input text + multi select + select + select button + slider + textarea + tree select
This commit is contained in:
@@ -1,17 +1,24 @@
|
||||
<!-- Needs custom color picker for alpha support -->
|
||||
<template>
|
||||
<div class="flex flex-col gap-1">
|
||||
<label v-if="widget.name" class="text-sm opacity-80">{{
|
||||
widget.name
|
||||
}}</label>
|
||||
<ColorPicker
|
||||
v-model="localValue"
|
||||
v-bind="filteredProps"
|
||||
:disabled="readonly"
|
||||
inline
|
||||
@update:model-value="onChange"
|
||||
/>
|
||||
</div>
|
||||
<WidgetLayoutField :widget="widget">
|
||||
<label
|
||||
:class="
|
||||
cn(WidgetInputBaseClass, 'flex items-center gap-2 w-full px-4 py-2')
|
||||
"
|
||||
>
|
||||
<ColorPicker
|
||||
v-model="localValue"
|
||||
v-bind="filteredProps"
|
||||
:disabled="readonly"
|
||||
class="w-8 h-4 !rounded-full overflow-hidden border-none"
|
||||
:pt="{
|
||||
preview: '!w-full !h-full !border-none'
|
||||
}"
|
||||
@update:model-value="onChange"
|
||||
/>
|
||||
<span class="text-xs">#{{ localValue }}</span>
|
||||
</label>
|
||||
</WidgetLayoutField>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
@@ -20,11 +27,15 @@ import { computed } from 'vue'
|
||||
|
||||
import { useWidgetValue } from '@/composables/graph/useWidgetValue'
|
||||
import type { SimplifiedWidget } from '@/types/simplifiedWidget'
|
||||
import { cn } from '@/utils/tailwindUtil'
|
||||
import {
|
||||
PANEL_EXCLUDED_PROPS,
|
||||
filterWidgetProps
|
||||
} from '@/utils/widgetPropFilter'
|
||||
|
||||
import { WidgetInputBaseClass } from './layout'
|
||||
import WidgetLayoutField from './layout/WidgetLayoutField.vue'
|
||||
|
||||
const props = defineProps<{
|
||||
widget: SimplifiedWidget<string>
|
||||
modelValue: string
|
||||
|
||||
@@ -157,6 +157,7 @@
|
||||
<Button
|
||||
label="Browse Files"
|
||||
size="small"
|
||||
severity="secondary"
|
||||
class="text-xs"
|
||||
:disabled="readonly"
|
||||
@click="triggerFileInput"
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
v-model="localValue"
|
||||
v-bind="filteredProps"
|
||||
:disabled="readonly"
|
||||
class="w-full text-xs py-2 px-4 bg-zinc-500/10 border-none outline outline-1 outline-offset-[-1px] outline-zinc-300/10 !rounded-lg hover:outline-blue-500/80"
|
||||
:class="cn(WidgetInputBaseClass, 'w-full text-xs py-2 px-4')"
|
||||
size="small"
|
||||
@update:model-value="onChange"
|
||||
/>
|
||||
@@ -17,11 +17,13 @@ import { computed } from 'vue'
|
||||
|
||||
import { useStringWidgetValue } from '@/composables/graph/useWidgetValue'
|
||||
import type { SimplifiedWidget } from '@/types/simplifiedWidget'
|
||||
import { cn } from '@/utils/tailwindUtil'
|
||||
import {
|
||||
INPUT_EXCLUDED_PROPS,
|
||||
filterWidgetProps
|
||||
} from '@/utils/widgetPropFilter'
|
||||
|
||||
import { WidgetInputBaseClass } from './layout'
|
||||
import WidgetLayoutField from './layout/WidgetLayoutField.vue'
|
||||
|
||||
const props = defineProps<{
|
||||
|
||||
@@ -2,10 +2,11 @@
|
||||
<WidgetLayoutField :widget="widget">
|
||||
<MultiSelect
|
||||
v-model="localValue"
|
||||
v-bind="filteredProps"
|
||||
:options="widget.options?.values || []"
|
||||
:disabled="readonly"
|
||||
class="w-full text-xs"
|
||||
:class="cn(WidgetInputBaseClass, 'w-full text-xs')"
|
||||
size="small"
|
||||
display="chip"
|
||||
:pt="{
|
||||
option: 'text-xs'
|
||||
}"
|
||||
@@ -16,15 +17,12 @@
|
||||
|
||||
<script setup lang="ts">
|
||||
import MultiSelect from 'primevue/multiselect'
|
||||
import { computed } from 'vue'
|
||||
|
||||
import { useWidgetValue } from '@/composables/graph/useWidgetValue'
|
||||
import type { SimplifiedWidget } from '@/types/simplifiedWidget'
|
||||
import {
|
||||
PANEL_EXCLUDED_PROPS,
|
||||
filterWidgetProps
|
||||
} from '@/utils/widgetPropFilter'
|
||||
import { cn } from '@/utils/tailwindUtil'
|
||||
|
||||
import { WidgetInputBaseClass } from './layout'
|
||||
import WidgetLayoutField from './layout/WidgetLayoutField.vue'
|
||||
|
||||
const props = defineProps<{
|
||||
@@ -44,14 +42,4 @@ const { localValue, onChange } = useWidgetValue({
|
||||
defaultValue: [],
|
||||
emit
|
||||
})
|
||||
|
||||
// MultiSelect specific excluded props include overlay styles
|
||||
const MULTISELECT_EXCLUDED_PROPS = [
|
||||
...PANEL_EXCLUDED_PROPS,
|
||||
'overlayStyle'
|
||||
] as const
|
||||
|
||||
const filteredProps = computed(() =>
|
||||
filterWidgetProps(props.widget.options, MULTISELECT_EXCLUDED_PROPS)
|
||||
)
|
||||
</script>
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
:options="selectOptions"
|
||||
v-bind="filteredProps"
|
||||
:disabled="readonly"
|
||||
class="w-full text-xs bg-[#F9F8F4] dark-theme:bg-[#0E0E12] border-[#E1DED5] dark-theme:border-[#15161C] !rounded-lg"
|
||||
:class="cn(WidgetInputBaseClass, 'w-full text-xs')"
|
||||
size="small"
|
||||
:pt="{
|
||||
option: 'text-xs'
|
||||
@@ -21,11 +21,13 @@ import { computed } from 'vue'
|
||||
|
||||
import { useWidgetValue } from '@/composables/graph/useWidgetValue'
|
||||
import type { SimplifiedWidget } from '@/types/simplifiedWidget'
|
||||
import { cn } from '@/utils/tailwindUtil'
|
||||
import {
|
||||
PANEL_EXCLUDED_PROPS,
|
||||
filterWidgetProps
|
||||
} from '@/utils/widgetPropFilter'
|
||||
|
||||
import { WidgetInputBaseClass } from './layout'
|
||||
import WidgetLayoutField from './layout/WidgetLayoutField.vue'
|
||||
|
||||
const props = defineProps<{
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
<template>
|
||||
<WidgetLayoutField :widget="widget">
|
||||
<div
|
||||
class="flex items-center gap-2 w-full rounded-lg pl-4 pr-2 bg-[#F9F8F4] dark-theme:bg-[#0E0E12] border-[#E1DED5] dark-theme:border-[#15161C] border-solid border"
|
||||
:class="
|
||||
cn(WidgetInputBaseClass, 'flex items-center gap-2 w-full pl-4 pr-2')
|
||||
"
|
||||
>
|
||||
<Slider
|
||||
v-model="localValue"
|
||||
@@ -33,11 +35,13 @@ import { computed, ref, watch } from 'vue'
|
||||
|
||||
import { useNumberWidgetValue } from '@/composables/graph/useWidgetValue'
|
||||
import type { SimplifiedWidget } from '@/types/simplifiedWidget'
|
||||
import { cn } from '@/utils/tailwindUtil'
|
||||
import {
|
||||
STANDARD_EXCLUDED_PROPS,
|
||||
filterWidgetProps
|
||||
} from '@/utils/widgetPropFilter'
|
||||
|
||||
import { WidgetInputBaseClass } from './layout'
|
||||
import WidgetLayoutField from './layout/WidgetLayoutField.vue'
|
||||
|
||||
const props = defineProps<{
|
||||
|
||||
@@ -3,7 +3,8 @@
|
||||
v-model="localValue"
|
||||
v-bind="filteredProps"
|
||||
:disabled="readonly"
|
||||
class="w-full text-xs"
|
||||
:class="cn(WidgetInputBaseClass, 'w-full text-xs')"
|
||||
:placeholder="widget.name || ''"
|
||||
size="small"
|
||||
rows="3"
|
||||
@update:model-value="onChange"
|
||||
@@ -16,11 +17,14 @@ import { computed } from 'vue'
|
||||
|
||||
import { useStringWidgetValue } from '@/composables/graph/useWidgetValue'
|
||||
import type { SimplifiedWidget } from '@/types/simplifiedWidget'
|
||||
import { cn } from '@/utils/tailwindUtil'
|
||||
import {
|
||||
INPUT_EXCLUDED_PROPS,
|
||||
filterWidgetProps
|
||||
} from '@/utils/widgetPropFilter'
|
||||
|
||||
import { WidgetInputBaseClass } from './layout'
|
||||
|
||||
const props = defineProps<{
|
||||
widget: SimplifiedWidget<string>
|
||||
modelValue: string
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
v-model="localValue"
|
||||
v-bind="filteredProps"
|
||||
:disabled="readonly"
|
||||
class="w-full text-xs"
|
||||
:class="cn(WidgetInputBaseClass, 'w-full text-xs')"
|
||||
size="small"
|
||||
@update:model-value="onChange"
|
||||
/>
|
||||
@@ -17,11 +17,13 @@ import { computed } from 'vue'
|
||||
|
||||
import { useWidgetValue } from '@/composables/graph/useWidgetValue'
|
||||
import type { SimplifiedWidget } from '@/types/simplifiedWidget'
|
||||
import { cn } from '@/utils/tailwindUtil'
|
||||
import {
|
||||
PANEL_EXCLUDED_PROPS,
|
||||
filterWidgetProps
|
||||
} from '@/utils/widgetPropFilter'
|
||||
|
||||
import { WidgetInputBaseClass } from './layout'
|
||||
import WidgetLayoutField from './layout/WidgetLayoutField.vue'
|
||||
|
||||
const props = defineProps<{
|
||||
|
||||
@@ -1,6 +1,11 @@
|
||||
<template>
|
||||
<div
|
||||
class="p-1 bg-zinc-500/10 rounded-lg outline outline-1 outline-offset-[-1px] outline-zinc-300/10 inline-flex justify-center items-center gap-1 hover:outline-blue-500/80"
|
||||
:class="
|
||||
cn(
|
||||
WidgetInputBaseClass,
|
||||
'p-1 inline-flex justify-center items-center gap-1'
|
||||
)
|
||||
"
|
||||
>
|
||||
<button
|
||||
v-for="(option, index) in options"
|
||||
@@ -33,6 +38,8 @@
|
||||
<script setup lang="ts">
|
||||
import { cn } from '@/utils/tailwindUtil'
|
||||
|
||||
import { WidgetInputBaseClass } from '../layout'
|
||||
|
||||
interface Props {
|
||||
modelValue: string | null | undefined
|
||||
options: any[]
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
export const WidgetInputBaseClass = [
|
||||
// Background
|
||||
'bg-zinc-500/10',
|
||||
// Outline
|
||||
'border-none',
|
||||
'outline',
|
||||
'outline-1',
|
||||
'outline-offset-[-1px]',
|
||||
'outline-zinc-300/10',
|
||||
// Rounded
|
||||
'!rounded-lg',
|
||||
// Hover
|
||||
'hover:outline-blue-500/80'
|
||||
].join(' ')
|
||||
@@ -25,6 +25,10 @@ const TYPE_TO_ENUM_MAP: Record<string, string> = {
|
||||
COMBO: WidgetType.COMBO,
|
||||
selectbutton: WidgetType.SELECTBUTTON,
|
||||
SELECTBUTTON: WidgetType.SELECTBUTTON,
|
||||
multiselect: WidgetType.MULTISELECT,
|
||||
MULTISELECT: WidgetType.MULTISELECT,
|
||||
treeselect: WidgetType.TREESELECT,
|
||||
TREESELECT: WidgetType.TREESELECT,
|
||||
|
||||
// Boolean
|
||||
toggle: WidgetType.TOGGLESWITCH,
|
||||
@@ -34,6 +38,7 @@ const TYPE_TO_ENUM_MAP: Record<string, string> = {
|
||||
// Multiline text
|
||||
multiline: WidgetType.TEXTAREA,
|
||||
textarea: WidgetType.TEXTAREA,
|
||||
TEXTAREA: WidgetType.TEXTAREA,
|
||||
customtext: WidgetType.TEXTAREA,
|
||||
MARKDOWN: WidgetType.MARKDOWN,
|
||||
|
||||
|
||||
Reference in New Issue
Block a user