/* ============================================================================= * M02_SO_Def_Spec.ts * 구조물 명세가 있는 종류(PLAN 52 · `STRUCTURE_SPECS`)의 이름 고치기 칸(52-11) — 나무 꼴 * 컨테이너 제목 › 항목 이름 › 값 이름 · 이름만 고침 · 키 · 필수/선택 · 꼴은 읽기만 · * 아래 미리보기 = B05 · B06 이 그리는 같은 명세 폼(`createSpecForm`)에 고친 이름을 얹음. * 명세 없는 종류(정의 그룹 꼴 · 52-12) = 그룹 제목 › 칸 이름 › 선택지 이름 · 미리보기 = B05 칸 부품 * (`field` · `optionControl` · 그룹 상자)으로 같은 차례. * 구조물군 · 종류 이름은 왼쪽 목록 · 머리 칸이 그대로 고침. * ========================================================================== */ import { createTag, el } from "@ui/ui_template_elements"; import { createSpecForm } from "../../A00_Common/design/design_structure_form"; import type { StructureSpec } from "../../A00_Common/design/design_structure_spec"; import { group } from "../../B05_Profile/B05_Profile_UI_Drainage_Facility_Fields"; import { field, optionControl } from "../../B05_Profile/B05_Profile_UI_Structures_Fields"; import type { StructDef, TypeDef } from "./M02_SO_Def_Model"; import { groupNameRows, setSpecName, specNameRows, type SpecNameRow, } from "./M02_SO_Def_Spec_Model"; import { head, textBox } from "./M02_SO_Def_Ui"; import { to, type OptionsTextKey } from "./M02_SO_Text"; const TAG: Record, OptionsTextKey> = { required: "SpecRequired", optional: "SpecOptional", select: "FormSelect", number: "FormNumber", text: "FormText", auto: "FormAuto", bool: "FormBool", }; /** 정의 그룹 꼴 미리보기 — 그룹 밖 칸 · 그룹 상자(제목 = 그룹 이름) · 선택지 = 이름 표 글(값 그대로). */ function groupPreview(def: StructDef, type: TypeDef): HTMLElement { const names = def.종류[type.type_id]?.이름 ?? {}; const options = type.options.filter((o) => o.enabled !== false); const cell = (o: (typeof options)[number]): HTMLElement => field( o.unit ? `${o.label} (${o.unit})` : o.label, optionControl( { input: o.input === "select" || o.input === "number" ? o.input : "text", choices: o.choices ?? [], default: null, required: !!o.required, }, undefined, (c) => names[`${o.key}=${c}`] ?? c, ), ); const groups = def.그룹[type.type_id] ?? []; const inGroup = new Set(groups.flatMap((g) => g.옵션)); const grid = (cells: HTMLElement[]): HTMLElement => el("div", { className: "b05-structure__grid", children: cells }); return el("div", { children: [ grid(options.filter((o) => !inGroup.has(o.key)).map(cell)), ...groups.map((g) => { const box = group(g.이름); box.body.append(grid(options.filter((o) => g.옵션.includes(o.key)).map(cell))); return box.root; }), ], }); } export function buildSpecBlock(opt: { def: StructDef; type: TypeDef; /** 없으면 정의 그룹 꼴(52-12) */ spec: StructureSpec | undefined; edit: boolean; changed: () => void; }): HTMLElement { const { def, type, spec, edit, changed } = opt; const rows = (spec ? specNameRows(def, spec) : groupNameRows(def, type)).map((row) => el("div", { className: `m02-sod__specrow is-level-${row.level}`, attrs: { "data-sod-spec": row.nameKey }, children: [ row.nameKey ? textBox(row.label, (v) => setSpecName(def, type.type_id, row, v), changed, { edit, attr: "data-sod-spec-name", cls: "m02-sod__name", }) : el("span", { text: to("SpecLoose") }), el("small", { className: "m02-opts__key", text: row.key }), ...(row.tag ? [createTag(to(TAG[row.tag]), "neutral")] : []), ], }), ); // 미리보기 — 값 없는 새 구조물 폼 · 잇기 줄 없음(조합은 프로젝트 몫) let preview: HTMLElement; if (spec) { const form = createSpecForm(null); const groups = Object.fromEntries((def.그룹[type.type_id] ?? []).map((g) => [g.id, g.이름])); form.write(spec, {}, def.종류[type.type_id]?.이름 ?? {}, groups); preview = form.root; } else preview = groupPreview(def, type); preview.inert = true; return el("div", { className: "m02-sod__block", attrs: { "data-sod-spec-block": "" }, children: [ ...head(to("SpecHead"), to("SpecNote")), ...(rows.length ? rows : [el("p", { className: "m02-side__empty", text: to("SpecNone") })]), ...head(to("SpecPreview")), el("div", { className: "m02-sod__specpreview", attrs: { "data-sod-spec-preview": "" }, children: [preview], }), ], }); }