From 861068cbf48ef6ee159bf13be3afc1d30d5b0e46 Mon Sep 17 00:00:00 2001 From: umsangdon Date: Sun, 6 Sep 2026 17:46:09 +0900 Subject: [PATCH] =?UTF-8?q?feat(B02):=20=ED=94=84=EB=A1=9C=EC=A0=9D?= =?UTF-8?q?=ED=8A=B8=EB=AA=85=EC=9D=84=20=EA=B3=A0=EC=B9=A0=20=EC=88=98=20?= =?UTF-8?q?=EC=9E=88=EB=8A=94=20=EC=9E=85=EB=A0=A5=20=EC=B9=B8=EC=9C=BC?= =?UTF-8?q?=EB=A1=9C=20=EC=A0=84=ED=99=98=C2=B7=EB=B9=84=EA=B3=A0=20?= =?UTF-8?q?=EC=9C=84=EC=B9=98=20=EC=9D=B4=EB=8F=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 「저장될 이름」 미리보기 줄을 없애고 프로젝트명 입력 칸 하나로 통합 — 사업연도·사업지역· 임도종류로 자동 채우되 사용자가 사이나 끝에 글을 넣거나 자동 부분을 고칠 수 있음 - 손댄 뒤 위 세 항목을 바꾸면 해당 조각만 갈아 끼워 사용자가 넣은 글은 보존 - 비고 칸을 노선 시작 누가거리 앞으로 이동 Co-Authored-By: Claude Opus 5 (1M context) --- B02_ProjRegister/B02_ProjRegister_UI_Page.ts | 63 +++++++++++++------ .../B02_ProjRegister_UI_Style.css | 7 --- 2 files changed, 44 insertions(+), 26 deletions(-) diff --git a/B02_ProjRegister/B02_ProjRegister_UI_Page.ts b/B02_ProjRegister/B02_ProjRegister_UI_Page.ts index 935e3dba..5ec4ca18 100644 --- a/B02_ProjRegister/B02_ProjRegister_UI_Page.ts +++ b/B02_ProjRegister/B02_ProjRegister_UI_Page.ts @@ -54,15 +54,14 @@ export function renderB02ProjRegister(root: HTMLElement): void { header.append(title, subtitle); // 입력 필드 - // 프로젝트명은 사업연도 + 사업지역 + 임도종류 + 직접 입력값을 이어 붙여 만든다 - // (2026-09-06 사용자 확정). 아래 미리보기 줄이 저장될 이름 그대로다. + // 프로젝트명은 사업연도 + 사업지역 + 임도종류로 **자동으로 채워지되 고칠 수 있는 칸**이다 + // (2026-09-06 사용자 지시 — 종전에는 미리보기 줄이었다). 사용자가 사이나 끝에 글을 넣어도 + // 위 세 항목을 다시 바꾸면 그 조각만 갈아 끼워 손댄 글이 살아남는다. const nameField = createInputField({ - label: "프로젝트명 (직접 입력 부분)", - placeholder: "예: 가리왕산지구", + label: "프로젝트명", + placeholder: "예: 2026 가리왕산 간선임도 1구간", required: true, }); - const namePreview = document.createElement("p"); - namePreview.className = "b02-proj__preview"; const regionField = createInputField({ label: L("B02_Proj_Field_Region"), placeholder: L("B02_Proj_Field_Region_Placeholder"), @@ -164,15 +163,40 @@ export function renderB02ProjRegister(root: HTMLElement): void { const roadTypeText = (): string => roadTypeField.select.options[roadTypeField.select.selectedIndex]?.textContent ?? ""; - const composedName = (): string => - [ - yearField.input.value.trim(), - regionField.input.value.trim(), - roadTypeText(), - nameField.input.value.trim(), - ] - .filter((part) => part.length > 0) - .join(" "); + /** 이름을 이루는 자동 조각 — 사업연도·사업지역·임도종류 순서다. */ + const nameParts = (): string[] => [ + yearField.input.value.trim(), + regionField.input.value.trim(), + roadTypeText(), + ]; + let lastParts = nameParts(); + let nameTouched = false; + nameField.input.addEventListener("input", () => { + nameTouched = true; + }); + /** + * 위 세 항목이 바뀌면 이름 칸을 따라 고친다. + * + * 아직 손대지 않은 칸은 통째로 다시 쓰고, 사용자가 고친 뒤에는 **바뀐 조각만 갈아 끼운다** + * — 사이나 끝에 넣은 글이 지워지지 않게 하기 위해서다. 지웠던 조각은 되살리지 않는다. + */ + const syncName = (): void => { + const next = nameParts(); + if (!nameTouched) { + nameField.input.value = next.filter((part) => part.length > 0).join(" "); + } else { + let text = nameField.input.value; + next.forEach((part, index) => { + const before = lastParts[index]; + if (before && part && part !== before && text.includes(before)) { + text = text.replace(before, part); + } + }); + nameField.input.value = text; + } + lastParts = next; + }; + const composedName = (): string => nameField.input.value.trim(); const routeLength = (): number | null => { const start = isBlank(routeStartField.input.value) ? null @@ -185,14 +209,15 @@ export function renderB02ProjRegister(root: HTMLElement): void { return end > from ? end - from : null; }; const refresh = (): void => { - namePreview.textContent = `저장될 이름: ${composedName() || "(입력 대기)"}`; + syncName(); const length = routeLength(); routeEndField.root.querySelector(".ui-field__label")!.textContent = length === null ? "노선 종료 누가거리 (m)" : `노선 종료 누가거리 (m) — 연장 ${length.toFixed(1)}m`; }; - for (const field of [nameField, regionField, yearField, routeStartField, routeEndField]) { + // 이름 칸 자신은 여기서 제외한다 — 스스로 고치는 도중에 값을 되돌리면 안 된다. + for (const field of [regionField, yearField, routeStartField, routeEndField]) { field.input.addEventListener("input", refresh); } roadTypeField.select.addEventListener("change", refresh); @@ -318,10 +343,10 @@ export function renderB02ProjRegister(root: HTMLElement): void { regionField.root, roadTypeField.root, nameField.root, - namePreview, + // 비고는 노선 구간 앞에 둔다 (2026-09-06 사용자 지시). + memoField.root, routeStartField.root, routeEndField.root, - memoField.root, clientOrgField.root, designDateField.root, pmField.root, diff --git a/B02_ProjRegister/B02_ProjRegister_UI_Style.css b/B02_ProjRegister/B02_ProjRegister_UI_Style.css index 97e37525..a1b10774 100644 --- a/B02_ProjRegister/B02_ProjRegister_UI_Style.css +++ b/B02_ProjRegister/B02_ProjRegister_UI_Style.css @@ -64,13 +64,6 @@ } } -/* 조합된 프로젝트명 미리보기 — 저장될 이름 그대로 보인다 (2026-09-06). */ -.b02-proj__preview { - margin: calc(-1 * var(--spacing-8)) 0 0; - color: var(--color-text-secondary); - font-size: var(--text-caption); -} - /* 취소·등록 버튼 줄 */ .b02-proj__actions { display: flex;