diff --git a/B05_Profile/B05_Profile_UI_Drainage_Panel.ts b/B05_Profile/B05_Profile_UI_Drainage_Panel.ts index 00985513..c22070aa 100644 --- a/B05_Profile/B05_Profile_UI_Drainage_Panel.ts +++ b/B05_Profile/B05_Profile_UI_Drainage_Panel.ts @@ -91,6 +91,9 @@ export interface DrainagePanel { /** 밖(리스트·그래프·3D)에서 관을 고른다 — 마커 선택·시설 폼·유역 강조까지 연다. * 이미 같으면 무시(2026-08-17 전역 선택 동기화). */ selectPipeAtChainage: (chainageM: number | null) => void; + /** 부속 옵션 폼(시설 편집) DOM — 사이드 「구조물 배치」 섹션이 가져다 붙인다 + * (구조물 편집은 사이드 패널이 정위치, 2026-08-17 사용자 지시). */ + facilityForm: HTMLElement; /** 측점 선택 마킹 — 계획선 위 해당 누가거리에 표식을 그린다(null이면 지움). */ markStation: (chainageM: number | null) => void; dispose: () => void; @@ -204,15 +207,9 @@ export function createDrainagePanel(callbacks: DrainagePanelCallbacks = {}): Dra }, }); - root.append( - panelHandle.root, - widthResizer.root, - header, - viewport, - facilityEditor.root, - summary, - basinList, - ); + root.append(panelHandle.root, widthResizer.root, header, viewport, summary, basinList); + // 시설 폼은 여기 두지 않는다 — 사이드 「구조물 배치」 섹션이 `facilityForm`으로 + // 가져다 붙인다(구조물 편집은 사이드가 정위치, 2026-08-17 사용자 지시). let projectId: string | null = null; let meta: VWorldMeta | null = null; @@ -772,6 +769,7 @@ export function createDrainagePanel(callbacks: DrainagePanelCallbacks = {}): Dra syncPipeSelection(); scheduleDraw(); }, + facilityForm: facilityEditor.root, async savePipes() { if (!projectId) return 0; const response = await saveDetailPipePoints( diff --git a/B05_Profile/B05_Profile_UI_Page.ts b/B05_Profile/B05_Profile_UI_Page.ts index 5b918a2f..84578016 100644 --- a/B05_Profile/B05_Profile_UI_Page.ts +++ b/B05_Profile/B05_Profile_UI_Page.ts @@ -396,6 +396,11 @@ export async function renderB05Route(root: HTMLElement): Promise { if (currentSectionDetail) renderStationLines(currentSectionDetail); } + // 부속 옵션 폼(시설 편집)은 사이드 「구조물 배치」 섹션 안에 붙인다 — 구조물 + // 편집은 사이드가 정위치(2026-08-17 사용자 지시). 폼 데이터는 배수유역 패널이 + // 정본(pipe_points)과 동기화한다. + panel.structures.mountFacilityForm(profilePanel.drainage.facilityForm); + viewer.markers.onChange(markStale); viewer.markers.onSelectionChange(panel.setSelected); viewer.markers.onStationSelectionChange((stationId) => { diff --git a/B05_Profile/B05_Profile_UI_Structures_Panel.ts b/B05_Profile/B05_Profile_UI_Structures_Panel.ts index 3b32f26e..46adbc50 100644 --- a/B05_Profile/B05_Profile_UI_Structures_Panel.ts +++ b/B05_Profile/B05_Profile_UI_Structures_Panel.ts @@ -62,6 +62,10 @@ export interface StructuresSection { getStructures: () => StructureInstance[]; /** 계곡 통과 시설 목록을 병합 표시한다(정본 = pipe_points, 배수유역 패널 경유). */ setPipeFacilities: (pipes: PipeFacilityItem[]) => void; + /** 부속 옵션 폼(배수유역 패널 소유 시설 편집 DOM)을 이 섹션 안에 붙인다 — + * 구조물 편집은 사이드 패널이 정위치(2026-08-17 사용자 지시). 표시/숨김은 + * 폼 스스로(선택된 관이 없으면 hidden) 관리한다. */ + mountFacilityForm: (element: HTMLElement) => void; /** 그래프·3D에서 고른 계곡 통과 시설을 목록에서 강조한다(null = 해제). */ selectPipeByChainage: (chainageM: number | null) => void; /** 종단도·3D에서 고른 구조물을 폼에 올린다. null이면 선택 해제. */ @@ -616,6 +620,10 @@ export function createStructuresSection(callbacks: StructuresCallbacks): Structu renderList(); }, getStructures: () => [...structures], + mountFacilityForm(element) { + // 목록 위, 액션 버튼 다음 — 계곡 시설을 고르면 그 자리에서 부속 옵션을 편집한다. + body.insertBefore(element, list); + }, setPipeFacilities(pipes) { pipeFacilities = pipes.map((pipe) => ({ ...pipe })); if ( diff --git a/B05_Profile/B05_Profile_UI_Style_Structures.css b/B05_Profile/B05_Profile_UI_Style_Structures.css index f0a79932..60cd06bc 100644 --- a/B05_Profile/B05_Profile_UI_Style_Structures.css +++ b/B05_Profile/B05_Profile_UI_Style_Structures.css @@ -97,6 +97,12 @@ .b05-drainage__facility .b05-route__irregular-row { display: flex; gap: 6px; + /* 사이드 「구조물 배치」 섹션 폭에서는 행이 줄바꿈되며 들어간다(2026-08-17 이동). */ + flex-wrap: wrap; +} + +.b05-drainage__facility .b05-route__field { + min-width: 96px; } .b05-drainage__facility .b05-route__field {