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"] }