feat(cad): 구조물 도면 미리보기 좌측 패널은 접힌 채로 엶 · 리본 접힘 모드에서 탭으로 편 리본은 밖을 누르면 다시 접힘
- M02 미리보기: 특성 · 도면층 패널을 숨기던 스타일에서 .cad-inspector 뺌 · load 곁값 panelsCollapsed: true 로 접힌 채 시작(› 누르면 펼침) - cad_host CadLoadExtra · 다리에 panelsCollapsed 칸 · B07 은 안 보냄 = 지금처럼 펼침 - 좌측 패널 접힘 상태를 ui-state 로 옮김 - 리본: 접힘 모드에서 탭 = 도면 위에 겹쳐 잠깐 펼침 · 리본 밖 누름 = 다시 접힘 · 접기 단추 = 고정 펼침 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EUypcnp5d1gU2aeKh9F2H7
This commit is contained in:
@@ -151,6 +151,12 @@ body > canvas[data-id="canvas"] {
|
||||
border-bottom: 1px solid var(--cad-line);
|
||||
transition: height 120ms ease;
|
||||
}
|
||||
/* 접힘 모드에서 탭으로 잠깐 펼침 — 도면 자리는 그대로 두고 위에 겹쳐 뜸(122px = 펼친 리본 높이) */
|
||||
.cad-ribbon[data-peek="true"] {
|
||||
z-index: 10;
|
||||
height: 122px;
|
||||
box-shadow: var(--shadow-lg);
|
||||
}
|
||||
.cad-ribbon-tabs {
|
||||
display: flex;
|
||||
gap: 2px;
|
||||
|
||||
@@ -12,7 +12,7 @@ import { QuickAccessBar } from './QuickAccessBar';
|
||||
import { Ribbon } from '../ribbon/Ribbon';
|
||||
import { StatusBar } from './StatusBar';
|
||||
import { useCadRefresh } from './use-cad-refresh';
|
||||
import { isRibbonCollapsed } from './ui-state';
|
||||
import { isInspectorCollapsed, isRibbonCollapsed, setInspectorCollapsed } from './ui-state';
|
||||
import { getActiveToolActor } from '../state';
|
||||
import type { Tool } from '../tools';
|
||||
import { ViewControls } from './ViewControls';
|
||||
@@ -20,11 +20,12 @@ import { DropHint } from './DropHint';
|
||||
|
||||
export const Toolbar: FC = () => {
|
||||
useCadRefresh();
|
||||
const [panelCollapsed, setPanelCollapsed] = useState(false);
|
||||
const [commandLineVisible, setCommandLineVisible] = useState(false);
|
||||
|
||||
const activeTool = (getActiveToolActor()?.getSnapshot()?.context?.type ?? null) as Tool | null;
|
||||
const ribbonCollapsed = isRibbonCollapsed();
|
||||
// 좌측 패널 접힘 — 호스트(M02 미리보기)가 접힌 채로 실을 수 있게 ui-state 에 둔다
|
||||
const panelCollapsed = isInspectorCollapsed();
|
||||
|
||||
useEffect(() => {
|
||||
// 편 상태의 폭은 App.css의 `--cad-panel-width` 기본값을 쓴다. 여기 숫자를 박아
|
||||
@@ -54,7 +55,7 @@ export const Toolbar: FC = () => {
|
||||
/>
|
||||
<InspectorPanel
|
||||
collapsed={panelCollapsed}
|
||||
onToggleCollapsed={() => setPanelCollapsed((value) => !value)}
|
||||
onToggleCollapsed={() => setInspectorCollapsed(!panelCollapsed)}
|
||||
/>
|
||||
<ViewControls />
|
||||
<DropHint />
|
||||
|
||||
@@ -25,7 +25,7 @@ import {
|
||||
setHostTitle,
|
||||
setLayers,
|
||||
} from '../state.ts';
|
||||
import { setRibbonCollapsed } from '../components/ui-state.ts';
|
||||
import { setInspectorCollapsed, setRibbonCollapsed } from '../components/ui-state.ts';
|
||||
import { toast } from 'react-toastify';
|
||||
import { runCommandInput } from '../commands/run-command.ts';
|
||||
import { setRecoveryScope } from '../helpers/autosave.ts';
|
||||
@@ -60,6 +60,8 @@ interface DrawingLoadMessage {
|
||||
hostSave?: boolean;
|
||||
/** 리본을 접힌 채로 여는가 — 없으면(B07) 펼침 그대로. */
|
||||
ribbonCollapsed?: boolean;
|
||||
/** 좌측 패널(특성 · 도면층)을 접힌 채로 여는가 — 없으면(B07) 지금 상태 그대로. */
|
||||
panelsCollapsed?: boolean;
|
||||
}
|
||||
|
||||
interface DrawingSaveRequestMessage {
|
||||
@@ -211,6 +213,7 @@ export function registerAisloDrawingBridge() {
|
||||
setHostTitle(event.data.hostTitle ?? 'B07 상세 설계');
|
||||
setHostSave(event.data.hostSave === true);
|
||||
setRibbonCollapsed(event.data.ribbonCollapsed === true);
|
||||
if (event.data.panelsCollapsed) setInspectorCollapsed(true);
|
||||
if (event.data.frameEdit) applyFramePreview();
|
||||
// 앞 도면에서 켜 둔 그리기 도구를 내린다. 안 내리면 **확정한 도면 위에도**
|
||||
// 그 도구가 계속 그린다 — 읽기 전용은 새 명령만 막기 때문이다(2026-09-01 실측:
|
||||
|
||||
@@ -153,6 +153,20 @@ export const Ribbon: FC<RibbonProps> = ({ activeTool, widgets, onCommandRun }) =
|
||||
const activeTabId = getActiveRibbonTab();
|
||||
const activeTab = RIBBON_TABS.find((tab) => tab.id === activeTabId) ?? RIBBON_TABS[0];
|
||||
const collapsed = isRibbonCollapsed();
|
||||
// 접힘 모드에서 탭을 누르면 잠깐 펼침(도면 위에 겹쳐 뜸) — 리본 밖을 누르면 다시 접힘
|
||||
// (오피스 「리본 자동 숨기기」). 접기 단추로 펼치면 고정 펼침.
|
||||
const [peek, setPeek] = useState(false);
|
||||
const navRef = useRef<HTMLElement>(null);
|
||||
const peeking = collapsed && peek;
|
||||
|
||||
useEffect(() => {
|
||||
if (!peeking) return;
|
||||
const close = (event: PointerEvent) => {
|
||||
if (!navRef.current?.contains(event.target as Node)) setPeek(false);
|
||||
};
|
||||
window.addEventListener('pointerdown', close, true);
|
||||
return () => window.removeEventListener('pointerdown', close, true);
|
||||
}, [peeking]);
|
||||
|
||||
const handleRun = (command: CadCommand) => {
|
||||
runCommand(command);
|
||||
@@ -160,7 +174,7 @@ export const Ribbon: FC<RibbonProps> = ({ activeTool, widgets, onCommandRun }) =
|
||||
};
|
||||
|
||||
return (
|
||||
<nav className="cad-ribbon controls" aria-label="CAD 리본">
|
||||
<nav ref={navRef} className="cad-ribbon controls" aria-label="CAD 리본" data-peek={peeking}>
|
||||
<div className="cad-ribbon-tabs">
|
||||
{RIBBON_TABS.map((tab) => (
|
||||
<button
|
||||
@@ -169,7 +183,7 @@ export const Ribbon: FC<RibbonProps> = ({ activeTool, widgets, onCommandRun }) =
|
||||
data-active={tab.id === activeTab.id}
|
||||
onClick={() => {
|
||||
setActiveRibbonTab(tab.id);
|
||||
if (collapsed) setRibbonCollapsed(false);
|
||||
if (collapsed) setPeek(true);
|
||||
}}
|
||||
>
|
||||
{tab.label}
|
||||
@@ -178,13 +192,16 @@ export const Ribbon: FC<RibbonProps> = ({ activeTool, widgets, onCommandRun }) =
|
||||
<button
|
||||
type="button"
|
||||
className="cad-ribbon-tabs__collapse"
|
||||
onClick={() => setRibbonCollapsed(!collapsed)}
|
||||
onClick={() => {
|
||||
setPeek(false);
|
||||
setRibbonCollapsed(!collapsed);
|
||||
}}
|
||||
title={collapsed ? '리본 펼치기' : '리본 접기'}
|
||||
>
|
||||
{collapsed ? '⌄' : '⌃'}
|
||||
</button>
|
||||
</div>
|
||||
{!collapsed && (
|
||||
{(!collapsed || peeking) && (
|
||||
<div className="cad-ribbon-panels">
|
||||
{activeTab.panels.map((panel) => (
|
||||
<Panel
|
||||
|
||||
@@ -39,6 +39,8 @@ export interface DrawingTemplateOptions {
|
||||
onChanged?: (dirty: boolean) => void;
|
||||
/** 페이지 제목 줄 안의 빈 칸 — 있으면 작도 영역 칸 · 파일 불러오기를 거기 한 줄로 놓는다. */
|
||||
headerSlot?: HTMLElement;
|
||||
/** CAD 좌측 패널(특성 · 도면층)을 접힌 채로 연다 — 누르면 펼침(구조물 도면 미리보기). */
|
||||
panelsCollapsed?: boolean;
|
||||
}
|
||||
|
||||
const RECOVERY_PREFIX = "OPEN_WEB_CAD__RECOVERY__";
|
||||
@@ -195,6 +197,7 @@ export function mountDrawingTemplate(
|
||||
hostTitle: "도면 양식 편집",
|
||||
hostSave: true,
|
||||
ribbonCollapsed: true,
|
||||
panelsCollapsed: options.panelsCollapsed,
|
||||
},
|
||||
);
|
||||
};
|
||||
|
||||
@@ -333,8 +333,7 @@ export function createStructurePanel(opts: StructurePanelOptions): StructurePane
|
||||
if (!inner?.head || inner.getElementById("m02-struct-hide")) return;
|
||||
const style = inner.createElement("style");
|
||||
style.id = "m02-struct-hide";
|
||||
style.textContent =
|
||||
".cad-titlebar, .cad-ribbon, .cad-inspector { display: none !important; }";
|
||||
style.textContent = ".cad-titlebar, .cad-ribbon { display: none !important; }";
|
||||
inner.head.append(style);
|
||||
};
|
||||
frame.addEventListener("load", apply);
|
||||
@@ -377,6 +376,7 @@ export function createStructurePanel(opts: StructurePanelOptions): StructurePane
|
||||
readOnly: true,
|
||||
name: `preview:${column ?? ""}`,
|
||||
layer: "system",
|
||||
panelsCollapsed: true, // 특성 · 도면층 패널은 접힌 채 — › 를 누르면 펼침
|
||||
});
|
||||
const frame = previewHost.querySelector("iframe");
|
||||
if (frame) hideToolbar(frame);
|
||||
|
||||
@@ -125,3 +125,23 @@ def test_열_머리_글_잇기():
|
||||
"SD010101 돌기슭막이 H=1.0",
|
||||
"돌기슭막이",
|
||||
]
|
||||
|
||||
|
||||
def test_미리보기_CAD_패널은_숨기지_않고_접힌_채로_엶():
|
||||
"""특성 · 도면층 패널을 숨기지 않음 — 곁값 panelsCollapsed 로 접어 실음(B07 은 안 보냄)."""
|
||||
panel = _text(PANEL)
|
||||
assert ".cad-inspector" not in panel and "panelsCollapsed: true" in panel
|
||||
drawing = _text(M02 / "M02_MasterTemplete_Drawing.ts")
|
||||
assert "panelsCollapsed: options.panelsCollapsed" in drawing
|
||||
assert "panelsCollapsed?: boolean" in _text(ROOT / "ui_template/cad_host/cad_host.ts")
|
||||
cad = ROOT / "B07_DesignDetail/openwebcad/src"
|
||||
bridge = _text(cad / "integration/aislo-drawing-bridge.ts")
|
||||
assert "if (event.data.panelsCollapsed) setInspectorCollapsed(true);" in bridge
|
||||
assert "isInspectorCollapsed()" in _text(cad / "components/Toolbar.tsx")
|
||||
|
||||
|
||||
def test_리본_접힘_모드에서_탭으로_편_것은_밖을_누르면_다시_접힘():
|
||||
ribbon = _text(ROOT / "B07_DesignDetail/openwebcad/src/ribbon/Ribbon.tsx")
|
||||
assert "if (collapsed) setPeek(true);" in ribbon # 탭 = 잠깐 펼침(접힘 모드 유지)
|
||||
assert "addEventListener('pointerdown', close, true)" in ribbon # 리본 밖 = 다시 접힘
|
||||
assert "setPeek(false);" in ribbon and "setRibbonCollapsed(!collapsed);" in ribbon # 단추
|
||||
|
||||
@@ -65,6 +65,8 @@ export interface CadLoadExtra {
|
||||
hostSave?: boolean;
|
||||
/** 리본을 접힌 채로 연다 — 안 보내면 펼침 그대로. */
|
||||
ribbonCollapsed?: boolean;
|
||||
/** 좌측 패널(특성 · 도면층)을 접힌 채로 연다 — 안 보내면(B07) 지금 상태 그대로. */
|
||||
panelsCollapsed?: boolean;
|
||||
}
|
||||
|
||||
export interface CadHost<D extends CadHostDrawing, M, Q> {
|
||||
|
||||
Reference in New Issue
Block a user