feat(720-2): 최상위 폴더 만들기 — 폴더 · 문서 줄 메뉴 + 단가산출 · 일위대가 층 줄 「+」(구조물 조합과 같은 addFolder([]))

- 구조물 조합 나무 「〇〇로 복사…」 몸을 TreePanel_CopyTo 로 뗌(TreePanel 700 → 688 줄 · 동작 같음)
- 낡은 시험 test_m02_layer_screen(복사 대상 글 자리 = CopyTo) · test_m02_precombo_scope(층 줄 add 인자) 새 꼴로

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-11-01 21:21:29 +09:00
co-authored by Claude Opus 5.5
parent 7621fff233
commit 194e1a9c39
8 changed files with 80 additions and 35 deletions
@@ -36,7 +36,7 @@ import {
type TreeRef,
type TreeView,
} from "./M02_MasterTemplete_Api_Fetch";
import { askCopyFolder, type CopyTarget } from "./M02_MasterTemplete_TreePanel_CopyTo";
import { copyToLayer, type CopyTarget } from "./M02_MasterTemplete_TreePanel_CopyTo";
import { askFolder, askNewItem, askText } from "./M02_MasterTemplete_TreePanel_Dialogs";
import { attachTreeDrag } from "./M02_MasterTemplete_TreePanel_Drag";
import {
@@ -196,7 +196,7 @@ export function createTreePanel(opt: TreePanelOptions): TreePanelHandle {
{ label: L("M02_TreeCopy").replace("{n}", n), run: () => copy(list) },
...(opt.copyTo ?? []).map((to) => ({
label: to.label.replace("{n}", n),
run: () => void copyTo(list, to),
run: () => copyTo(list, to),
})),
];
};
@@ -243,6 +243,7 @@ export function createTreePanel(opt: TreePanelOptions): TreePanelHandle {
...(isTop
? []
: [
{ label: L("M02_TreeAddTopFolder"), run: () => void addFolder([]) }, // 720-2 = 「+」 길
{ label: L("M02_TreeRename"), run: () => void rename(target) },
{ label: L("M02_TreeMove"), run: () => void move(target) },
{ label: L("M02_Delete"), run: () => void remove(target) },
@@ -554,25 +555,12 @@ export function createTreePanel(opt: TreePanelOptions): TreePanelHandle {
showToast(L("M02_TreeCopied").replace("{n}", String(list.length)), "success");
}
/** 「〇〇로 복사…」 — 그 층 폴더를 고름(`askCopyFolder`) → 새 키 · 같은 이름 「(2)」 · 이 나무는 그대로 */
async function copyTo(list: Target[], to: CopyTarget): Promise<void> {
if (!api.paste || !list.length) return;
/** 「〇〇로 복사…」(39-6) — 몸은 `TreePanel_CopyTo` */
function copyTo(list: Target[], to: CopyTarget): void {
const paste_ = api.paste;
if (!paste_ || !list.length) return;
const clip = { kind: clipKind, from: { layer: opt.layer, owner }, refs: list.map(refOf) };
try {
const dest = await askCopyFolder(api.fetch, to, list.length);
if (!dest) return;
await api.paste(to.layer, to.owner, clip, dest);
const where = to.label.replace(/ ?\(.*$/, "").replace(/(으로|로) 복사…?$/, "");
showToast(
L("M02_TreeCopiedTo")
.replace("{n}", String(list.length))
.replace("{layer}", where)
.replace("{folder}", dest.join(" / ") || L("M02_TreeTop")),
"success",
);
} catch (error) {
showToast(L("M02_ActionFailed").replace("{value}", why(error)), "error");
}
void copyToLayer({ fetch: api.fetch, paste: paste_ }, clip, to);
}
async function paste(dest: string[]): Promise<void> {