diff --git a/docs/plan-composite-params.md b/docs/plan-composite-params.md index f308de6..a06ad9d 100644 --- a/docs/plan-composite-params.md +++ b/docs/plan-composite-params.md @@ -20,7 +20,12 @@ > preview > научен применять **генераторы** (`executeGenerate`, кнопка Generate) и > рендерить все kinds схемы (slider/number/color/select/checkbox/dimension/ -> color-pair/offset/position9/font-style/plate/gradient). +> color-pair/offset/position9/font-style/plate/gradient). **Пер-инструмент +> раскладка `schema.layout` реализована** (шаг 32): тип `ToolSchemaLayout` +> {groups: [{title?, cols?, fields}]}, рендер групп в `SchemaFields.svelte` +> (заголовок группы + сетка колонок, неупомянутые поля — в общей группе), +> пилот — `add-text` (группы Text/Placement/Plate). +> Следующее: шаг 33 — UI-макет каждого переведённого инструмента (ревью по одному). > > Ключевые файлы нового registry: `web/src/lib/registry-new/{types,index,*}.ts` > (по файлу на категорию: geometry/alpha/convert/analyze/filters/color/generate) @@ -411,7 +416,12 @@ Typed field builders + `Field` + `toolSchema

()` + `ToolSchema

` — 31. По мере перевода инструментов в Фазе 2-3 — рендер схемы (из Фазы 1) покрывает их автоматически; составные виджеты (dimension, color-pair, offset, position9, font-style, plate, gradient) — по одному, каждый с ревью. -32. Пер-инструмент layout (`schema.layout`): группировка полей рамки и т.п. +32. Пер-инструмент layout (`schema.layout`) — **реализован** ✔. + `ToolSchemaLayout.groups: { title?, cols?, fields[] }` в registry-schema; + `SchemaFields.svelte` рендерит группы (подпись + сетка `1..n` колонок, + неупомянутые поля — в общей группе в конце, без заголовка). Пилот — + `add-text-png` (Text: text+style; Placement: position+margin; Plate). + Тесты: schema-layout в registry-schema.test.ts; полные запуски чисты. 33. Для каждого переведённого инструмента — UI-макет, принимается отдельно. ### Фаза 5 — зачистка diff --git a/web/src/lib/components/kit/SchemaFields.svelte b/web/src/lib/components/kit/SchemaFields.svelte index 3c0051c..442c424 100644 --- a/web/src/lib/components/kit/SchemaFields.svelte +++ b/web/src/lib/components/kit/SchemaFields.svelte @@ -56,16 +56,61 @@ .replace(/[_-]+/g, " ") .replace(/\b\w/g, (c) => c.toUpperCase()); } + + interface LayoutGroup { + key: string; + title?: string; + cols: number; + fields: string[]; + } + + const layoutGroups = $derived.by((): LayoutGroup[] => { + const all = Object.keys(schema.fields); + const groups = schema.layout?.groups ?? []; + const used: Record = {}; + const named = groups + .map((g, gi) => { + const fields = g.fields.filter((f) => { + if (used[f] || !(f in schema.fields)) return false; + used[f] = true; + return true; + }); + return { + key: `${g.title ?? "group"}-${gi}`, + title: g.title, + cols: Math.max(1, Math.trunc(g.cols ?? 1)), + fields, + } satisfies LayoutGroup; + }) + .filter((g) => g.fields.length > 0); + const rest = all.filter((f) => !used[f]); + if (rest.length > 0) { + named.push({ key: "__default", title: undefined, cols: 1, fields: rest }); + } + return named; + }); -{#each Object.entries(schema.fields) as [id, field] (id)} - {@const Control = FIELDS[field.spec.kind]} - onchange(id, v)} - /> +{#each layoutGroups as group (group.key)} + {#if group.title} + {group.title} + {/if} +

1 + ? `repeat(${group.cols}, minmax(0, 1fr))` + : undefined} + > + {#each group.fields as id (id)} + {@const Control = FIELDS[schema.fields[id].spec.kind]} + onchange(id, v)} + /> + {/each} +
{/each}
@@ -76,6 +121,23 @@