feat(B06): 기슭막이 높이·자리 체계 개편 + 조정창 방향키 조작

- 조정창 십자 키패드 키보드 방향키 조작(집수정 9키는 십자 축만)
- 배관 기슭막이 높이 = 순수 높이(바닥~상단), 하한·기본 = 관경+1.0m (고정 2.0m 폐기)
- 매몰 시 전면 발끝 지반 추적 바닥 심화 삭제 — 바닥 = invert-0.5 고정
- 상하(d) 0점 = 성토선 0 지점(벽 상단=노견), 기본 자리 = 성토사면 경사길이 4m 지점
  (d=null 자동, 저장·표시·정수맞춤 pinned 판정 연동, 구세션 d=0 호환)
- 유입 접속 절토선: 지반 교차 없으면 1m 공간 확보에서 끝
- 자동 집수정 기본 형상 L형 -> I형 (선택지 밖 구조물 그려지던 불일치)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-23 20:34:30 +09:00
co-authored by Claude Fable 5
parent 7217747e81
commit 5371534fc3
11 changed files with 209 additions and 126 deletions
@@ -337,6 +337,38 @@ export function buildStructurePanel(deps: StructurePanelDeps): StructurePanelHan
);
extraParts.controls.append(countMinus, countValue, countPlus);
// 키보드 방향키 = 십자 버튼(2026-08-23 사용자). 9키(집수정)도 **십자 축만** —
// 모서리(크기) 키는 대상 아님. 셀렉트 포커스 중엔 드롭다운 탐색에 양보한다.
// 창은 카드마다 새로 만들어지므로 문서 리스너는 show/hide에 맞춰 붙였다 떼고,
// 카드가 통째로 사라진 경우(root 분리)엔 스스로 해제한다.
const ARROW_SLOT: Record<string, string> = {
ArrowUp: "up",
ArrowDown: "down",
ArrowLeft: "left",
ArrowRight: "right",
};
const onArrowKey = (event: KeyboardEvent) => {
if (!root.isConnected) {
document.removeEventListener("keydown", onArrowKey);
return;
}
const slot = ARROW_SLOT[event.key];
if (!slot || root.classList.contains("is-hidden")) return;
const focus = event.target as HTMLElement | null;
if (focus && (focus.tagName === "SELECT" || focus.tagName === "INPUT")) return;
for (const candidate of [basinRow, moveRow]) {
if (candidate.row.classList.contains("is-hidden")) continue;
const button = candidate.controls.querySelector<HTMLButtonElement>(
`.b06-structure-panel__btn--${slot}`,
);
if (button) {
event.preventDefault();
button.click();
return;
}
}
};
const closeButton = makeButton("✕", L("B06_Cross_Revet_Close"), () => deps.close());
closeButton.classList.add("b06-structure-panel__close");
@@ -362,7 +394,9 @@ export function buildStructurePanel(deps: StructurePanelDeps): StructurePanelHan
show: (key) => {
current = key;
root.classList.toggle("is-hidden", key === null);
document.removeEventListener("keydown", onArrowKey);
if (!key) return;
document.addEventListener("keydown", onArrowKey);
const isExtra = key.startsWith("extra");
const movable = deps.canNudge(key);
const structure = deps.structureFor();
@@ -431,11 +465,15 @@ export function buildStructurePanel(deps: StructurePanelDeps): StructurePanelHan
(Math.abs(adjust.x) > 1e-9
? `${L(adjust.x > 0 ? "B06_Cross_Revet_Outward" : "B06_Cross_Revet_Inward")} ${Math.abs(adjust.x).toFixed(1)}m`
: L("B06_Cross_Revet_Auto"));
// d = null → 자동(기본 자리). 숫자는 성토선 0점(벽 상단=노견) 기준 절대값
// (배관 벽 — 2026-08-23). 0 = 성토선 0 지점.
slopeLine.textContent =
`${L("B06_Cross_Slope_Label")} ` +
(Math.abs(adjust.d) > 1e-9
? `${L(adjust.d > 0 ? "B06_Cross_Revet_DirDown" : "B06_Cross_Revet_DirUp")} ${Math.abs(adjust.d).toFixed(1)}m`
: L("B06_Cross_Revet_Auto"));
(adjust.d == null
? L("B06_Cross_Revet_Auto")
: Math.abs(adjust.d) > 1e-9
? `${L(adjust.d > 0 ? "B06_Cross_Revet_DirDown" : "B06_Cross_Revet_DirUp")} ${Math.abs(adjust.d).toFixed(1)}m`
: "0m");
},
};
}