From b8a19e983f05cbf244802c7970803a7f2a576c79 Mon Sep 17 00:00:00 2001 From: umsangdon Date: Mon, 26 Oct 2026 22:33:45 +0900 Subject: [PATCH] =?UTF-8?q?style(cad):=20CAD=20=EC=95=B1=20=EA=B2=89?= =?UTF-8?q?=EC=9D=84=20=EC=95=B1=20=EA=B3=B5=ED=86=B5=20=EA=B0=92=20=C2=B7?= =?UTF-8?q?=20=ED=81=AC=EA=B8=B0=20=EB=8B=A8=20=C2=B7=20=ED=99=95=EC=9D=B8?= =?UTF-8?q?=EC=B0=BD=20=EB=B6=80=ED=92=88=EC=9C=BC=EB=A1=9C=20=E2=80=94=20?= =?UTF-8?q?window.confirm=20=C2=B7=20prompt=20=EA=B1=B7=EC=9D=8C=20(PLAN?= =?UTF-8?q?=20553-6)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 블록 이름 묻기 = 부품 글 묻기(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 --- B07_DesignDetail/openwebcad/src/App.css | 25 ++++--- .../openwebcad/src/App_Layers.css | 37 +++++----- .../src/commands/commands.insert.ts | 16 +++-- .../src/components/BlockLibraryPanel.tsx | 8 ++- .../openwebcad/src/components/Button.tsx | 2 +- .../src/components/DropdownButton.tsx | 69 ------------------- .../src/inputController/snap-menu.css | 8 +-- B07_DesignDetail/openwebcad/src/main.tsx | 2 + B07_DesignDetail/openwebcad/tsconfig.app.json | 11 ++- 9 files changed, 66 insertions(+), 112 deletions(-) delete mode 100644 B07_DesignDetail/openwebcad/src/components/DropdownButton.tsx diff --git a/B07_DesignDetail/openwebcad/src/App.css b/B07_DesignDetail/openwebcad/src/App.css index 9c4c7197a..60d087d89 100644 --- a/B07_DesignDetail/openwebcad/src/App.css +++ b/B07_DesignDetail/openwebcad/src/App.css @@ -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 { diff --git a/B07_DesignDetail/openwebcad/src/App_Layers.css b/B07_DesignDetail/openwebcad/src/App_Layers.css index c46a6d7d1..f45c4a0e5 100644 --- a/B07_DesignDetail/openwebcad/src/App_Layers.css +++ b/B07_DesignDetail/openwebcad/src/App_Layers.css @@ -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; diff --git a/B07_DesignDetail/openwebcad/src/commands/commands.insert.ts b/B07_DesignDetail/openwebcad/src/commands/commands.insert.ts index 6cb2b8d73..e3c5561c7 100644 --- a/B07_DesignDetail/openwebcad/src/commands/commands.insert.ts +++ b/B07_DesignDetail/openwebcad/src/commands/commands.insert.ts @@ -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 '블록 이름 입력'; }, }, { diff --git a/B07_DesignDetail/openwebcad/src/components/BlockLibraryPanel.tsx b/B07_DesignDetail/openwebcad/src/components/BlockLibraryPanel.tsx index 3fc99300a..0743bbbe3 100644 --- a/B07_DesignDetail/openwebcad/src/components/BlockLibraryPanel.tsx +++ b/B07_DesignDetail/openwebcad/src/components/BlockLibraryPanel.tsx @@ -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), + ); }} > ✕ diff --git a/B07_DesignDetail/openwebcad/src/components/Button.tsx b/B07_DesignDetail/openwebcad/src/components/Button.tsx index f95ddc2c4..c02ce12fa 100644 --- a/B07_DesignDetail/openwebcad/src/components/Button.tsx +++ b/B07_DesignDetail/openwebcad/src/components/Button.tsx @@ -39,7 +39,7 @@ export const Button: FC = ({ }) => { // 색은 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 || '', diff --git a/B07_DesignDetail/openwebcad/src/components/DropdownButton.tsx b/B07_DesignDetail/openwebcad/src/components/DropdownButton.tsx deleted file mode 100644 index 995abf0c5..000000000 --- a/B07_DesignDetail/openwebcad/src/components/DropdownButton.tsx +++ /dev/null @@ -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 = ({ - label, - title, - iconName, - iconComponent, - className, - style, - buttonStyle, - dataId, - children, - defaultOpen = false, -}) => { - const [isOpen, setIsOpen] = useLocalStorageState( - `${LOCAL_STORAGE_KEY.DROPDOWN}___${dataId}`, - { defaultValue: defaultOpen } - ); - - const classParts = [ - 'flex flex-col gap-2 relative', - className || '', - isOpen ? ' bg-slate-900' : '', - ]; - return ( -
-
- ); -}; diff --git a/B07_DesignDetail/openwebcad/src/inputController/snap-menu.css b/B07_DesignDetail/openwebcad/src/inputController/snap-menu.css index 8d313cc24..aea05f221 100644 --- a/B07_DesignDetail/openwebcad/src/inputController/snap-menu.css +++ b/B07_DesignDetail/openwebcad/src/inputController/snap-menu.css @@ -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); } diff --git a/B07_DesignDetail/openwebcad/src/main.tsx b/B07_DesignDetail/openwebcad/src/main.tsx index 38280e159..81e9a91f6 100644 --- a/B07_DesignDetail/openwebcad/src/main.tsx +++ b/B07_DesignDetail/openwebcad/src/main.tsx @@ -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); diff --git a/B07_DesignDetail/openwebcad/tsconfig.app.json b/B07_DesignDetail/openwebcad/tsconfig.app.json index 87ee7f72c..79edf6ba4 100644 --- a/B07_DesignDetail/openwebcad/tsconfig.app.json +++ b/B07_DesignDetail/openwebcad/tsconfig.app.json @@ -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"] }