Global modal system
This commit is contained in:
@@ -7,11 +7,9 @@
|
||||
import LightboxModal from "./LightboxModal.svelte";
|
||||
import Sidebar from "./Sidebar.svelte";
|
||||
import SidebarItem from "./SidebarItem.svelte";
|
||||
// import Modal from "./Modal.svelte";
|
||||
// import A1111PromptDisplay from "./A1111PromptDisplay.svelte";
|
||||
import notify from "$lib/notify";
|
||||
import ComfyWorkflowsView from "./ComfyWorkflowsView.svelte";
|
||||
|
||||
import notify from "$lib/notify";
|
||||
import ComfyWorkflowsView from "./ComfyWorkflowsView.svelte";
|
||||
import GlobalModal from "./GlobalModal.svelte";
|
||||
|
||||
export let app: ComfyApp = undefined;
|
||||
let hasShownUIHelpToast: boolean = false;
|
||||
@@ -36,11 +34,6 @@
|
||||
document.getElementById("app-root").classList.remove("dark")
|
||||
}
|
||||
|
||||
// let showModal: boolean = false;
|
||||
//
|
||||
// $: showModal = $a1111Prompt != null
|
||||
//
|
||||
// let selectedTab
|
||||
</script>
|
||||
|
||||
<svelte:head>
|
||||
@@ -49,20 +42,6 @@
|
||||
{/if}
|
||||
</svelte:head>
|
||||
|
||||
<!--
|
||||
<Modal bind:showModal on:close={() => ($a1111Prompt = null)}>
|
||||
<div slot="header" class="prompt-modal-header">
|
||||
<h1 style="padding-bottom: 1rem;">A1111 Prompt Details</h1>
|
||||
</div>
|
||||
<A1111PromptDisplay prompt={$a1111Prompt} />
|
||||
<div slot="buttons" let:closeDialog>
|
||||
<Button variant="secondary" on:click={closeDialog}>
|
||||
Close
|
||||
</Button>
|
||||
</div>
|
||||
</Modal>
|
||||
-->
|
||||
|
||||
<div id="main" class:dark={uiTheme === "gradio-dark"}>
|
||||
<div id="container">
|
||||
<Sidebar selected="generate">
|
||||
@@ -74,6 +53,7 @@
|
||||
</Sidebar>
|
||||
</div>
|
||||
<LightboxModal />
|
||||
<GlobalModal/>
|
||||
</div>
|
||||
<SvelteToast options={toastOptions} />
|
||||
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
import { LiteGraph, LGraph, LGraphCanvas, LGraphNode, type LGraphNodeConstructor, type LGraphNodeExecutable, type SerializedLGraph, type SerializedLGraphGroup, type SerializedLGraphNode, type SerializedLLink, NodeMode, type Vector2, BuiltInSlotType, type INodeInputSlot, type NodeID, type NodeTypeSpec, type NodeTypeOpts, type SlotIndex, type UUID } from "@litegraph-ts/core";
|
||||
import type { LConnectionKind, INodeSlot } from "@litegraph-ts/core";
|
||||
import ComfyAPI, { type ComfyAPIStatusResponse, type ComfyBoxPromptExtraData, type ComfyPromptRequest, type ComfyNodeID, type PromptID } from "$lib/api"
|
||||
import { getPngMetadata, importA1111, parsePNGMetadata } from "$lib/pnginfo";
|
||||
import { importA1111, parsePNGMetadata } from "$lib/pnginfo";
|
||||
import EventEmitter from "events";
|
||||
import type TypedEmitter from "typed-emitter";
|
||||
import A1111PromptDisplay from "./A1111PromptDisplay.svelte";
|
||||
|
||||
|
||||
// Import nodes
|
||||
import "@litegraph-ts/nodes-basic"
|
||||
@@ -28,7 +30,7 @@ import { ComfyBackendNode } from "$lib/nodes/ComfyBackendNode";
|
||||
import { get, writable, type Writable } from "svelte/store";
|
||||
import { tick } from "svelte";
|
||||
import uiState from "$lib/stores/uiState";
|
||||
import { download, graphToGraphVis, jsonToJsObject, promptToGraphVis, range, workflowToGraphVis } from "$lib/utils";
|
||||
import { basename, download, graphToGraphVis, jsonToJsObject, promptToGraphVis, range, workflowToGraphVis } from "$lib/utils";
|
||||
import notify from "$lib/notify";
|
||||
import configState from "$lib/stores/configState";
|
||||
import { blankGraph } from "$lib/defaultGraph";
|
||||
@@ -45,7 +47,7 @@ import layoutStates from "$lib/stores/layoutStates";
|
||||
import { ComfyWorkflow, type WorkflowAttributes, type WorkflowInstID } from "$lib/stores/workflowState";
|
||||
import workflowState from "$lib/stores/workflowState";
|
||||
import convertVanillaWorkflow, { type ComfyVanillaWorkflow } from "$lib/convertVanillaWorkflow";
|
||||
import convertVanillaWorkflow from "$lib/convertVanillaWorkflow";
|
||||
import modalState from "$lib/stores/modalState";
|
||||
|
||||
export const COMFYBOX_SERIAL_VERSION = 1;
|
||||
|
||||
@@ -142,6 +144,11 @@ type CanvasState = {
|
||||
canvas: ComfyGraphCanvas,
|
||||
}
|
||||
|
||||
export type WorkflowLoadError = {
|
||||
message: string,
|
||||
error: Error
|
||||
}
|
||||
|
||||
function isComfyBoxWorkflow(data: any): data is SerializedAppState {
|
||||
return data != null && (typeof data === "object") && data.comfyBoxWorkflow;
|
||||
}
|
||||
@@ -167,7 +174,6 @@ export default class ComfyApp {
|
||||
ctrlDown: boolean = false;
|
||||
selectedGroupMoving: boolean = false;
|
||||
alreadySetup: Writable<boolean> = writable(false);
|
||||
a1111Prompt: Writable<A1111PromptAndInfo | null> = writable(null);
|
||||
|
||||
private queueItems: PromptQueueItem[] = [];
|
||||
private processingQueue: boolean = false;
|
||||
@@ -266,10 +272,10 @@ export default class ComfyApp {
|
||||
}
|
||||
|
||||
|
||||
convertVanillaWorkflow(workflow: ComfyVanillaWorkflow): SerializedAppState {
|
||||
convertVanillaWorkflow(workflow: ComfyVanillaWorkflow, title: string): SerializedAppState {
|
||||
const attrs: WorkflowAttributes = {
|
||||
...defaultWorkflowAttributes,
|
||||
title: "ComfyUI Workflow"
|
||||
title
|
||||
}
|
||||
|
||||
const canvas: SerializedGraphCanvasState = {
|
||||
@@ -579,8 +585,8 @@ export default class ComfyApp {
|
||||
return workflow;
|
||||
}
|
||||
|
||||
async openVanillaWorkflow(data: SerializedLGraph) {
|
||||
const converted = this.convertVanillaWorkflow(data)
|
||||
async openVanillaWorkflow(data: SerializedLGraph, filename: string) {
|
||||
const converted = this.convertVanillaWorkflow(data, basename(filename))
|
||||
console.info("WORKFLWO", converted)
|
||||
notify("Converted ComfyUI workflow to ComfyBox format.", { type: "info" })
|
||||
await this.openWorkflow(converted);
|
||||
@@ -818,7 +824,7 @@ export default class ComfyApp {
|
||||
await this.openWorkflow(JSON.parse(pngInfo.comfyBoxWorkflow));
|
||||
} else if (pngInfo.workflow) {
|
||||
const workflow = JSON.parse(pngInfo.workflow);
|
||||
await this.openVanillaWorkflow(workflow);
|
||||
await this.openVanillaWorkflow(workflow, file.name);
|
||||
} else if (pngInfo.parameters) {
|
||||
const parsed = parseA1111(pngInfo.parameters)
|
||||
if ("error" in parsed) {
|
||||
@@ -826,11 +832,19 @@ export default class ComfyApp {
|
||||
return;
|
||||
}
|
||||
const converted = convertA1111ToStdPrompt(parsed)
|
||||
this.a1111Prompt.set({
|
||||
const a1111Info: A1111PromptAndInfo = {
|
||||
infotext: pngInfo.parameters,
|
||||
parsedInfotext: parsed,
|
||||
stdPrompt: converted,
|
||||
imageFile: file
|
||||
}
|
||||
modalState.pushModal({
|
||||
title: "A1111 Prompt Details",
|
||||
svelteComponent: A1111PromptDisplay,
|
||||
svelteProps: {
|
||||
prompt: a1111Info
|
||||
},
|
||||
showCloseButton: true
|
||||
})
|
||||
}
|
||||
else {
|
||||
@@ -846,7 +860,7 @@ export default class ComfyApp {
|
||||
await this.openWorkflow(result);
|
||||
}
|
||||
else if (isVanillaWorkflow(result)) {
|
||||
await this.openVanillaWorkflow(result);
|
||||
await this.openVanillaWorkflow(result, file.name);
|
||||
}
|
||||
};
|
||||
reader.readAsText(file);
|
||||
@@ -990,6 +1004,5 @@ export default class ComfyApp {
|
||||
* Clean current state
|
||||
*/
|
||||
clean() {
|
||||
this.a1111Prompt.set(null);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
<script lang="ts">
|
||||
import { Button } from "@gradio/button";
|
||||
import type ComfyApp from "./ComfyApp";
|
||||
import DropZone from "./DropZone.svelte";
|
||||
|
||||
export let app: ComfyApp;
|
||||
export let transitioning: boolean = false;
|
||||
@@ -13,6 +14,7 @@
|
||||
<div class="wrapper litegraph">
|
||||
<div class="canvas-wrapper pane-wrapper">
|
||||
<canvas id="graph-canvas" />
|
||||
<DropZone {app} />
|
||||
</div>
|
||||
<div class="bar">
|
||||
{#if !transitioning}
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
import Spinner from "./Spinner.svelte";
|
||||
import PromptDisplay from "./PromptDisplay.svelte";
|
||||
import { ListIcon as List } from "svelte-feather-icons";
|
||||
import { convertComfyOutputToComfyURL, convertFilenameToComfyURL, getNodeInfo } from "$lib/utils"
|
||||
import { convertComfyOutputToComfyURL, convertFilenameToComfyURL, getNodeInfo, truncateString } from "$lib/utils"
|
||||
import type { Writable } from "svelte/store";
|
||||
import type { QueueItemType } from "$lib/api";
|
||||
import { ImageViewer } from "$lib/ImageViewer";
|
||||
@@ -75,7 +75,7 @@
|
||||
if (entry.workflowID != null) {
|
||||
const workflow = workflowState.getWorkflow(entry.workflowID);
|
||||
if (workflow != null && workflow.attrs.title) {
|
||||
message = `Workflow: ${workflow.attrs.title}`
|
||||
message = `${workflow.attrs.title}`
|
||||
}
|
||||
if (subgraphs?.length > 0)
|
||||
message += ` (${subgraphs.join(', ')})`
|
||||
@@ -208,7 +208,6 @@
|
||||
</Modal>
|
||||
|
||||
<div class="queue">
|
||||
<!-- <DropZone {app} /> -->
|
||||
<div class="queue-entries {mode}-mode" bind:this={queueList}>
|
||||
{#if _entries.length > 0}
|
||||
{#each _entries as entry}
|
||||
@@ -230,7 +229,7 @@
|
||||
{/if}
|
||||
<div class="queue-entry-details">
|
||||
<div class="queue-entry-message">
|
||||
{entry.message}
|
||||
{truncateString(entry.message, 20)}
|
||||
</div>
|
||||
<div class="queue-entry-submessage">
|
||||
{entry.submessage}
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
import { dndzone, SHADOW_ITEM_MARKER_PROPERTY_NAME, SHADOW_PLACEHOLDER_ITEM_ID } from 'svelte-dnd-action';
|
||||
import { fade } from 'svelte/transition';
|
||||
import { cubicIn } from 'svelte/easing';
|
||||
import { truncateString } from '$lib/utils';
|
||||
|
||||
export let app: ComfyApp;
|
||||
export let uiTheme: string = "gradio-dark" // TODO config
|
||||
@@ -235,7 +236,7 @@
|
||||
class:selected={item.id === $workflowState.activeWorkflowID}
|
||||
on:click={() => app.setActiveWorkflow(item.id)}>
|
||||
<span class="workflow-tab-title">
|
||||
{workflow.attrs.title}
|
||||
{truncateString(workflow.attrs.title, 32)}
|
||||
{#if workflow.isModified}
|
||||
*
|
||||
{/if}
|
||||
|
||||
@@ -1,15 +1,12 @@
|
||||
<script lang="ts">
|
||||
import { writable, type Writable } from "svelte/store";
|
||||
import modalState from "$lib/stores/modalState";
|
||||
import type ComfyApp from "./ComfyApp";
|
||||
|
||||
export let app: ComfyApp;
|
||||
let a1111Prompt: Writable<any | null> = writable(null);
|
||||
let dropZone: HTMLDivElement | null = null;
|
||||
let disabled = false;
|
||||
|
||||
$: a1111Prompt = app.a1111Prompt;
|
||||
|
||||
$: disabled = a1111Prompt && $a1111Prompt;
|
||||
$: disabled = $modalState.activeModals.length > 0;
|
||||
|
||||
$: if (disabled) {
|
||||
hideDropZone();
|
||||
|
||||
44
src/lib/components/GlobalModal.svelte
Normal file
44
src/lib/components/GlobalModal.svelte
Normal file
@@ -0,0 +1,44 @@
|
||||
<script lang="ts">
|
||||
import modalState, { type ModalData } from "$lib/stores/modalState";
|
||||
import { Button } from "@gradio/button";
|
||||
import Modal from "./Modal.svelte";
|
||||
|
||||
function onClose(modal: ModalData | null) {
|
||||
if (modal == null)
|
||||
return;
|
||||
|
||||
if (modal.onClose)
|
||||
modal.onClose()
|
||||
|
||||
modalState.closeModal(modal.id)
|
||||
}
|
||||
</script>
|
||||
|
||||
{#each $modalState.activeModals as modal(modal.id)}
|
||||
<Modal showModal={true} on:close={() => onClose(modal)}>
|
||||
<div slot="header" class="modal-header">
|
||||
{#if modal != null}
|
||||
<h1 style="padding-bottom: 1rem;">{modal.title}</h1>
|
||||
{/if}
|
||||
</div>
|
||||
<svelte:fragment>
|
||||
{#if modal != null && modal.svelteComponent != null}
|
||||
<svelte:component this={modal.svelteComponent} {...modal.svelteProps}/>
|
||||
{/if}
|
||||
</svelte:fragment>
|
||||
<div slot="buttons" let:closeDialog>
|
||||
{#if modal != null && modal.buttons?.length > 0}
|
||||
{#each modal.buttons as button}
|
||||
<Button variant={button.variant} on:click={button.onClick}>
|
||||
{button.name}
|
||||
</Button>
|
||||
{/each}
|
||||
{/if}
|
||||
{#if modal.showCloseButton}
|
||||
<Button variant="secondary" on:click={closeDialog}>
|
||||
Close
|
||||
</Button>
|
||||
{/if}
|
||||
</div>
|
||||
</Modal>
|
||||
{/each}
|
||||
@@ -8,6 +8,7 @@
|
||||
import Gallery from "$lib/components/gradio/gallery/Gallery.svelte";
|
||||
import { ImageViewer } from "$lib/ImageViewer";
|
||||
import type { Styles } from "@gradio/utils";
|
||||
import { countNewLines } from "$lib/utils";
|
||||
|
||||
const splitLength = 50;
|
||||
|
||||
@@ -29,10 +30,6 @@
|
||||
&& typeof input[1] === "number"
|
||||
}
|
||||
|
||||
function countNewLines(str: string): number {
|
||||
return str.split(/\r\n|\r|\n/).length
|
||||
}
|
||||
|
||||
function isMultiline(input: any): boolean {
|
||||
return typeof input === "string" && (input.length > splitLength || countNewLines(input) > 1);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user