mirror of
https://github.com/Ku6epXBOCTuK/easy-png-tools.git
synced 2026-11-13 17:08:20 +00:00
feat: collapse\expand steps in pipeline
This commit is contained in:
@@ -20,9 +20,6 @@
|
|||||||
(любой шаг, не только первый), остальные шаги и их параметры сохраняются,
|
(любой шаг, не только первый), остальные шаги и их параметры сохраняются,
|
||||||
вход перечитывается. Открытый вопрос: что делать с несовместимыми входами
|
вход перечитывается. Открытый вопрос: что делать с несовместимыми входами
|
||||||
(text-source ↔ file).
|
(text-source ↔ file).
|
||||||
- [ ] **Идея 2. Сворачивать инструменты в chain** — оценка S. Тоггл сворачивания
|
|
||||||
звена до заголовка «Шаг n: название» (превью скрываются). Состояние
|
|
||||||
свёрнутости помнить в workspace-pipeline.
|
|
||||||
- [ ] **Идея 3. Несколько цепочек: сохранение и загрузка** — оценка M.
|
- [ ] **Идея 3. Несколько цепочек: сохранение и загрузка** — оценка M.
|
||||||
Именованные цепочки в localStorage (список, создать/переименовать/
|
Именованные цепочки в localStorage (список, создать/переименовать/
|
||||||
удалить), быстрое переключение. Формат экспортного JSON расширить
|
удалить), быстрое переключение. Формат экспортного JSON расширить
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { GripVertical, X } from "@lucide/svelte";
|
import { ChevronDown, ChevronRight, GripVertical, X } from "@lucide/svelte";
|
||||||
import IconButton from "$lib/components/ui/IconButton.svelte";
|
import IconButton from "$lib/components/ui/IconButton.svelte";
|
||||||
import { t } from "$lib/i18n/t";
|
import { t } from "$lib/i18n/t";
|
||||||
import type { Snippet } from "svelte";
|
import type { Snippet } from "svelte";
|
||||||
@@ -9,9 +9,11 @@
|
|||||||
title?: string;
|
title?: string;
|
||||||
type?: string;
|
type?: string;
|
||||||
draggable?: boolean;
|
draggable?: boolean;
|
||||||
|
collapsed?: boolean;
|
||||||
tools?: Snippet;
|
tools?: Snippet;
|
||||||
children?: Snippet;
|
children?: Snippet;
|
||||||
onremove?: () => void;
|
onremove?: () => void;
|
||||||
|
ontoggle?: () => void;
|
||||||
ondragstart?: (e: DragEvent) => void;
|
ondragstart?: (e: DragEvent) => void;
|
||||||
ondragover?: (e: DragEvent) => void;
|
ondragover?: (e: DragEvent) => void;
|
||||||
ondrop?: (e: DragEvent) => void;
|
ondrop?: (e: DragEvent) => void;
|
||||||
@@ -23,9 +25,11 @@
|
|||||||
title,
|
title,
|
||||||
type,
|
type,
|
||||||
draggable = false,
|
draggable = false,
|
||||||
|
collapsed = false,
|
||||||
tools,
|
tools,
|
||||||
children,
|
children,
|
||||||
onremove,
|
onremove,
|
||||||
|
ontoggle,
|
||||||
ondragstart,
|
ondragstart,
|
||||||
ondragover,
|
ondragover,
|
||||||
ondrop,
|
ondrop,
|
||||||
@@ -54,6 +58,15 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="step-tools">
|
<div class="step-tools">
|
||||||
{#if tools}{@render tools()}{/if}
|
{#if tools}{@render tools()}{/if}
|
||||||
|
{#if ontoggle}
|
||||||
|
<IconButton
|
||||||
|
icon={collapsed ? ChevronRight : ChevronDown}
|
||||||
|
label={collapsed ? t("chain.expandStep") : t("chain.collapseStep")}
|
||||||
|
variant="clear"
|
||||||
|
size="s"
|
||||||
|
onclick={() => ontoggle()}
|
||||||
|
/>
|
||||||
|
{/if}
|
||||||
{#if onremove}
|
{#if onremove}
|
||||||
<IconButton
|
<IconButton
|
||||||
icon={X}
|
icon={X}
|
||||||
@@ -65,7 +78,7 @@
|
|||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
</header>
|
</header>
|
||||||
{#if children}
|
{#if children && !collapsed}
|
||||||
<div class="step-body">
|
<div class="step-body">
|
||||||
{@render children()}
|
{@render children()}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -240,6 +240,12 @@
|
|||||||
steps = removeStep(steps, key);
|
steps = removeStep(steps, key);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function toggleStep(index: number) {
|
||||||
|
const step = steps[index];
|
||||||
|
if (!step) return;
|
||||||
|
steps = steps.with(index, { ...step, collapsed: !step.collapsed });
|
||||||
|
}
|
||||||
|
|
||||||
function onStepDrop(e: DragEvent, to: number) {
|
function onStepDrop(e: DragEvent, to: number) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
if (dragFrom !== null) steps = moveStep(steps, dragFrom, to);
|
if (dragFrom !== null) steps = moveStep(steps, dragFrom, to);
|
||||||
@@ -458,6 +464,8 @@
|
|||||||
index={i + 1}
|
index={i + 1}
|
||||||
title={stepTitle(step.id)}
|
title={stepTitle(step.id)}
|
||||||
draggable
|
draggable
|
||||||
|
collapsed={step.collapsed ?? false}
|
||||||
|
ontoggle={() => toggleStep(i)}
|
||||||
onremove={steps.length > 1
|
onremove={steps.length > 1
|
||||||
? () => removeStepAt(step.key)
|
? () => removeStepAt(step.key)
|
||||||
: undefined}
|
: undefined}
|
||||||
|
|||||||
@@ -49,6 +49,8 @@ export const en: Dict = {
|
|||||||
},
|
},
|
||||||
chain: {
|
chain: {
|
||||||
addStep: "Add step",
|
addStep: "Add step",
|
||||||
|
collapseStep: "Collapse step",
|
||||||
|
expandStep: "Expand step",
|
||||||
inputLegend: "Input",
|
inputLegend: "Input",
|
||||||
resultLegend: "Result",
|
resultLegend: "Result",
|
||||||
paramsLegend: "Parameters",
|
paramsLegend: "Parameters",
|
||||||
|
|||||||
@@ -50,6 +50,8 @@ export const ru: Dict = {
|
|||||||
},
|
},
|
||||||
chain: {
|
chain: {
|
||||||
addStep: "Добавить шаг",
|
addStep: "Добавить шаг",
|
||||||
|
collapseStep: "Свернуть шаг",
|
||||||
|
expandStep: "Развернуть шаг",
|
||||||
inputLegend: "Вход",
|
inputLegend: "Вход",
|
||||||
resultLegend: "Результат",
|
resultLegend: "Результат",
|
||||||
paramsLegend: "Параметры",
|
paramsLegend: "Параметры",
|
||||||
|
|||||||
@@ -2,10 +2,10 @@ import { getTool, PAGES, type Page } from "./registry";
|
|||||||
import { defaultSchemaParams, sanitizeSchemaParams } from "./registry-schema";
|
import { defaultSchemaParams, sanitizeSchemaParams } from "./registry-schema";
|
||||||
|
|
||||||
export interface ChainStep {
|
export interface ChainStep {
|
||||||
/** Стабильный ключ для keyed each и drag-n-drop (переживает reorder). */
|
|
||||||
key: string;
|
key: string;
|
||||||
id: string;
|
id: string;
|
||||||
params: Record<string, unknown>;
|
params: Record<string, unknown>;
|
||||||
|
collapsed?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const CHAIN_VERSION = 1;
|
export const CHAIN_VERSION = 1;
|
||||||
@@ -77,6 +77,8 @@ export function parseChain(data: unknown): ChainStep[] | null {
|
|||||||
out.push({
|
out.push({
|
||||||
key: uid(),
|
key: uid(),
|
||||||
id,
|
id,
|
||||||
|
collapsed:
|
||||||
|
(raw as { collapsed?: unknown }).collapsed === true ? true : undefined,
|
||||||
params: sanitizeSchemaParams(
|
params: sanitizeSchemaParams(
|
||||||
tool.schema,
|
tool.schema,
|
||||||
(params ?? {}) as Record<string, unknown>,
|
(params ?? {}) as Record<string, unknown>,
|
||||||
@@ -101,7 +103,11 @@ export function saveChain(slug: string, steps: ChainStep[]): void {
|
|||||||
storageKey(slug),
|
storageKey(slug),
|
||||||
JSON.stringify({
|
JSON.stringify({
|
||||||
version: CHAIN_VERSION,
|
version: CHAIN_VERSION,
|
||||||
steps: steps.map((s) => ({ id: s.id, params: s.params })),
|
steps: steps.map((s) => ({
|
||||||
|
id: s.id,
|
||||||
|
params: s.params,
|
||||||
|
...(s.collapsed ? { collapsed: true } : {}),
|
||||||
|
})),
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -79,6 +79,18 @@ describe("pipeline: parseChain (localStorage/импорт)", () => {
|
|||||||
expect(chain[0].params).toMatchObject({ x: 5, y: 0 });
|
expect(chain[0].params).toMatchObject({ x: 5, y: 0 });
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("parseChain сохраняет collapsed, по умолчанию шаг развёрнут", () => {
|
||||||
|
const chain = parseChain({
|
||||||
|
version: CHAIN_VERSION,
|
||||||
|
steps: [
|
||||||
|
{ id: "crop", params: {}, collapsed: true },
|
||||||
|
{ id: "resize", params: {} },
|
||||||
|
],
|
||||||
|
})!;
|
||||||
|
expect(chain[0].collapsed).toBe(true);
|
||||||
|
expect(chain[1].collapsed).toBeUndefined();
|
||||||
|
});
|
||||||
|
|
||||||
it.each([
|
it.each([
|
||||||
["нет версии", { steps: [{ id: "crop" }] }],
|
["нет версии", { steps: [{ id: "crop" }] }],
|
||||||
["другая версия", { version: 99, steps: [{ id: "crop" }] }],
|
["другая версия", { version: 99, steps: [{ id: "crop" }] }],
|
||||||
|
|||||||
Reference in New Issue
Block a user