Better bottom bar
This commit is contained in:
@@ -41,17 +41,17 @@
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
{#if container && children}
|
{#if container && children}
|
||||||
{@const edit = $uiState.uiEditMode === "widgets" && zIndex > 1}
|
{@const edit = $uiState.uiUnlocked && $uiState.uiEditMode === "widgets" && zIndex > 1}
|
||||||
{#key $attrsChanged}
|
{#key $attrsChanged}
|
||||||
<div class="container {container.attrs.direction} {container.attrs.classes} {classes.join(' ')} z-index{zIndex}"
|
<div class="container {container.attrs.direction} {container.attrs.classes} {classes.join(' ')} z-index{zIndex}"
|
||||||
class:hide-block={container.attrs.blockVariant === "hidden"}
|
class:hide-block={container.attrs.blockVariant === "hidden"}
|
||||||
class:selected={$uiState.uiEditMode !== "disabled" && $layoutState.currentSelection.includes(container.id)}
|
class:selected={$uiState.uiUnlocked && $layoutState.currentSelection.includes(container.id)}
|
||||||
class:root-container={zIndex === 0}
|
class:root-container={zIndex === 0}
|
||||||
class:is-executing={container.isNodeExecuting}
|
class:is-executing={container.isNodeExecuting}
|
||||||
class:edit={edit}>
|
class:edit={edit}>
|
||||||
<Block>
|
<Block>
|
||||||
{#if container.attrs.title !== ""}
|
{#if container.attrs.title !== ""}
|
||||||
<label for={String(container.id)} class={$uiState.uiEditMode === "widgets" ? "edit-title-label" : ""}>
|
<label for={String(container.id)} class={($uiState.uiUnlocked && $uiState.uiEditMode === "widgets") ? "edit-title-label" : ""}>
|
||||||
<BlockTitle>{container.attrs.title}</BlockTitle>
|
<BlockTitle>{container.attrs.title}</BlockTitle>
|
||||||
</label>
|
</label>
|
||||||
{/if}
|
{/if}
|
||||||
@@ -64,7 +64,7 @@
|
|||||||
centreDraggedOnCursor: true,
|
centreDraggedOnCursor: true,
|
||||||
morphDisabled: true,
|
morphDisabled: true,
|
||||||
dropFromOthersDisabled: zIndex === 0,
|
dropFromOthersDisabled: zIndex === 0,
|
||||||
dragDisabled: zIndex === 0 || $layoutState.currentSelection.length > 2 || $uiState.uiEditMode === "disabled"
|
dragDisabled: zIndex === 0 || $layoutState.currentSelection.length > 2 || !$uiState.uiUnlocked
|
||||||
}}"
|
}}"
|
||||||
on:consider="{handleConsider}"
|
on:consider="{handleConsider}"
|
||||||
on:finalize="{handleFinalize}"
|
on:finalize="{handleFinalize}"
|
||||||
|
|||||||
@@ -19,6 +19,7 @@
|
|||||||
import ComfyQueue from "./ComfyQueue.svelte";
|
import ComfyQueue from "./ComfyQueue.svelte";
|
||||||
import ComfyProperties from "./ComfyProperties.svelte";
|
import ComfyProperties from "./ComfyProperties.svelte";
|
||||||
import queueState from "$lib/stores/queueState";
|
import queueState from "$lib/stores/queueState";
|
||||||
|
import ComfyUnlockUIButton from "./ComfyUnlockUIButton.svelte";
|
||||||
|
|
||||||
export let app: ComfyApp = undefined;
|
export let app: ComfyApp = undefined;
|
||||||
let imageViewer: ImageViewer;
|
let imageViewer: ImageViewer;
|
||||||
@@ -29,7 +30,7 @@
|
|||||||
let containerElem: HTMLDivElement;
|
let containerElem: HTMLDivElement;
|
||||||
let resizeTimeout: NodeJS.Timeout | null;
|
let resizeTimeout: NodeJS.Timeout | null;
|
||||||
let hasShownUIHelpToast: boolean = false;
|
let hasShownUIHelpToast: boolean = false;
|
||||||
let uiTheme: string = "anapnoe";
|
let uiTheme: string = "";
|
||||||
|
|
||||||
let debugLayout: boolean = false;
|
let debugLayout: boolean = false;
|
||||||
|
|
||||||
@@ -69,7 +70,7 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let propsSidebarSize = 0; //15;
|
let propsSidebarSize = 15; //15;
|
||||||
|
|
||||||
function toggleProps() {
|
function toggleProps() {
|
||||||
if (propsSidebarSize == 0) {
|
if (propsSidebarSize == 0) {
|
||||||
@@ -124,7 +125,7 @@
|
|||||||
app.lCanvas.recenter();
|
app.lCanvas.recenter();
|
||||||
}
|
}
|
||||||
|
|
||||||
$: if ($uiState.uiEditMode !== "disabled" && !hasShownUIHelpToast) {
|
$: if ($uiState.uiUnlocked && !hasShownUIHelpToast) {
|
||||||
hasShownUIHelpToast = true;
|
hasShownUIHelpToast = true;
|
||||||
toast.push("Right-click to open context menu.")
|
toast.push("Right-click to open context menu.")
|
||||||
}
|
}
|
||||||
@@ -158,7 +159,7 @@
|
|||||||
(window as any).app = app;
|
(window as any).app = app;
|
||||||
(window as any).appPane = uiPane;
|
(window as any).appPane = uiPane;
|
||||||
|
|
||||||
await import('../../scss/ux.scss');
|
// await import('../../scss/ux.scss');
|
||||||
|
|
||||||
refreshView();
|
refreshView();
|
||||||
})
|
})
|
||||||
@@ -203,50 +204,56 @@
|
|||||||
</Splitpanes>
|
</Splitpanes>
|
||||||
</div>
|
</div>
|
||||||
<div id="bottombar">
|
<div id="bottombar">
|
||||||
<Button variant="primary" on:click={queuePrompt}>
|
<div class="left">
|
||||||
Queue Prompt
|
<Button variant="primary" on:click={queuePrompt}>
|
||||||
</Button>
|
Queue Prompt
|
||||||
<Button variant="secondary" on:click={toggleGraph}>
|
</Button>
|
||||||
Toggle Graph
|
<Button variant="secondary" on:click={toggleGraph}>
|
||||||
</Button>
|
Toggle Graph
|
||||||
<Button variant="secondary" on:click={toggleProps}>
|
</Button>
|
||||||
Toggle Props
|
<Button variant="secondary" on:click={toggleProps}>
|
||||||
</Button>
|
Toggle Props
|
||||||
<Button variant="secondary" on:click={toggleQueue}>
|
</Button>
|
||||||
Toggle Queue
|
<Button variant="secondary" on:click={toggleQueue}>
|
||||||
</Button>
|
Toggle Queue
|
||||||
<Button variant="secondary" on:click={doSave}>
|
</Button>
|
||||||
Save
|
<Button variant="secondary" on:click={doSave}>
|
||||||
</Button>
|
Save
|
||||||
<Button variant="secondary" on:click={doReset}>
|
</Button>
|
||||||
Reset
|
<Button variant="secondary" on:click={doReset}>
|
||||||
</Button>
|
Reset
|
||||||
<Button variant="secondary" on:click={doLoadDefault}>
|
</Button>
|
||||||
Load Default
|
<Button variant="secondary" on:click={doLoadDefault}>
|
||||||
</Button>
|
Load Default
|
||||||
<Button variant="secondary" on:click={doRecenter}>
|
</Button>
|
||||||
Recenter
|
<Button variant="secondary" on:click={doRecenter}>
|
||||||
</Button>
|
Recenter
|
||||||
<Button variant="secondary" on:click={doRefreshCombos}>
|
</Button>
|
||||||
🔄
|
<Button variant="secondary" on:click={doRefreshCombos}>
|
||||||
</Button>
|
🔄
|
||||||
<!-- <Checkbox label="Lock Nodes" bind:value={$uiState.nodesLocked}/>
|
</Button>
|
||||||
<Checkbox label="Disable Interaction" bind:value={$uiState.graphLocked}/> -->
|
<!-- <Checkbox label="Lock Nodes" bind:value={$uiState.nodesLocked}/>
|
||||||
<Checkbox label="Auto-Add UI" bind:value={$uiState.autoAddUI}/>
|
<Checkbox label="Disable Interaction" bind:value={$uiState.graphLocked}/> -->
|
||||||
<label class="label" for="enable-ui-editing">
|
<span style="display: inline-flex !important">
|
||||||
<BlockTitle>Enable UI Editing</BlockTitle>
|
<Checkbox label="Auto-Add UI" bind:value={$uiState.autoAddUI}/>
|
||||||
<select id="enable-ui-editing" name="enable-ui-editing" bind:value={$uiState.uiEditMode}>
|
</span>
|
||||||
<option value="disabled">Disabled</option>
|
<span class="label" for="ui-edit-mode">
|
||||||
<option value="widgets">Widgets</option>
|
<BlockTitle>UI Edit mode</BlockTitle>
|
||||||
</select>
|
<select id="ui-edit-mode" name="ui-edit-mode" bind:value={$uiState.uiEditMode}>
|
||||||
</label>
|
<option value="widgets">Widgets</option>
|
||||||
<label class="label" for="ui-theme">
|
</select>
|
||||||
<BlockTitle>Theme</BlockTitle>
|
</span>
|
||||||
<select id="ui-theme" name="ui-theme" bind:value={uiTheme}>
|
<span class="label" for="ui-theme">
|
||||||
<option value="">None</option>
|
<BlockTitle>Theme</BlockTitle>
|
||||||
<option value="anapnoe">Anapnoe</option>
|
<select id="ui-theme" name="ui-theme" bind:value={uiTheme}>
|
||||||
</select>
|
<option value="">None</option>
|
||||||
</label>
|
<option value="anapnoe">Anapnoe</option>
|
||||||
|
</select>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div class="right">
|
||||||
|
<ComfyUnlockUIButton bind:toggled={$uiState.uiUnlocked} />
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<LightboxModal />
|
<LightboxModal />
|
||||||
</div>
|
</div>
|
||||||
@@ -276,10 +283,23 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
#bottombar {
|
#bottombar {
|
||||||
|
padding-top: 0.5em;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-wrap: wrap;
|
align-items: center;
|
||||||
|
width: 100%;
|
||||||
gap: var(--layout-gap);
|
gap: var(--layout-gap);
|
||||||
margin: 10px;
|
padding-left: 1em;
|
||||||
|
padding-right: 1em;
|
||||||
|
margin-top: auto;
|
||||||
|
overflow-x: auto;
|
||||||
|
|
||||||
|
> .left {
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
> .right {
|
||||||
|
margin-left: auto
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.canvas-wrapper {
|
.canvas-wrapper {
|
||||||
@@ -350,4 +370,8 @@
|
|||||||
label.label > :global(span) {
|
label.label > :global(span) {
|
||||||
top: 20%;
|
top: 20%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
span.left {
|
||||||
|
right: 0px;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
import { TextBox, Checkbox } from "@gradio/form";
|
import { TextBox, Checkbox } from "@gradio/form";
|
||||||
import { LGraphNode } from "@litegraph-ts/core"
|
import { LGraphNode } from "@litegraph-ts/core"
|
||||||
import layoutState, { type IDragItem, type WidgetLayout, ALL_ATTRIBUTES, type AttributesSpec } from "$lib/stores/layoutState"
|
import layoutState, { type IDragItem, type WidgetLayout, ALL_ATTRIBUTES, type AttributesSpec } from "$lib/stores/layoutState"
|
||||||
|
import uiState from "$lib/stores/uiState"
|
||||||
import { get } from "svelte/store"
|
import { get } from "svelte/store"
|
||||||
import type { ComfyWidgetNode } from "$lib/nodes";
|
import type { ComfyWidgetNode } from "$lib/nodes";
|
||||||
import ComfyNumberProperty from "./ComfyNumberProperty.svelte";
|
import ComfyNumberProperty from "./ComfyNumberProperty.svelte";
|
||||||
@@ -41,74 +42,92 @@
|
|||||||
targetType = ""
|
targetType = ""
|
||||||
}
|
}
|
||||||
|
|
||||||
function validNodeProperty(spec: AttributesSpec, node: LGraphNode): boolean {
|
function validNodeProperty(spec: AttributesSpec, node: LGraphNode | null): boolean {
|
||||||
|
if (node == null)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (spec.canShow && !spec.canShow(node))
|
||||||
|
return false;
|
||||||
|
|
||||||
if (spec.validNodeTypes) {
|
if (spec.validNodeTypes) {
|
||||||
return spec.validNodeTypes.indexOf(node.type) !== -1;
|
return spec.validNodeTypes.indexOf(node.type) !== -1;
|
||||||
}
|
}
|
||||||
return spec.name in node.properties
|
return spec.name in node.properties
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateAttribute(entry: AttributesSpec, target: IDragItem, value: any) {
|
function validWidgetAttribute(spec: AttributesSpec, widget: IDragItem | null): boolean {
|
||||||
if (target) {
|
if (widget == null)
|
||||||
const name = entry.name
|
return false;
|
||||||
console.warn("updateAttribute", name, value)
|
if (spec.canShow)
|
||||||
|
return spec.canShow(widget);
|
||||||
|
|
||||||
target.attrs[name] = value
|
return spec.name in widget.attrs
|
||||||
target.attrsChanged.set(!get(target.attrsChanged))
|
}
|
||||||
|
|
||||||
if (node && "propsChanged" in node) {
|
function updateAttribute(entry: AttributesSpec, target: IDragItem | null, value: any) {
|
||||||
const comfyNode = node as ComfyWidgetNode
|
if (target == null)
|
||||||
comfyNode.propsChanged.set(get(comfyNode.propsChanged) + 1)
|
return;
|
||||||
}
|
|
||||||
|
const name = entry.name
|
||||||
|
console.warn("updateAttribute", name, value)
|
||||||
|
|
||||||
|
target.attrs[name] = value
|
||||||
|
target.attrsChanged.set(!get(target.attrsChanged))
|
||||||
|
|
||||||
|
if (node && "propsChanged" in node) {
|
||||||
|
const comfyNode = node as ComfyWidgetNode
|
||||||
|
comfyNode.propsChanged.set(get(comfyNode.propsChanged) + 1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateProperty(entry: AttributesSpec, value: any) {
|
function updateProperty(entry: AttributesSpec, value: any) {
|
||||||
if (node) {
|
if (node == null)
|
||||||
const name = entry.name
|
return
|
||||||
console.warn("updateProperty", name, value)
|
|
||||||
|
|
||||||
node.properties[name] = value;
|
const name = entry.name
|
||||||
|
console.warn("updateProperty", name, value)
|
||||||
|
|
||||||
if ("propsChanged" in node) {
|
node.properties[name] = value;
|
||||||
const comfyNode = node as ComfyWidgetNode
|
|
||||||
comfyNode.propsChanged.set(get(comfyNode.propsChanged) + 1)
|
if ("propsChanged" in node) {
|
||||||
}
|
const comfyNode = node as ComfyWidgetNode
|
||||||
|
comfyNode.propsChanged.set(get(comfyNode.propsChanged) + 1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function getVar(node: LGraphNode, entry: AttributesSpec) {
|
function getVar(node: LGraphNode, spec: AttributesSpec) {
|
||||||
let value = node[entry.name]
|
let value = node[spec.name] || spec.defaultValue
|
||||||
if (entry.serialize)
|
if (spec.serialize)
|
||||||
value = entry.serialize(value)
|
value = spec.serialize(value)
|
||||||
console.debug("[ComfyProperties] getVar", entry, value, node)
|
console.debug("[ComfyProperties] getVar", spec, value, node)
|
||||||
return value
|
return value
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateVar(entry: any, value: any) {
|
function updateVar(entry: any, value: any) {
|
||||||
if (node) {
|
if (node == null)
|
||||||
const name = entry.name
|
return;
|
||||||
console.warn("updateProperty", name, value)
|
|
||||||
|
|
||||||
if (entry.deserialize)
|
const name = entry.name
|
||||||
value = entry.deserialize(value)
|
console.warn("updateVar", name, value)
|
||||||
|
|
||||||
console.debug("[ComfyProperties] updateVar", entry, value, name, node)
|
if (entry.deserialize)
|
||||||
node[name] = value;
|
value = entry.deserialize(value)
|
||||||
|
|
||||||
if ("propsChanged" in node) {
|
console.debug("[ComfyProperties] updateVar", entry, value, name, node)
|
||||||
const comfyNode = node as ComfyWidgetNode
|
node[name] = value;
|
||||||
comfyNode.propsChanged.set(get(comfyNode.propsChanged) + 1)
|
|
||||||
}
|
if ("propsChanged" in node) {
|
||||||
|
const comfyNode = node as ComfyWidgetNode
|
||||||
|
comfyNode.propsChanged.set(get(comfyNode.propsChanged) + 1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateWorkflowAttribute(entry: AttributesSpec, value: any) {
|
function updateWorkflowAttribute(entry: AttributesSpec, value: any) {
|
||||||
const name = entry.name
|
const name = entry.name
|
||||||
console.warn("updateWorkflowAttribute", name, value)
|
console.warn("updateWorkflowAttribute", name, value)
|
||||||
|
|
||||||
$layoutState.attrs[name] = value
|
$layoutState.attrs[name] = value
|
||||||
$layoutState = $layoutState
|
$layoutState = $layoutState
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@@ -117,9 +136,10 @@
|
|||||||
<div class="target-name">
|
<div class="target-name">
|
||||||
<span>
|
<span>
|
||||||
<span class="title">{target?.attrs?.title || node?.title || "Workflow"}<span>
|
<span class="title">{target?.attrs?.title || node?.title || "Workflow"}<span>
|
||||||
{#if targetType !== ""}
|
{#if targetType !== ""}
|
||||||
<span class="type">({targetType})</span>
|
<span class="type">({targetType})</span>
|
||||||
{/if}
|
{/if}
|
||||||
|
</span>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -130,37 +150,37 @@
|
|||||||
<span class="title">{category.categoryName}</span>
|
<span class="title">{category.categoryName}</span>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
{#each category.specs as spec(spec.name)}
|
{#each category.specs as spec(spec.id)}
|
||||||
{#if spec.location === "widget" && target && spec.name in target.attrs}
|
{#if spec.location === "widget" && validWidgetAttribute(spec, target)}
|
||||||
<div class="props-entry">
|
<div class="props-entry">
|
||||||
{#if spec.type === "string"}
|
{#if spec.type === "string"}
|
||||||
<TextBox
|
<TextBox
|
||||||
value={target.attrs[spec.name]}
|
value={target.attrs[spec.name] || spec.defaultValue}
|
||||||
on:change={(e) => updateAttribute(spec, target, e.detail)}
|
on:change={(e) => updateAttribute(spec, target, e.detail)}
|
||||||
on:input={(e) => updateAttribute(spec, target, e.detail)}
|
on:input={(e) => updateAttribute(spec, target, e.detail)}
|
||||||
label={spec.name}
|
label={spec.name}
|
||||||
max_lines={1}
|
max_lines={1}
|
||||||
/>
|
/>
|
||||||
{:else if spec.type === "boolean"}
|
{:else if spec.type === "boolean"}
|
||||||
<Checkbox
|
<Checkbox
|
||||||
value={target.attrs[spec.name]}
|
value={target.attrs[spec.name] || spec.defaultValue}
|
||||||
on:change={(e) => updateAttribute(spec, target, e.detail)}
|
on:change={(e) => updateAttribute(spec, target, e.detail)}
|
||||||
label={spec.name}
|
label={spec.name}
|
||||||
/>
|
/>
|
||||||
{:else if spec.type === "number"}
|
{:else if spec.type === "number"}
|
||||||
<ComfyNumberProperty
|
<ComfyNumberProperty
|
||||||
name={spec.name}
|
name={spec.name}
|
||||||
value={target.attrs[spec.name]}
|
value={target.attrs[spec.name] || spec.defaultValue}
|
||||||
step={1}
|
step={1}
|
||||||
on:change={(e) => updateAttribute(spec, target, e.detail)}
|
on:change={(e) => updateAttribute(spec, target, e.detail)}
|
||||||
/>
|
/>
|
||||||
{:else if spec.type === "enum"}
|
{:else if spec.type === "enum"}
|
||||||
<ComfyComboProperty
|
<ComfyComboProperty
|
||||||
name={spec.name}
|
name={spec.name}
|
||||||
value={target.attrs[spec.name]}
|
value={target.attrs[spec.name] || spec.defaultValue}
|
||||||
values={spec.values}
|
values={spec.values}
|
||||||
on:change={(e) => updateAttribute(spec, target, e.detail)}
|
on:change={(e) => updateAttribute(spec, target, e.detail)}
|
||||||
/>
|
/>
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
{:else if node}
|
{:else if node}
|
||||||
@@ -168,32 +188,32 @@
|
|||||||
<div class="props-entry">
|
<div class="props-entry">
|
||||||
{#if spec.type === "string"}
|
{#if spec.type === "string"}
|
||||||
<TextBox
|
<TextBox
|
||||||
value={node.properties[spec.name]}
|
value={node.properties[spec.name] || spec.defaultValue}
|
||||||
on:change={(e) => updateProperty(spec, e.detail)}
|
on:change={(e) => updateProperty(spec, e.detail)}
|
||||||
on:input={(e) => updateProperty(spec, e.detail)}
|
on:input={(e) => updateProperty(spec, e.detail)}
|
||||||
label={spec.name}
|
label={spec.name}
|
||||||
max_lines={1}
|
max_lines={1}
|
||||||
/>
|
/>
|
||||||
{:else if spec.type === "boolean"}
|
{:else if spec.type === "boolean"}
|
||||||
<Checkbox
|
<Checkbox
|
||||||
value={node.properties[spec.name]}
|
value={node.properties[spec.name] || spec.defaultValue}
|
||||||
label={spec.name}
|
label={spec.name}
|
||||||
on:change={(e) => updateProperty(spec, e.detail)}
|
on:change={(e) => updateProperty(spec, e.detail)}
|
||||||
/>
|
/>
|
||||||
{:else if spec.type === "number"}
|
{:else if spec.type === "number"}
|
||||||
<ComfyNumberProperty
|
<ComfyNumberProperty
|
||||||
name={spec.name}
|
name={spec.name}
|
||||||
value={node.properties[spec.name]}
|
value={node.properties[spec.name] || spec.defaultValue}
|
||||||
step={1}
|
step={1}
|
||||||
on:change={(e) => updateProperty(spec, e.detail)}
|
on:change={(e) => updateProperty(spec, e.detail)}
|
||||||
/>
|
/>
|
||||||
{:else if spec.type === "enum"}
|
{:else if spec.type === "enum"}
|
||||||
<ComfyComboProperty
|
<ComfyComboProperty
|
||||||
name={spec.name}
|
name={spec.name}
|
||||||
value={node.properties[spec.name]}
|
value={node.properties[spec.name] || spec.defaultValue}
|
||||||
values={spec.values}
|
values={spec.values}
|
||||||
on:change={(e) => updateProperty(spec, e.detail)}
|
on:change={(e) => updateProperty(spec, e.detail)}
|
||||||
/>
|
/>
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
{:else if spec.location === "nodeVars" && spec.name in node}
|
{:else if spec.location === "nodeVars" && spec.name in node}
|
||||||
@@ -207,25 +227,25 @@
|
|||||||
max_lines={1}
|
max_lines={1}
|
||||||
/>
|
/>
|
||||||
{:else if spec.type === "boolean"}
|
{:else if spec.type === "boolean"}
|
||||||
<Checkbox
|
<Checkbox
|
||||||
value={getVar(node, spec)}
|
value={getVar(node, spec)}
|
||||||
on:change={(e) => updateVar(spec, e.detail)}
|
on:change={(e) => updateVar(spec, e.detail)}
|
||||||
label={spec.name}
|
label={spec.name}
|
||||||
/>
|
/>
|
||||||
{:else if spec.type === "number"}
|
{:else if spec.type === "number"}
|
||||||
<ComfyNumberProperty
|
<ComfyNumberProperty
|
||||||
name={spec.name}
|
name={spec.name}
|
||||||
value={getVar(node, spec)}
|
value={getVar(node, spec)}
|
||||||
step={1}
|
step={1}
|
||||||
on:change={(e) => updateVar(spec, e.detail)}
|
on:change={(e) => updateVar(spec, e.detail)}
|
||||||
/>
|
/>
|
||||||
{:else if spec.type === "enum"}
|
{:else if spec.type === "enum"}
|
||||||
<ComfyComboProperty
|
<ComfyComboProperty
|
||||||
name={spec.name}
|
name={spec.name}
|
||||||
value={getVar(node, spec)}
|
value={getVar(node, spec)}
|
||||||
values={spec.values}
|
values={spec.values}
|
||||||
on:change={(e) => updateVar(spec, e.detail)}
|
on:change={(e) => updateVar(spec, e.detail)}
|
||||||
/>
|
/>
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
@@ -233,32 +253,32 @@
|
|||||||
<div class="props-entry">
|
<div class="props-entry">
|
||||||
{#if spec.type === "string"}
|
{#if spec.type === "string"}
|
||||||
<TextBox
|
<TextBox
|
||||||
value={$layoutState.attrs[spec.name]}
|
value={$layoutState.attrs[spec.name] || spec.defaultValue}
|
||||||
on:change={(e) => updateWorkflowAttribute(spec, e.detail)}
|
on:change={(e) => updateWorkflowAttribute(spec, e.detail)}
|
||||||
on:input={(e) => updateWorkflowAttribute(spec, e.detail)}
|
on:input={(e) => updateWorkflowAttribute(spec, e.detail)}
|
||||||
label={spec.name}
|
label={spec.name}
|
||||||
max_lines={1}
|
max_lines={1}
|
||||||
/>
|
/>
|
||||||
{:else if spec.type === "boolean"}
|
{:else if spec.type === "boolean"}
|
||||||
<Checkbox
|
<Checkbox
|
||||||
value={$layoutState.attrs[spec.name]}
|
value={$layoutState.attrs[spec.name] || spec.defaultValue}
|
||||||
on:change={(e) => updateWorkflowAttribute(spec, e.detail)}
|
on:change={(e) => updateWorkflowAttribute(spec, e.detail)}
|
||||||
label={spec.name}
|
label={spec.name}
|
||||||
/>
|
/>
|
||||||
{:else if spec.type === "number"}
|
{:else if spec.type === "number"}
|
||||||
<ComfyNumberProperty
|
<ComfyNumberProperty
|
||||||
name={spec.name}
|
name={spec.name}
|
||||||
value={$layoutState.attrs[spec.name]}
|
value={$layoutState.attrs[spec.name] || spec.defaultValue}
|
||||||
step={1}
|
step={1}
|
||||||
on:change={(e) => updateWorkflowAttribute(spec, e.detail)}
|
on:change={(e) => updateWorkflowAttribute(spec, e.detail)}
|
||||||
/>
|
/>
|
||||||
{:else if spec.type === "enum"}
|
{:else if spec.type === "enum"}
|
||||||
<ComfyComboProperty
|
<ComfyComboProperty
|
||||||
name={spec.name}
|
name={spec.name}
|
||||||
value={$layoutState.attrs[spec.name]}
|
value={$layoutState.attrs[spec.name] || spec.defaultValue}
|
||||||
values={spec.values}
|
values={spec.values}
|
||||||
on:change={(e) => updateWorkflowAttribute(spec, e.detail)}
|
on:change={(e) => updateWorkflowAttribute(spec, e.detail)}
|
||||||
/>
|
/>
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
|
|||||||
@@ -69,7 +69,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function onRightClick(e) {
|
async function onRightClick(e) {
|
||||||
if ($uiState.uiEditMode === "disabled")
|
if (!$uiState.uiUnlocked)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
|||||||
42
src/lib/components/ComfyUnlockUIButton.svelte
Normal file
42
src/lib/components/ComfyUnlockUIButton.svelte
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import { Button } from "@gradio/button"
|
||||||
|
import { LockOpen2, LockClosed } from "radix-icons-svelte"
|
||||||
|
|
||||||
|
export let toggled: boolean = false;
|
||||||
|
|
||||||
|
function toggle() {
|
||||||
|
toggled = !toggled;
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class="wrapper button lg" class:toggled>
|
||||||
|
<Button on:click={toggle} variant={toggled ? "primary" : "secondary"}>
|
||||||
|
{#if toggled}
|
||||||
|
<LockOpen2 />
|
||||||
|
{:else}
|
||||||
|
<LockClosed />
|
||||||
|
{/if}
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
.wrapper {
|
||||||
|
display: inline-flex;
|
||||||
|
width: var(--size-12);
|
||||||
|
height: var(--size-12);
|
||||||
|
|
||||||
|
> :global(.lg) {
|
||||||
|
border: var(--button-border-width) solid var(--neutral-400);
|
||||||
|
}
|
||||||
|
|
||||||
|
&.toggled {
|
||||||
|
:global(svg) {
|
||||||
|
color: var(--button-primary-text-color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
:global(svg) {
|
||||||
|
color: var(--button-secondary-text-color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -40,7 +40,8 @@
|
|||||||
propsChanged = null;
|
propsChanged = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
$: showHandles = $uiState.uiEditMode === "widgets" // TODO
|
$: showHandles = $uiState.uiUnlocked
|
||||||
|
&& $uiState.uiEditMode === "widgets" // TODO
|
||||||
&& zIndex > 1
|
&& zIndex > 1
|
||||||
&& !$layoutState.isMenuOpen
|
&& !$layoutState.isMenuOpen
|
||||||
|
|
||||||
@@ -61,12 +62,12 @@
|
|||||||
<BlockContainer {container} {classes} {zIndex} {showHandles} />
|
<BlockContainer {container} {classes} {zIndex} {showHandles} />
|
||||||
{/key}
|
{/key}
|
||||||
{:else if widget && widget.node}
|
{:else if widget && widget.node}
|
||||||
{@const edit = $uiState.uiEditMode === "widgets" && zIndex > 1}
|
{@const edit = $uiState.uiUnlocked && $uiState.uiEditMode === "widgets" && zIndex > 1}
|
||||||
{#key $attrsChanged}
|
{#key $attrsChanged}
|
||||||
{#key $propsChanged}
|
{#key $propsChanged}
|
||||||
<div class="widget {widget.attrs.classes} {getWidgetClass()}"
|
<div class="widget {widget.attrs.classes} {getWidgetClass()}"
|
||||||
class:edit={edit}
|
class:edit={edit}
|
||||||
class:selected={$uiState.uiEditMode !== "disabled" && $layoutState.currentSelection.includes(widget.id)}
|
class:selected={$uiState.uiUnlocked && $layoutState.currentSelection.includes(widget.id)}
|
||||||
class:is-executing={$queueState.runningNodeId && $queueState.runningNodeId == widget.node.id}
|
class:is-executing={$queueState.runningNodeId && $queueState.runningNodeId == widget.node.id}
|
||||||
class:hidden={widget.attrs.hidden}
|
class:hidden={widget.attrs.hidden}
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -39,15 +39,18 @@ export type Attributes = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export type AttributesSpec = {
|
export type AttributesSpec = {
|
||||||
|
id?: number, // for svelte keyed each
|
||||||
name: string,
|
name: string,
|
||||||
type: string,
|
type: string,
|
||||||
location: "widget" | "nodeProps" | "nodeVars" | "workflow"
|
location: "widget" | "nodeProps" | "nodeVars" | "workflow"
|
||||||
editable: boolean,
|
editable: boolean,
|
||||||
|
|
||||||
|
defaultValue?: any,
|
||||||
values?: string[],
|
values?: string[],
|
||||||
hidden?: boolean,
|
hidden?: boolean,
|
||||||
validNodeTypes?: string[],
|
validNodeTypes?: string[],
|
||||||
|
|
||||||
|
canShow?: (arg: IDragItem | LGraphNode) => boolean,
|
||||||
serialize?: (arg: any) => string,
|
serialize?: (arg: any) => string,
|
||||||
deserialize?: (arg: string) => any,
|
deserialize?: (arg: string) => any,
|
||||||
}
|
}
|
||||||
@@ -86,18 +89,22 @@ const ALL_ATTRIBUTES: AttributesSpecList = [
|
|||||||
type: "enum",
|
type: "enum",
|
||||||
location: "widget",
|
location: "widget",
|
||||||
editable: true,
|
editable: true,
|
||||||
values: ["horizontal", "vertical"]
|
values: ["horizontal", "vertical"],
|
||||||
|
defaultValue: "vertical",
|
||||||
|
canShow: (di: IDragItem) => di.type === "container"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "flexGrow",
|
name: "flexGrow",
|
||||||
type: "number",
|
type: "number",
|
||||||
location: "widget",
|
location: "widget",
|
||||||
|
defaultValue: 100,
|
||||||
editable: true
|
editable: true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "classes",
|
name: "classes",
|
||||||
type: "string",
|
type: "string",
|
||||||
location: "widget",
|
location: "widget",
|
||||||
|
defaultValue: "",
|
||||||
editable: true,
|
editable: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -105,7 +112,20 @@ const ALL_ATTRIBUTES: AttributesSpecList = [
|
|||||||
type: "enum",
|
type: "enum",
|
||||||
location: "widget",
|
location: "widget",
|
||||||
editable: true,
|
editable: true,
|
||||||
values: ["block", "hidden"]
|
values: ["block", "hidden"],
|
||||||
|
defaultValue: "block",
|
||||||
|
canShow: (di: IDragItem) => di.type === "container"
|
||||||
|
},
|
||||||
|
|
||||||
|
// Container variants
|
||||||
|
{
|
||||||
|
name: "variant",
|
||||||
|
type: "enum",
|
||||||
|
location: "widget",
|
||||||
|
editable: true,
|
||||||
|
values: ["block", "accordion", "tabs"],
|
||||||
|
defaultValue: "block",
|
||||||
|
canShow: (di: IDragItem) => di.type === "container"
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
@@ -156,6 +176,7 @@ const ALL_ATTRIBUTES: AttributesSpecList = [
|
|||||||
location: "nodeProps",
|
location: "nodeProps",
|
||||||
editable: true,
|
editable: true,
|
||||||
validNodeTypes: ["ui/button"],
|
validNodeTypes: ["ui/button"],
|
||||||
|
defaultValue: "bang"
|
||||||
},
|
},
|
||||||
|
|
||||||
// Workflow
|
// Workflow
|
||||||
@@ -163,11 +184,21 @@ const ALL_ATTRIBUTES: AttributesSpecList = [
|
|||||||
name: "defaultSubgraph",
|
name: "defaultSubgraph",
|
||||||
type: "string",
|
type: "string",
|
||||||
location: "workflow",
|
location: "workflow",
|
||||||
editable: true
|
editable: true,
|
||||||
|
defaultValue: ""
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
|
let i = 0;
|
||||||
|
for (const cat of Object.values(ALL_ATTRIBUTES)) {
|
||||||
|
for (const val of Object.values(cat.specs)) {
|
||||||
|
val.id = i;
|
||||||
|
i += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export { ALL_ATTRIBUTES };
|
export { ALL_ATTRIBUTES };
|
||||||
|
|
||||||
export interface IDragItem {
|
export interface IDragItem {
|
||||||
|
|||||||
@@ -2,13 +2,14 @@ import { writable } from 'svelte/store';
|
|||||||
import type { Readable, Writable } from 'svelte/store';
|
import type { Readable, Writable } from 'svelte/store';
|
||||||
import type ComfyApp from "$lib/components/ComfyApp"
|
import type ComfyApp from "$lib/components/ComfyApp"
|
||||||
|
|
||||||
export type UIEditMode = "disabled" | "widgets" | "containers" | "layout";
|
export type UIEditMode = "widgets" | "containers" | "layout";
|
||||||
|
|
||||||
export type UIState = {
|
export type UIState = {
|
||||||
app: ComfyApp,
|
app: ComfyApp,
|
||||||
nodesLocked: boolean,
|
nodesLocked: boolean,
|
||||||
graphLocked: boolean,
|
graphLocked: boolean,
|
||||||
autoAddUI: boolean,
|
autoAddUI: boolean,
|
||||||
|
uiUnlocked: boolean,
|
||||||
uiEditMode: UIEditMode,
|
uiEditMode: UIEditMode,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -19,7 +20,8 @@ const store: WritableUIStateStore = writable(
|
|||||||
graphLocked: false,
|
graphLocked: false,
|
||||||
nodesLocked: false,
|
nodesLocked: false,
|
||||||
autoAddUI: true,
|
autoAddUI: true,
|
||||||
uiEditMode: "disabled",
|
uiUnlocked: false,
|
||||||
|
uiEditMode: "widgets"
|
||||||
})
|
})
|
||||||
|
|
||||||
const uiStateStore: WritableUIStateStore =
|
const uiStateStore: WritableUIStateStore =
|
||||||
|
|||||||
Reference in New Issue
Block a user