- 명세 없는 종류 = 그룹 제목(그룹.이름) › 칸 이름(옵션 label) › 선택지 이름(종류.이름 `{옵션}={값}` · 값 그대로) · 그룹 밖 칸은 머리 줄 아래
- 칸 더하기 · 빼기 · 꼴 · 필수는 읽기만 · 칸 없는 종류(개거 · 노출형 횡단수로)는 「고칠 이름 없음」 · 종류 이름은 머리 칸
- 옛 편집기(옵션 · 배치 · 그룹 · 규칙 · 기준 측점)는 OLD_EDITOR 거짓으로 숨김(코드 그대로)
- 미리보기 = B05 칸 부품(field · optionControl · 그룹 상자)으로 같은 차례
- B05 · B06 고르기 칸 보기 글 = 정의 이름 표(값 그대로 · 규칙 선택지 · 시설 폼 덧보기 포함)
- 시험: test_m02_so_def_spec 정의 그룹 꼴 더함 · 헬퍼가 이웃 TS 를 읽게 고침 · ui_checks/52-11 에 맹암거 · 바닥막이 · 개거 더함
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UoSr2sqvYtBf1dtQdus88s
120 lines
4.8 KiB
TypeScript
120 lines
4.8 KiB
TypeScript
/* =============================================================================
|
|
* 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<NonNullable<SpecNameRow["tag"]>, OptionsTextKey> = {
|
|
required: "SpecRequired",
|
|
optional: "SpecOptional",
|
|
select: "FormSelect",
|
|
number: "FormNumber",
|
|
auto: "FormAuto",
|
|
text: "FormText",
|
|
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],
|
|
}),
|
|
],
|
|
});
|
|
}
|