refactor(M02): 좌측 「일위대가 조합」 컨테이너 · 조합 나무 · 둘째 층 단추 벌 지움(39-2)

- Labor.ts · Labor_Tree.ts 지움 · 페이지 · 좌측 이음 · 해시 표시(mark) 지움
- 나무 부품 일위대가 전용 칸(clipKind · maxDepth · item) 지움
- 옛 나무 시험을 새 짜임 검사로 갈음

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BVPp2o6Mh2FZJr72yW3ofZ
This commit is contained in:
2026-10-04 17:22:24 +09:00
co-authored by Claude Opus 5.5
parent ddd73349f2
commit ab84c763b7
8 changed files with 39 additions and 463 deletions
@@ -39,7 +39,6 @@ import {
type StructureColumn,
} from "./M02_MasterTemplete_Structure";
import { buildMatsetSection } from "./M02_MasterTemplete_Matset";
import type { LaborSection } from "./M02_MasterTemplete_Labor";
import { buildOptionsSection } from "./M02_MasterTemplete_Options";
import { canEdit, type Selection } from "./M02_MasterTemplete_UI_Main";
@@ -74,8 +73,6 @@ export interface SideOptions {
confirmLeave: () => Promise<boolean>;
/** 메인 칸에 양식 밖 화면(자재 조합 상세)을 띄움 */
showView: (label: string, node: HTMLElement) => (dirty: boolean) => void;
/** 「일위대가 조합」 컨테이너(구조물 조합 위 · PLAN 27-2b) — 페이지가 만듦(뿌리 셋이 페이지 것) */
labor?: (hooks: { onOpen: () => void }) => LaborSection;
/** 「구조물 조합」 줄 아래 — 층 단추 · 고른 층의 구조물 라이브러리 나무(PLAN 29-2 · 페이지가 만듦) */
tree?: HTMLElement[];
}
@@ -85,7 +82,7 @@ export interface SideHandle {
refresh: () => Promise<void>;
/** 고름 표시를 지금 열린 것 한 줄로 — 편집 칸이 무엇을 열든(카드 [도면 수정] 등) 부름 */
paint: () => void;
/** 진입 해시 `open`(PLAN 27-1d) — 그 컨테이너를 펼침(옵션은 열기까지) · 시스템 층에만 있음 */
/** 진입 해시 `open`(PLAN 27-1d) — 그 컨테이너를 펼침(옵션은 열기까지) · 옵션 · 도면은 시스템 층에만 */
reveal: (target: "옵션" | "도면" | "일위대가") => void;
}
@@ -136,7 +133,7 @@ export function buildSide(opt: SideOptions): SideHandle {
confirmLeave: opt.confirmLeave,
show: opt.showView,
close: () => opt.onOpen(null),
onOpen: () => (options.clear(), labor?.clear(), paint()),
onOpen: () => (options.clear(), paint()),
});
const matsetSection = section(matset.title, matset.body, ...matset.actions);
// 펼칠 때마다 새로 받음 — 재료산출 옆 판이 갈라 낸 조합도 바로 보이게
@@ -148,9 +145,8 @@ export function buildSide(opt: SideOptions): SideHandle {
isAdmin: canEdit(layer, opt.isAdmin),
confirmLeave: opt.confirmLeave,
show: opt.showView,
onOpen: () => (matset.clear(), labor?.clear(), paint()),
onOpen: () => (matset.clear(), paint()),
});
const labor = opt.labor?.({ onOpen: () => (matset.clear(), options.clear(), paint()) });
/** 컨테이너 제목을 펼치면 그 화면을 엶 — 같은 이름 줄 단추를 갈음(PLAN 29-6) */
const openOnExpand = (sec: HTMLElement, run: () => void): HTMLElement => {
sec.querySelector(".ui-collapsible__title")?.addEventListener("click", () => {
@@ -181,15 +177,9 @@ export function buildSide(opt: SideOptions): SideHandle {
: null;
const listHost = el("div", {
className: "m02-side__lists ui-sidebar-panel",
children: [
...(labor ? [openOnExpand(section(labor.title, labor.body), () => void labor.open())] : []),
summary,
...(extras ? [extras.옵션, extras.도면] : []),
],
children: [summary, ...(extras ? [extras.옵션, extras.도면] : [])],
});
attachCollapsible(listHost);
// 들어오면 「일위대가 조합」 · 「구조물 조합」 둘 다 펼친 채(PLAN 31-5 · 구조물 조합은 위에서 펼침)
labor?.body.closest("section")?.classList.remove("is-collapsed");
const root = el("div", { className: "m02-side ui-sidebar-panel", children: [listHost] });
@@ -263,7 +253,6 @@ export function buildSide(opt: SideOptions): SideHandle {
paintButtons();
if (opt.getOpen()) matset.clear();
if (opt.getOpen()) options.clear();
if (opt.getOpen()) labor?.clear();
}
// 여는 것은 편집 칸(`onOpen`) — 편집 칸이 열 때마다 `paint` 를 부름(페이지가 이음)
@@ -388,10 +377,7 @@ export function buildSide(opt: SideOptions): SideHandle {
}
const reveal = (target: "옵션" | "도면" | "일위대가"): void => {
if (target === "일위대가") {
labor?.body.closest("section")?.classList.remove("is-collapsed");
return void labor?.open();
}
if (target === "일위대가") return; // 구조물 조합은 처음부터 펼침
extras?.[target].classList.remove("is-collapsed");
if (target === "옵션") options.body.querySelector<HTMLElement>("button")?.click();
};