diff --git a/B06_Section/B06_Section_UI_Cross_Detail.ts b/B06_Section/B06_Section_UI_Cross_Detail.ts index b60605153..e8a67dd2c 100644 --- a/B06_Section/B06_Section_UI_Cross_Detail.ts +++ b/B06_Section/B06_Section_UI_Cross_Detail.ts @@ -2,11 +2,11 @@ * B06_Section_UI_Cross_Detail.ts * 횡단 카드 측구 줄 맨 오른쪽 [상세] → 모달(138-4). * - * 맨 위 = 도면 표 위 글(`design.structure_note` · 세션 초안 → [저장]이 patch 로 내보냄 · + * 위 = 카드 그림 복제(어두운 바탕 · CAD 꼴 · 남은 높이를 채움) · + * 가운데 = 도면 표 위 글(`design.structure_note` · 세션 초안 → [저장]이 patch 로 내보냄 · * B07 횡단도 수량표 바로 위에 줄마다 찍힘 — `_Engine_Cad_Table.cross_note_lines`) · - * 가운데 = 카드 그림 복제(어두운 바탕 · CAD 꼴) · 아래 = B07 횡단 수량표(값 · 칸 배치 모두 - * 서버 `cross-quantity-table` 한 길 · 캐시 설계로 · 열 때 부름). - * 막은 투명(누름 통과) · 자리는 그 카드를 안 가리는 넓은 쪽(좌/우 → 위/아래). + * 아래 = B07 횡단 수량표(값 · 칸 배치 모두 서버 `cross-quantity-table` 한 길 · 캐시 설계로 · 열 때 부름). + * 공용 큰 창(`wide`) · 공용 막(밖 누르면 닫힘) · 스크롤 없음(150-2). * 모달이 열린 채 카드를 다시 그리면 그림 · 표를 새로 맞춤. * ========================================================================== */ @@ -64,51 +64,6 @@ function writeNote(section: CrossSection, text: string): void { writeState("structure-notes", all, host.projectId, routeId); } -/* ── 자리 ───────────────────────────────────────────────────────────── */ - -const GAP_PX = 12; -const MIN_WIDTH_PX = 360; -const MAX_WIDTH_PX = 720; - -/** 카드를 안 가리는 넓은 쪽에 붙임 — 좌우가 좁으면 위아래. */ -function place(dialog: HTMLElement, card: HTMLElement | null): void { - const vw = window.innerWidth; - const vh = window.innerHeight; - const rect = card?.getBoundingClientRect(); - const style = dialog.style; - style.position = "fixed"; - style.margin = "0"; - if (!rect) { - style.width = `${Math.min(MAX_WIDTH_PX, vw - GAP_PX * 2)}px`; - style.left = `${(vw - Math.min(MAX_WIDTH_PX, vw - GAP_PX * 2)) / 2}px`; - style.top = `${GAP_PX}px`; - style.maxHeight = `${vh - GAP_PX * 2}px`; - return; - } - const left = rect.left; - const right = vw - rect.right; - if (Math.max(left, right) >= MIN_WIDTH_PX + GAP_PX * 2) { - const width = Math.min(MAX_WIDTH_PX, Math.max(left, right) - GAP_PX * 2); - const top = Math.min(Math.max(rect.top, GAP_PX), vh - GAP_PX - 240); - style.width = `${width}px`; - style.left = `${right >= left ? rect.right + GAP_PX : rect.left - GAP_PX - width}px`; - style.top = `${Math.max(top, GAP_PX)}px`; - style.maxHeight = `${vh - Math.max(top, GAP_PX) - GAP_PX}px`; - return; - } - const width = Math.min(MAX_WIDTH_PX, vw - GAP_PX * 2); - style.width = `${width}px`; - style.left = `${Math.min(Math.max(rect.left, GAP_PX), vw - GAP_PX - width)}px`; - const below = vh - rect.bottom; - if (below >= rect.top) { - style.top = `${rect.bottom + GAP_PX}px`; - style.maxHeight = `${Math.max(below - GAP_PX * 2, 160)}px`; - } else { - style.top = `${GAP_PX}px`; - style.maxHeight = `${Math.max(rect.top - GAP_PX * 2, 160)}px`; - } -} - /* ── 표(B07 칸 배치 그대로) ─────────────────────────────────────────────── */ function cell( @@ -182,9 +137,8 @@ export function openCrossDetail(section: CrossSection): void { title: `${title} 상세`, closeLabel: "닫기", dialogClass: "b06-detail", - backdropClass: "b06-detail__backdrop", + wide: true, mount(body, close) { - const dialog = body.parentElement as HTMLElement; const note = document.createElement("textarea"); note.className = "ui-input b06-detail__note"; note.rows = 3; @@ -195,7 +149,7 @@ export function openCrossDetail(section: CrossSection): void { cad.className = "b06-detail__cad"; const tableBox = document.createElement("div"); tableBox.className = "b06-detail__table"; - body.append(note, cad, tableBox); + body.append(cad, note, tableBox); // 표 칸 누름 = 그림 그 항목 강조 · 다시 누르면 끔(150-4) let picked: string | null = null; @@ -220,7 +174,6 @@ export function openCrossDetail(section: CrossSection): void { const card = cardOf(state.section); const svg = card?.querySelector("svg.b06-section__chart"); cad.replaceChildren(svg ? svg.cloneNode(true) : document.createTextNode("그림 없음")); - place(dialog, card); showPicked(); }, loadTable() { diff --git a/B06_Section/B06_Section_UI_Style_Cross_Detail.css b/B06_Section/B06_Section_UI_Style_Cross_Detail.css index 39629a215..53adc3245 100644 --- a/B06_Section/B06_Section_UI_Style_Cross_Detail.css +++ b/B06_Section/B06_Section_UI_Style_Cross_Detail.css @@ -1,6 +1,6 @@ /* ============================================================================= * B06_Section_UI_Style_Cross_Detail.css - * 횡단 카드 [상세] 단추 · 모달(138-4) — 투명 막(누름 통과) · 글 칸 · CAD 꼴 그림 · B07 수량표. + * 횡단 카드 [상세] 단추 · 모달(138-4 · 150-2) — 공용 큰 창 · 그림(남은 높이) → 글 칸 → B07 수량표. * ========================================================================== */ /* 측구 줄 맨 오른쪽 — ⋯ 가 보이면 그 옆, 숨으면 혼자 오른쪽 끝 */ @@ -13,25 +13,23 @@ margin-left: 0; } -/* 막은 투명 · 누름은 아래 화면으로 — 모달 몸만 받음 */ -.ui-modal__backdrop.b06-detail__backdrop { - background-color: transparent; - pointer-events: none; -} - -.b06-detail__backdrop > .ui-modal.b06-detail { - pointer-events: auto; - overflow: auto; - box-shadow: var(--shadow-lg); +/* 스크롤 없음 — 글 · 표는 제 높이 · 그림이 남은 높이를 채움 */ +.ui-modal.b06-detail > .ui-modal__body { + overflow: hidden; } .b06-detail__note { + flex: none; width: 100%; box-sizing: border-box; - resize: vertical; + resize: none; font: inherit; } +.b06-detail__table { + flex: none; +} + /* 가벼운 CAD 꼴 — 어두운 바탕 · 카드 그림 복제에 다크 색 토큰을 덮어씀 */ .b06-detail__cad { --color-bg: #111111; @@ -50,12 +48,15 @@ background: #111111; color: #f2f2f2; overflow: hidden; + flex: 1; + min-height: 0; } +/* viewBox 그대로 — 비율 유지하며 칸 가득 */ .b06-detail__cad > svg { display: block; width: 100%; - height: auto; + height: 100%; } /* B07 횡단 수량 산출표 — 칸 배치 그대로 */ diff --git a/resources/tester/test_150_detail_pick.py b/resources/tester/test_150_detail_pick.py index 93004248f..1657f1a71 100644 --- a/resources/tester/test_150_detail_pick.py +++ b/resources/tester/test_150_detail_pick.py @@ -76,3 +76,17 @@ def test_상세_표_칸_키_누름_배선(): assert "element.dataset.key = key" in src assert "highlightDetail(svg, state.section.design, picked)" in src assert 'closest("[data-key]")' in src + + +def test_상세_큰_창_공용_막_그림_글_표_순서(): + """150-2 — 투명 막 지움(밖 누르면 공용 닫기) · 큰 창 · 그림 → 글 → 표 · 스크롤 없음.""" + base = os.path.join(ROOT, "B06_Section") + with open(os.path.join(base, "B06_Section_UI_Cross_Detail.ts"), encoding="utf-8") as f: + src = f.read() + with open(os.path.join(base, "B06_Section_UI_Style_Cross_Detail.css"), encoding="utf-8") as f: + css = f.read().replace(chr(13), "") + assert "wide: true" in src and "backdropClass" not in src + assert "body.append(cad, note, tableBox)" in src + assert "pointer-events: none" not in css and "b06-detail__backdrop" not in css + assert ".ui-modal.b06-detail > .ui-modal__body {\n overflow: hidden;" in css + assert "flex: 1;\n min-height: 0;" in css and "height: 100%;" in css