Merge remote-tracking branch 'origin/sub_laptop_4' into sub_laptop_1
This commit is contained in:
@@ -149,6 +149,7 @@ body > canvas[data-id="canvas"] {
|
|||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
background: var(--cad-chrome-raised);
|
background: var(--cad-chrome-raised);
|
||||||
border-bottom: 1px solid var(--cad-line);
|
border-bottom: 1px solid var(--cad-line);
|
||||||
|
transition: height 120ms ease;
|
||||||
}
|
}
|
||||||
.cad-ribbon-tabs {
|
.cad-ribbon-tabs {
|
||||||
display: flex;
|
display: flex;
|
||||||
@@ -157,6 +158,21 @@ body > canvas[data-id="canvas"] {
|
|||||||
padding: 0 8px;
|
padding: 0 8px;
|
||||||
border-bottom: 1px solid var(--cad-line);
|
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 {
|
.cad-ribbon-tabs button {
|
||||||
padding: 0 14px;
|
padding: 0 14px;
|
||||||
border: 1px solid transparent;
|
border: 1px solid transparent;
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ import { QuickAccessBar } from './QuickAccessBar';
|
|||||||
import { Ribbon } from '../ribbon/Ribbon';
|
import { Ribbon } from '../ribbon/Ribbon';
|
||||||
import { StatusBar } from './StatusBar';
|
import { StatusBar } from './StatusBar';
|
||||||
import { useCadRefresh } from './use-cad-refresh';
|
import { useCadRefresh } from './use-cad-refresh';
|
||||||
|
import { isRibbonCollapsed } from './ui-state';
|
||||||
import { getActiveToolActor } from '../state';
|
import { getActiveToolActor } from '../state';
|
||||||
import type { Tool } from '../tools';
|
import type { Tool } from '../tools';
|
||||||
import { ViewControls } from './ViewControls';
|
import { ViewControls } from './ViewControls';
|
||||||
@@ -22,6 +23,7 @@ export const Toolbar: FC = () => {
|
|||||||
const [commandLineVisible, setCommandLineVisible] = useState(false);
|
const [commandLineVisible, setCommandLineVisible] = useState(false);
|
||||||
|
|
||||||
const activeTool = (getActiveToolActor()?.getSnapshot()?.context?.type ?? null) as Tool | null;
|
const activeTool = (getActiveToolActor()?.getSnapshot()?.context?.type ?? null) as Tool | null;
|
||||||
|
const ribbonCollapsed = isRibbonCollapsed();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
// 편 상태의 폭은 App.css의 `--cad-panel-width` 기본값을 쓴다. 여기 숫자를 박아
|
// 편 상태의 폭은 App.css의 `--cad-panel-width` 기본값을 쓴다. 여기 숫자를 박아
|
||||||
@@ -32,8 +34,11 @@ export const Toolbar: FC = () => {
|
|||||||
'--cad-command-height',
|
'--cad-command-height',
|
||||||
commandLineVisible ? '86px' : '0px'
|
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'));
|
window.dispatchEvent(new Event('resize'));
|
||||||
}, [panelCollapsed, commandLineVisible]);
|
}, [panelCollapsed, commandLineVisible, ribbonCollapsed]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
|||||||
@@ -12,6 +12,8 @@ let inspectorCollapsed = false;
|
|||||||
let quickPropertiesVisible = false;
|
let quickPropertiesVisible = false;
|
||||||
let activeRibbonTab = 'home';
|
let activeRibbonTab = 'home';
|
||||||
let blockLibraryVisible = false;
|
let blockLibraryVisible = false;
|
||||||
|
/** 호스트(M02)가 처음부터 접어 실을 때 true — 탭을 누르면 펼침(`setActiveRibbonTab`). */
|
||||||
|
let ribbonCollapsed = false;
|
||||||
|
|
||||||
const notify = () => notifyWindow(HtmlEvent.UPDATE_STATE);
|
const notify = () => notifyWindow(HtmlEvent.UPDATE_STATE);
|
||||||
|
|
||||||
@@ -20,12 +22,18 @@ export const isInspectorCollapsed = () => inspectorCollapsed;
|
|||||||
export const isQuickPropertiesVisible = () => quickPropertiesVisible;
|
export const isQuickPropertiesVisible = () => quickPropertiesVisible;
|
||||||
export const getActiveRibbonTab = () => activeRibbonTab;
|
export const getActiveRibbonTab = () => activeRibbonTab;
|
||||||
export const isBlockLibraryVisible = () => blockLibraryVisible;
|
export const isBlockLibraryVisible = () => blockLibraryVisible;
|
||||||
|
export const isRibbonCollapsed = () => ribbonCollapsed;
|
||||||
|
|
||||||
export function setActiveRibbonTab(tabId: string): void {
|
export function setActiveRibbonTab(tabId: string): void {
|
||||||
activeRibbonTab = tabId;
|
activeRibbonTab = tabId;
|
||||||
notify();
|
notify();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function setRibbonCollapsed(collapsed: boolean): void {
|
||||||
|
ribbonCollapsed = collapsed;
|
||||||
|
notify();
|
||||||
|
}
|
||||||
|
|
||||||
export function openInspector(tab: InspectorTab): void {
|
export function openInspector(tab: InspectorTab): void {
|
||||||
inspectorTab = tab;
|
inspectorTab = tab;
|
||||||
inspectorCollapsed = false;
|
inspectorCollapsed = false;
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ import {
|
|||||||
setHostTitle,
|
setHostTitle,
|
||||||
setLayers,
|
setLayers,
|
||||||
} from '../state.ts';
|
} from '../state.ts';
|
||||||
|
import { setRibbonCollapsed } from '../components/ui-state.ts';
|
||||||
import { toast } from 'react-toastify';
|
import { toast } from 'react-toastify';
|
||||||
import { runCommandInput } from '../commands/run-command.ts';
|
import { runCommandInput } from '../commands/run-command.ts';
|
||||||
import { setRecoveryScope } from '../helpers/autosave.ts';
|
import { setRecoveryScope } from '../helpers/autosave.ts';
|
||||||
@@ -57,6 +58,8 @@ interface DrawingLoadMessage {
|
|||||||
hostTitle?: string;
|
hostTitle?: string;
|
||||||
/** 저장(💾 · Ctrl+S)을 부모 [저장]에 맡기는가. */
|
/** 저장(💾 · Ctrl+S)을 부모 [저장]에 맡기는가. */
|
||||||
hostSave?: boolean;
|
hostSave?: boolean;
|
||||||
|
/** 리본을 접힌 채로 여는가 — 없으면(B07) 펼침 그대로. */
|
||||||
|
ribbonCollapsed?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface DrawingSaveRequestMessage {
|
interface DrawingSaveRequestMessage {
|
||||||
@@ -207,6 +210,7 @@ export function registerAisloDrawingBridge() {
|
|||||||
setHostReadOnly(event.data.readOnly === true);
|
setHostReadOnly(event.data.readOnly === true);
|
||||||
setHostTitle(event.data.hostTitle ?? 'B07 상세 설계');
|
setHostTitle(event.data.hostTitle ?? 'B07 상세 설계');
|
||||||
setHostSave(event.data.hostSave === true);
|
setHostSave(event.data.hostSave === true);
|
||||||
|
setRibbonCollapsed(event.data.ribbonCollapsed === true);
|
||||||
if (event.data.frameEdit) applyFramePreview();
|
if (event.data.frameEdit) applyFramePreview();
|
||||||
// 앞 도면에서 켜 둔 그리기 도구를 내린다. 안 내리면 **확정한 도면 위에도**
|
// 앞 도면에서 켜 둔 그리기 도구를 내린다. 안 내리면 **확정한 도면 위에도**
|
||||||
// 그 도구가 계속 그린다 — 읽기 전용은 새 명령만 막기 때문이다(2026-09-01 실측:
|
// 그 도구가 계속 그린다 — 읽기 전용은 새 명령만 막기 때문이다(2026-09-01 실측:
|
||||||
|
|||||||
@@ -3,7 +3,12 @@ import { type FC, type ReactNode, useEffect, useRef, useState } from 'react';
|
|||||||
import type { CadCommand } from '../commands/command.types';
|
import type { CadCommand } from '../commands/command.types';
|
||||||
import { getCommandById } from '../commands/registry';
|
import { getCommandById } from '../commands/registry';
|
||||||
import { runCommand } from '../commands/run-command';
|
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 type { Tool } from '../tools';
|
||||||
import { RIBBON_TABS, type RibbonPanel, type RibbonWidget } from './ribbon.config';
|
import { RIBBON_TABS, type RibbonPanel, type RibbonWidget } from './ribbon.config';
|
||||||
|
|
||||||
@@ -147,6 +152,7 @@ const Panel: FC<{
|
|||||||
export const Ribbon: FC<RibbonProps> = ({ activeTool, widgets, onCommandRun }) => {
|
export const Ribbon: FC<RibbonProps> = ({ activeTool, widgets, onCommandRun }) => {
|
||||||
const activeTabId = getActiveRibbonTab();
|
const activeTabId = getActiveRibbonTab();
|
||||||
const activeTab = RIBBON_TABS.find((tab) => tab.id === activeTabId) ?? RIBBON_TABS[0];
|
const activeTab = RIBBON_TABS.find((tab) => tab.id === activeTabId) ?? RIBBON_TABS[0];
|
||||||
|
const collapsed = isRibbonCollapsed();
|
||||||
|
|
||||||
const handleRun = (command: CadCommand) => {
|
const handleRun = (command: CadCommand) => {
|
||||||
runCommand(command);
|
runCommand(command);
|
||||||
@@ -161,23 +167,36 @@ export const Ribbon: FC<RibbonProps> = ({ activeTool, widgets, onCommandRun }) =
|
|||||||
type="button"
|
type="button"
|
||||||
key={tab.id}
|
key={tab.id}
|
||||||
data-active={tab.id === activeTab.id}
|
data-active={tab.id === activeTab.id}
|
||||||
onClick={() => setActiveRibbonTab(tab.id)}
|
onClick={() => {
|
||||||
|
setActiveRibbonTab(tab.id);
|
||||||
|
if (collapsed) setRibbonCollapsed(false);
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
{tab.label}
|
{tab.label}
|
||||||
</button>
|
</button>
|
||||||
))}
|
))}
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
className="cad-ribbon-tabs__collapse"
|
||||||
|
onClick={() => setRibbonCollapsed(!collapsed)}
|
||||||
|
title={collapsed ? '리본 펼치기' : '리본 접기'}
|
||||||
|
>
|
||||||
|
{collapsed ? '⌄' : '⌃'}
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div className="cad-ribbon-panels">
|
{!collapsed && (
|
||||||
{activeTab.panels.map((panel) => (
|
<div className="cad-ribbon-panels">
|
||||||
<Panel
|
{activeTab.panels.map((panel) => (
|
||||||
key={panel.label}
|
<Panel
|
||||||
panel={panel}
|
key={panel.label}
|
||||||
activeTool={activeTool}
|
panel={panel}
|
||||||
widgets={widgets}
|
activeTool={activeTool}
|
||||||
onRun={handleRun}
|
widgets={widgets}
|
||||||
/>
|
onRun={handleRun}
|
||||||
))}
|
/>
|
||||||
</div>
|
))}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</nav>
|
</nav>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -189,7 +189,13 @@ export function mountDrawingTemplate(
|
|||||||
null,
|
null,
|
||||||
!readOnly,
|
!readOnly,
|
||||||
{},
|
{},
|
||||||
{ recoveryScope, readOnly, hostTitle: "도면 양식 편집", hostSave: true },
|
{
|
||||||
|
recoveryScope,
|
||||||
|
readOnly,
|
||||||
|
hostTitle: "도면 양식 편집",
|
||||||
|
hostSave: true,
|
||||||
|
ribbonCollapsed: true,
|
||||||
|
},
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -63,6 +63,8 @@ export interface CadLoadExtra {
|
|||||||
hostTitle?: string;
|
hostTitle?: string;
|
||||||
/** 저장(💾 · Ctrl+S)을 부모 [저장]에 맡긴다 — 켜면 `onHostSave` 로 옴. */
|
/** 저장(💾 · Ctrl+S)을 부모 [저장]에 맡긴다 — 켜면 `onHostSave` 로 옴. */
|
||||||
hostSave?: boolean;
|
hostSave?: boolean;
|
||||||
|
/** 리본을 접힌 채로 연다 — 안 보내면 펼침 그대로. */
|
||||||
|
ribbonCollapsed?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface CadHost<D extends CadHostDrawing, M, Q> {
|
export interface CadHost<D extends CadHostDrawing, M, Q> {
|
||||||
|
|||||||
Reference in New Issue
Block a user