mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-04-30 11:11:53 +00:00
[feat] Add file upload support to canvas background image setting (#3958)
Co-authored-by: github-actions <github-actions@github.com>
This commit is contained in:
251
browser_tests/tests/backgroundImageUpload.spec.ts
Normal file
251
browser_tests/tests/backgroundImageUpload.spec.ts
Normal file
@@ -0,0 +1,251 @@
|
|||||||
|
import { expect } from '@playwright/test'
|
||||||
|
|
||||||
|
import { comfyPageFixture as test } from '../fixtures/ComfyPage'
|
||||||
|
|
||||||
|
test.describe('Background Image Upload', () => {
|
||||||
|
test.beforeEach(async ({ comfyPage }) => {
|
||||||
|
// Reset the background image setting before each test
|
||||||
|
await comfyPage.setSetting('Comfy.Canvas.BackgroundImage', '')
|
||||||
|
})
|
||||||
|
|
||||||
|
test.afterEach(async ({ comfyPage }) => {
|
||||||
|
// Clean up background image setting after each test
|
||||||
|
await comfyPage.setSetting('Comfy.Canvas.BackgroundImage', '')
|
||||||
|
})
|
||||||
|
|
||||||
|
test('should show background image upload component in settings', async ({
|
||||||
|
comfyPage
|
||||||
|
}) => {
|
||||||
|
// Open settings dialog
|
||||||
|
await comfyPage.page.keyboard.press('Control+,')
|
||||||
|
|
||||||
|
// Navigate to Appearance category
|
||||||
|
const appearanceOption = comfyPage.page.locator('text=Appearance')
|
||||||
|
await appearanceOption.click()
|
||||||
|
|
||||||
|
// Find the background image setting
|
||||||
|
const backgroundImageSetting = comfyPage.page.locator(
|
||||||
|
'#Comfy\\.Canvas\\.BackgroundImage'
|
||||||
|
)
|
||||||
|
await expect(backgroundImageSetting).toBeVisible()
|
||||||
|
|
||||||
|
// Verify the component has the expected elements using semantic selectors
|
||||||
|
const urlInput = backgroundImageSetting.locator('input[type="text"]')
|
||||||
|
await expect(urlInput).toBeVisible()
|
||||||
|
await expect(urlInput).toHaveAttribute('placeholder')
|
||||||
|
|
||||||
|
const uploadButton = backgroundImageSetting.locator(
|
||||||
|
'button:has(.pi-upload)'
|
||||||
|
)
|
||||||
|
await expect(uploadButton).toBeVisible()
|
||||||
|
|
||||||
|
const clearButton = backgroundImageSetting.locator('button:has(.pi-trash)')
|
||||||
|
await expect(clearButton).toBeVisible()
|
||||||
|
await expect(clearButton).toBeDisabled() // Should be disabled when no image
|
||||||
|
})
|
||||||
|
|
||||||
|
test('should upload image file and set as background', async ({
|
||||||
|
comfyPage
|
||||||
|
}) => {
|
||||||
|
// Open settings dialog
|
||||||
|
await comfyPage.page.keyboard.press('Control+,')
|
||||||
|
|
||||||
|
// Navigate to Appearance category
|
||||||
|
const appearanceOption = comfyPage.page.locator('text=Appearance')
|
||||||
|
await appearanceOption.click()
|
||||||
|
|
||||||
|
// Find the background image setting
|
||||||
|
const backgroundImageSetting = comfyPage.page.locator(
|
||||||
|
'#Comfy\\.Canvas\\.BackgroundImage'
|
||||||
|
)
|
||||||
|
// Click the upload button to trigger file input
|
||||||
|
const uploadButton = backgroundImageSetting.locator(
|
||||||
|
'button:has(.pi-upload)'
|
||||||
|
)
|
||||||
|
|
||||||
|
// Set up file upload handler
|
||||||
|
const fileChooserPromise = comfyPage.page.waitForEvent('filechooser')
|
||||||
|
await uploadButton.click()
|
||||||
|
const fileChooser = await fileChooserPromise
|
||||||
|
|
||||||
|
// Upload the test image
|
||||||
|
await fileChooser.setFiles(comfyPage.assetPath('image32x32.webp'))
|
||||||
|
|
||||||
|
// Wait for upload to complete and verify the setting was updated
|
||||||
|
await comfyPage.page.waitForTimeout(500) // Give time for file reading
|
||||||
|
|
||||||
|
// Verify the URL input now has an API URL
|
||||||
|
const urlInput = backgroundImageSetting.locator('input[type="text"]')
|
||||||
|
const inputValue = await urlInput.inputValue()
|
||||||
|
expect(inputValue).toMatch(/^\/api\/view\?.*subfolder=backgrounds/)
|
||||||
|
|
||||||
|
// Verify clear button is now enabled
|
||||||
|
const clearButton = backgroundImageSetting.locator('button:has(.pi-trash)')
|
||||||
|
await expect(clearButton).toBeEnabled()
|
||||||
|
|
||||||
|
// Verify the setting value was actually set
|
||||||
|
const settingValue = await comfyPage.getSetting(
|
||||||
|
'Comfy.Canvas.BackgroundImage'
|
||||||
|
)
|
||||||
|
expect(settingValue).toMatch(/^\/api\/view\?.*subfolder=backgrounds/)
|
||||||
|
})
|
||||||
|
|
||||||
|
test('should accept URL input for background image', async ({
|
||||||
|
comfyPage
|
||||||
|
}) => {
|
||||||
|
const testImageUrl = 'https://example.com/test-image.png'
|
||||||
|
|
||||||
|
// Open settings dialog
|
||||||
|
await comfyPage.page.keyboard.press('Control+,')
|
||||||
|
|
||||||
|
// Navigate to Appearance category
|
||||||
|
const appearanceOption = comfyPage.page.locator('text=Appearance')
|
||||||
|
await appearanceOption.click()
|
||||||
|
|
||||||
|
// Find the background image setting
|
||||||
|
const backgroundImageSetting = comfyPage.page.locator(
|
||||||
|
'#Comfy\\.Canvas\\.BackgroundImage'
|
||||||
|
)
|
||||||
|
// Enter URL in the input field
|
||||||
|
const urlInput = backgroundImageSetting.locator('input[type="text"]')
|
||||||
|
await urlInput.fill(testImageUrl)
|
||||||
|
|
||||||
|
// Trigger blur event to ensure the value is set
|
||||||
|
await urlInput.blur()
|
||||||
|
|
||||||
|
// Verify clear button is now enabled
|
||||||
|
const clearButton = backgroundImageSetting.locator('button:has(.pi-trash)')
|
||||||
|
await expect(clearButton).toBeEnabled()
|
||||||
|
|
||||||
|
// Verify the setting value was updated
|
||||||
|
const settingValue = await comfyPage.getSetting(
|
||||||
|
'Comfy.Canvas.BackgroundImage'
|
||||||
|
)
|
||||||
|
expect(settingValue).toBe(testImageUrl)
|
||||||
|
})
|
||||||
|
|
||||||
|
test('should clear background image when clear button is clicked', async ({
|
||||||
|
comfyPage
|
||||||
|
}) => {
|
||||||
|
const testImageUrl = 'https://example.com/test-image.png'
|
||||||
|
|
||||||
|
// First set a background image
|
||||||
|
await comfyPage.setSetting('Comfy.Canvas.BackgroundImage', testImageUrl)
|
||||||
|
|
||||||
|
// Open settings dialog
|
||||||
|
await comfyPage.page.keyboard.press('Control+,')
|
||||||
|
|
||||||
|
// Navigate to Appearance category
|
||||||
|
const appearanceOption = comfyPage.page.locator('text=Appearance')
|
||||||
|
await appearanceOption.click()
|
||||||
|
|
||||||
|
// Find the background image setting
|
||||||
|
const backgroundImageSetting = comfyPage.page.locator(
|
||||||
|
'#Comfy\\.Canvas\\.BackgroundImage'
|
||||||
|
)
|
||||||
|
// Verify the input has the test URL
|
||||||
|
const urlInput = backgroundImageSetting.locator('input[type="text"]')
|
||||||
|
await expect(urlInput).toHaveValue(testImageUrl)
|
||||||
|
|
||||||
|
// Verify clear button is enabled
|
||||||
|
const clearButton = backgroundImageSetting.locator('button:has(.pi-trash)')
|
||||||
|
await expect(clearButton).toBeEnabled()
|
||||||
|
|
||||||
|
// Click the clear button
|
||||||
|
await clearButton.click()
|
||||||
|
|
||||||
|
// Verify the input is now empty
|
||||||
|
await expect(urlInput).toHaveValue('')
|
||||||
|
|
||||||
|
// Verify clear button is now disabled
|
||||||
|
await expect(clearButton).toBeDisabled()
|
||||||
|
|
||||||
|
// Verify the setting value was cleared
|
||||||
|
const settingValue = await comfyPage.getSetting(
|
||||||
|
'Comfy.Canvas.BackgroundImage'
|
||||||
|
)
|
||||||
|
expect(settingValue).toBe('')
|
||||||
|
})
|
||||||
|
|
||||||
|
test('should show tooltip on upload and clear buttons', async ({
|
||||||
|
comfyPage
|
||||||
|
}) => {
|
||||||
|
// Open settings dialog
|
||||||
|
await comfyPage.page.keyboard.press('Control+,')
|
||||||
|
|
||||||
|
// Navigate to Appearance category
|
||||||
|
const appearanceOption = comfyPage.page.locator('text=Appearance')
|
||||||
|
await appearanceOption.click()
|
||||||
|
|
||||||
|
// Find the background image setting
|
||||||
|
const backgroundImageSetting = comfyPage.page.locator(
|
||||||
|
'#Comfy\\.Canvas\\.BackgroundImage'
|
||||||
|
)
|
||||||
|
// Hover over upload button and verify tooltip appears
|
||||||
|
const uploadButton = backgroundImageSetting.locator(
|
||||||
|
'button:has(.pi-upload)'
|
||||||
|
)
|
||||||
|
await uploadButton.hover()
|
||||||
|
|
||||||
|
// Wait for tooltip to appear and verify it exists
|
||||||
|
await comfyPage.page.waitForTimeout(700) // Tooltip delay
|
||||||
|
const uploadTooltip = comfyPage.page.locator('.p-tooltip:visible')
|
||||||
|
await expect(uploadTooltip).toBeVisible()
|
||||||
|
|
||||||
|
// Move away to hide tooltip
|
||||||
|
await comfyPage.page.locator('body').hover()
|
||||||
|
await comfyPage.page.waitForTimeout(100)
|
||||||
|
|
||||||
|
// Set a background to enable clear button
|
||||||
|
const urlInput = backgroundImageSetting.locator('input[type="text"]')
|
||||||
|
await urlInput.fill('https://example.com/test.png')
|
||||||
|
await urlInput.blur()
|
||||||
|
|
||||||
|
// Hover over clear button and verify tooltip appears
|
||||||
|
const clearButton = backgroundImageSetting.locator('button:has(.pi-trash)')
|
||||||
|
await clearButton.hover()
|
||||||
|
|
||||||
|
// Wait for tooltip to appear and verify it exists
|
||||||
|
await comfyPage.page.waitForTimeout(700) // Tooltip delay
|
||||||
|
const clearTooltip = comfyPage.page.locator('.p-tooltip:visible')
|
||||||
|
await expect(clearTooltip).toBeVisible()
|
||||||
|
})
|
||||||
|
|
||||||
|
test('should maintain reactive updates between URL input and clear button state', async ({
|
||||||
|
comfyPage
|
||||||
|
}) => {
|
||||||
|
// Open settings dialog
|
||||||
|
await comfyPage.page.keyboard.press('Control+,')
|
||||||
|
|
||||||
|
// Navigate to Appearance category
|
||||||
|
const appearanceOption = comfyPage.page.locator('text=Appearance')
|
||||||
|
await appearanceOption.click()
|
||||||
|
|
||||||
|
// Find the background image setting
|
||||||
|
const backgroundImageSetting = comfyPage.page.locator(
|
||||||
|
'#Comfy\\.Canvas\\.BackgroundImage'
|
||||||
|
)
|
||||||
|
const urlInput = backgroundImageSetting.locator('input[type="text"]')
|
||||||
|
const clearButton = backgroundImageSetting.locator('button:has(.pi-trash)')
|
||||||
|
|
||||||
|
// Initially clear button should be disabled
|
||||||
|
await expect(clearButton).toBeDisabled()
|
||||||
|
|
||||||
|
// Type some text - clear button should become enabled
|
||||||
|
await urlInput.fill('test')
|
||||||
|
await expect(clearButton).toBeEnabled()
|
||||||
|
|
||||||
|
// Clear the text manually - clear button should become disabled again
|
||||||
|
await urlInput.fill('')
|
||||||
|
await expect(clearButton).toBeDisabled()
|
||||||
|
|
||||||
|
// Add text again - clear button should become enabled
|
||||||
|
await urlInput.fill('https://example.com/image.png')
|
||||||
|
await expect(clearButton).toBeEnabled()
|
||||||
|
|
||||||
|
// Use clear button - should clear input and disable itself
|
||||||
|
await clearButton.click()
|
||||||
|
await expect(urlInput).toHaveValue('')
|
||||||
|
await expect(clearButton).toBeDisabled()
|
||||||
|
})
|
||||||
|
})
|
||||||
103
src/components/common/BackgroundImageUpload.vue
Normal file
103
src/components/common/BackgroundImageUpload.vue
Normal file
@@ -0,0 +1,103 @@
|
|||||||
|
<template>
|
||||||
|
<div class="flex gap-2">
|
||||||
|
<InputText
|
||||||
|
v-model="modelValue"
|
||||||
|
class="flex-1"
|
||||||
|
:placeholder="$t('g.imageUrl')"
|
||||||
|
/>
|
||||||
|
<Button
|
||||||
|
v-tooltip="$t('g.upload')"
|
||||||
|
:icon="isUploading ? 'pi pi-spin pi-spinner' : 'pi pi-upload'"
|
||||||
|
size="small"
|
||||||
|
:disabled="isUploading"
|
||||||
|
@click="triggerFileInput"
|
||||||
|
/>
|
||||||
|
<Button
|
||||||
|
v-tooltip="$t('g.clear')"
|
||||||
|
outlined
|
||||||
|
icon="pi pi-trash"
|
||||||
|
severity="danger"
|
||||||
|
size="small"
|
||||||
|
:disabled="!modelValue"
|
||||||
|
@click="clearImage"
|
||||||
|
/>
|
||||||
|
<input
|
||||||
|
ref="fileInput"
|
||||||
|
type="file"
|
||||||
|
class="hidden"
|
||||||
|
accept="image/*"
|
||||||
|
@change="handleFileUpload"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import Button from 'primevue/button'
|
||||||
|
import InputText from 'primevue/inputtext'
|
||||||
|
import { ref } from 'vue'
|
||||||
|
|
||||||
|
import { api } from '@/scripts/api'
|
||||||
|
import { useToastStore } from '@/stores/toastStore'
|
||||||
|
|
||||||
|
const modelValue = defineModel<string>()
|
||||||
|
|
||||||
|
const fileInput = ref<HTMLInputElement | null>(null)
|
||||||
|
const isUploading = ref(false)
|
||||||
|
|
||||||
|
const triggerFileInput = () => {
|
||||||
|
fileInput.value?.click()
|
||||||
|
}
|
||||||
|
|
||||||
|
const uploadFile = async (file: File): Promise<string | null> => {
|
||||||
|
const body = new FormData()
|
||||||
|
body.append('image', file)
|
||||||
|
body.append('subfolder', 'backgrounds')
|
||||||
|
|
||||||
|
const resp = await api.fetchApi('/upload/image', {
|
||||||
|
method: 'POST',
|
||||||
|
body
|
||||||
|
})
|
||||||
|
|
||||||
|
if (resp.status !== 200) {
|
||||||
|
useToastStore().addAlert(
|
||||||
|
`Upload failed: ${resp.status} - ${resp.statusText}`
|
||||||
|
)
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
const data = await resp.json()
|
||||||
|
return data.subfolder ? `${data.subfolder}/${data.name}` : data.name
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleFileUpload = async (event: Event) => {
|
||||||
|
const target = event.target as HTMLInputElement
|
||||||
|
if (target.files && target.files[0]) {
|
||||||
|
const file = target.files[0]
|
||||||
|
|
||||||
|
isUploading.value = true
|
||||||
|
try {
|
||||||
|
const uploadedPath = await uploadFile(file)
|
||||||
|
if (uploadedPath) {
|
||||||
|
// Set the value to the API view URL with subfolder parameter
|
||||||
|
const params = new URLSearchParams({
|
||||||
|
filename: uploadedPath,
|
||||||
|
type: 'input',
|
||||||
|
subfolder: 'backgrounds'
|
||||||
|
})
|
||||||
|
modelValue.value = `/api/view?${params.toString()}`
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
useToastStore().addAlert(`Upload error: ${String(error)}`)
|
||||||
|
} finally {
|
||||||
|
isUploading.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const clearImage = () => {
|
||||||
|
modelValue.value = ''
|
||||||
|
if (fileInput.value) {
|
||||||
|
fileInput.value.value = ''
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
@@ -36,6 +36,7 @@ import Select from 'primevue/select'
|
|||||||
import ToggleSwitch from 'primevue/toggleswitch'
|
import ToggleSwitch from 'primevue/toggleswitch'
|
||||||
import { type Component, markRaw } from 'vue'
|
import { type Component, markRaw } from 'vue'
|
||||||
|
|
||||||
|
import BackgroundImageUpload from '@/components/common/BackgroundImageUpload.vue'
|
||||||
import CustomFormValue from '@/components/common/CustomFormValue.vue'
|
import CustomFormValue from '@/components/common/CustomFormValue.vue'
|
||||||
import FormColorPicker from '@/components/common/FormColorPicker.vue'
|
import FormColorPicker from '@/components/common/FormColorPicker.vue'
|
||||||
import FormImageUpload from '@/components/common/FormImageUpload.vue'
|
import FormImageUpload from '@/components/common/FormImageUpload.vue'
|
||||||
@@ -102,6 +103,8 @@ function getFormComponent(item: FormItem): Component {
|
|||||||
return FormColorPicker
|
return FormColorPicker
|
||||||
case 'url':
|
case 'url':
|
||||||
return UrlInput
|
return UrlInput
|
||||||
|
case 'backgroundImage':
|
||||||
|
return BackgroundImageUpload
|
||||||
default:
|
default:
|
||||||
return InputText
|
return InputText
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -197,40 +197,46 @@ const confirmRemoveAll = (event: Event) => {
|
|||||||
const menu = ref<InstanceType<typeof ContextMenu> | null>(null)
|
const menu = ref<InstanceType<typeof ContextMenu> | null>(null)
|
||||||
const menuTargetTask = ref<TaskItemImpl | null>(null)
|
const menuTargetTask = ref<TaskItemImpl | null>(null)
|
||||||
const menuTargetNode = ref<ComfyNode | null>(null)
|
const menuTargetNode = ref<ComfyNode | null>(null)
|
||||||
const menuItems = computed<MenuItem[]>(() => [
|
const menuItems = computed<MenuItem[]>(() => {
|
||||||
{
|
const items: MenuItem[] = [
|
||||||
label: t('g.delete'),
|
{
|
||||||
icon: 'pi pi-trash',
|
label: t('g.delete'),
|
||||||
command: () => menuTargetTask.value && removeTask(menuTargetTask.value),
|
icon: 'pi pi-trash',
|
||||||
disabled: isExpanded.value || isInFolderView.value
|
command: () => menuTargetTask.value && removeTask(menuTargetTask.value),
|
||||||
},
|
disabled: isExpanded.value || isInFolderView.value
|
||||||
{
|
|
||||||
label: t('g.loadWorkflow'),
|
|
||||||
icon: 'pi pi-file-export',
|
|
||||||
command: () => menuTargetTask.value?.loadWorkflow(app),
|
|
||||||
disabled: !menuTargetTask.value?.workflow
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: t('g.goToNode'),
|
|
||||||
icon: 'pi pi-arrow-circle-right',
|
|
||||||
command: () => {
|
|
||||||
if (!menuTargetNode.value) return
|
|
||||||
|
|
||||||
useLitegraphService().goToNode(menuTargetNode.value.id)
|
|
||||||
},
|
},
|
||||||
visible: !!menuTargetNode.value
|
{
|
||||||
},
|
label: t('g.loadWorkflow'),
|
||||||
{
|
icon: 'pi pi-file-export',
|
||||||
label: t('g.setAsBackground'),
|
command: () => menuTargetTask.value?.loadWorkflow(app),
|
||||||
icon: 'pi pi-image',
|
disabled: !menuTargetTask.value?.workflow
|
||||||
command: () => {
|
},
|
||||||
const url = menuTargetTask.value?.previewOutput?.url
|
{
|
||||||
if (url) {
|
label: t('g.goToNode'),
|
||||||
void settingStore.set('Comfy.Canvas.BackgroundImage', url)
|
icon: 'pi pi-arrow-circle-right',
|
||||||
}
|
command: () => {
|
||||||
|
if (!menuTargetNode.value) return
|
||||||
|
useLitegraphService().goToNode(menuTargetNode.value.id)
|
||||||
|
},
|
||||||
|
visible: !!menuTargetNode.value
|
||||||
}
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
if (menuTargetTask.value?.previewOutput?.mediaType === 'images') {
|
||||||
|
items.push({
|
||||||
|
label: t('g.setAsBackground'),
|
||||||
|
icon: 'pi pi-image',
|
||||||
|
command: () => {
|
||||||
|
const url = menuTargetTask.value?.previewOutput?.url
|
||||||
|
if (url) {
|
||||||
|
void settingStore.set('Comfy.Canvas.BackgroundImage', url)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
])
|
|
||||||
|
return items
|
||||||
|
})
|
||||||
|
|
||||||
const handleContextMenu = ({
|
const handleContextMenu = ({
|
||||||
task,
|
task,
|
||||||
|
|||||||
@@ -830,15 +830,12 @@ export const CORE_SETTINGS: SettingParams[] = [
|
|||||||
id: 'Comfy.Canvas.BackgroundImage',
|
id: 'Comfy.Canvas.BackgroundImage',
|
||||||
category: ['Appearance', 'Canvas', 'Background'],
|
category: ['Appearance', 'Canvas', 'Background'],
|
||||||
name: 'Canvas background image',
|
name: 'Canvas background image',
|
||||||
type: 'text',
|
type: 'backgroundImage',
|
||||||
tooltip:
|
tooltip:
|
||||||
'Image URL for the canvas background. You can right-click an image in the outputs panel and select "Set as Background" to use it.',
|
'Image URL for the canvas background. You can right-click an image in the outputs panel and select "Set as Background" to use it, or upload your own image using the upload button.',
|
||||||
defaultValue: '',
|
defaultValue: '',
|
||||||
versionAdded: '1.20.4',
|
versionAdded: '1.20.4',
|
||||||
attrs: {
|
versionModified: '1.20.5'
|
||||||
inputmode: 'url',
|
|
||||||
placeholder: 'https://example.com/image.png'
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'LiteGraph.Pointer.TrackpadGestures',
|
id: 'LiteGraph.Pointer.TrackpadGestures',
|
||||||
|
|||||||
@@ -118,7 +118,9 @@
|
|||||||
"unknownError": "Unknown error",
|
"unknownError": "Unknown error",
|
||||||
"title": "Title",
|
"title": "Title",
|
||||||
"edit": "Edit",
|
"edit": "Edit",
|
||||||
"copy": "Copy"
|
"copy": "Copy",
|
||||||
|
"imageUrl": "Image URL",
|
||||||
|
"clear": "Clear"
|
||||||
},
|
},
|
||||||
"manager": {
|
"manager": {
|
||||||
"title": "Custom Nodes Manager",
|
"title": "Custom Nodes Manager",
|
||||||
|
|||||||
@@ -27,7 +27,7 @@
|
|||||||
},
|
},
|
||||||
"Comfy_Canvas_BackgroundImage": {
|
"Comfy_Canvas_BackgroundImage": {
|
||||||
"name": "Canvas background image",
|
"name": "Canvas background image",
|
||||||
"tooltip": "Image URL for the canvas background. You can right-click an image in the outputs panel and select \"Set as Background\" to use it."
|
"tooltip": "Image URL for the canvas background. You can right-click an image in the outputs panel and select \"Set as Background\" to use it, or upload your own image using the upload button."
|
||||||
},
|
},
|
||||||
"Comfy_Canvas_SelectionToolbox": {
|
"Comfy_Canvas_SelectionToolbox": {
|
||||||
"name": "Show selection toolbox"
|
"name": "Show selection toolbox"
|
||||||
|
|||||||
@@ -253,6 +253,7 @@
|
|||||||
"capture": "captura",
|
"capture": "captura",
|
||||||
"category": "Categoría",
|
"category": "Categoría",
|
||||||
"choose_file_to_upload": "elige archivo para subir",
|
"choose_file_to_upload": "elige archivo para subir",
|
||||||
|
"clear": "Limpiar",
|
||||||
"close": "Cerrar",
|
"close": "Cerrar",
|
||||||
"color": "Color",
|
"color": "Color",
|
||||||
"comingSoon": "Próximamente",
|
"comingSoon": "Próximamente",
|
||||||
@@ -293,6 +294,7 @@
|
|||||||
"goToNode": "Ir al nodo",
|
"goToNode": "Ir al nodo",
|
||||||
"icon": "Icono",
|
"icon": "Icono",
|
||||||
"imageFailedToLoad": "Falló la carga de la imagen",
|
"imageFailedToLoad": "Falló la carga de la imagen",
|
||||||
|
"imageUrl": "URL de la imagen",
|
||||||
"import": "Importar",
|
"import": "Importar",
|
||||||
"inProgress": "En progreso",
|
"inProgress": "En progreso",
|
||||||
"insert": "Insertar",
|
"insert": "Insertar",
|
||||||
|
|||||||
@@ -253,6 +253,7 @@
|
|||||||
"capture": "capture",
|
"capture": "capture",
|
||||||
"category": "Catégorie",
|
"category": "Catégorie",
|
||||||
"choose_file_to_upload": "choisissez le fichier à télécharger",
|
"choose_file_to_upload": "choisissez le fichier à télécharger",
|
||||||
|
"clear": "Effacer",
|
||||||
"close": "Fermer",
|
"close": "Fermer",
|
||||||
"color": "Couleur",
|
"color": "Couleur",
|
||||||
"comingSoon": "Bientôt disponible",
|
"comingSoon": "Bientôt disponible",
|
||||||
@@ -293,6 +294,7 @@
|
|||||||
"goToNode": "Aller au nœud",
|
"goToNode": "Aller au nœud",
|
||||||
"icon": "Icône",
|
"icon": "Icône",
|
||||||
"imageFailedToLoad": "Échec du chargement de l'image",
|
"imageFailedToLoad": "Échec du chargement de l'image",
|
||||||
|
"imageUrl": "URL de l'image",
|
||||||
"import": "Importer",
|
"import": "Importer",
|
||||||
"inProgress": "En cours",
|
"inProgress": "En cours",
|
||||||
"insert": "Insérer",
|
"insert": "Insérer",
|
||||||
|
|||||||
@@ -253,6 +253,7 @@
|
|||||||
"capture": "キャプチャ",
|
"capture": "キャプチャ",
|
||||||
"category": "カテゴリ",
|
"category": "カテゴリ",
|
||||||
"choose_file_to_upload": "アップロードするファイルを選択",
|
"choose_file_to_upload": "アップロードするファイルを選択",
|
||||||
|
"clear": "クリア",
|
||||||
"close": "閉じる",
|
"close": "閉じる",
|
||||||
"color": "色",
|
"color": "色",
|
||||||
"comingSoon": "近日公開",
|
"comingSoon": "近日公開",
|
||||||
@@ -293,6 +294,7 @@
|
|||||||
"goToNode": "ノードに移動",
|
"goToNode": "ノードに移動",
|
||||||
"icon": "アイコン",
|
"icon": "アイコン",
|
||||||
"imageFailedToLoad": "画像の読み込みに失敗しました",
|
"imageFailedToLoad": "画像の読み込みに失敗しました",
|
||||||
|
"imageUrl": "画像URL",
|
||||||
"import": "インポート",
|
"import": "インポート",
|
||||||
"inProgress": "進行中",
|
"inProgress": "進行中",
|
||||||
"insert": "挿入",
|
"insert": "挿入",
|
||||||
|
|||||||
@@ -253,6 +253,7 @@
|
|||||||
"capture": "캡처",
|
"capture": "캡처",
|
||||||
"category": "카테고리",
|
"category": "카테고리",
|
||||||
"choose_file_to_upload": "업로드할 파일 선택",
|
"choose_file_to_upload": "업로드할 파일 선택",
|
||||||
|
"clear": "지우기",
|
||||||
"close": "닫기",
|
"close": "닫기",
|
||||||
"color": "색상",
|
"color": "색상",
|
||||||
"comingSoon": "곧 출시 예정",
|
"comingSoon": "곧 출시 예정",
|
||||||
@@ -293,6 +294,7 @@
|
|||||||
"goToNode": "노드로 이동",
|
"goToNode": "노드로 이동",
|
||||||
"icon": "아이콘",
|
"icon": "아이콘",
|
||||||
"imageFailedToLoad": "이미지를 로드하지 못했습니다.",
|
"imageFailedToLoad": "이미지를 로드하지 못했습니다.",
|
||||||
|
"imageUrl": "이미지 URL",
|
||||||
"import": "가져오기",
|
"import": "가져오기",
|
||||||
"inProgress": "진행 중",
|
"inProgress": "진행 중",
|
||||||
"insert": "삽입",
|
"insert": "삽입",
|
||||||
|
|||||||
@@ -253,6 +253,7 @@
|
|||||||
"capture": "захват",
|
"capture": "захват",
|
||||||
"category": "Категория",
|
"category": "Категория",
|
||||||
"choose_file_to_upload": "выберите файл для загрузки",
|
"choose_file_to_upload": "выберите файл для загрузки",
|
||||||
|
"clear": "Очистить",
|
||||||
"close": "Закрыть",
|
"close": "Закрыть",
|
||||||
"color": "Цвет",
|
"color": "Цвет",
|
||||||
"comingSoon": "Скоро будет",
|
"comingSoon": "Скоро будет",
|
||||||
@@ -293,6 +294,7 @@
|
|||||||
"goToNode": "Перейти к ноде",
|
"goToNode": "Перейти к ноде",
|
||||||
"icon": "Иконка",
|
"icon": "Иконка",
|
||||||
"imageFailedToLoad": "Не удалось загрузить изображение",
|
"imageFailedToLoad": "Не удалось загрузить изображение",
|
||||||
|
"imageUrl": "URL изображения",
|
||||||
"import": "Импорт",
|
"import": "Импорт",
|
||||||
"inProgress": "В процессе",
|
"inProgress": "В процессе",
|
||||||
"insert": "Вставить",
|
"insert": "Вставить",
|
||||||
|
|||||||
@@ -253,6 +253,7 @@
|
|||||||
"capture": "捕获",
|
"capture": "捕获",
|
||||||
"category": "类别",
|
"category": "类别",
|
||||||
"choose_file_to_upload": "选择要上传的文件",
|
"choose_file_to_upload": "选择要上传的文件",
|
||||||
|
"clear": "清除",
|
||||||
"close": "关闭",
|
"close": "关闭",
|
||||||
"color": "颜色",
|
"color": "颜色",
|
||||||
"comingSoon": "即将推出",
|
"comingSoon": "即将推出",
|
||||||
@@ -293,6 +294,7 @@
|
|||||||
"goToNode": "转到节点",
|
"goToNode": "转到节点",
|
||||||
"icon": "图标",
|
"icon": "图标",
|
||||||
"imageFailedToLoad": "图像加载失败",
|
"imageFailedToLoad": "图像加载失败",
|
||||||
|
"imageUrl": "图片网址",
|
||||||
"import": "导入",
|
"import": "导入",
|
||||||
"inProgress": "进行中",
|
"inProgress": "进行中",
|
||||||
"insert": "插入",
|
"insert": "插入",
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ export type SettingInputType =
|
|||||||
| 'color'
|
| 'color'
|
||||||
| 'url'
|
| 'url'
|
||||||
| 'hidden'
|
| 'hidden'
|
||||||
|
| 'backgroundImage'
|
||||||
|
|
||||||
export type SettingCustomRenderer = (
|
export type SettingCustomRenderer = (
|
||||||
name: string,
|
name: string,
|
||||||
|
|||||||
Reference in New Issue
Block a user