feat: restore old toolchain button
This commit is contained in:
@@ -94,7 +94,6 @@
|
||||
repeating-conic-gradient(var(--check-a) 0% 25%, var(--check-b) 0% 50%);
|
||||
background-size: 16px 16px;
|
||||
border: 1px solid var(--border);
|
||||
border-radius: var(--radius-m);
|
||||
}
|
||||
|
||||
canvas.pipette {
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
import { decodeFile, isSupportedImage, unsupportedImageMessage } from '$lib/core/io';
|
||||
import type { PixelImage } from '$lib/core/types';
|
||||
import { defaultParams, getTool, outputOf, sanitizeParams, type ToolEntry } from '$lib/registry';
|
||||
import { newStepId, type PipelineStep } from '$lib/tools/pipeline';
|
||||
import { loadStoredSteps, newStepId, saveSteps, type PipelineStep } from '$lib/tools/pipeline';
|
||||
import DownloadButton from './DownloadButton.svelte';
|
||||
import ParamForm from './ParamForm.svelte';
|
||||
import Preview from './Preview.svelte';
|
||||
@@ -15,7 +15,7 @@
|
||||
import SourceCard from './tool/SourceCard.svelte';
|
||||
import TextInputCard from './tool/TextInputCard.svelte';
|
||||
|
||||
let { tool }: { tool: ToolEntry } = $props();
|
||||
let { tool, restoreChain = false }: { tool: ToolEntry; restoreChain?: boolean } = $props();
|
||||
|
||||
type Status = 'idle' | 'loaded' | 'processing' | 'error';
|
||||
|
||||
@@ -28,7 +28,8 @@
|
||||
let info = $state<ImageInfo | null>(null);
|
||||
let errorText = $state('');
|
||||
let values = $state<Record<string, any>>({});
|
||||
let chain = $state<PipelineStep[]>([]);
|
||||
// svelte-ignore state_referenced_locally
|
||||
let chain = $state<PipelineStep[]>(restoreChain ? loadStoredSteps() : []);
|
||||
let chainResults = $state<(PixelImage | null)[]>([]);
|
||||
let lastRunChainJson = '';
|
||||
|
||||
@@ -204,6 +205,12 @@
|
||||
return runner.schedule(() => void runTool());
|
||||
});
|
||||
|
||||
$effect(() => {
|
||||
const filled = chain.filter((step) => step.toolId !== '');
|
||||
if (filled.length === 0 && !hasLastRun) return;
|
||||
saveSteps(filled);
|
||||
});
|
||||
|
||||
function showError(e: unknown) {
|
||||
status = source ? 'loaded' : 'idle';
|
||||
errorText = e instanceof Error ? e.message : String(e);
|
||||
|
||||
@@ -1,41 +0,0 @@
|
||||
<script lang="ts">
|
||||
import ParamForm from '../ParamForm.svelte';
|
||||
import type { PipelineStep } from '$lib/tools/pipeline';
|
||||
import { getTool } from '$lib/registry';
|
||||
|
||||
interface Props {
|
||||
step: PipelineStep;
|
||||
}
|
||||
|
||||
let { step }: Props = $props();
|
||||
|
||||
const tool = $derived(getTool(step.toolId));
|
||||
</script>
|
||||
|
||||
{#if tool}
|
||||
<div class="editor panel">
|
||||
<h3 class="heading-section">{tool.title}</h3>
|
||||
<p class="description text-caption text-muted">{tool.description}</p>
|
||||
{#if tool.params.length > 0}
|
||||
<ParamForm params={tool.params} bind:values={step.values} />
|
||||
{:else}
|
||||
<p class="hint text-caption text-muted">У этого шага нет параметров.</p>
|
||||
{/if}
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<style>
|
||||
.editor {
|
||||
padding: var(--space-3);
|
||||
}
|
||||
|
||||
h3 {
|
||||
margin-bottom: var(--space-1);
|
||||
font-size: var(--text-m);
|
||||
}
|
||||
|
||||
.description,
|
||||
.hint {
|
||||
margin: 0 0 var(--space-2);
|
||||
}
|
||||
</style>
|
||||
@@ -1,128 +0,0 @@
|
||||
<script lang="ts">
|
||||
import type { PipelineStep } from '$lib/tools/pipeline';
|
||||
import { getTool } from '$lib/registry';
|
||||
|
||||
interface Props {
|
||||
steps: PipelineStep[];
|
||||
selectedIndex: number;
|
||||
onSelect: (index: number) => void;
|
||||
onMoveUp: (index: number) => void;
|
||||
onMoveDown: (index: number) => void;
|
||||
onRemove: (index: number) => void;
|
||||
}
|
||||
|
||||
let { steps, selectedIndex, onSelect, onMoveUp, onMoveDown, onRemove }: Props = $props();
|
||||
|
||||
function toolTitle(step: PipelineStep): string {
|
||||
return getTool(step.toolId)?.title ?? step.toolId;
|
||||
}
|
||||
</script>
|
||||
|
||||
{#if steps.length === 0}
|
||||
<p class="empty text-caption text-muted">Цепочка пуста — добавьте первый инструмент.</p>
|
||||
{:else}
|
||||
<ol>
|
||||
{#each steps as step, index (step.id)}
|
||||
<li>
|
||||
<button type="button" class="label" class:selected={index === selectedIndex} onclick={() => onSelect(index)}>
|
||||
<span class="num">{index + 1}</span>
|
||||
{toolTitle(step)}
|
||||
</button>
|
||||
<span class="controls">
|
||||
<button type="button" aria-label="Выше" disabled={index === 0} onclick={() => onMoveUp(index)}>↑</button>
|
||||
<button
|
||||
type="button"
|
||||
aria-label="Ниже"
|
||||
disabled={index === steps.length - 1}
|
||||
onclick={() => onMoveDown(index)}
|
||||
>↓</button>
|
||||
<button type="button" class="remove" aria-label="Удалить шаг" onclick={() => onRemove(index)}>✕</button>
|
||||
</span>
|
||||
</li>
|
||||
{/each}
|
||||
</ol>
|
||||
{/if}
|
||||
|
||||
<style>
|
||||
ol {
|
||||
list-style: none;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--space-1);
|
||||
}
|
||||
|
||||
li {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: var(--space-1);
|
||||
}
|
||||
|
||||
.label {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
text-align: left;
|
||||
padding: var(--space-1) var(--space-2);
|
||||
border: 1px solid transparent;
|
||||
border-radius: var(--radius-s);
|
||||
background: none;
|
||||
color: var(--text);
|
||||
cursor: pointer;
|
||||
font-size: var(--text-m);
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.label:hover,
|
||||
.label.selected {
|
||||
background: color-mix(in srgb, var(--accent) 8%, var(--surface));
|
||||
border-color: var(--border);
|
||||
}
|
||||
|
||||
.num {
|
||||
display: inline-block;
|
||||
min-width: 1.4ch;
|
||||
margin-right: var(--space-1);
|
||||
color: var(--text-muted);
|
||||
font-family: var(--font-mono);
|
||||
font-size: var(--text-xs);
|
||||
}
|
||||
|
||||
.controls {
|
||||
display: flex;
|
||||
gap: 2px;
|
||||
}
|
||||
|
||||
.controls button {
|
||||
width: 1.6rem;
|
||||
height: 1.6rem;
|
||||
padding: 0;
|
||||
border: 1px solid var(--border);
|
||||
border-radius: var(--radius-s);
|
||||
background: var(--surface);
|
||||
color: var(--text-muted);
|
||||
line-height: 1;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.controls button:hover:not(:disabled) {
|
||||
border-color: var(--accent);
|
||||
color: var(--accent);
|
||||
}
|
||||
|
||||
.controls .remove:hover:not(:disabled) {
|
||||
border-color: var(--danger);
|
||||
color: var(--danger);
|
||||
}
|
||||
|
||||
.controls button:disabled {
|
||||
opacity: 0.4;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
.empty {
|
||||
margin: 0;
|
||||
}
|
||||
</style>
|
||||
@@ -1,50 +0,0 @@
|
||||
<script lang="ts">
|
||||
import Button from '../ui/Button.svelte';
|
||||
import { CATEGORIES } from '$lib/categories';
|
||||
import { TOOLS } from '$lib/registry';
|
||||
|
||||
interface Props {
|
||||
onAdd: (toolId: string) => void;
|
||||
}
|
||||
|
||||
let { onAdd }: Props = $props();
|
||||
|
||||
const steppable = TOOLS.filter(
|
||||
(tool) => (tool.resultType ?? 'image') === 'image' && (!tool.sourceMode || tool.sourceMode === 'file')
|
||||
);
|
||||
|
||||
let selected = $state(steppable[0]?.id ?? '');
|
||||
</script>
|
||||
|
||||
<div class="picker">
|
||||
<select bind:value={selected} aria-label="Инструмент для нового шага">
|
||||
{#each CATEGORIES as category (category.id)}
|
||||
{@const categoryTools = steppable.filter((tool) => tool.category === category.id)}
|
||||
{#if categoryTools.length > 0}
|
||||
<optgroup label={category.label}>
|
||||
{#each categoryTools as tool (tool.id)}
|
||||
<option value={tool.id}>{tool.title}</option>
|
||||
{/each}
|
||||
</optgroup>
|
||||
{/if}
|
||||
{/each}
|
||||
</select>
|
||||
<Button variant="secondary" onclick={() => onAdd(selected)}>Добавить шаг</Button>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.picker {
|
||||
display: flex;
|
||||
gap: var(--space-2);
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
select {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
padding: var(--space-1) var(--space-2);
|
||||
border: 1px solid var(--border);
|
||||
border-radius: var(--radius-s);
|
||||
background: var(--surface);
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user