Updates for mobile
This commit is contained in:
@@ -22,6 +22,7 @@
|
||||
import ComfyUnlockUIButton from "./ComfyUnlockUIButton.svelte";
|
||||
import ComfyGraphView from "./ComfyGraphView.svelte";
|
||||
import { download } from "$lib/utils";
|
||||
import notify from "$lib/notify";
|
||||
|
||||
export let app: ComfyApp = undefined;
|
||||
let imageViewer: ImageViewer;
|
||||
@@ -141,7 +142,7 @@
|
||||
return;
|
||||
|
||||
app.saveStateToLocalStorage();
|
||||
toast.push("Saved to local storage.")
|
||||
notify("Saved to local storage.")
|
||||
//
|
||||
// const date = new Date();
|
||||
// const formattedDate = date.toISOString().replace(/:/g, '-').replace(/\.\d{3}/g, '').replace('T', '_').replace("Z", "");
|
||||
@@ -165,7 +166,7 @@
|
||||
|
||||
$: if ($uiState.uiUnlocked && !hasShownUIHelpToast) {
|
||||
hasShownUIHelpToast = true;
|
||||
toast.push("Right-click to open context menu.")
|
||||
notify("Right-click to open context menu.")
|
||||
}
|
||||
|
||||
if (debugLayout) {
|
||||
|
||||
@@ -28,6 +28,7 @@ import { ComfyBackendNode } from "$lib/nodes/ComfyBackendNode";
|
||||
import { get } from "svelte/store";
|
||||
import uiState from "$lib/stores/uiState";
|
||||
import { promptToGraphVis, workflowToGraphVis } from "$lib/utils";
|
||||
import notify from "$lib/notify";
|
||||
|
||||
export const COMFYBOX_SERIAL_VERSION = 1;
|
||||
|
||||
@@ -601,11 +602,7 @@ export default class ComfyApp {
|
||||
} catch (error) {
|
||||
// this.ui.dialog.show(error.response || error.toString());
|
||||
const mes = error.response || error.toString()
|
||||
toast.push(`Error queuing prompt:\n${mes}`, {
|
||||
theme: {
|
||||
'--toastBackground': 'var(--color-red-500)',
|
||||
}
|
||||
})
|
||||
notify(`Error queuing prompt:\n${mes}`, null, "error")
|
||||
console.error(promptToGraphVis(p))
|
||||
console.error("Error queuing prompt", mes, num, p)
|
||||
break;
|
||||
@@ -643,7 +640,7 @@ export default class ComfyApp {
|
||||
}
|
||||
else {
|
||||
console.error("No metadata found in image file.", pngInfo)
|
||||
toast.push("No metadata found in image file.")
|
||||
notify("No metadata found in image file.")
|
||||
}
|
||||
}
|
||||
} else if (file.type === "application/json" || file.name.endsWith(".json")) {
|
||||
|
||||
@@ -1,15 +1,7 @@
|
||||
<script lang="ts">
|
||||
import queueState from "$lib/stores/queueState";
|
||||
import ProgressBar from "./ProgressBar.svelte";
|
||||
|
||||
function getNodeInfo(nodeId: number): string {
|
||||
let app = (window as any).app;
|
||||
if (!app)
|
||||
return String(nodeId);
|
||||
|
||||
const title = app.lGraph.getNodeById(nodeId)?.title || String(nodeId);
|
||||
return title + " (" + nodeId + ")"
|
||||
}
|
||||
import { getNodeInfo } from "$lib/utils"
|
||||
|
||||
const entries = [
|
||||
{
|
||||
|
||||
@@ -23,15 +23,17 @@
|
||||
|
||||
<style>
|
||||
.progress {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
text-align: center;
|
||||
background-color: lightgrey;
|
||||
padding: 3px;
|
||||
padding: 0px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.bar {
|
||||
height: 100%;
|
||||
background-color: #B3D8A9;
|
||||
height: 20px;
|
||||
}
|
||||
|
||||
.label {
|
||||
|
||||
@@ -6,6 +6,7 @@ import { toast } from '@zerodevx/svelte-toast'
|
||||
import type { GalleryOutput } from "./ComfyWidgetNodes";
|
||||
import { get } from "svelte/store";
|
||||
import queueState from "$lib/stores/queueState";
|
||||
import notify from "$lib/notify";
|
||||
|
||||
export interface ComfyQueueEventsProperties extends Record<any, any> {
|
||||
}
|
||||
@@ -199,7 +200,7 @@ export class ComfyNotifyAction extends ComfyGraphNode {
|
||||
override onAction(action: any, param: any) {
|
||||
const message = this.getInputData(0);
|
||||
if (message) {
|
||||
toast.push(message);
|
||||
notify(message);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -113,7 +113,7 @@ export class ComfyBackendNode extends ComfyGraphNode {
|
||||
}
|
||||
}
|
||||
else {
|
||||
console.error("[ComfyBackendNode] Missing input config in onConfigure()!", input, configs)
|
||||
console.debug("[ComfyBackendNode] Missing input config in onConfigure()", input, configs)
|
||||
input.config = {}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -158,7 +158,7 @@ export default class ComfyImageCacheNode extends ComfyGraphNode {
|
||||
else {
|
||||
this.properties.filenames[newIndex] = { filename: null, status: "uploading" }
|
||||
this.onPropertyChanged("filenames", this.properties.filenames)
|
||||
const url = "http://localhost:8188" // TODO make configurable
|
||||
const url = `http://${location.hostname}:8188` // TODO make configurable
|
||||
const params = new URLSearchParams(data)
|
||||
|
||||
const promise = fetch(url + "/view?" + params)
|
||||
|
||||
@@ -516,11 +516,11 @@ export class ComfyGalleryNode extends ComfyWidgetNode<GradioFileData[]> {
|
||||
private convertItems(output: GalleryOutput): GradioFileData[] {
|
||||
return output.images.map(r => {
|
||||
// TODO configure backend URL
|
||||
const url = "http://localhost:8188/view?"
|
||||
const url = `http://${location.hostname}:8188` // TODO make configurable
|
||||
const params = new URLSearchParams(r)
|
||||
return {
|
||||
name: null,
|
||||
data: url + params
|
||||
data: url + "/view?" + params
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
37
src/lib/notify.ts
Normal file
37
src/lib/notify.ts
Normal file
@@ -0,0 +1,37 @@
|
||||
import { toast } from "@zerodevx/svelte-toast";
|
||||
import type { SvelteToastOptions } from "@zerodevx/svelte-toast/stores";
|
||||
import { f7 } from "framework7-svelte"
|
||||
|
||||
let notification;
|
||||
|
||||
function notifyf7(text: string, title?: string) {
|
||||
if (!notification) {
|
||||
notification = f7.notification.create({
|
||||
title: title,
|
||||
titleRightText: 'now',
|
||||
// subtitle: 'Notification with close on click',
|
||||
text: text,
|
||||
closeOnClick: true,
|
||||
closeTimeout: 3000,
|
||||
});
|
||||
}
|
||||
// Open it
|
||||
notification.open();
|
||||
}
|
||||
|
||||
function notifyToast(text: string, type?: string) {
|
||||
const options: SvelteToastOptions = {}
|
||||
|
||||
if (type === "error") {
|
||||
options.theme = {
|
||||
'--toastBackground': 'var(--color-red-500)',
|
||||
}
|
||||
}
|
||||
|
||||
toast.push(text, options);
|
||||
}
|
||||
|
||||
export default function notify(text: string, title?: string, type?: string) {
|
||||
notifyf7(text, title);
|
||||
notifyToast(text, title);
|
||||
}
|
||||
@@ -99,3 +99,12 @@ export function promptToGraphVis(prompt: SerializedPrompt): string {
|
||||
out += "}"
|
||||
return out
|
||||
}
|
||||
|
||||
export function getNodeInfo(nodeId: number): string {
|
||||
let app = (window as any).app;
|
||||
if (!app)
|
||||
return String(nodeId);
|
||||
|
||||
const title = app.lGraph.getNodeById(nodeId)?.title || String(nodeId);
|
||||
return title + " (" + nodeId + ")"
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
let option: any
|
||||
|
||||
export let debug: boolean = false;
|
||||
let input: HTMLInputElement | null = null
|
||||
|
||||
$: widget && setNodeValue(widget);
|
||||
|
||||
@@ -53,6 +54,11 @@
|
||||
return links[0].data
|
||||
}
|
||||
|
||||
function onSelect() {
|
||||
if (input)
|
||||
input.blur();
|
||||
}
|
||||
|
||||
let lastPropsChanged: number = 0;
|
||||
let werePropsChanged: boolean = false;
|
||||
|
||||
@@ -76,8 +82,10 @@
|
||||
disabled={widget.attrs.disabled || node.properties.values.length === 0}
|
||||
clearable={false}
|
||||
showChevron={true}
|
||||
inputAttributes={{ autocomplete: 'off' }}
|
||||
bind:input
|
||||
on:change
|
||||
on:select
|
||||
on:select={onSelect}
|
||||
on:filter
|
||||
on:blur
|
||||
/>
|
||||
|
||||
@@ -35,6 +35,7 @@
|
||||
function onRelease(e: Event) {
|
||||
if (nodeValue && option) {
|
||||
$nodeValue = option
|
||||
navigator.vibrate(100)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,38 +1,101 @@
|
||||
<script lang="ts">
|
||||
import ComfyApp, { type SerializedAppState } from "$lib/components/ComfyApp";
|
||||
import notify from "$lib/notify";
|
||||
import uiState from "$lib/stores/uiState";
|
||||
import queueState from "$lib/stores/queueState";
|
||||
import { getNodeInfo } from "$lib/utils"
|
||||
|
||||
import { Link, Toolbar } from "framework7-svelte"
|
||||
import { f7 } from "framework7-svelte"
|
||||
import ProgressBar from "$lib/components/ProgressBar.svelte";
|
||||
|
||||
export let subworkflowID: number = -1;
|
||||
let app: ComfyApp = undefined;
|
||||
let fileInput: HTMLInputElement = undefined;
|
||||
|
||||
$: if (!app)
|
||||
app = $uiState.app
|
||||
|
||||
function queuePrompt() {
|
||||
app.queuePrompt(0, 1);
|
||||
showNotification();
|
||||
notify("Prompt was queued", "Queued");
|
||||
}
|
||||
|
||||
let notification;
|
||||
const showNotification = () => {
|
||||
if (!notification) {
|
||||
notification = f7.notification.create({
|
||||
title: 'Queued',
|
||||
titleRightText: 'now',
|
||||
// subtitle: 'Notification with close on click',
|
||||
text: 'Prompt was queued',
|
||||
closeOnClick: true,
|
||||
closeTimeout: 3000,
|
||||
});
|
||||
function doLoad(): void {
|
||||
if (!app?.lGraph || !fileInput)
|
||||
return;
|
||||
|
||||
fileInput.click();
|
||||
}
|
||||
// Open it
|
||||
notification.open();
|
||||
|
||||
function loadWorkflow(): void {
|
||||
app.handleFile(fileInput.files[0]);
|
||||
fileInput.files = null;
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="bottom">
|
||||
{#if $queueState.runningNodeId || $queueState.progress}
|
||||
<div class="node-name">
|
||||
<span>Node: {getNodeInfo($queueState.runningNodeId)}</span>
|
||||
</div>
|
||||
<div class="progress-bar">
|
||||
<ProgressBar value={$queueState.progress?.value} max={$queueState.progress?.max} />
|
||||
</div>
|
||||
{/if}
|
||||
{#if typeof $queueState.queueRemaining === "number" && $queueState.queueRemaining > 0}
|
||||
<div class="queue-remaining in-progress">
|
||||
<div>
|
||||
Queued prompts: {$queueState.queueRemaining}.
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
<Toolbar bottom>
|
||||
<Link on:click={queuePrompt}>Queue Prompt</Link>
|
||||
<Link on:click={() => app.refreshComboInNodes()}>🔄</Link>
|
||||
<Link on:click={doLoad}>Load</Link>
|
||||
<input bind:this={fileInput} id="comfy-file-input" type="file" accept=".json" on:change={loadWorkflow} />
|
||||
</Toolbar>
|
||||
|
||||
<style lang="scss">
|
||||
#comfy-file-input {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.bottom {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
position: absolute;
|
||||
text-align: center;
|
||||
width: 100%;
|
||||
height: 2rem;
|
||||
bottom: calc(var(--f7-toolbar-height) + var(--f7-safe-area-bottom));
|
||||
z-index: var(--layer-top);
|
||||
background-color: grey;
|
||||
|
||||
.node-name {
|
||||
flex-grow: 1;
|
||||
background-color: var(--color-red-300);
|
||||
padding: 0.2em;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.progress-bar {
|
||||
flex-grow: 10;
|
||||
background-color: var(--color-red-300);
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.queue-remaining {
|
||||
flex-grow: 1;
|
||||
padding: 0.2em;
|
||||
&.in-progress {
|
||||
background-color: var(--secondary-300);
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
import uiState from "$lib/stores/uiState"
|
||||
|
||||
let app: ComfyApp | null = null;
|
||||
let lCanvas: LGraphCanvas | null = null;
|
||||
let lCanvas: ComfyGraphCanvas | null = null;
|
||||
let canvasEl: HTMLCanvasElement | null = null;
|
||||
|
||||
$: if (!app)
|
||||
@@ -21,13 +21,14 @@
|
||||
lCanvas.draw(true, true);
|
||||
}
|
||||
|
||||
$: if (app && canvasEl) {
|
||||
$: if (app != null && canvasEl != null) {
|
||||
if (!lCanvas) {
|
||||
lCanvas = new ComfyGraphCanvas(app, canvasEl);
|
||||
lCanvas.allow_interaction = false;
|
||||
LiteGraph.dialog_close_on_mouse_leave = false;
|
||||
LiteGraph.search_hide_on_mouse_leave = false;
|
||||
LiteGraph.pointerevents_method = "pointer";
|
||||
app.lGraph.eventBus.on("afterExecute", () => lCanvas.draw(true))
|
||||
}
|
||||
resizeCanvas();
|
||||
}
|
||||
|
||||
@@ -1,26 +1,22 @@
|
||||
<script lang="ts">
|
||||
import ComfyApp, { type SerializedAppState } from "$lib/components/ComfyApp";
|
||||
import uiState from "$lib/stores/uiState";
|
||||
import layoutState, { type IDragItem } from "$lib/stores/layoutState";
|
||||
|
||||
import queueState from "$lib/stores/queueState";
|
||||
import { Page, Navbar, Link, BlockTitle, Block, List, ListItem, Toolbar } from "framework7-svelte"
|
||||
import WidgetContainer from "$lib/components/WidgetContainer.svelte";
|
||||
|
||||
export let subworkflowID: number = -1;
|
||||
let app: ComfyApp = undefined;
|
||||
|
||||
$: if (!app)
|
||||
app = $uiState.app
|
||||
|
||||
</script>
|
||||
|
||||
<Page name="subworkflow">
|
||||
<Navbar title="Workflow {subworkflowID}" backLink="Back" />
|
||||
|
||||
<div>Workflow!</div>
|
||||
<WidgetContainer bind:dragItem={$layoutState.root} classes={["root-container", "mobile"]} />
|
||||
</Page>
|
||||
|
||||
<style>
|
||||
.is-executing {
|
||||
border: 5px dashed var(--color-green-600) !important;
|
||||
<style lang="scss">
|
||||
// TODO generalize this to all properties!
|
||||
:global(.root-container.mobile > .block > .v-pane) {
|
||||
flex-direction: column !important;
|
||||
}
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user