diff --git a/B07_DesignDetail/B07_DesignDetail_UI_PlanManage.ts b/B07_DesignDetail/B07_DesignDetail_UI_PlanManage.ts index 5328ed77f..7cff7b98c 100644 --- a/B07_DesignDetail/B07_DesignDetail_UI_PlanManage.ts +++ b/B07_DesignDetail/B07_DesignDetail_UI_PlanManage.ts @@ -3,8 +3,8 @@ * [평면도 관리] 모달(PLAN 130-1) — 좌측 패널이 좁아 종류 · 대피소 자리 · 장 보기를 한 창에 모음. * * 왼쪽 = 종류 목록(× 지우기) · 종류 추가 · 업데이트 폼 · 대피소 · 사토장 자리 · 평면도 장 목록 - * 오른쪽 = 고른 장 미리보기(보기 전용 CAD · 장 바꾸기) · [확정 풀기] · [CAD 에서 열기] - * 고치기는 지금 서버 길 그대로(종류 파일 · 확정 풀기) — 고칠 때마다 모달 안을 다시 받고, + * 오른쪽 = 고른 장 미리보기(보기 전용 CAD · 캔버스만 `bare`) · 확정 배지 · [CAD 에서 열기] + * 고치기는 지금 서버 길 그대로(종류 파일) — 고칠 때마다 모달 안을 다시 받고, * 닫을 때 `onClosed(changed)` 로 좌측 목록 · 도면을 다시 읽음. * ========================================================================== */ @@ -16,7 +16,6 @@ import { fetchDesignDrawing, fetchDesignDrawingList, fetchPlanKinds, - invalidateDesignDrawing, type CadDrawing, type DesignDrawingItem, type PlanKindsState, @@ -115,7 +114,7 @@ export function openPlanManager(controls: PlanManageControls): void { .querySelectorAll(".b07-plan-manage__sheets .b07-drawing-button") .forEach((item) => (item.dataset.active = String(item.dataset.drawingId === picked))); - /** 장 하나를 미리보기에 — 보기 전용 · 확정이면 [확정 풀기](지금 [수정]과 같은 서버 길). */ + /** 장 하나를 미리보기에 — 보기 전용 · 확정 풀기는 메인 [수정](140-1). */ const show = async (drawing: DesignDrawingItem, label: string): Promise => { picked = drawing.id; markActive(); @@ -127,12 +126,6 @@ export function openPlanManager(controls: PlanManageControls): void { const badge = el("span", "b07-plan-manage__badge", response.confirmed ? "확정" : "확정 전"); badge.dataset.confirmed = String(response.confirmed); head.append(badge); - if (response.confirmed) - head.append( - button("b07-plan-tools__button", "확정 풀기", () => { - void run(() => invalidateDesignDrawing(projectId, drawing.id), edits); - }), - ); head.append(button("b07-plan-tools__button", "CAD 에서 열기", () => finish(drawing.id))); preview.load( response.drawing, @@ -146,6 +139,7 @@ export function openPlanManager(controls: PlanManageControls): void { hostTitle: "평면도 미리보기", ribbonCollapsed: true, panelsCollapsed: true, + bare: true, }, ); } catch (error) { diff --git a/B07_DesignDetail/openwebcad/src/App.css b/B07_DesignDetail/openwebcad/src/App.css index 847978336..f80bac8e1 100644 --- a/B07_DesignDetail/openwebcad/src/App.css +++ b/B07_DesignDetail/openwebcad/src/App.css @@ -58,6 +58,10 @@ button { .cad-host-save { --cad-title-height: 0px; } +.cad-bare { + --cad-title-height: 0px; + --cad-status-height: 0px; +} .controls { pointer-events: auto; } diff --git a/B07_DesignDetail/openwebcad/src/components/Toolbar.tsx b/B07_DesignDetail/openwebcad/src/components/Toolbar.tsx index 67e6dc26e..ba0b5e184 100644 --- a/B07_DesignDetail/openwebcad/src/components/Toolbar.tsx +++ b/B07_DesignDetail/openwebcad/src/components/Toolbar.tsx @@ -13,7 +13,7 @@ import { Ribbon } from '../ribbon/Ribbon'; import { StatusBar } from './StatusBar'; import { useCadRefresh } from './use-cad-refresh'; import { isInspectorCollapsed, isRibbonCollapsed, setInspectorCollapsed } from './ui-state'; -import { getActiveToolActor } from '../state'; +import { getActiveToolActor, isBare } from '../state'; import type { Tool } from '../tools'; import { ViewControls } from './ViewControls'; import { DropHint } from './DropHint'; @@ -26,21 +26,27 @@ export const Toolbar: FC = () => { const ribbonCollapsed = isRibbonCollapsed(); // 좌측 패널 접힘 — 호스트(M02 미리보기)가 접힌 채로 실을 수 있게 ui-state 에 둔다 const panelCollapsed = isInspectorCollapsed(); + // 캔버스만(B07 평면도 관리 모달) — 겉칸을 안 그리고 높이 · 폭 변수를 0 으로 + const bare = isBare(); useEffect(() => { // 편 상태의 폭은 App.css의 `--cad-panel-width` 기본값을 쓴다. 여기 숫자를 박아 // 두면 스타일에서 넓혀도 이 인라인 값이 덮는다(2026-09-01 실측: 300px 무시됨). - if (panelCollapsed) document.documentElement.style.setProperty('--cad-panel-width', '0px'); + if (panelCollapsed || bare) document.documentElement.style.setProperty('--cad-panel-width', '0px'); else document.documentElement.style.removeProperty('--cad-panel-width'); document.documentElement.style.setProperty( '--cad-command-height', - commandLineVisible ? '86px' : '0px' + commandLineVisible && !bare ? '86px' : '0px' ); // 리본 접힘 — 탭 줄(26px)만 남기고 패널 줄 자리를 걷는다(`Ribbon.tsx` 가 안 그림). - if (ribbonCollapsed) document.documentElement.style.setProperty('--cad-ribbon-height', '26px'); + if (bare) document.documentElement.style.setProperty('--cad-ribbon-height', '0px'); + else if (ribbonCollapsed) + document.documentElement.style.setProperty('--cad-ribbon-height', '26px'); else document.documentElement.style.removeProperty('--cad-ribbon-height'); window.dispatchEvent(new Event('resize')); - }, [panelCollapsed, commandLineVisible, ribbonCollapsed]); + }, [panelCollapsed, commandLineVisible, ribbonCollapsed, bare]); + + if (bare) return null; return ( <> diff --git a/B07_DesignDetail/openwebcad/src/integration/aislo-drawing-bridge.ts b/B07_DesignDetail/openwebcad/src/integration/aislo-drawing-bridge.ts index 47ecd4f5b..3960d5b73 100644 --- a/B07_DesignDetail/openwebcad/src/integration/aislo-drawing-bridge.ts +++ b/B07_DesignDetail/openwebcad/src/integration/aislo-drawing-bridge.ts @@ -27,6 +27,7 @@ import { setLayers, setOriginMarker, setViewOnly, + setBare, } from '../state.ts'; import { setInspectorCollapsed, setRibbonCollapsed } from '../components/ui-state.ts'; import { toast } from 'react-toastify'; @@ -68,6 +69,8 @@ interface DrawingLoadMessage { panelsCollapsed?: boolean; /** 미리보기 — 왼쪽 끌기 = 화면 옮기기 · 두 번 누름 = 전체 맞춤 · 선택 · 명령 안내 없음. */ viewOnly?: boolean; + /** 캔버스만 — 제목줄 · 리본 · 패널 · 상태막대를 안 그림(B07 평면도 관리 모달). */ + bare?: boolean; originMarker?: boolean; } @@ -227,6 +230,7 @@ export function registerAisloDrawingBridge() { setRibbonCollapsed(event.data.ribbonCollapsed === true); if (event.data.panelsCollapsed) setInspectorCollapsed(true); setViewOnly(event.data.viewOnly === true); + setBare(event.data.bare === true); setOriginMarker(event.data.originMarker === true); if (event.data.frameEdit) applyFramePreview(); // 앞 도면에서 켜 둔 그리기 도구를 내린다. 안 내리면 **확정한 도면 위에도** diff --git a/B07_DesignDetail/openwebcad/src/state.test.ts b/B07_DesignDetail/openwebcad/src/state.test.ts index a45b4fe21..5a1351e4d 100644 --- a/B07_DesignDetail/openwebcad/src/state.test.ts +++ b/B07_DesignDetail/openwebcad/src/state.test.ts @@ -7,9 +7,11 @@ import { getEntities, getHighlightedEntityIds, isDrawingDirty, + isBare, isDrawingReadOnly, resetUndoBaseline, setActiveLayerId, + setBare, setDesignMeta, setEntities, setHighlightedEntityIds, @@ -120,3 +122,23 @@ describe('isDrawingReadOnly', () => { expect(isDrawingReadOnly()).toBe(false); }); }); + +describe('setBare', () => { + it('캔버스만 — 켜면 뿌리에 cad-bare(제목줄 · 상태막대 0), 끄면 걷힌다', () => { + stubWindow(); + const classes = new Set(); + (globalThis as { document?: unknown }).document = { + documentElement: { + classList: { + toggle: (name: string, on: boolean) => (on ? classes.add(name) : classes.delete(name)), + }, + }, + }; + setBare(true); + expect(isBare()).toBe(true); + expect(classes.has('cad-bare')).toBe(true); + setBare(false); + expect(isBare()).toBe(false); + expect(classes.has('cad-bare')).toBe(false); + }); +}); diff --git a/B07_DesignDetail/openwebcad/src/state.ts b/B07_DesignDetail/openwebcad/src/state.ts index 10b70c21e..559e75731 100644 --- a/B07_DesignDetail/openwebcad/src/state.ts +++ b/B07_DesignDetail/openwebcad/src/state.ts @@ -197,6 +197,8 @@ let viewOnly = false; let originMarker = false; let hostTitle = 'B07 상세 설계'; let hostSave = false; +/** 캔버스만(B07 평면도 관리 모달) — 제목줄 · 리본 · 패널 · 상태막대를 안 그린다. */ +let bare = false; /** * 실은 뒤로 실제 편집이 있었는가. 도면을 바꾸기 전에 부모가 물어보는 근거다 — @@ -512,6 +514,13 @@ export const setHostSave = (enabled: boolean) => { // 제목 줄이 없어지면 그 높이만큼 위로 당긴다(App.css `.cad-host-save`). document.documentElement.classList.toggle('cad-host-save', enabled); }; +export const isBare = (): boolean => bare; +export const setBare = (enabled: boolean) => { + bare = enabled; + // 제목 줄 · 상태막대 높이를 걷는다(App.css `.cad-bare`) — 리본 · 패널은 Toolbar 가 0 으로. + document.documentElement.classList.toggle('cad-bare', enabled); + notifyWindow(HtmlEvent.UPDATE_STATE); +}; export const getHostTitle = (): string => hostTitle; export const setHostTitle = (title: string) => { hostTitle = title; diff --git a/resources/tester/helper_130_b07_plan_manage.cjs b/resources/tester/helper_130_b07_plan_manage.cjs index 5b6aea7ba..dddea378f 100644 --- a/resources/tester/helper_130_b07_plan_manage.cjs +++ b/resources/tester/helper_130_b07_plan_manage.cjs @@ -320,7 +320,7 @@ const { buildDrawingSidePanel } = loadTs(path.join(B07, "B07_DesignDetail_UI_Pan confirms: confirms.length, }; - // 미리보기 장 바꾸기 — 「지형 2장」 → 「노선배치도」(확정 → [확정 풀기]) + // 미리보기 장 바꾸기 — 「지형 2장」 → 「노선배치도」(확정 배지만 · [확정 풀기] 없음 140-1) const pickSheet = async (id) => { modal.body .querySelectorAll(".b07-plan-manage__sheets .b07-drawing-button") @@ -340,14 +340,6 @@ const { buildDrawingSidePanel } = loadTs(path.join(B07, "B07_DesignDetail_UI_Pan }; await pickSheet("plan_k_route"); out.routeHead = head().textContent; - byText(head(), "BUTTON", "확정 풀기")[0].click(); - await settle(); - await settle(); - out.release = { - call: calls.find((c) => c[0] === "invalidate"), - head: head().textContent, - preview: cad.loads.at(-1).drawing.entities[0].id, - }; // 닫기 — 고친 게 있으니 changed = true · 미리보기 듣기 멈춤 modal.opts.beforeClose(); diff --git a/resources/tester/test_130_b07_plan_manage.py b/resources/tester/test_130_b07_plan_manage.py index 457190f4f..23542bb27 100644 --- a/resources/tester/test_130_b07_plan_manage.py +++ b/resources/tester/test_130_b07_plan_manage.py @@ -5,7 +5,7 @@ - 좌측 「평면도」 = 장 단추 + [평면도 관리] 하나 · 종류 폼 · 대피소 칸 · × 없음. - 단추 → 공용 모달(큰 창) · 안에 종류 목록 · 종류 폼 · 대피소 · 사토장 자리 · 장 목록 · 첫 장 미리보기(보기 전용). - 종류 추가 · 업데이트(축척 포함) · 지우기 = 지금 서버 길 · 고칠 때마다 모달 안을 다시 받음. - - 미리보기 장 바꾸기 · 확정이면 [확정 풀기](invalidate) · 닫으면 changed=True · [CAD 에서 열기] = 그 장 id. + - 미리보기 장 바꾸기 · 캔버스만(bare) · 확정 배지만(확정 풀기 없음 140-1) · 닫으면 changed=True · [CAD 에서 열기] = 그 장 id. Node 헬퍼 `helper_130_b07_plan_manage.cjs` 가 화면 그릇 흉내로 돌림. 화면은 사용자 확인. """ @@ -54,6 +54,7 @@ def test_첫_장_미리보기는_보기_전용(out): assert out["open"]["preview"] == "plan_k_terrain" extra = out["open"]["extra"] assert extra["readOnly"] is True and extra["viewOnly"] is True + assert extra["bare"] is True # 140-1 캔버스만(제목줄 · 리본 · 상태막대 없음) assert extra["recoveryScope"] == "b07-plan-preview" # 본 CAD 자동백업 칸과 안 겹침 @@ -82,12 +83,10 @@ def test_미리보기_장_바꾸기(out): assert "확정 전" in s2["head"] and "확정 풀기" not in s2["head"] -def test_확정이면_확정_풀기(out): - assert "확정 풀기" in out["routeHead"] - rel = out["release"] - assert rel["call"] == ["invalidate", "plan_k_route"] - assert "확정 풀기" not in rel["head"] - assert rel["preview"] == "plan_k_route" # 보던 장 그대로 +def test_확정이면_배지만(out): + # 140-1 확정 풀기는 메인 [수정] — 모달엔 배지 · [CAD 에서 열기]만 + assert "확정" in out["routeHead"] and "CAD 에서 열기" in out["routeHead"] + assert "확정 풀기" not in out["routeHead"] def test_닫으면_좌측_다시_읽기_신호(out): diff --git a/ui_template/cad_host/cad_host.ts b/ui_template/cad_host/cad_host.ts index 2931d1e82..cd0f3d601 100644 --- a/ui_template/cad_host/cad_host.ts +++ b/ui_template/cad_host/cad_host.ts @@ -77,6 +77,8 @@ export interface CadLoadExtra { panelsCollapsed?: boolean; /** 미리보기 — 왼쪽 끌기 = 화면 옮기기 · 두 번 누름 = 전체 맞춤 · 선택 · 명령 안내 없음. */ viewOnly?: boolean; + /** 캔버스만 — 제목줄 · 리본 · 패널 · 상태막대를 안 그린다(B07 평면도 관리 모달). */ + bare?: boolean; /** 좌표 0,0 에 기준점 십자를 그린다(그리기 겹판 · 저장 안 됨) — 안 보내면 없음. */ originMarker?: boolean; }