feat(B05,B06): 구조물 배치 컨테이너를 B06에 장착하고 [횡단 조정] 사본을 세운다

B05/B06 인터페이스 일원화 1차 (2026-08-29 사용자 확정 계획):
- A00_Common/b_structures_section.ts: B05 구조물 배치 폼·목록 공용 진입점
  (재수출 + 스타일 동봉)
- B06 좌측 패널에 [구조물 배치] 섹션 + 하단 dock [목록][구분선][저장버튼]
  (B05 동일 템플릿). 구조물 조작은 세션 pending으로 쌓여 기존
  flushPendingStructures([임시저장]·[확정])로 정본 반영
- 선택 연동: 목록·폼 → 최근접 카드 focusStation, 횡단도 벽·세월교·BOX →
  좌측 폼에 소유 측점 시설 로드(wireStructureSelection)
- [횡단 조정] 하위 컨테이너(Adjust_Dock): 오버레이 조정창을 같은 deps로
  사본 인스턴스 생성해 세움 — 로직 이동 0, 카드 재렌더로 자동 동기.
  9키·십자 행은 사본에서 숨김(사용자 지시 7), 방향키 이중 입력 방지
- A군 시설 추가·이동·삭제는 B06에서 안내 토스트(배수유역 체인은 B05 몫)

검증: 공용 브라우저 — 구간값 길이 사본 + 10.0→11.0m 양측 동기,
오버레이 - 원복, ✕ 닫기 시 사본 해제. B05 회귀 없음. typecheck 통과.
This commit is contained in:
2026-08-29 14:20:49 +09:00
parent 11abd303e7
commit 2e28af6e86
11 changed files with 427 additions and 66 deletions
@@ -111,11 +111,17 @@ const LENGTH_STEP_M = SPAN_STEP_M * 2;
*/
const panelScrollTops = new Map<string, number>();
/** 구조물 조정 오버레이 창을 만든다. 처음에는 숨어 있다. */
export function buildStructurePanel(deps: StructurePanelDeps): StructurePanelHandle {
/** 구조물 조정 오버레이 창을 만든다. 처음에는 숨어 있다.
* `opts.dock` — 좌측 [횡단 조정] 사본(2026-08-29 일원화): 흐름 배치 스타일을 입고,
* 방향키 문서 리스너를 달지 않는다(오버레이 창과 이중으로 눌리는 것 방지). */
export function buildStructurePanel(
deps: StructurePanelDeps,
opts?: { dock?: boolean },
): StructurePanelHandle {
const root = document.createElement("div");
root.className = "b06-structure-panel";
root.classList.add("is-hidden");
if (opts?.dock) root.classList.add("b06-structure-panel--dock");
root.addEventListener("scroll", () => {
if (!root.classList.contains("is-hidden")) panelScrollTops.set(deps.scrollKey, root.scrollTop);
});
@@ -482,7 +488,7 @@ export function buildStructurePanel(deps: StructurePanelDeps): StructurePanelHan
root.classList.toggle("is-hidden", key === null);
document.removeEventListener("keydown", onArrowKey);
if (!key) return;
document.addEventListener("keydown", onArrowKey);
if (!opts?.dock) document.addEventListener("keydown", onArrowKey);
// 다단 벽 — 유출측(extra0…)과 유입·집수정 계류측(bextra0…)이 같은 이름을 쓴다.
const isExtra = key.startsWith("extra") || key.startsWith("bextra");
const extraIndex = key.startsWith("bextra") ? Number(key.slice(6)) : Number(key.slice(5));