merge: origin/dev 받음 — 도면 칸 CAD 💾 · 접기와 sub1 저장 안 한 고침 알림 통로를 다 살림

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PxvYb5ufV1kWdBvZbpDfu6
This commit is contained in:
2026-09-25 17:06:37 +09:00
co-authored by Claude Sonnet 5
14 changed files with 260 additions and 46 deletions
@@ -34,6 +34,8 @@ export interface DrawingTemplateOptions {
layer?: string;
/** 프로젝트 층이면 프로젝트 id — 칸이 `m02:project:프로젝트id:이름` 이 된다. */
projectId?: string | null;
/** 저장 안 한 고침이 생기면 true — CAD 편집 · 작도 영역 값 바꿈. */
onChanged?: (dirty: boolean) => void;
}
const RECOVERY_PREFIX = "OPEN_WEB_CAD__RECOVERY__";
@@ -128,6 +130,7 @@ export function mountDrawingTemplate(
const areaInputs = AREA_LABELS.map((label, index) => {
const field = createInputField({ label, type: "number", value: String(start[index]) });
field.input.disabled = readOnly;
field.input.addEventListener("input", () => options.onChanged?.(true));
return field;
});
area.append(areaTitle, ...areaInputs.map((field) => field.root));
@@ -167,21 +170,6 @@ export function mountDrawingTemplate(
showToast(error instanceof Error ? error.message : "자리표 목록을 받지 못했습니다.", "error"),
);
// CAD 안 💾 · Ctrl+S — 양식 파일은 페이지 [저장] 만 쓴다. 저장 중 또 눌러도 한 번만 부른다.
let saving = false;
const hostSave = (): void => {
if (readOnly) return void showToast("이 양식은 볼 수만 있습니다.", "info");
if (saving || !options.onSave) return;
saving = true;
getDoc()
.then((next) => options.onSave?.(next))
.catch((error) =>
showToast(error instanceof Error ? error.message : "양식을 저장하지 못했습니다.", "error"),
)
.finally(() => (saving = false));
};
const cad = createCadHost<DrawingTemplateDoc>({ title: "도면 양식", onHostSave: hostSave });
const load = (drawing: DrawingTemplateDoc): void => {
cad.beginLoading();
cad.load(