diff --git a/B07_DesignDetail/openwebcad/src/App.css b/B07_DesignDetail/openwebcad/src/App.css index fadc2fdc..1091d467 100644 --- a/B07_DesignDetail/openwebcad/src/App.css +++ b/B07_DesignDetail/openwebcad/src/App.css @@ -149,6 +149,7 @@ body > canvas[data-id="canvas"] { flex-direction: column; background: var(--cad-chrome-raised); border-bottom: 1px solid var(--cad-line); + transition: height 120ms ease; } .cad-ribbon-tabs { display: flex; @@ -157,6 +158,21 @@ body > canvas[data-id="canvas"] { padding: 0 8px; border-bottom: 1px solid var(--cad-line); } +.cad-ribbon-tabs__collapse { + margin-left: auto; + width: 24px; + height: 20px; + align-self: center; + padding: 0; + border: 1px solid transparent; + border-radius: 4px; + background: transparent; + color: var(--cad-text-dim); + font-size: 11px; +} +.cad-ribbon-tabs__collapse:hover { + background: var(--cad-hover); +} .cad-ribbon-tabs button { padding: 0 14px; border: 1px solid transparent; diff --git a/B07_DesignDetail/openwebcad/src/components/Toolbar.tsx b/B07_DesignDetail/openwebcad/src/components/Toolbar.tsx index c45c847c..f197d58e 100644 --- a/B07_DesignDetail/openwebcad/src/components/Toolbar.tsx +++ b/B07_DesignDetail/openwebcad/src/components/Toolbar.tsx @@ -12,6 +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 { getActiveToolActor } from '../state'; import type { Tool } from '../tools'; import { ViewControls } from './ViewControls'; @@ -22,6 +23,7 @@ export const Toolbar: FC = () => { const [commandLineVisible, setCommandLineVisible] = useState(false); const activeTool = (getActiveToolActor()?.getSnapshot()?.context?.type ?? null) as Tool | null; + const ribbonCollapsed = isRibbonCollapsed(); useEffect(() => { // 편 상태의 폭은 App.css의 `--cad-panel-width` 기본값을 쓴다. 여기 숫자를 박아 @@ -32,8 +34,11 @@ export const Toolbar: FC = () => { '--cad-command-height', commandLineVisible ? '86px' : '0px' ); + // 리본 접힘 — 탭 줄(26px)만 남기고 패널 줄 자리를 걷는다(`Ribbon.tsx` 가 안 그림). + 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]); + }, [panelCollapsed, commandLineVisible, ribbonCollapsed]); return ( <> diff --git a/B07_DesignDetail/openwebcad/src/components/ui-state.ts b/B07_DesignDetail/openwebcad/src/components/ui-state.ts index b6a19552..868f1375 100644 --- a/B07_DesignDetail/openwebcad/src/components/ui-state.ts +++ b/B07_DesignDetail/openwebcad/src/components/ui-state.ts @@ -12,6 +12,8 @@ let inspectorCollapsed = false; let quickPropertiesVisible = false; let activeRibbonTab = 'home'; let blockLibraryVisible = false; +/** 호스트(M02)가 처음부터 접어 실을 때 true — 탭을 누르면 펼침(`setActiveRibbonTab`). */ +let ribbonCollapsed = false; const notify = () => notifyWindow(HtmlEvent.UPDATE_STATE); @@ -20,12 +22,18 @@ export const isInspectorCollapsed = () => inspectorCollapsed; export const isQuickPropertiesVisible = () => quickPropertiesVisible; export const getActiveRibbonTab = () => activeRibbonTab; export const isBlockLibraryVisible = () => blockLibraryVisible; +export const isRibbonCollapsed = () => ribbonCollapsed; export function setActiveRibbonTab(tabId: string): void { activeRibbonTab = tabId; notify(); } +export function setRibbonCollapsed(collapsed: boolean): void { + ribbonCollapsed = collapsed; + notify(); +} + export function openInspector(tab: InspectorTab): void { inspectorTab = tab; inspectorCollapsed = false; diff --git a/B07_DesignDetail/openwebcad/src/integration/aislo-drawing-bridge.ts b/B07_DesignDetail/openwebcad/src/integration/aislo-drawing-bridge.ts index a29f203c..b42e3130 100644 --- a/B07_DesignDetail/openwebcad/src/integration/aislo-drawing-bridge.ts +++ b/B07_DesignDetail/openwebcad/src/integration/aislo-drawing-bridge.ts @@ -25,6 +25,7 @@ import { setHostTitle, setLayers, } from '../state.ts'; +import { setRibbonCollapsed } from '../components/ui-state.ts'; import { toast } from 'react-toastify'; import { runCommandInput } from '../commands/run-command.ts'; import { setRecoveryScope } from '../helpers/autosave.ts'; @@ -57,6 +58,8 @@ interface DrawingLoadMessage { hostTitle?: string; /** 저장(💾 · Ctrl+S)을 부모 [저장]에 맡기는가. */ hostSave?: boolean; + /** 리본을 접힌 채로 여는가 — 없으면(B07) 펼침 그대로. */ + ribbonCollapsed?: boolean; } interface DrawingSaveRequestMessage { @@ -207,6 +210,7 @@ export function registerAisloDrawingBridge() { setHostReadOnly(event.data.readOnly === true); setHostTitle(event.data.hostTitle ?? 'B07 상세 설계'); setHostSave(event.data.hostSave === true); + setRibbonCollapsed(event.data.ribbonCollapsed === true); if (event.data.frameEdit) applyFramePreview(); // 앞 도면에서 켜 둔 그리기 도구를 내린다. 안 내리면 **확정한 도면 위에도** // 그 도구가 계속 그린다 — 읽기 전용은 새 명령만 막기 때문이다(2026-09-01 실측: diff --git a/B07_DesignDetail/openwebcad/src/ribbon/Ribbon.tsx b/B07_DesignDetail/openwebcad/src/ribbon/Ribbon.tsx index 57fe1f00..b46d3c77 100644 --- a/B07_DesignDetail/openwebcad/src/ribbon/Ribbon.tsx +++ b/B07_DesignDetail/openwebcad/src/ribbon/Ribbon.tsx @@ -3,7 +3,12 @@ import { type FC, type ReactNode, useEffect, useRef, useState } from 'react'; import type { CadCommand } from '../commands/command.types'; import { getCommandById } from '../commands/registry'; import { runCommand } from '../commands/run-command'; -import { getActiveRibbonTab, setActiveRibbonTab } from '../components/ui-state'; +import { + getActiveRibbonTab, + isRibbonCollapsed, + setActiveRibbonTab, + setRibbonCollapsed, +} from '../components/ui-state'; import type { Tool } from '../tools'; import { RIBBON_TABS, type RibbonPanel, type RibbonWidget } from './ribbon.config'; @@ -147,6 +152,7 @@ const Panel: FC<{ export const Ribbon: FC = ({ activeTool, widgets, onCommandRun }) => { const activeTabId = getActiveRibbonTab(); const activeTab = RIBBON_TABS.find((tab) => tab.id === activeTabId) ?? RIBBON_TABS[0]; + const collapsed = isRibbonCollapsed(); const handleRun = (command: CadCommand) => { runCommand(command); @@ -161,23 +167,36 @@ export const Ribbon: FC = ({ activeTool, widgets, onCommandRun }) = type="button" key={tab.id} data-active={tab.id === activeTab.id} - onClick={() => setActiveRibbonTab(tab.id)} + onClick={() => { + setActiveRibbonTab(tab.id); + if (collapsed) setRibbonCollapsed(false); + }} > {tab.label} ))} + -
- {activeTab.panels.map((panel) => ( - - ))} -
+ {!collapsed && ( +
+ {activeTab.panels.map((panel) => ( + + ))} +
+ )} ); }; diff --git a/M02_MasterTemplete/M02_MasterTemplete_Drawing.ts b/M02_MasterTemplete/M02_MasterTemplete_Drawing.ts index 63ae1738..6c0bec41 100644 --- a/M02_MasterTemplete/M02_MasterTemplete_Drawing.ts +++ b/M02_MasterTemplete/M02_MasterTemplete_Drawing.ts @@ -189,7 +189,13 @@ export function mountDrawingTemplate( null, !readOnly, {}, - { recoveryScope, readOnly, hostTitle: "도면 양식 편집", hostSave: true }, + { + recoveryScope, + readOnly, + hostTitle: "도면 양식 편집", + hostSave: true, + ribbonCollapsed: true, + }, ); }; diff --git a/ui_template/cad_host/cad_host.ts b/ui_template/cad_host/cad_host.ts index 397138cd..d9c8a3c0 100644 --- a/ui_template/cad_host/cad_host.ts +++ b/ui_template/cad_host/cad_host.ts @@ -63,6 +63,8 @@ export interface CadLoadExtra { hostTitle?: string; /** 저장(💾 · Ctrl+S)을 부모 [저장]에 맡긴다 — 켜면 `onHostSave` 로 옴. */ hostSave?: boolean; + /** 리본을 접힌 채로 연다 — 안 보내면 펼침 그대로. */ + ribbonCollapsed?: boolean; } export interface CadHost {