style(cad): CAD 앱 겉을 앱 공통 값 · 크기 단 · 확인창 부품으로 — window.confirm · prompt 걷음 (PLAN 553-6)
- 블록 이름 묻기 = 부품 글 묻기(askText) · 블록 지우기 = 위험 확인(showConfirmDialog) — CAD 창 안에 앱과 같은 확인창 꼴(injectBaseStyles) - 크기 단 — 리본 특성 칸 19 → 18 · 빠른 실행 24×20 → 20 · 상태막대 단추 21 → 22 · 명령 칸 26 → 28 · 왼쪽 판 탭 38 → 36 · Button 40 → 42 · 블록 · 자리표 단추 22 · 24 · 큰 리본 도구 66 · 리본 탭 줄은 꼴 그대로 - 마우스 바탕 = --color-hover · 켜짐 바탕 = --color-accent-soft(옛 보라 별칭 걷음) · 떠 있는 판 · 메뉴 둥글기 = 공통 값(날 2 · 3 · 5 px 11 곳 → 0) - 안 쓰는 DropdownButton 지움(grep 0) · 그림(캔버스 바탕 · --draw-*) 전후 같음 · B07 전후 촬영 CAD 안 배치 바뀜 = 빠른 실행 칸만 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -27,7 +27,9 @@
|
||||
--cad-text-dim: var(--color-text-secondary);
|
||||
--cad-text-muted: var(--color-text-muted);
|
||||
--cad-accent: var(--color-accent);
|
||||
--cad-hover: var(--color-mist-violet);
|
||||
--cad-hover: var(--color-hover);
|
||||
/* 켜짐 바탕 = 앱 켜기 꼴(553-6) */
|
||||
--cad-on: var(--color-accent-soft);
|
||||
--cad-canvas: var(--draw-canvas);
|
||||
}
|
||||
|
||||
@@ -197,7 +199,7 @@ body > canvas[data-id="canvas"] {
|
||||
overflow-y: auto;
|
||||
background: var(--cad-chrome-raised);
|
||||
border: 1px solid var(--cad-line);
|
||||
border-radius: 4px;
|
||||
border-radius: var(--radius-cards);
|
||||
box-shadow: var(--shadow-lg);
|
||||
}
|
||||
.cad-ribbon-overflow button {
|
||||
@@ -206,7 +208,7 @@ body > canvas[data-id="canvas"] {
|
||||
align-items: center;
|
||||
padding: 5px 8px;
|
||||
border: 0;
|
||||
border-radius: 3px;
|
||||
border-radius: var(--radius-sm);
|
||||
background: transparent;
|
||||
font-size: 11px;
|
||||
text-align: left;
|
||||
@@ -220,7 +222,7 @@ body > canvas[data-id="canvas"] {
|
||||
align-self: center;
|
||||
}
|
||||
.cad-ribbon-tabs .cad-quick-access button {
|
||||
width: 24px;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
padding: 0;
|
||||
border: 1px solid transparent;
|
||||
@@ -254,13 +256,13 @@ body > canvas[data-id="canvas"] {
|
||||
}
|
||||
.cad-prop select,
|
||||
.cad-prop input[type="number"] {
|
||||
height: 19px;
|
||||
height: 18px;
|
||||
min-width: 78px;
|
||||
padding: 0 3px;
|
||||
color: var(--cad-text);
|
||||
background: var(--cad-chrome-sunken);
|
||||
border: 1px solid var(--cad-line);
|
||||
border-radius: 3px;
|
||||
border-radius: 4px;
|
||||
font-size: 11px;
|
||||
}
|
||||
.cad-prop input[type="number"] {
|
||||
@@ -268,13 +270,13 @@ body > canvas[data-id="canvas"] {
|
||||
width: 52px;
|
||||
}
|
||||
.cad-prop input[type="color"] {
|
||||
height: 19px;
|
||||
height: 18px;
|
||||
width: 44px;
|
||||
padding: 1px;
|
||||
background: var(--cad-chrome-sunken);
|
||||
/* 흰색을 골라도 스와치 자리가 보이게 테두리를 진하게 준다 (2026-09-01) */
|
||||
border: 1px solid var(--cad-text-muted);
|
||||
border-radius: 3px;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
}
|
||||
/* 고른 것들 색이 다름(488) — 빈 견본(투명 · 점선 테두리) */
|
||||
@@ -283,6 +285,7 @@ input[type="color"][data-mixed="true"]::-webkit-color-swatch { background: trans
|
||||
.cad-ribbon-props .cad-tool[data-size="small"] {
|
||||
height: 22px;
|
||||
min-width: 0;
|
||||
border-radius: 4px;
|
||||
}
|
||||
.cad-tool {
|
||||
display: flex;
|
||||
@@ -293,7 +296,7 @@ input[type="color"][data-mixed="true"]::-webkit-color-swatch { background: trans
|
||||
min-width: 48px;
|
||||
padding: 3px 6px;
|
||||
border: 1px solid transparent;
|
||||
border-radius: 3px;
|
||||
border-radius: var(--radius-buttons);
|
||||
background: transparent;
|
||||
font-size: 10px;
|
||||
white-space: nowrap;
|
||||
@@ -328,7 +331,7 @@ input[type="color"][data-mixed="true"]::-webkit-color-swatch { background: trans
|
||||
}
|
||||
.cad-tool[data-active="true"] {
|
||||
border-color: var(--cad-accent);
|
||||
background: var(--cad-hover);
|
||||
background: var(--cad-on);
|
||||
box-shadow: inset 0 -2px var(--cad-accent);
|
||||
}
|
||||
.cad-tool:disabled {
|
||||
@@ -376,7 +379,7 @@ input[type="color"][data-mixed="true"]::-webkit-color-swatch { background: trans
|
||||
.cad-inspector-tabs {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
height: 38px;
|
||||
height: 36px;
|
||||
border-bottom: 1px solid var(--cad-line);
|
||||
}
|
||||
.cad-inspector-tabs button {
|
||||
|
||||
@@ -41,7 +41,7 @@
|
||||
align-items: center;
|
||||
overflow: hidden;
|
||||
border: 1px solid var(--cad-line);
|
||||
border-radius: 4px;
|
||||
border-radius: var(--radius-buttons);
|
||||
background: var(--cad-chrome-raised);
|
||||
box-shadow: var(--shadow-lg);
|
||||
}
|
||||
@@ -144,13 +144,13 @@ body.cad-file-dragging::after {
|
||||
padding: 4px;
|
||||
background: var(--cad-chrome-raised);
|
||||
border: 1px solid var(--cad-line);
|
||||
border-radius: 4px;
|
||||
border-radius: var(--radius-cards);
|
||||
box-shadow: var(--shadow-lg);
|
||||
}
|
||||
.cad-command-suggestions button {
|
||||
padding: 4px 8px;
|
||||
border: 0;
|
||||
border-radius: 3px;
|
||||
border-radius: var(--radius-sm);
|
||||
background: transparent;
|
||||
font: 11px Consolas, monospace;
|
||||
text-align: left;
|
||||
@@ -182,10 +182,10 @@ body.cad-file-dragging::after {
|
||||
}
|
||||
.cad-command-area input {
|
||||
flex: 1;
|
||||
height: 26px;
|
||||
height: 28px;
|
||||
padding: 0 8px;
|
||||
border: 1px solid var(--cad-line);
|
||||
border-radius: 2px;
|
||||
border-radius: var(--radius-inputs);
|
||||
outline: none;
|
||||
background: var(--cad-chrome-sunken);
|
||||
color: var(--cad-text);
|
||||
@@ -211,10 +211,10 @@ body.cad-file-dragging::after {
|
||||
border-top: 1px solid var(--cad-line);
|
||||
}
|
||||
.cad-statusbar button {
|
||||
height: 21px;
|
||||
height: 22px;
|
||||
padding: 0 8px;
|
||||
border: 1px solid transparent;
|
||||
border-radius: 2px;
|
||||
border-radius: 4px;
|
||||
background: transparent;
|
||||
color: var(--cad-text-dim);
|
||||
font-size: 10px;
|
||||
@@ -267,7 +267,7 @@ body.cad-file-dragging::after {
|
||||
min-width: 0;
|
||||
padding: 0 4px;
|
||||
border: 1px solid var(--cad-line);
|
||||
border-radius: 3px;
|
||||
border-radius: 6px;
|
||||
background: var(--cad-chrome-sunken);
|
||||
color: var(--cad-text);
|
||||
font-size: 11px;
|
||||
@@ -308,7 +308,7 @@ body.cad-file-dragging::after {
|
||||
padding: 8px 10px 10px;
|
||||
background: var(--cad-chrome-raised);
|
||||
border: 1px solid var(--cad-line);
|
||||
border-radius: 5px;
|
||||
border-radius: var(--radius-cards);
|
||||
box-shadow: var(--shadow-lg);
|
||||
}
|
||||
.cad-quick-properties__header {
|
||||
@@ -336,7 +336,7 @@ body.cad-file-dragging::after {
|
||||
padding: 8px 10px 10px;
|
||||
background: var(--cad-chrome-raised);
|
||||
border: 1px solid var(--cad-line);
|
||||
border-radius: 5px;
|
||||
border-radius: var(--radius-cards);
|
||||
box-shadow: var(--shadow-lg);
|
||||
}
|
||||
.cad-block-library__empty {
|
||||
@@ -381,9 +381,10 @@ body.cad-file-dragging::after {
|
||||
}
|
||||
.cad-block-library__actions button {
|
||||
flex: 1;
|
||||
padding: 4px 0;
|
||||
height: 24px;
|
||||
padding: 0;
|
||||
border: 1px solid var(--cad-line);
|
||||
border-radius: 3px;
|
||||
border-radius: 6px;
|
||||
background: transparent;
|
||||
color: var(--cad-text-dim);
|
||||
font-size: 11px;
|
||||
@@ -405,7 +406,7 @@ body.cad-file-dragging::after {
|
||||
width: 236px;
|
||||
padding: 8px;
|
||||
border: 1px solid var(--cad-line);
|
||||
border-radius: 6px;
|
||||
border-radius: var(--radius-cards);
|
||||
background: var(--cad-chrome-raised);
|
||||
box-shadow: var(--shadow-lg);
|
||||
color: var(--cad-text);
|
||||
@@ -444,7 +445,8 @@ body.cad-file-dragging::after {
|
||||
}
|
||||
|
||||
.cad-frame-tokens__button {
|
||||
padding: 3px 7px;
|
||||
height: 22px;
|
||||
padding: 0 8px;
|
||||
border: 1px solid var(--cad-line);
|
||||
border-radius: 4px;
|
||||
background: var(--cad-chrome);
|
||||
@@ -454,7 +456,7 @@ body.cad-file-dragging::after {
|
||||
}
|
||||
|
||||
.cad-frame-tokens__button:hover {
|
||||
background: var(--cad-accent-soft, var(--cad-chrome-raised));
|
||||
background: var(--cad-hover);
|
||||
}
|
||||
|
||||
/* 자리표 칸 크기 입력 (2026-09-06) */
|
||||
@@ -468,9 +470,10 @@ body.cad-file-dragging::after {
|
||||
|
||||
.cad-frame-tokens__size input {
|
||||
width: 64px;
|
||||
padding: 2px 4px;
|
||||
height: 24px;
|
||||
padding: 0 4px;
|
||||
border: 1px solid var(--cad-line);
|
||||
border-radius: 4px;
|
||||
border-radius: 6px;
|
||||
background: var(--cad-chrome);
|
||||
color: var(--cad-text);
|
||||
font-size: 11px;
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
/** 삽입 탭 명령 (조사표 4절 중 구현분) */
|
||||
import { toast } from 'react-toastify';
|
||||
import { askText } from '../../../../ui_template/ui_template_modal';
|
||||
import { saveBlockFromEntities } from '../blocks/block-library';
|
||||
import { setBlockLibraryVisible } from '../components/ui-state';
|
||||
import { importImageFromFile } from '../helpers/import-export-handlers/import-image-from-file';
|
||||
@@ -39,13 +40,16 @@ export const INSERT_COMMANDS: CadCommand[] = [
|
||||
needsSelection: true,
|
||||
run: () => {
|
||||
const entities = getSelectedEntities();
|
||||
const name = window.prompt('블록 이름', '')?.trim();
|
||||
if (!name) return '블록 작성 취소';
|
||||
void saveBlockFromEntities(name, entities).then(() => {
|
||||
toast.success(`블록 '${name}' 저장 (객체 ${entities.length}개)`);
|
||||
setBlockLibraryVisible(true);
|
||||
// 글 묻기 = 부품 확인창(553-6 · window.prompt 대신)
|
||||
void askText({ message: '블록 이름', okLabel: '저장' }).then((raw) => {
|
||||
const name = raw?.trim();
|
||||
if (!name) return;
|
||||
void saveBlockFromEntities(name, entities).then(() => {
|
||||
toast.success(`블록 '${name}' 저장 (객체 ${entities.length}개)`);
|
||||
setBlockLibraryVisible(true);
|
||||
});
|
||||
});
|
||||
return `블록 '${name}' 저장`;
|
||||
return '블록 이름 입력';
|
||||
},
|
||||
},
|
||||
{
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
/** 블록 라이브러리 팔레트 — 저장한 블록을 고르면 삽입 도구가 켜진다 (INSERT/BLOCK) */
|
||||
import type { FC } from 'react';
|
||||
import { showConfirmDialog } from '../../../../ui_template/ui_template_modal';
|
||||
import {
|
||||
deleteBlock,
|
||||
exportBlocksToFile,
|
||||
@@ -45,9 +46,10 @@ export const BlockLibraryPanel: FC = () => {
|
||||
type="button"
|
||||
title="삭제"
|
||||
onClick={() => {
|
||||
if (window.confirm(`블록 '${block.name}'을 삭제하시겠습니까?`)) {
|
||||
deleteBlock(block.name);
|
||||
}
|
||||
// 위험 확인 = 부품 확인창(553-6 · window.confirm 대신)
|
||||
void showConfirmDialog(`블록 '${block.name}'을 삭제하시겠습니까?`, '삭제').then(
|
||||
(ok) => ok && deleteBlock(block.name),
|
||||
);
|
||||
}}
|
||||
>
|
||||
✕
|
||||
|
||||
@@ -39,7 +39,7 @@ export const Button: FC<ButtonProps> = ({
|
||||
}) => {
|
||||
// 색은 App.css의 테마 토큰이 data-type/data-active로 준다 — 여기서는 배치만.
|
||||
const classParts = [
|
||||
'font-semibold py-4 h-10 flex flex-row justify-start w-full items-center',
|
||||
'font-semibold py-4 h-[42px] flex flex-row justify-start w-full items-center',
|
||||
size === 'regular' ? 'pl-2 pr-2 gap-2' : '',
|
||||
size === 'small' ? 'pl-2 pr-2 gap-0' : '',
|
||||
className || '',
|
||||
|
||||
@@ -1,69 +0,0 @@
|
||||
import type { CSSProperties, FC, ReactNode } from 'react';
|
||||
import useLocalStorageState from 'use-local-storage-state';
|
||||
import { LOCAL_STORAGE_KEY } from '../App.types.ts';
|
||||
import { keyboardHandler } from '../helpers/keyboard-handler.ts';
|
||||
import { Button } from './Button.tsx';
|
||||
import { Icon, IconName } from './Icon/Icon.tsx';
|
||||
|
||||
interface DropdownButtonProps {
|
||||
label?: string;
|
||||
title?: string;
|
||||
iconName?: IconName;
|
||||
iconComponent?: ReactNode;
|
||||
active?: boolean;
|
||||
onClick?: () => void;
|
||||
className?: string;
|
||||
style?: CSSProperties;
|
||||
buttonStyle?: CSSProperties;
|
||||
dataId: string;
|
||||
children?: ReactNode;
|
||||
defaultOpen?: boolean;
|
||||
}
|
||||
|
||||
export const DropdownButton: FC<DropdownButtonProps> = ({
|
||||
label,
|
||||
title,
|
||||
iconName,
|
||||
iconComponent,
|
||||
className,
|
||||
style,
|
||||
buttonStyle,
|
||||
dataId,
|
||||
children,
|
||||
defaultOpen = false,
|
||||
}) => {
|
||||
const [isOpen, setIsOpen] = useLocalStorageState<boolean>(
|
||||
`${LOCAL_STORAGE_KEY.DROPDOWN}___${dataId}`,
|
||||
{ defaultValue: defaultOpen }
|
||||
);
|
||||
|
||||
const classParts = [
|
||||
'flex flex-col gap-2 relative',
|
||||
className || '',
|
||||
isOpen ? ' bg-slate-900' : '',
|
||||
];
|
||||
return (
|
||||
<div className={classParts.join(' ')} style={style} data-id={dataId}>
|
||||
<Button
|
||||
iconName={iconName}
|
||||
iconComponent={iconComponent}
|
||||
label={label}
|
||||
title={title}
|
||||
active={isOpen}
|
||||
onClick={() => setIsOpen(!isOpen)}
|
||||
style={buttonStyle}
|
||||
className={'w-full data-[active=true]:bg-blue-950 data-[active=true]:text-white'}
|
||||
/>
|
||||
<Icon name={IconName.SolidDownSmall} className={'absolute top-2.5 right-1 text-blue-700'} />
|
||||
{isOpen && (
|
||||
<div
|
||||
className="flex flex-row flex-wrap max-w-72 gap-1 pl-1 pb-6"
|
||||
onClick={() => setIsOpen(false)}
|
||||
onKeyUp={keyboardHandler(() => setIsOpen(false))}
|
||||
>
|
||||
{children}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -7,15 +7,15 @@
|
||||
min-width: 160px;
|
||||
padding: 4px;
|
||||
border: 1px solid var(--color-border);
|
||||
border-radius: 6px;
|
||||
border-radius: var(--radius-cards);
|
||||
background: var(--color-surface-raised);
|
||||
box-shadow: var(--shadow-sm);
|
||||
box-shadow: var(--shadow-lg);
|
||||
}
|
||||
|
||||
.cad-snap-menu > button {
|
||||
padding: 4px 10px;
|
||||
border: 0;
|
||||
border-radius: 4px;
|
||||
border-radius: var(--radius-sm);
|
||||
background: transparent;
|
||||
color: var(--color-text);
|
||||
font-size: 13px;
|
||||
@@ -25,5 +25,5 @@
|
||||
|
||||
.cad-snap-menu > button:hover,
|
||||
.cad-snap-menu > button:focus-visible {
|
||||
background: var(--color-surface-hover, rgba(127, 127, 127, 0.15));
|
||||
background: var(--color-hover);
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ import { SNAP_POINT_DISTANCE } from './App.consts';
|
||||
import App from './App.tsx';
|
||||
import { TOOL_STATE_MACHINES } from './commands/registry';
|
||||
import { ScreenCanvasDrawController } from './drawControllers/screenCanvas.drawController';
|
||||
import { injectBaseStyles } from '../../../ui_template/ui_template_elements_styles';
|
||||
import { registerAutoSave } from './helpers/autosave.ts';
|
||||
import { registerCadDebugHook } from './helpers/debug-hook.ts';
|
||||
import { draw } from './helpers/draw';
|
||||
@@ -47,6 +48,7 @@ import { ActorEvent, type DrawEvent } from './tools/tool.types';
|
||||
|
||||
// 호스트 앱의 화이트/블랙 모드를 먼저 붙인 뒤 렌더한다.
|
||||
syncThemeFromHost();
|
||||
injectBaseStyles(); // 부품 단추 · 확인창 꼴(553-6 · 앱과 같은 한 벌)
|
||||
// 부모가 `?bare` 로 띄우면 첫 그림부터 캔버스만 — 도면을 넘길 때 다시 정함(522-2)
|
||||
if (new URLSearchParams(window.location.search).has('bare')) setBare(true);
|
||||
|
||||
|
||||
@@ -25,6 +25,15 @@
|
||||
"noUnusedParameters": true,
|
||||
"noFallthroughCasesInSwitch": true
|
||||
},
|
||||
"include": ["src", "../../A00_Common/key_shortcut.ts", "../../A00_Common/input_prefs.ts"],
|
||||
"include": [
|
||||
"src",
|
||||
"../../A00_Common/key_shortcut.ts",
|
||||
"../../A00_Common/input_prefs.ts",
|
||||
"../../ui_template/ui_template_modal.ts",
|
||||
"../../ui_template/ui_template_button.ts",
|
||||
"../../ui_template/ui_template_icons.ts",
|
||||
"../../ui_template/ui_template_elements_base.ts",
|
||||
"../../ui_template/ui_template_elements_styles.ts"
|
||||
],
|
||||
"exclude": ["node_modules"]
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user