Grid view for history

This commit is contained in:
space-nuko
2023-05-22 10:17:49 -05:00
parent 44698e2768
commit 69266c928e
12 changed files with 406 additions and 194 deletions

View File

@@ -73,6 +73,7 @@
"klecks": "workspace:*",
"pollen-css": "^4.6.2",
"radix-icons-svelte": "^1.2.1",
"svelte-bootstrap-icons": "^2.3.1",
"svelte-feather-icons": "^4.0.0",
"svelte-preprocess": "^5.0.3",
"svelte-select": "^5.5.3",

7
pnpm-lock.yaml generated
View File

@@ -97,6 +97,9 @@ importers:
radix-icons-svelte:
specifier: ^1.2.1
version: 1.2.1
svelte-bootstrap-icons:
specifier: ^2.3.1
version: 2.3.1
svelte-feather-icons:
specifier: ^4.0.0
version: 4.0.0
@@ -7908,6 +7911,10 @@ packages:
resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==}
engines: {node: '>= 0.4'}
/svelte-bootstrap-icons@2.3.1:
resolution: {integrity: sha512-Vqhgmcd55hEoB/MrPESvVYo4+m++2q9l00a5lzGkgbXTiO6go21PTU9DaeAJ446WBiEmg3Q8sv9QVOBmh5c1ww==}
dev: false
/svelte-check@2.2.6(postcss-load-config@3.1.4)(postcss@8.4.21)(svelte@3.58.0):
resolution: {integrity: sha512-oJux/afbmcZO+N+ADXB88h6XANLie8Y2rh2qBlhgfkpr2c3t/q/T0w2JWrHqagaDL8zeNwO8a8RVFBkrRox8gg==}
hasBin: true

View File

@@ -1,6 +1,6 @@
<script lang="ts">
import { ListIcon as List, ImageIcon as Image, SettingsIcon as Settings } from "svelte-feather-icons";
import ComfyApp, { type A1111PromptAndInfo, type SerializedAppState } from "./ComfyApp";
import { Image, Gear } from "svelte-bootstrap-icons";
import ComfyApp from "./ComfyApp";
import uiState from "$lib/stores/uiState";
import configState from "$lib/stores/configState";
import workflowState from "$lib/stores/workflowState";
@@ -62,7 +62,7 @@
<SidebarItem id="generate" name="Generate" icon={Image}>
<ComfyWorkflowsView {app} {uiTheme} />
</SidebarItem>
<SidebarItem id="settings" name="Settings" icon={Settings}>
<SidebarItem id="settings" name="Settings" icon={Gear}>
</SidebarItem>
</Sidebar>
</div>

View File

@@ -29,7 +29,7 @@
<label class="number-wrapper">
<BlockTitle>{name}</BlockTitle>
<div class="number">
<input type="number" bind:value {min} {max} {step} {disabled}>
<input type="number" bind:value {min} {max} {step} {disabled} />
</div>
</label>

View File

@@ -1,9 +1,23 @@
<script lang="ts" context="module">
export type QueueUIEntryStatus = QueueEntryStatus | "pending" | "running";
export type QueueUIEntry = {
entry: QueueEntry,
message: string,
submessage: string,
date?: string,
status: QueueUIEntryStatus,
images?: string[], // URLs
details?: string // shown in a tooltip on hover
}
</script>
<script lang="ts">
import queueState, { type CompletedQueueEntry, type QueueEntry, type QueueEntryStatus } from "$lib/stores/queueState";
import ProgressBar from "./ProgressBar.svelte";
import Spinner from "./Spinner.svelte";
import PromptDisplay from "./PromptDisplay.svelte";
import { ListIcon as List } from "svelte-feather-icons";
import { List, ListUl, Grid } from "svelte-bootstrap-icons";
import { convertComfyOutputToComfyURL, convertFilenameToComfyURL, getNodeInfo, truncateString } from "$lib/utils"
import type { Writable } from "svelte/store";
import type { QueueItemType } from "$lib/api";
@@ -14,6 +28,8 @@
import Modal from "./Modal.svelte";
import DropZone from "./DropZone.svelte";
import workflowState from "$lib/stores/workflowState";
import ComfyQueueListDisplay from "./ComfyQueueListDisplay.svelte";
import ComfyQueueGridDisplay from "./ComfyQueueGridDisplay.svelte";
export let app: ComfyApp;
@@ -22,25 +38,16 @@
let queueCompleted: Writable<CompletedQueueEntry[]> | null = null;
let queueList: HTMLDivElement | null = null;
type QueueUIEntryStatus = QueueEntryStatus | "pending" | "running";
type QueueUIEntry = {
entry: QueueEntry,
message: string,
submessage: string,
date?: string,
status: QueueUIEntryStatus,
images?: string[], // URLs
details?: string // shown in a tooltip on hover
}
$: if ($queueState) {
queuePending = $queueState.queuePending
queueRunning = $queueState.queueRunning
queueCompleted = $queueState.queueCompleted
}
type DisplayModeType = "list" | "grid";
let mode: QueueItemType = "queue";
let displayMode: DisplayModeType = "list";
let changed = true;
function switchMode(newMode: QueueItemType) {
@@ -53,6 +60,16 @@
}
}
function switchDisplayMode(newDisplayMode: DisplayModeType) {
// changed = displayMode !== newDisplayMode
displayMode = newDisplayMode
// if (changed) {
// _queuedEntries = []
// _runningEntries = []
// _entries = []
// }
}
let _queuedEntries: QueueUIEntry[] = []
let _runningEntries: QueueUIEntry[] = []
let _entries: QueueUIEntry[] = []
@@ -156,12 +173,12 @@
console.warn("[ComfyQueue] BUILDHISTORY", _entries, $queueCompleted)
}
function showLightbox(entry: QueueUIEntry, index: number, e: Event) {
function showLightbox(images: string[], index: number, e: Event) {
e.preventDefault()
if (!entry.images)
if (!images)
return
ImageViewer.instance.showModal(entry.images, index);
ImageViewer.instance.showModal(images, index);
e.stopPropagation()
}
@@ -184,7 +201,7 @@
let expandAll = false;
let selectedPrompt = null;
let selectedImages = [];
function showPrompt(entry: QueueUIEntry, e: MouseEvent) {
function showPrompt(entry: QueueUIEntry) {
selectedPrompt = entry.entry.prompt;
selectedImages = entry.images;
showModal = true;
@@ -219,48 +236,33 @@
</div>
</Modal>
<div class="queue">
<div class="queue-entries {mode}-mode" bind:this={queueList}>
<div class="queue {mode}-mode">
{#if mode === "history"}
<div class="display-mode-buttons">
<div class="mode-button image-display-button ternary"
on:click={() => switchDisplayMode("list")}
class:selected={displayMode === "list"}>
<List width="100%" height="100%" />
</div>
<div class="mode-button image-display-button ternary"
on:click={() => switchDisplayMode("grid")}
class:selected={displayMode === "grid"}>
<Grid width="100%" height="100%" />
</div>
</div>
{/if}
<div class="queue-entries" bind:this={queueList}>
{#if _entries.length > 0}
{#each _entries as entry}
<div class="queue-entry {entry.status}" on:click={(e) => showPrompt(entry, e)}>
{#if entry.images.length > 0}
<div class="queue-entry-images"
style="--cols: {Math.ceil(Math.sqrt(Math.min(entry.images.length, 4)))}" >
{#each entry.images.slice(0, 4) as image, i}
<div>
<img class="queue-entry-image"
on:click={(e) => showLightbox(entry, i, e)}
src={image}
alt="thumbnail" />
</div>
{/each}
</div>
{:else}
<!-- <div class="queue-entry-image-placeholder" /> -->
{/if}
<div class="queue-entry-details">
<div class="queue-entry-message">
{truncateString(entry.message, 20)}
</div>
<div class="queue-entry-submessage">
{entry.submessage}
</div>
</div>
</div>
<div class="queue-entry-rest {entry.status}">
{#if entry.date != null}
<span class="queue-entry-queued-at">
{entry.date}
</span>
{/if}
</div>
{/each}
{#if mode === "history" && displayMode === "grid"}
<ComfyQueueGridDisplay entries={_entries} {showLightbox} {showPrompt} {mode} />
{:else}
<ComfyQueueListDisplay entries={_entries} {showLightbox} {showPrompt} {mode} />
{/if}
{:else}
<div class="queue-empty">
<div class="queue-empty-container">
<div class="queue-empty-icon">
<List size="120rem" />
<ListUl width="100%" height="10rem" />
</div>
<div class="queue-empty-message">
(No entries)
@@ -272,12 +274,12 @@
<div class="mode-buttons">
<div class="mode-button secondary"
on:click={() => switchMode("queue")}
class:mode-selected={mode === "queue"}>
class:selected={mode === "queue"}>
Queue
</div>
<div class="mode-button secondary"
on:click={() => switchMode("history")}
class:mode-selected={mode === "history"}>
class:selected={mode === "history"}>
History
</div>
</div>
@@ -315,10 +317,12 @@
<style lang="scss">
$pending-height: 200px;
$display-mode-buttons-height: 2rem;
$bottom-bar-height: 70px;
$workflow-tabs-height: 2.5rem;
$mode-buttons-height: 30px;
$queue-height: calc(100vh - #{$pending-height} - #{$mode-buttons-height} - #{$bottom-bar-height} - #{$workflow-tabs-height} - 0.9rem);
$queue-height-history: calc(#{$queue-height} - #{$display-mode-buttons-height});
.prompt-modal-header {
padding-left: 0.2rem;
@@ -329,20 +333,22 @@
}
.queue {
color: var(--body-text-color);
&.queue-mode > .queue-entries {
height: $queue-height;
max-height: $queue-height;
}
&.history-mode > .queue-entries {
height: $queue-height-history;
max-height: $queue-height-history;
}
}
.queue-entries {
height: $queue-height;
max-height: $queue-height;
display: flex;
overflow-y: auto;
flex-flow: column nowrap;
&.queue-mode > :first-child {
// elements stick to bottom in queue mode only
// next element in queue is on the bottom
margin-top: auto !important;
}
height: $queue-height;
> .queue-empty {
display: flex;
@@ -368,105 +374,21 @@
}
}
.queue-entry {
padding: 1.0rem;
.display-mode-buttons {
display: flex;
flex-direction: row;
border-bottom: 1px solid var(--block-border-color);
border-top: 1px solid var(--table-border-color);
background: var(--panel-background-fill);
max-height: 14rem;
top: 0px;
height: $display-mode-buttons-height;
margin-bottom: auto;
&:hover:not(:has(img:hover)) {
cursor: pointer;
background: var(--block-background-fill);
> .mode-button {
width: 100%;
color: var(--neutral-500);
&.running {
background: var(--comfy-accent-soft);
&.selected {
color: var(--body-text-color);
}
}
&.success {
/* background: green; */
}
&.error {
background: red;
}
&.all_cached, &.interrupted {
filter: brightness(80%);
background: var(--comfy-disabled-textbox-background-fill);
color: var(--comfy-disable-textbox-text-color);
}
&.running {
background: var(--block-background-fill);
border: 3px dashed var(--neutral-500);
}
&.pending, &.unknown {
}
}
.queue-entry-rest {
width: 100%;
position: relative;
&.all_cached, &.interrupted {
filter: brightness(80%);
color: var(--comfy-accent-soft);
}
}
$thumbnails-size: 12rem;
.queue-entry-images {
--cols: 1;
margin: auto;
width: calc($thumbnails-size * 2);
display: grid;
display: inline-grid;
grid-template-columns: repeat(var(--cols), 1fr);
grid-template-rows: repeat(var(--cols), 1fr);
column-gap: 1px;
row-gap: 1px;
vertical-align: top;
flex: 1 1 40%;
img {
aspect-ratio: 1 / 1;
object-fit: cover;
&:hover {
cursor: pointer;
filter: brightness(120%) contrast(120%);
}
}
}
.queue-entry-details {
position: relative;
padding: 1rem;
width: 100%;
display: flex;
flex-direction: column;
justify-content: center;
white-space: nowrap;
}
.queue-entry-message {
font-size: 15px;
}
.queue-entry-submessage {
font-size: 12px;
}
.queue-entry-queued-at {
width: auto;
font-size: 12px;
position:absolute;
right: 0px;
bottom: 0px;
padding: 0.4rem 0.6rem;
color: var(--body-text-color);
}
.mode-buttons {
@@ -502,13 +424,20 @@
}
}
&.ternary {
background: var(--panel-background-fill);
&:hover {
background: var(--block-background-fill );
}
}
&:hover {
filter: brightness(85%);
}
&:active {
filter: brightness(50%)
}
&.mode-selected {
&.selected {
filter: brightness(80%)
}
}
@@ -521,7 +450,7 @@
&:active {
filter: brightness(50%)
}
&.mode-selected {
&.selected {
filter: brightness(150%)
}
}

View File

@@ -0,0 +1,118 @@
<script lang="ts">
import type { QueueItemType } from "$lib/api";
import { truncateString } from "$lib/utils";
import type { QueueUIEntry } from "./ComfyQueue.svelte";
export let entries: QueueUIEntry[] = [];
export let showPrompt: (entry: QueueUIEntry) => void;
export let showLightbox: (images: string[], index: number, e: Event) => void;
export let mode: QueueItemType = "queue";
let allEntries: [QueueUIEntry, string][] = []
let allImages: string[] = []
let gridColumns: number = 3;
$: buildImageList(entries);
function buildImageList(entries: QueueUIEntry[]) {
allEntries = []
for (const entry of entries) {
for (const image of entry.images) {
allEntries.push([entry, image]);
}
}
allImages = allEntries.map(p => p[1]);
}
function handleClick(e: MouseEvent, entry: QueueUIEntry, index: number) {
if (e.ctrlKey) {
showPrompt(entry);
}
else {
showLightbox(allImages, index, e)
}
}
</script>
<div class="grid-wrapper">
<div class="grid-columns">
<div>
<input type="range" bind:value={gridColumns} min={1} max={8} step={1} />
</div>
</div>
<div class="grid-entries">
<div class="grid" style:--cols={gridColumns}>
{#each allEntries as [entry, image], i}
<div class="grid-entry">
<!-- svelte-ignore a11y-click-events-have-key-events -->
<img class="grid-entry-image"
on:click={(e) => handleClick(e, entry, i)}
src={image}
alt="thumbnail" />
</div>
{/each}
</div>
</div>
</div>
<style lang="scss">
$grid-columns-control-height: 3rem;
.grid-wrapper {
height: 100%;
}
.grid-columns {
width: 100%;
height: $grid-columns-control-height;
position: relative;
display: flex;
flex-direction: column;
padding: var(--spacing-lg) 0;
> div {
width: 100%;
margin: auto;
padding: 0 1rem;
input {
width: 100%;
margin: auto;
}
}
}
.grid-entries {
height: calc(100% - #{$grid-columns-control-height});
padding: 0 var(--spacing-lg) var(--spacing-lg) var(--spacing-lg);
overflow-y: auto;
}
.grid {
--cols: 3;
width: 100%;
display: grid;
position: relative;
top: 0px;
grid-template-columns: repeat(var(--cols), minmax(0, 1fr));
grid-auto-rows: 1fr;
gap: var(--spacing-lg);
}
.grid-entry {
display: flex;
justify-content: center;
align-items: center;
aspect-ratio: 1 / 1;
object-fit: cover;
}
.grid-entry-image {
aspect-ratio: 1 / 1;
object-fit: cover;
&:hover {
cursor: pointer;
filter: brightness(120%) contrast(120%);
}
}
</style>

View File

@@ -0,0 +1,162 @@
<script lang="ts">
import type { QueueItemType } from "$lib/api";
import { truncateString } from "$lib/utils";
import type { QueueUIEntry } from "./ComfyQueue.svelte";
export let entries: QueueUIEntry[] = [];
export let showPrompt: (entry: QueueUIEntry) => void;
export let showLightbox: (images: string[], index: number, e: Event) => void;
export let mode: QueueItemType = "queue";
</script>
<div class="queue-wrapper {mode}-mode">
{#each entries as entry}
<div class="queue-entry {entry.status}" on:click={(e) => showPrompt(entry, e)}>
{#if entry.images.length > 0}
<div class="queue-entry-images"
style="--cols: {Math.ceil(Math.sqrt(Math.min(entry.images.length, 4)))}" >
{#each entry.images.slice(0, 4) as image, i}
<div>
<!-- svelte-ignore a11y-click-events-have-key-events -->
<img class="queue-entry-image"
on:click={(e) => showLightbox(entry.images, i, e)}
src={image}
alt="thumbnail" />
</div>
{/each}
</div>
{/if}
<div class="queue-entry-details">
<div class="queue-entry-message">
{truncateString(entry.message, 20)}
</div>
<div class="queue-entry-submessage">
{entry.submessage}
</div>
</div>
</div>
<div class="queue-entry-rest {entry.status}">
{#if entry.date != null}
<span class="queue-entry-queued-at">
{entry.date}
</span>
{/if}
</div>
{/each}
</div>
<style lang="scss">
.queue-wrapper {
height: 100%;
display: flex;
overflow-y: auto;
flex-flow: column nowrap;
&.queue-mode > :global(:first-child) {
// elements stick to bottom in queue mode only
// next element in queue is on the bottom
margin-top: auto !important;
}
}
.queue-entry {
padding: 1.0rem;
display: flex;
flex-direction: row;
border-bottom: 1px solid var(--block-border-color);
border-top: 1px solid var(--table-border-color);
background: var(--panel-background-fill);
max-height: 14rem;
&:hover:not(:has(img:hover)) {
cursor: pointer;
background: var(--block-background-fill);
&.running {
background: var(--comfy-accent-soft);
}
}
&.success {
/* background: green; */
}
&.error {
background: red;
}
&.all_cached, &.interrupted {
filter: brightness(80%);
background: var(--comfy-disabled-textbox-background-fill);
color: var(--comfy-disable-textbox-text-color);
}
&.running {
background: var(--block-background-fill);
border: 3px dashed var(--neutral-500);
}
&.pending, &.unknown {
}
}
.queue-entry-rest {
width: 100%;
position: relative;
&.all_cached, &.interrupted {
filter: brightness(80%);
color: var(--comfy-accent-soft);
}
}
$thumbnails-size: 12rem;
.queue-entry-images {
--cols: 1;
margin: auto;
width: calc($thumbnails-size * 2);
display: grid;
display: inline-grid;
grid-template-columns: repeat(var(--cols), 1fr);
grid-template-rows: repeat(var(--cols), 1fr);
column-gap: 1px;
row-gap: 1px;
vertical-align: top;
flex: 1 1 40%;
img {
aspect-ratio: 1 / 1;
object-fit: cover;
&:hover {
cursor: pointer;
filter: brightness(120%) contrast(120%);
}
}
}
.queue-entry-details {
position: relative;
padding: 1rem;
width: 100%;
display: flex;
flex-direction: column;
justify-content: center;
white-space: nowrap;
}
.queue-entry-message {
font-size: 15px;
}
.queue-entry-submessage {
font-size: 12px;
}
.queue-entry-queued-at {
width: auto;
font-size: 12px;
position:absolute;
right: 0px;
bottom: 0px;
padding: 0.4rem 0.6rem;
color: var(--body-text-color);
}
</style>

View File

@@ -1,6 +1,6 @@
<script lang="ts">
import { Pane, Splitpanes } from 'svelte-splitpanes';
import { PlusSquareIcon as PlusSquare } from 'svelte-feather-icons';
import { PlusSquareDotted } from 'svelte-bootstrap-icons';
import { Button } from "@gradio/button";
import { BlockTitle } from "@gradio/atoms";
import ComfyWorkflowView from "./ComfyWorkflowView.svelte";
@@ -253,7 +253,7 @@
</div>
<button class="workflow-add-new-button"
on:click={createNewWorkflow}>
<PlusSquare size="100%" strokeWidth={1.5} />
<PlusSquareDotted width="100%" height="100%" />
</button>
</div>
<div id="bottombar">

View File

@@ -62,7 +62,7 @@
{#if t.id === $selected_tab}
<button class="selected">
{#if t.icon !== null}
<svelte:component this={t.icon} size="100%" strokeWidth={1.5} />
<svelte:component this={t.icon} width="100%" height="100%" strokeWidth={1.5} />
{:else}
{t.name}
{/if}
@@ -75,7 +75,7 @@
}}
>
{#if t.icon !== null}
<svelte:component this={t.icon} size="100%" strokeWidth={1.5} />
<svelte:component this={t.icon} width="100%" height="100%" strokeWidth={1.5} />
{:else}
{t.name}
{/if}

View File

@@ -1,5 +1,5 @@
import { parseWhateverIntoImageMetadata, type ComfyBoxImageMetadata, type ComfyUploadImageType } from "$lib/utils";
import { BuiltInSlotType, LiteGraph, type IComboWidget, type ITextWidget, type PropertyLayout, type SlotLayout } from "@litegraph-ts/core";
import { BuiltInSlotType, LiteGraph, type IComboWidget, type ITextWidget, type PropertyLayout, type SlotLayout, type INumberWidget } from "@litegraph-ts/core";
import { get, writable, type Writable } from "svelte/store";
import GalleryWidget from "$lib/widgets/GalleryWidget.svelte";
@@ -42,15 +42,17 @@ export default class ComfyGalleryNode extends ComfyWidgetNode<ComfyBoxImageMetad
selectedFilename: string | null = null;
selectedIndexWidget: ITextWidget;
selectedIndexWidget: INumberWidget;
modeWidget: IComboWidget;
imageWidth: Writable<number> = writable(0);
imageHeight: Writable<number> = writable(0);
selectedImage: Writable<number | null> = writable(null);
constructor(name?: string) {
super(name, [])
this.selectedIndexWidget = this.addWidget("text", "Selected", String(this.properties.index), "index")
this.selectedIndexWidget = this.addWidget("number", "Selected", get(this.selectedImage))
this.selectedIndexWidget.disabled = true;
this.modeWidget = this.addWidget("combo", "Mode", this.properties.updateMode, null, { property: "updateMode", values: ["replace", "append"] })
}
@@ -63,11 +65,14 @@ export default class ComfyGalleryNode extends ComfyWidgetNode<ComfyBoxImageMetad
override onExecute() {
const value = get(this.value)
const index = get(this.selectedImage)
this.setOutputData(0, value)
this.setOutputData(1, this.properties.index)
this.setOutputData(1, index)
if (this.properties.index != null && value && value[this.properties.index] != null) {
const image = value[this.properties.index];
this.selectedIndexWidget.value = index;
if (index != null && value && value[index] != null) {
const image = value[index];
image.width = get(this.imageWidth)
image.height = get(this.imageHeight)
}
@@ -101,7 +106,6 @@ export default class ComfyGalleryNode extends ComfyWidgetNode<ComfyBoxImageMetad
override setValue(value: any, noChangedEvent: boolean = false) {
super.setValue(value, noChangedEvent)
this.setProperty("index", null)
}
}

View File

@@ -7,7 +7,6 @@
import type { Styles } from "@gradio/utils";
import type { WidgetLayout } from "$lib/stores/layoutStates";
import { writable, type Writable } from "svelte/store";
import type { FileData as GradioFileData } from "@gradio/upload";
import type { SelectData as GradioSelectData } from "@gradio/utils";
import { clamp, comfyBoxImageToComfyURL, type ComfyBoxImageMetadata } from "$lib/utils";
import { f7 } from "framework7-svelte";
@@ -18,10 +17,9 @@
let node: ComfyGalleryNode | null = null;
let nodeValue: Writable<ComfyBoxImageMetadata[]> | null = null;
let propsChanged: Writable<number> | null = null;
let option: number | null = null;
let imageWidth: Writable<number> = writable(0);
let imageHeight: Writable<number> = writable(0);
let selected_image: number | null = null;
let selected_image: Writable<number | null> = writable(null);
$: widget && setNodeValue(widget);
@@ -32,6 +30,7 @@
propsChanged = node.propsChanged;
imageWidth = node.imageWidth
imageHeight = node.imageHeight
selected_image = node.selectedImage;
if ($nodeValue != null) {
if (node.properties.index < 0 || node.properties.index >= $nodeValue.length) {
@@ -81,7 +80,7 @@
thumbs: images.map(i => i.url),
type: 'popup',
});
mobileLightbox.open(selected_image)
mobileLightbox.open($selected_image)
}
function onClicked(e: CustomEvent<HTMLImageElement>) {
@@ -97,20 +96,6 @@
// Update index
node.setProperty("index", e.detail.index as number)
}
$: if ($propsChanged > -1 && widget && $nodeValue) {
if (widget.attrs.variant === "image") {
node.setProperty("index", selected_image)
}
else {
node.setProperty("index", $nodeValue.length > 0 ? 0 : null)
}
}
else {
node.setProperty("index", null)
}
$: node.setProperty("index", selected_image)
</script>
{#if widget && node && nodeValue && $nodeValue}
@@ -148,7 +133,7 @@
on:clicked={onClicked}
bind:imageWidth={$imageWidth}
bind:imageHeight={$imageHeight}
bind:selected_image
bind:selected_image={$selected_image}
/>
</div>
</Block>

View File

@@ -108,6 +108,12 @@ hr {
color: var(--panel-border-color);
}
input {
color: var(--body-text-color);
background: var(--input-background-fill);
border: var(--input-border-width) solid var(--input-border-color)
}
input:not(input[type=radio]), textarea {
border-radius: 0 !important;
}