Files
Aislo/B07_DesignDetail/openwebcad/src/components/PropertiesEditor.tsx
T
eomsangdonandClaude Opus 5.5 de250ab759 refactor(cad): CAD 앱 겉 자체 변종을 부품 상자 부품으로 — 상태막대 켜기 칩 · 패널 탭 · 떠 있는 판 · 메뉴 · 아이콘 단추 · 확인창 (PLAN 553-6)
- 부품 상자 CSS · 단추 기본 꼴을 CAD iframe 에 실음(integration/ui-kit.ts) · 자리 · 폭은 cad-* 그대로
- 상태막대 = ui-toggle--chip 22 · 특성/레이어 = ui-tabs 36 · ↶↷ · 리본 접기 · 탐색 막대 = ui-icon-btn 20 · 32
- 빠른 특성 · 블록 라이브러리 · 자리표 = ui-float-panel · 리본 넘침 · 스냅 · 명령 자동완성 = ui-ctx-menu
- window.confirm · window.prompt → askConfirm · askText · 빈 안내 = ui-empty 작은 꼴
- 높이 단: 리본 칸 19→18 · 명령 칸 26→28 · 레이어 줄 40→42 · 문서 탭 25→24 · 도각 편집 단추 24
- 마우스 바탕 = --color-hover · 켜짐 = --color-accent-soft · 도면 그림 색(--draw-*) 안 건드림
- 안 쓰는 DropdownButton 지움(쓰는 곳 0 · grep)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-26 22:35:43 +09:00

166 lines
4.3 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/** 특성 팔레트 본문 — 선택 객체의 값을 읽고 바로 고친다 (PROPERTIES) */
import type { FC } from 'react';
import type { Entity } from '../entities/Entity';
import { polylineLength, sampleEntityPoints } from '../helpers/geometry/sample-entity';
import {
commonValue,
LINE_TYPES,
LINE_WIDTHS,
paintNowCommitLater,
restyle,
selectionLineStyle,
styleTargets,
} from '../helpers/selection-style';
import { getLayers, getSelectedEntities } from '../state';
interface PropertiesEditorProps {
compact?: boolean;
}
/** 고른 것을 사본으로 바꿈 — 되돌리기 한 칸(488) · 선 특성은 글 뺌 */
const applyToSelection = (mutate: (entity: Entity) => void) =>
restyle(getSelectedEntities(), mutate);
const applyToLines = (mutate: (entity: Entity) => void) =>
restyle(styleTargets(getSelectedEntities()), mutate);
/** 여러 객체가 값이 다르면 빈 칸(488 · 리본과 같은 규칙 · 고르면 모두에 적용) */
export const PropertiesEditor: FC<PropertiesEditorProps> = ({ compact = false }) => {
const selected = getSelectedEntities();
const layers = getLayers();
const first = selected[0];
const view = selectionLineStyle();
if (!first) {
return (
<div className="ui-empty ui-empty--small">
<p className="ui-empty__text">선택된 객체가 없습니다.</p>
</div>
);
}
const points = sampleEntityPoints(first);
const box = first.getBoundingBox();
return (
<div className="cad-properties-editor" data-compact={compact}>
<div className="cad-properties-editor__title">
{selected.length === 1 ? first.getType() : `여러 객체 (${selected.length})`}
</div>
<label>
<span>색상</span>
<input
type="color"
value={view.color || '#000000'}
data-mixed={view.color ? undefined : 'true'}
onChange={(event) => {
// 끄는 동안 = 화면만 · 멎은 뒤 되돌리기 한 칸(리본 색 칸과 같은 길)
const color = event.target.value;
paintNowCommitLater(styleTargets(getSelectedEntities()), (entity) => {
entity.lineColor = color;
});
}}
/>
</label>
<label>
<span>선 두께</span>
<select
value={view.width}
onChange={(event) =>
applyToLines((entity) => {
entity.lineWidth = Number(event.target.value);
})
}
>
<option value="" hidden />
{LINE_WIDTHS.map((width) => (
<option key={width} value={width}>
{width}px
</option>
))}
</select>
</label>
<label>
<span>선종류</span>
<select
value={view.lineType}
onChange={(event) => {
const dash = LINE_TYPES.find((type) => type.value === event.target.value)?.dash;
applyToLines((entity) => {
entity.lineDash = dash ? [...dash] : undefined;
});
}}
>
<option value="" hidden />
{LINE_TYPES.map((type) => (
<option key={type.value} value={type.value}>
{type.label}
</option>
))}
</select>
</label>
<label>
<span>레이어</span>
<select
value={commonValue(selected, (entity) => entity.layerId)}
onChange={(event) =>
applyToSelection((entity) => {
entity.layerId = event.target.value;
})
}
>
<option value="" hidden />
{layers.map((layer) => (
<option key={layer.id} value={layer.id}>
{layer.name}
</option>
))}
</select>
</label>
<label>
<span>투명도</span>
<input
type="number"
min={0}
max={90}
step={5}
value={Math.round((1 - (first.opacity ?? 1)) * 100)}
onChange={(event) => {
const percent = Math.min(90, Math.max(0, Number(event.target.value)));
applyToSelection((entity) => {
entity.opacity = 1 - percent / 100;
});
}}
/>
</label>
{!compact && (
<dl className="cad-properties-editor__readout">
<div>
<dt>길이</dt>
<dd>{polylineLength(points).toFixed(3)}</dd>
</div>
<div>
<dt>크기</dt>
<dd>
{(box.xmax - box.xmin).toFixed(3)} × {(box.ymax - box.ymin).toFixed(3)}
</dd>
</div>
<div>
<dt>시작점</dt>
<dd>{points[0] ? `${points[0].x.toFixed(2)}, ${points[0].y.toFixed(2)}` : '-'}</dd>
</div>
<div>
<dt>그룹</dt>
<dd>{first.groupId ? '있음' : '없음'}</dd>
</div>
</dl>
)}
</div>
);
};