feat(M02): 좌측 같은 이름 단추 · 나무 뿌리 줄 없앰 · 「+」 더하기 · 찾기 하나(AND) (PLAN 29-6)

- 「일위대가 조합」 · 「구조물 조합」 컨테이너 안 같은 이름 줄 단추 없앰 — 제목을 펼치면 그 화면을 엶
- 나무 맨 위 뿌리 줄 없앰 — 폴더 · 항목부터 · 맨 위 더하기는 빈 자리 오른쪽 클릭 · 층 단추 옆 「+」(읽기만 층 = 숨김) · 빈 나무 안내글 맞춤
- 찾기 칸 하나 — 띄어쓰기 낱말 모두(AND · 대소문자 무시) · 이름 · 키 · 경로(구분 · 상세구분) · 단위 · 공용 matchText 를 나무 · 일위대가 조합 목록이 함께 씀(목록의 따로 찾기 칸 없앰)
- 시험 — 찾기 AND · 새 배치 맞춤

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-09-30 18:15:43 +09:00
co-authored by Claude Opus 5.5
parent 95849aefbd
commit c1ad11e869
14 changed files with 127 additions and 51 deletions
+13 -10
View File
@@ -42,6 +42,8 @@ export interface LaborLibrary {
root: HTMLElement;
/** 좌측 패널 나무 */
tree: HTMLElement;
/** 나무 맨 위 더하기 「+」(층 단추 옆) */
add: HTMLElement;
refresh: () => Promise<void>;
/** 메인 칸 「저장 안 한 고침」 손잡이 */
bind: (setDirty: (dirty: boolean) => void) => void;
@@ -103,9 +105,16 @@ export function buildLaborLibrary(opt: LaborLibraryOptions): LaborLibrary {
else editor.showList();
},
});
// 찾기 칸 하나(PLAN 29-6) — 나무와 조합 목록을 같은 글 · 같은 규칙으로 거름
tree.search
.querySelector("input")
?.addEventListener("input", (event) =>
editor.setQuery((event.target as HTMLInputElement).value),
);
return {
root: el("div", { className: "m02-labor", children: [tree.search, editor.root] }),
tree: tree.root,
add: tree.add,
refresh: () => tree.refresh(),
bind: (fn) => (setDirty = fn),
};
@@ -120,8 +129,8 @@ export interface LaborSectionOptions {
onOpen: () => void;
/** 라이브러리 — `reveal` = 메인 칸에 일위대가 화면을 띄움(나무 항목을 누를 때) */
make: (reveal: () => Promise<void>) => LaborLibrary;
/** 줄 아래 층 단추(PLAN 29-2) */
bar?: HTMLElement;
/** 층 단추(PLAN 29-2) — `add` = 나무 맨 위 더하기 「+」를 단추 옆에 */
bar?: (add: HTMLElement) => HTMLElement;
}
export interface LaborSection {
@@ -132,16 +141,11 @@ export interface LaborSection {
clear: () => void;
}
/** 컨테이너 몸 = 층 단추 + 나무(같은 이름 줄 단추 없음 · 컨테이너 제목을 펼치면 엶 · PLAN 29-6) */
export function buildLaborSection(opt: LaborSectionOptions): LaborSection {
const row = el("button", {
className: "m02-side__item ui-sidebar-row",
text: tc("Library"),
attrs: { type: "button", "data-labor-row": "" },
});
let opened = false;
const mark = (on: boolean): void => {
opened = on;
row.classList.toggle("is-active", on);
};
async function open(): Promise<void> {
@@ -156,8 +160,7 @@ export function buildLaborSection(opt: LaborSectionOptions): LaborSection {
void library.refresh();
const body = el("div", {
className: "m02-side__items ui-sidebar-list",
children: [row, ...(opt.bar ? [opt.bar] : []), library.tree],
children: [...(opt.bar ? [opt.bar(library.add)] : []), library.tree],
});
row.addEventListener("click", () => void open());
return { title: tc("Title"), body, open, clear: () => mark(false) };
}