Fix editor and consolidate file upload widget
This commit is contained in:
@@ -33,6 +33,7 @@
|
|||||||
uploaded: ComfyImageLocation[];
|
uploaded: ComfyImageLocation[];
|
||||||
upload_error: any;
|
upload_error: any;
|
||||||
clear: undefined;
|
clear: undefined;
|
||||||
|
image_clicked: undefined;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
if (value) {
|
if (value) {
|
||||||
@@ -58,6 +59,10 @@
|
|||||||
dispatch("clear")
|
dispatch("clear")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function onImgClicked() {
|
||||||
|
dispatch("image_clicked")
|
||||||
|
}
|
||||||
|
|
||||||
interface GradioUploadResponse {
|
interface GradioUploadResponse {
|
||||||
error?: string;
|
error?: string;
|
||||||
files?: Array<ComfyImageLocation>;
|
files?: Array<ComfyImageLocation>;
|
||||||
@@ -205,6 +210,7 @@
|
|||||||
<ModifyUpload on:clear={handle_clear} absolute />
|
<ModifyUpload on:clear={handle_clear} absolute />
|
||||||
<img src={convertComfyOutputToComfyURL(firstImage)}
|
<img src={convertComfyOutputToComfyURL(firstImage)}
|
||||||
alt={firstImage.filename}
|
alt={firstImage.filename}
|
||||||
|
on:click={onImgClicked}
|
||||||
bind:this={imgElem}
|
bind:this={imgElem}
|
||||||
bind:naturalWidth={imgWidth}
|
bind:naturalWidth={imgWidth}
|
||||||
bind:naturalHeight={imgHeight}
|
bind:naturalHeight={imgHeight}
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
export let showModal; // boolean
|
export let showModal; // boolean
|
||||||
export let closeOnClick = true; // boolean
|
export let closeOnClick = true; // boolean
|
||||||
export let showCloseButton = true; // boolean
|
export const closeDialog = _ => doClose();
|
||||||
|
|
||||||
let dialog; // HTMLDialogElement
|
let dialog; // HTMLDialogElement
|
||||||
|
|
||||||
@@ -32,19 +32,21 @@
|
|||||||
|
|
||||||
<!-- svelte-ignore a11y-click-events-have-key-events -->
|
<!-- svelte-ignore a11y-click-events-have-key-events -->
|
||||||
<dialog
|
<dialog
|
||||||
bind:this={dialog}
|
bind:this={dialog}
|
||||||
on:close={close}
|
on:close={close}
|
||||||
on:cancel={doClose}
|
on:cancel={doClose}
|
||||||
on:click|self={close}
|
on:click|self={close}
|
||||||
>
|
>
|
||||||
<div on:click|stopPropagation>
|
<div on:click|stopPropagation>
|
||||||
<slot name="header" />
|
<slot name="header" />
|
||||||
<slot />
|
<slot />
|
||||||
<!-- svelte-ignore a11y-autofocus -->
|
<div class="button-row">
|
||||||
{#if showCloseButton}
|
<slot name="buttons">
|
||||||
<Button variant="secondary" on:click={doClose}>Close</Button>
|
<!-- svelte-ignore a11y-autofocus -->
|
||||||
{/if}
|
<Button variant="secondary" on:click={doClose}>Close</Button>
|
||||||
</div>
|
</slot>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</dialog>
|
</dialog>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
@@ -53,6 +55,7 @@
|
|||||||
border-radius: 0.2em;
|
border-radius: 0.2em;
|
||||||
border: none;
|
border: none;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
dialog::backdrop {
|
dialog::backdrop {
|
||||||
background: rgba(0, 0, 0, 0.3);
|
background: rgba(0, 0, 0, 0.3);
|
||||||
@@ -85,4 +88,10 @@
|
|||||||
button {
|
button {
|
||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.button-row {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
gap: var(--spacing-sm);
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
110
src/lib/components/NumberInput.svelte
Normal file
110
src/lib/components/NumberInput.svelte
Normal file
@@ -0,0 +1,110 @@
|
|||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import { BlockTitle } from "@gradio/atoms";
|
||||||
|
import { createEventDispatcher } from "svelte";
|
||||||
|
|
||||||
|
export let value: number = 0;
|
||||||
|
export let min: number = -1024
|
||||||
|
export let max: number = 1024
|
||||||
|
export let step: number = 1;
|
||||||
|
export let label: string = "";
|
||||||
|
export let disabled: boolean = false;
|
||||||
|
let inputValue = value;
|
||||||
|
|
||||||
|
const dispatch = createEventDispatcher<{ change: number; release: number }>();
|
||||||
|
|
||||||
|
function handle_input(e: Event) {
|
||||||
|
const element = e.currentTarget as HTMLInputElement;
|
||||||
|
let newValue = parseFloat(element.value);
|
||||||
|
if (isNaN(newValue)) {
|
||||||
|
newValue = min;
|
||||||
|
}
|
||||||
|
inputValue = Math.min(Math.max(inputValue, min), max);
|
||||||
|
value = inputValue;
|
||||||
|
dispatch("release", value);
|
||||||
|
}
|
||||||
|
|
||||||
|
function handle_release(e: MouseEvent) {
|
||||||
|
dispatch("release", value);
|
||||||
|
}
|
||||||
|
|
||||||
|
$: {
|
||||||
|
inputValue = value;
|
||||||
|
dispatch("change", value);
|
||||||
|
}
|
||||||
|
|
||||||
|
const clamp = () => {
|
||||||
|
value = Math.min(Math.max(value, min), max);
|
||||||
|
dispatch("release", value);
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class="wrap">
|
||||||
|
<div class="head">
|
||||||
|
<label>
|
||||||
|
<BlockTitle>{label}</BlockTitle>
|
||||||
|
</label>
|
||||||
|
<input
|
||||||
|
data-testid="number-input"
|
||||||
|
type="number"
|
||||||
|
bind:value={inputValue}
|
||||||
|
on:input={handle_input}
|
||||||
|
min={min}
|
||||||
|
max={max}
|
||||||
|
on:blur={clamp}
|
||||||
|
{step}
|
||||||
|
{disabled}
|
||||||
|
on:pointerup={handle_release}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
.wrap {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.head {
|
||||||
|
display: flex;
|
||||||
|
|
||||||
|
> label {
|
||||||
|
padding: 0.5rem 1.0rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
input[type="number"] {
|
||||||
|
display: block;
|
||||||
|
width: 100%;
|
||||||
|
position: relative;
|
||||||
|
outline: none !important;
|
||||||
|
box-shadow: var(--input-shadow);
|
||||||
|
border: var(--input-border-width) solid var(--input-border-color);
|
||||||
|
border-radius: var(--input-radius);
|
||||||
|
background: var(--input-background-fill);
|
||||||
|
padding: var(--size-2) var(--size-2);
|
||||||
|
color: var(--body-text-color);
|
||||||
|
font-size: var(--input-text-size);
|
||||||
|
line-height: var(--line-sm);
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
input:disabled {
|
||||||
|
-webkit-text-fill-color: var(--body-text-color);
|
||||||
|
-webkit-opacity: 1;
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type="number"]:focus {
|
||||||
|
box-shadow: var(--input-shadow-focus);
|
||||||
|
border-color: var(--input-border-color-focus);
|
||||||
|
}
|
||||||
|
|
||||||
|
input::placeholder {
|
||||||
|
color: var(--input-placeholder-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
input[disabled] {
|
||||||
|
cursor: not-allowed;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
58
src/lib/components/gradio/app/Column.svelte
Normal file
58
src/lib/components/gradio/app/Column.svelte
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import { create_classes } from "@gradio/utils";
|
||||||
|
import type { Styles } from "@gradio/utils";
|
||||||
|
|
||||||
|
export let scale: number = 1;
|
||||||
|
export let min_width: number = 0;
|
||||||
|
export let elem_id: string = "";
|
||||||
|
export let elem_classes: Array<string> = [];
|
||||||
|
export let visible: boolean = true;
|
||||||
|
export let variant: "default" | "panel" | "compact" = "default";
|
||||||
|
export let style: Styles = {};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div
|
||||||
|
id={elem_id}
|
||||||
|
class={elem_classes.join(" ")}
|
||||||
|
class:gap={style.gap !== false}
|
||||||
|
class:compact={variant === "compact"}
|
||||||
|
class:panel={variant === "panel"}
|
||||||
|
class:hide={!visible}
|
||||||
|
style={`min-width: min(${min_width}px, 100%); flex-grow: ${scale}`}
|
||||||
|
>
|
||||||
|
<slot />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
div {
|
||||||
|
display: flex;
|
||||||
|
position: relative;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
div > :global(*),
|
||||||
|
div > :global(.form > *) {
|
||||||
|
width: var(--size-full);
|
||||||
|
}
|
||||||
|
|
||||||
|
.gap {
|
||||||
|
gap: var(--layout-gap);
|
||||||
|
}
|
||||||
|
|
||||||
|
.hide {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.compact > :global(*),
|
||||||
|
.compact :global(.box) {
|
||||||
|
border-radius: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.compact,
|
||||||
|
.panel {
|
||||||
|
border: solid var(--panel-border-width) var(--panel-border-color);
|
||||||
|
border-radius: var(--container-radius);
|
||||||
|
background: var(--panel-background-fill);
|
||||||
|
padding: var(--spacing-lg);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
60
src/lib/components/gradio/app/Row.svelte
Normal file
60
src/lib/components/gradio/app/Row.svelte
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import type { Styles } from "@gradio/utils";
|
||||||
|
|
||||||
|
export let style: Styles = {};
|
||||||
|
export let elem_id: string;
|
||||||
|
export let elem_classes: Array<string> = [];
|
||||||
|
export let visible: boolean = true;
|
||||||
|
export let variant: "default" | "panel" | "compact" = "default";
|
||||||
|
export let min_width: string = "160px";
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div
|
||||||
|
class:compact={variant === "compact"}
|
||||||
|
class:panel={variant === "panel"}
|
||||||
|
class:unequal-height={style.equal_height === false}
|
||||||
|
class:stretch={style.equal_height}
|
||||||
|
class:hide={!visible}
|
||||||
|
id={elem_id}
|
||||||
|
class={elem_classes.join(" ")}
|
||||||
|
style="--row-min-width: {min_width}"
|
||||||
|
>
|
||||||
|
<slot />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
div {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: var(--layout-gap);
|
||||||
|
width: var(--size-full);
|
||||||
|
}
|
||||||
|
|
||||||
|
.hide {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
.compact > :global(*),
|
||||||
|
.compact :global(.box) {
|
||||||
|
border-radius: 0;
|
||||||
|
}
|
||||||
|
.compact,
|
||||||
|
.panel {
|
||||||
|
border-radius: var(--container-radius);
|
||||||
|
background: var(--background-fill-secondary);
|
||||||
|
padding: var(--size-2);
|
||||||
|
}
|
||||||
|
.unequal-height {
|
||||||
|
align-items: flex-start;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stretch {
|
||||||
|
align-items: stretch;
|
||||||
|
}
|
||||||
|
|
||||||
|
div > :global(*),
|
||||||
|
div > :global(.form > *) {
|
||||||
|
flex: 1 1 0%;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
min-width: min(--row-min-width, 100%);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -1,16 +1,19 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { type WidgetLayout } from "$lib/stores/layoutState";
|
import { type WidgetLayout } from "$lib/stores/layoutState";
|
||||||
import { Block, BlockTitle } from "@gradio/atoms";
|
import { Block } from "@gradio/atoms";
|
||||||
import { get, type Writable, writable } from "svelte/store";
|
import { TextBox } from "@gradio/form";
|
||||||
|
import Row from "$lib/components/gradio/app/Row.svelte";
|
||||||
|
import { get, type Writable } from "svelte/store";
|
||||||
import Modal from "$lib/components/Modal.svelte";
|
import Modal from "$lib/components/Modal.svelte";
|
||||||
import { Button } from "@gradio/button";
|
import { Button } from "@gradio/button";
|
||||||
import type { ComfyImageEditorNode, ComfyImageLocation, MultiImageData } from "$lib/nodes/ComfyWidgetNodes";
|
import type { ComfyImageEditorNode, ComfyImageLocation } from "$lib/nodes/ComfyWidgetNodes";
|
||||||
import { Embed as Klecks, KL, KlApp, klHistory, type KlAppOptionsEmbed } from "klecks";
|
import { Embed as Klecks } from "klecks";
|
||||||
|
|
||||||
import "klecks/style/style.scss";
|
import "klecks/style/style.scss";
|
||||||
import ImageUpload from "$lib/components/ImageUpload.svelte";
|
import ImageUpload from "$lib/components/ImageUpload.svelte";
|
||||||
import { uploadImageToComfyUI, type ComfyUploadImageAPIResponse, convertComfyOutputToComfyURL, type ComfyBoxImageMetadata, comfyFileToComfyBoxMetadata, comfyBoxImageToComfyURL, comfyBoxImageToComfyFile } from "$lib/utils";
|
import { uploadImageToComfyUI, type ComfyBoxImageMetadata, comfyFileToComfyBoxMetadata, comfyBoxImageToComfyURL, comfyBoxImageToComfyFile, type ComfyUploadImageType } from "$lib/utils";
|
||||||
import notify from "$lib/notify";
|
import notify from "$lib/notify";
|
||||||
|
import NumberInput from "$lib/components/NumberInput.svelte";
|
||||||
|
|
||||||
export let widget: WidgetLayout | null = null;
|
export let widget: WidgetLayout | null = null;
|
||||||
export let isMobile: boolean = false;
|
export let isMobile: boolean = false;
|
||||||
@@ -40,6 +43,7 @@
|
|||||||
node = widget.node as ComfyImageEditorNode
|
node = widget.node as ComfyImageEditorNode
|
||||||
nodeValue = node.value;
|
nodeValue = node.value;
|
||||||
attrsChanged = widget.attrsChanged;
|
attrsChanged = widget.attrsChanged;
|
||||||
|
status = $nodeValue && $nodeValue.length > 0 ? "uploaded" : "empty"
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -67,7 +71,7 @@
|
|||||||
const ctx = canvas.getContext('2d');
|
const ctx = canvas.getContext('2d');
|
||||||
ctx.save();
|
ctx.save();
|
||||||
ctx.fillStyle = fill,
|
ctx.fillStyle = fill,
|
||||||
ctx.fillRect(0, 0, canvas.width, canvas.height);
|
ctx.fillRect(0, 0, canvas.width, canvas.height);
|
||||||
ctx.restore();
|
ctx.restore();
|
||||||
return canvas;
|
return canvas;
|
||||||
}
|
}
|
||||||
@@ -97,25 +101,45 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
const FILENAME: string = "ComfyUITemp.png";
|
const FILENAME: string = "ComfyUITemp.png";
|
||||||
// const SUBFOLDER: string = "ComfyBox_Editor";
|
const SUBFOLDER: string = "ComfyBox_Editor";
|
||||||
|
const DIRECTORY: ComfyUploadImageType = "input";
|
||||||
|
|
||||||
async function submitKlecksToComfyUI(onSuccess: () => void, onError: () => void) {
|
async function submitKlecksToComfyUI(onSuccess: () => void, onError: () => void) {
|
||||||
const blob = kl.getPNG();
|
const blob = kl.getPNG();
|
||||||
|
|
||||||
await uploadImageToComfyUI(blob, FILENAME, "input")
|
status = "uploading"
|
||||||
|
|
||||||
|
await uploadImageToComfyUI(blob, FILENAME, DIRECTORY, SUBFOLDER)
|
||||||
.then((entry: ComfyImageLocation) => {
|
.then((entry: ComfyImageLocation) => {
|
||||||
const meta: ComfyBoxImageMetadata = comfyFileToComfyBoxMetadata(entry);
|
const meta: ComfyBoxImageMetadata = comfyFileToComfyBoxMetadata(entry);
|
||||||
$nodeValue = [meta] // TODO more than one image
|
$nodeValue = [meta] // TODO more than one image
|
||||||
|
status = "uploaded"
|
||||||
notify("Saved image to ComfyUI!", { type: "success" })
|
notify("Saved image to ComfyUI!", { type: "success" })
|
||||||
onSuccess();
|
onSuccess();
|
||||||
})
|
})
|
||||||
.catch(err => {
|
.catch(err => {
|
||||||
notify(`Failed to upload image from editor: ${err}`, { type: "error", timeout: 10000 })
|
notify(`Failed to upload image from editor: ${err}`, { type: "error", timeout: 10000 })
|
||||||
|
status = "error"
|
||||||
|
uploadError = err;
|
||||||
$nodeValue = []
|
$nodeValue = []
|
||||||
onError();
|
onError();
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let closeDialog = null;
|
||||||
|
|
||||||
|
async function saveAndClose() {
|
||||||
|
console.log(closeDialog, kl)
|
||||||
|
if (!closeDialog || !kl)
|
||||||
|
return;
|
||||||
|
|
||||||
|
submitKlecksToComfyUI(() => {}, () => {});
|
||||||
|
closeDialog()
|
||||||
|
}
|
||||||
|
|
||||||
|
let blankImageWidth = 512;
|
||||||
|
let blankImageHeight = 512;
|
||||||
|
|
||||||
async function openImageEditor() {
|
async function openImageEditor() {
|
||||||
if (!editorRoot)
|
if (!editorRoot)
|
||||||
return;
|
return;
|
||||||
@@ -134,12 +158,12 @@
|
|||||||
console.warn("[ImageEditorWidget] OPENING", widget, $nodeValue)
|
console.warn("[ImageEditorWidget] OPENING", widget, $nodeValue)
|
||||||
|
|
||||||
let canvas = null;
|
let canvas = null;
|
||||||
let width = 512;
|
let width = blankImageWidth;
|
||||||
let height = 512;
|
let height = blankImageHeight;
|
||||||
|
|
||||||
if ($nodeValue && $nodeValue.length > 0) {
|
if ($nodeValue && $nodeValue.length > 0) {
|
||||||
const comfyImage = $nodeValue[0];
|
const comfyImage = $nodeValue[0];
|
||||||
const comfyURL = convertComfyOutputToComfyURL(comfyImage);
|
const comfyURL = comfyBoxImageToComfyURL(comfyImage);
|
||||||
[canvas, width, height] = await generateImageCanvas(comfyURL);
|
[canvas, width, height] = await generateImageCanvas(comfyURL);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@@ -162,7 +186,7 @@
|
|||||||
}, 1000);
|
}, 1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
let status = "none"
|
let status = "empty";
|
||||||
let uploadError = null;
|
let uploadError = null;
|
||||||
|
|
||||||
function onUploading() {
|
function onUploading() {
|
||||||
@@ -181,14 +205,16 @@
|
|||||||
function onClear() {
|
function onClear() {
|
||||||
console.warn("CLEAR!!!")
|
console.warn("CLEAR!!!")
|
||||||
uploadError = null;
|
uploadError = null;
|
||||||
status = "none"
|
status = "empty"
|
||||||
|
$nodeValue = []
|
||||||
}
|
}
|
||||||
|
|
||||||
function onUploadError(e: CustomEvent<any>) {
|
function onUploadError(e: CustomEvent<any>) {
|
||||||
console.warn("ERROR!!!")
|
console.warn("ERROR!!!")
|
||||||
status = "error"
|
status = "error"
|
||||||
uploadError = e.detail
|
uploadError = e.detail
|
||||||
notify(`Failed to upload image to ComfyUI: ${err}`, { type: "error", timeout: 10000 })
|
$nodeValue = []
|
||||||
|
notify(`Failed to upload image to ComfyUI: ${uploadError}`, { type: "error", timeout: 10000 })
|
||||||
}
|
}
|
||||||
|
|
||||||
function onChange(e: CustomEvent<ComfyImageLocation[]>) {
|
function onChange(e: CustomEvent<ComfyImageLocation[]>) {
|
||||||
@@ -200,7 +226,7 @@
|
|||||||
else
|
else
|
||||||
_value = []
|
_value = []
|
||||||
|
|
||||||
$: canEdit = status === "none" || status === "uploaded";
|
$: canEdit = status === "empty" || status === "uploaded";
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="wrapper comfy-image-editor">
|
<div class="wrapper comfy-image-editor">
|
||||||
@@ -217,6 +243,7 @@
|
|||||||
on:upload_error={onUploadError}
|
on:upload_error={onUploadError}
|
||||||
on:clear={onClear}
|
on:clear={onClear}
|
||||||
on:change={onChange}
|
on:change={onChange}
|
||||||
|
on:image_clicked={openImageEditor}
|
||||||
/>
|
/>
|
||||||
{:else}
|
{:else}
|
||||||
<div class="comfy-image-editor-panel">
|
<div class="comfy-image-editor-panel">
|
||||||
@@ -232,24 +259,59 @@
|
|||||||
on:upload_error={onUploadError}
|
on:upload_error={onUploadError}
|
||||||
on:clear={onClear}
|
on:clear={onClear}
|
||||||
on:change={onChange}
|
on:change={onChange}
|
||||||
|
on:image_clicked={openImageEditor}
|
||||||
/>
|
/>
|
||||||
<Modal bind:showModal closeOnClick={false} on:close={disposeEditor}>
|
<Modal bind:showModal closeOnClick={false} on:close={disposeEditor} bind:closeDialog>
|
||||||
<div>
|
<div>
|
||||||
<div id="klecks-loading-screen">
|
<div id="klecks-loading-screen">
|
||||||
<span id="klecks-loading-screen-text"></span>
|
<span id="klecks-loading-screen-text"></span>
|
||||||
</div>
|
</div>
|
||||||
<div class="image-editor-root" bind:this={editorRoot} />
|
<div class="image-editor-root" bind:this={editorRoot} />
|
||||||
</div>
|
</div>
|
||||||
|
<div slot="buttons">
|
||||||
|
<Button variant="primary" on:click={saveAndClose}>
|
||||||
|
Save and Close
|
||||||
|
</Button>
|
||||||
|
<Button variant="secondary" on:click={closeDialog}>
|
||||||
|
Discard Edits
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
</Modal>
|
</Modal>
|
||||||
<Block>
|
<Block>
|
||||||
<Button variant="primary" disabled={!canEdit} on:click={openImageEditor}>
|
{#if !$nodeValue || $nodeValue.length === 0}
|
||||||
Edit Image
|
<Row>
|
||||||
</Button>
|
<Row>
|
||||||
<BlockTitle>Status: {status}</BlockTitle>
|
<Button variant="secondary" disabled={!canEdit} on:click={openImageEditor}>
|
||||||
{#if uploadError}
|
Create Image
|
||||||
<div>
|
</Button>
|
||||||
Upload error: {uploadError}
|
<div>
|
||||||
</div>
|
<TextBox show_label={false} disabled={true} value="Status: {status}"/>
|
||||||
|
</div>
|
||||||
|
{#if uploadError}
|
||||||
|
<div>
|
||||||
|
Upload error: {uploadError}
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
</Row>
|
||||||
|
<Row>
|
||||||
|
<NumberInput label={"Width"} min={64} max={2048} step={64} bind:value={blankImageWidth} />
|
||||||
|
<NumberInput label={"Height"} min={64} max={2048} step={64} bind:value={blankImageHeight} />
|
||||||
|
</Row>
|
||||||
|
</Row>
|
||||||
|
{:else}
|
||||||
|
<Row>
|
||||||
|
<Button variant="secondary" disabled={!canEdit} on:click={openImageEditor}>
|
||||||
|
Edit Image
|
||||||
|
</Button>
|
||||||
|
<div>
|
||||||
|
<TextBox show_label={false} disabled={true} value="Status: {status}"/>
|
||||||
|
</div>
|
||||||
|
{#if uploadError}
|
||||||
|
<div>
|
||||||
|
Upload error: {uploadError}
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
</Row>
|
||||||
{/if}
|
{/if}
|
||||||
</Block>
|
</Block>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user