feat(M02): 좌측 같은 이름 단추 · 나무 뿌리 줄 없앰 · 「+」 더하기 · 찾기 하나(AND) (PLAN 29-6)
- 「일위대가 조합」 · 「구조물 조합」 컨테이너 안 같은 이름 줄 단추 없앰 — 제목을 펼치면 그 화면을 엶 - 나무 맨 위 뿌리 줄 없앰 — 폴더 · 항목부터 · 맨 위 더하기는 빈 자리 오른쪽 클릭 · 층 단추 옆 「+」(읽기만 층 = 숨김) · 빈 나무 안내글 맞춤 - 찾기 칸 하나 — 띄어쓰기 낱말 모두(AND · 대소문자 무시) · 이름 · 키 · 경로(구분 · 상세구분) · 단위 · 공용 matchText 를 나무 · 일위대가 조합 목록이 함께 씀(목록의 따로 찾기 칸 없앰) - 시험 — 찾기 AND · 새 배치 맞춤 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -47,8 +47,6 @@ export interface TreePanelOptions {
|
||||
layer: Layer;
|
||||
/** 남의 층 주인(회사 `{C}` · 개인 `{C}/{U}`) — 없으면 자기 층 */
|
||||
owner?: string | null;
|
||||
/** 맨 위 줄 글 — 없으면 층 이름 */
|
||||
label?: string;
|
||||
/** 나무 읽기 · 고치기 길 — 없으면 구조물 조합 나무(`/layers/{층}/tree`) */
|
||||
api?: {
|
||||
fetch: (layer: Layer, owner: string | null) => Promise<TreeView>;
|
||||
@@ -73,6 +71,8 @@ export interface TreePanelHandle {
|
||||
root: HTMLElement;
|
||||
/** 찾기 칸 — 부르는 쪽이 상세 위쪽에 붙임(PLAN 29-2) */
|
||||
search: HTMLElement;
|
||||
/** 「+」 — 맨 위 폴더 · 항목 더하기 · 부르는 쪽이 층 단추 옆에 붙임(읽기만 층 = 숨김 · 29-6) */
|
||||
add: HTMLElement;
|
||||
refresh: () => Promise<void>;
|
||||
/** 표에서 고른 열을 나무에 표시(null = 지움) */
|
||||
select: (colId: string | null) => void;
|
||||
@@ -84,15 +84,6 @@ const why = (error: unknown): string => (error instanceof Error ? error.message
|
||||
const hint = (text: string): HTMLElement => el("p", { className: "m02-tree__hint", text });
|
||||
|
||||
export function createTreePanel(opt: TreePanelOptions): TreePanelHandle {
|
||||
const layerLabel =
|
||||
opt.label ??
|
||||
L(
|
||||
opt.layer === "company"
|
||||
? "M02_PickerCompany"
|
||||
: opt.layer === "personal"
|
||||
? "M02_PickerPersonal"
|
||||
: "M02_PickerSystem",
|
||||
);
|
||||
const owner = opt.owner ?? null;
|
||||
const api = opt.api ?? { fetch: fetchTree, edit: editTree };
|
||||
let view: TreeView | null = null;
|
||||
@@ -107,6 +98,16 @@ export function createTreePanel(opt: TreePanelOptions): TreePanelHandle {
|
||||
const body = el("div", { className: "m02-tree__body", attrs: { tabindex: "-1" } });
|
||||
const root = el("div", { className: "m02-tree", children: [body] });
|
||||
search.root.classList.add("m02-tree__search");
|
||||
// 층 단추 옆 「+」 — 맨 위에 폴더 · 항목 더하기(뿌리 줄 오른쪽 클릭을 갈음)
|
||||
const add = el("button", {
|
||||
className: "m02-tree__add",
|
||||
text: "+",
|
||||
attrs: { type: "button", title: L("M02_TreeAddTop"), "aria-label": L("M02_TreeAddTop") },
|
||||
});
|
||||
add.hidden = !opt.canEdit;
|
||||
add.addEventListener("click", (event) =>
|
||||
openTreeMenu(event, menuOf({ kind: "folder", path: [] })),
|
||||
);
|
||||
|
||||
/* --- 그리기 --- */
|
||||
const menuOf = (target: Target): TreeMenuItem[] => {
|
||||
@@ -158,7 +159,7 @@ export function createTreePanel(opt: TreePanelOptions): TreePanelHandle {
|
||||
return node(
|
||||
{ kind: "folder", path: folder.path },
|
||||
{
|
||||
label: folder.path.length ? folder.path[folder.path.length - 1] : layerLabel,
|
||||
label: folder.path[folder.path.length - 1] ?? "", // 맨 위(빈 경로)는 그리지 않음
|
||||
count: countItems(folder),
|
||||
folder: true,
|
||||
children: kids,
|
||||
@@ -184,7 +185,8 @@ export function createTreePanel(opt: TreePanelOptions): TreePanelHandle {
|
||||
const tree = buildFolders(view, text);
|
||||
const none = countItems(tree) === 0 && (searching || !tree.folders.length);
|
||||
body.replaceChildren(
|
||||
...renderTree([folderNode(tree, searching)], make),
|
||||
// 맨 위 뿌리 줄 없음 — 폴더 · 항목부터(PLAN 29-6 · 뿌리 메뉴 = 빈 자리 오른쪽 클릭 · 「+」)
|
||||
...renderTree(folderNode(tree, searching).children ?? [], make),
|
||||
...(none
|
||||
? [
|
||||
hint(
|
||||
@@ -401,5 +403,5 @@ export function createTreePanel(opt: TreePanelOptions): TreePanelHandle {
|
||||
}
|
||||
});
|
||||
|
||||
return { root, search: search.root, refresh, select };
|
||||
return { root, search: search.root, add, refresh, select };
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user