feat(M02): 48-2 구조물 옵션 정의 편집 화면 — 군 · 종류 · 옵션 · 선택지 · 배치 격자 · 그룹 형상 · 규칙 · 판 이력
- 옛 「옵션 보이기 · 그룹」 화면을 정의 편집 화면으로 넓힘(시스템 관리자 고쳐 씀 · 다른 역할 읽기만) - 자료 손질 = M02_SO_Def_Model.ts(정의 틀 48-1 꼴) · 시험 test_m02_so_def_model.py Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016PSXsvyDxjNmufteN5bqmt
This commit is contained in:
@@ -0,0 +1,120 @@
|
||||
/* =============================================================================
|
||||
* M02_SO_Def_Layout.ts
|
||||
* 구조물 정의 편집 화면(PLAN 48-2) — 고른 종류의 **배치 격자**(B05 · B06 좌측 구조물 칸 = 두 칸)
|
||||
* 옵션마다 줄 · 칸 · 너비 + 미리보기(기준 측점은 맨 위 한 줄 · 겹치면 빨강).
|
||||
* 자리를 안 정한 옵션은 차례대로 빈 칸을 채움 · 숫자를 고치면 그 옵션 자리만 정의 `배치` 에 남음.
|
||||
* ========================================================================== */
|
||||
|
||||
import { el } from "@ui/ui_template_elements";
|
||||
import {
|
||||
baseShown,
|
||||
GRID_COLS,
|
||||
live,
|
||||
overlaps,
|
||||
placeAll,
|
||||
type Spot,
|
||||
type StructDef,
|
||||
type TypeDef,
|
||||
} from "./M02_SO_Def_Model";
|
||||
import { head, numberBox } from "./M02_SO_Def_Ui";
|
||||
import { to } from "./M02_SO_Text";
|
||||
|
||||
export interface LayoutBlockOptions {
|
||||
def: StructDef;
|
||||
type: TypeDef;
|
||||
edit: boolean;
|
||||
changed: () => void;
|
||||
}
|
||||
|
||||
const ROW_MAX = 60;
|
||||
|
||||
/** 미리보기 — 두 칸 격자 · 옵션마다 상자 */
|
||||
function preview(def: StructDef, type: TypeDef, cells: Map<string, Spot>): HTMLElement {
|
||||
const bad = new Set(overlaps(cells));
|
||||
const base = baseShown(def, type.type_id);
|
||||
const offset = base ? 1 : 0;
|
||||
const boxes: HTMLElement[] = [];
|
||||
if (base)
|
||||
boxes.push(
|
||||
el("div", {
|
||||
className: "m02-sod__cell is-base",
|
||||
text: to("BaseStation"),
|
||||
attrs: { style: `grid-row: 1; grid-column: 1 / span ${GRID_COLS}` },
|
||||
}),
|
||||
);
|
||||
for (const o of live(type.options)) {
|
||||
const c = cells.get(o.key)!;
|
||||
boxes.push(
|
||||
el("div", {
|
||||
className: `m02-sod__cell${bad.has(o.key) ? " is-bad" : ""}`,
|
||||
text: o.label,
|
||||
attrs: {
|
||||
"data-sod-cell": o.key,
|
||||
title: o.label,
|
||||
style: `grid-row: ${c.줄 + offset}; grid-column: ${c.칸} / span ${c.너비}`,
|
||||
},
|
||||
}),
|
||||
);
|
||||
}
|
||||
return el("div", {
|
||||
className: "m02-sod__grid",
|
||||
attrs: {
|
||||
"data-sod-preview": "",
|
||||
style: `grid-template-columns: repeat(${GRID_COLS}, minmax(0, 1fr))`,
|
||||
},
|
||||
children: boxes,
|
||||
});
|
||||
}
|
||||
|
||||
export function buildLayoutBlock(opt: LayoutBlockOptions): HTMLElement {
|
||||
const { def, type, edit, changed } = opt;
|
||||
const cells = placeAll(type.options, def.배치[type.type_id]);
|
||||
const rows = live(type.options).map((o) => {
|
||||
const c = cells.get(o.key)!;
|
||||
const fix = (patch: Partial<Spot>): void => {
|
||||
(def.배치[type.type_id] ??= {})[o.key] = { ...c, ...patch };
|
||||
changed();
|
||||
};
|
||||
return el("div", {
|
||||
className: "m02-sod__place",
|
||||
attrs: { "data-sod-place-row": o.key },
|
||||
children: [
|
||||
el("span", { className: "m02-sod__placename", text: o.label }),
|
||||
el("small", { text: to("GridRow") }),
|
||||
numberBox(c.줄, (n) => fix({ 줄: n }), {
|
||||
edit,
|
||||
min: 1,
|
||||
max: ROW_MAX,
|
||||
attr: "data-sod-row",
|
||||
}),
|
||||
el("small", { text: to("GridCol") }),
|
||||
numberBox(c.칸, (n) => fix({ 칸: n }), {
|
||||
edit,
|
||||
min: 1,
|
||||
max: GRID_COLS,
|
||||
attr: "data-sod-col",
|
||||
}),
|
||||
el("small", { text: to("GridWidth") }),
|
||||
numberBox(c.너비, (n) => fix({ 너비: n }), {
|
||||
edit,
|
||||
min: 1,
|
||||
max: GRID_COLS,
|
||||
attr: "data-sod-width",
|
||||
}),
|
||||
],
|
||||
});
|
||||
});
|
||||
return el("div", {
|
||||
className: "m02-sod__block",
|
||||
children: [
|
||||
...head(to("LayoutHead"), to("LayoutNote")),
|
||||
el("div", {
|
||||
className: "m02-sod__layout",
|
||||
children: [
|
||||
el("div", { className: "m02-sod__places", children: rows }),
|
||||
preview(def, type, cells),
|
||||
],
|
||||
}),
|
||||
],
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user