From cadff2af9092f9b54908b43941d45a2d321ce892 Mon Sep 17 00:00:00 2001 From: umsangdon Date: Fri, 16 Oct 2026 20:38:46 +0900 Subject: [PATCH] =?UTF-8?q?feat(=EC=84=A4=EC=A0=95):=20357-1=C2=B72=20?= =?UTF-8?q?=EC=A0=80=EC=9E=A5=20=EB=B2=84=ED=8A=BC=20[=EB=8B=AB=EA=B8=B0]?= =?UTF-8?q?=EC=99=80=20=EA=B0=99=EC=9D=80=20=ED=81=AC=EA=B8=B0=20=C2=B7=20?= =?UTF-8?q?=EC=A0=80=EC=9E=A5=ED=95=98=EB=A9=B4=20=EB=B0=94=EB=A1=9C=20?= =?UTF-8?q?=EB=8B=AB=ED=9E=98=20=C2=B7=20=EB=8B=A8=EC=B6=95=ED=82=A4=20?= =?UTF-8?q?=ED=83=AD=20=ED=95=9C=20=EC=A4=84=EC=94=A9(=EC=9E=85=EB=A0=A5?= =?UTF-8?q?=20=3D=20=EB=8F=99=EC=9E=91)=20=C2=B7=20=ED=82=A4=20=EC=B9=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 단추 → 버튼 (마우스 · 다른 곳 단축키 글) - test_app_settings 저장 뒤 닫힘으로 고침 Co-Authored-By: Claude Sonnet 5.5 Claude-Session: https://claude.ai/code/session_013QyNXY2TUKXCFMwAca2APG --- A00_Common/app_settings.css | 33 +++++++++++++++++ A00_Common/app_settings.ts | 37 +++++++++++++------ resources/tester/test_app_settings.py | 21 +++++------ ui_template/ui_template_locale_common.ts | 45 ++++++++++++------------ 4 files changed, 93 insertions(+), 43 deletions(-) diff --git a/A00_Common/app_settings.css b/A00_Common/app_settings.css index 4ac71bdcf..b2841ec1a 100644 --- a/A00_Common/app_settings.css +++ b/A00_Common/app_settings.css @@ -51,3 +51,36 @@ .app-settings__error:empty { display: none; } + +.app-settings__rules { + margin: 0 0 var(--spacing-8); + padding: 0; + list-style: none; +} + +.app-settings__rules > li { + display: grid; + grid-template-columns: minmax(0, 15em) 1fr; + align-items: center; + gap: var(--spacing-12); + padding: var(--spacing-4) 0; + border-bottom: 1px solid var(--color-border); + white-space: nowrap; +} + +.app-settings__keys { + display: flex; + flex-wrap: wrap; + gap: var(--spacing-4); +} + +.app-settings__keys > kbd { + padding: 0 var(--spacing-8); + border: 1px solid var(--color-border); + border-radius: var(--radius-sm); + background: var(--color-surface-raised); + color: var(--color-text); + font-family: var(--font-mono); + font-size: 0.85em; + line-height: 1.7; +} diff --git a/A00_Common/app_settings.ts b/A00_Common/app_settings.ts index d5ab19607..8e8efc4d5 100644 --- a/A00_Common/app_settings.ts +++ b/A00_Common/app_settings.ts @@ -37,7 +37,7 @@ const MOUSE_RULES: LocaleKey[] = [ "App_Settings_Rule_Pinch", ]; -/** ③ 안내표 줄 — [자리, 키] */ +/** ③ 안내 — [자리, 키] */ const KEY_ROWS: [LocaleKey, LocaleKey][] = [ ["App_Settings_Keys_All", "App_Settings_Keys_All_Keys"], ["App_Settings_Keys_Profile", "App_Settings_Keys_Profile_Keys"], @@ -55,6 +55,26 @@ const normalize = (p: InputPrefs): InputPrefs => ({ }); const snapshot = (p: InputPrefs): string => JSON.stringify(normalize(p)); +/** 규칙 목록 — 한 줄 = 「입력 = 동작」 · 입력은 키 칩(` · ` 로 여럿) · 동작 없는 줄은 칩만 */ +function ruleList(keys: LocaleKey[]): HTMLElement { + const items = keys + .flatMap((key) => L(key).split("\n")) + .map((line) => { + const at = line.indexOf(" = "); + const input = at < 0 ? line : line.slice(0, at); + return el("li", { + children: [ + el("span", { + className: "app-settings__keys", + children: input.split(" · ").map((text) => el("kbd", { text })), + }), + ...(at < 0 ? [] : [el("span", { text: line.slice(at + 3) })]), + ], + }); + }); + return el("ul", { className: "app-settings__rules", children: items }); +} + function mouseTab(draft: InputPrefs): HTMLElement { const group = el("div", { className: "app-settings__radios", @@ -73,18 +93,14 @@ function mouseTab(draft: InputPrefs): HTMLElement { el("h4", { text: L("App_Settings_Wheel") }), group, el("h4", { text: L("App_Settings_Rules") }), - el("ul", { children: MOUSE_RULES.map((key) => el("li", { text: L(key) })) }), + ruleList(MOUSE_RULES), ], }); } function keysTab(): HTMLElement { - const rows = KEY_ROWS.map(([place, keys]) => - el("tr", { children: [el("th", { text: L(place) }), el("td", { text: L(keys) })] }), - ); - return el("table", { - className: "app-settings__table", - children: [el("tbody", { children: rows })], + return el("div", { + children: KEY_ROWS.flatMap(([place, keys]) => [el("h4", { text: L(place) }), ruleList([keys])]), }); } @@ -138,10 +154,9 @@ export function openAppSettings(): void { const saveButton = createButton({ label: L("Common_Btn_Save"), variant: "filled", - size: "sm", - onClick: () => void save(), + onClick: () => save() && modal.close(), }); - openModal({ + const modal = openModal({ title: L("App_Settings"), closeLabel: L("Common_Btn_Close"), dialogClass: "app-settings", diff --git a/resources/tester/test_app_settings.py b/resources/tester/test_app_settings.py index 9fde1be4c..9016b0b37 100644 --- a/resources/tester/test_app_settings.py +++ b/resources/tester/test_app_settings.py @@ -140,16 +140,16 @@ def test_설정_창_탭_저장_물음(): page.click(".ui-confirm button >> nth=0") # 취소 assert page.locator(".app-settings").count() == 1 and _writes(page) == [] - # [저장] = 한 번 씀 · 읽기 층 방향 뒤집힘 · 닫을 때 안 물음 + # [저장] = 한 번 씀 · 바로 닫힘(물음 없음) · 읽기 층 방향 뒤집힘 _save(page) + assert page.locator(".app-settings").count() == 0 + assert page.locator(".ui-confirm").count() == 0 assert len(_writes(page)) == 1 assert json.loads(_writes(page)[0]) == {"wheelZoom": "pull", "cadAliases": {}} assert page.evaluate(WHEEL_IN, 100) is True and page.evaluate(WHEEL_IN, -100) is False - _save(page) # 고친 것 없음 — 또 안 씀 - assert len(_writes(page)) == 1 - _close(page) - assert page.locator(".app-settings").count() == 0 - assert page.locator(".ui-confirm").count() == 0 + _open_settings(page) + _save(page) # 고친 것 없음 — 또 안 씀 · 닫힘 + assert len(_writes(page)) == 1 and page.locator(".app-settings").count() == 0 # CAD 별칭 — 잘못이면 안 씀 · 칸 표시 _open_settings(page) @@ -163,25 +163,26 @@ def test_설정_창_탭_저장_물음(): _save(page) assert page.inner_text(".app-settings__error").strip(), (line_v, circle_v) assert page.locator(".app-settings input[aria-invalid=true]").count() >= 1 - assert len(_writes(page)) == 1 + assert len(_writes(page)) == 1 and page.locator(".app-settings").count() == 1 # 창 남음 page.fill(line, "ll") page.fill(circle, "") _save(page) - assert page.inner_text(".app-settings__error").strip() == "" + assert page.locator(".app-settings").count() == 0 # 저장 성공 = 닫힘 assert len(_writes(page)) == 2 assert json.loads(_writes(page)[1]) == {"wheelZoom": "pull", "cadAliases": {"LINE": ["LL"]}} # 닫을 때 물음 — 버림 = 안 씀 · 저장 = 한 번 더 + _open_settings(page) page.click("[data-settings-tab=mouse]") page.check("input[name=app-settings-wheel][value=push]") _close(page) - page.click(".ui-confirm button >> nth=1") # 버리고 넘어감 + page.click(".ui-confirm button >> nth=1") # 폐기 assert page.locator(".app-settings").count() == 0 and len(_writes(page)) == 2 assert page.evaluate(WHEEL_IN, 100) is True _open_settings(page) page.check("input[name=app-settings-wheel][value=push]") _close(page) - page.click(".ui-confirm button >> nth=2") # 저장 후 넘어감 + page.click(".ui-confirm button >> nth=2") # 저장 assert page.locator(".app-settings").count() == 0 and len(_writes(page)) == 3 assert json.loads(_writes(page)[2])["wheelZoom"] == "push" assert page.evaluate(WHEEL_IN, 100) is False diff --git a/ui_template/ui_template_locale_common.ts b/ui_template/ui_template_locale_common.ts index b2035a21e..7a5e3a990 100644 --- a/ui_template/ui_template_locale_common.ts +++ b/ui_template/ui_template_locale_common.ts @@ -40,7 +40,7 @@ export const ui_locales_common = { * ------------------------------------------------------------------------ */ Common_Status_Loading: ["불러오는 중...", "Loading..."], Common_Load_Failed: ["불러오지 못함", "Failed to load"], - Common_Reload: ["다시 불러오기", "Reload"], + Common_Reload: ["새로고침", "Reload"], Common_Status_Saving: ["저장 중...", "Saving..."], Common_Status_Processing: ["처리 중...", "Processing..."], Common_Status_Success: ["완료되었습니다", "Completed"], @@ -117,16 +117,17 @@ export const ui_locales_common = { App_Settings_Wheel: ["휠 확대 방향(모든 화면)", "Wheel zoom-in direction (all views)"], App_Settings_Wheel_Pull: ["당기면 확대(휠을 몸 쪽으로)", "Pull to zoom in (wheel toward you)"], App_Settings_Wheel_Push: ["밀면 확대(휠을 앞으로)", "Push to zoom in (wheel away)"], - App_Settings_Rules: ["마우스 단추", "Mouse buttons"], - App_Settings_Rule_Pan: ["화면 옮기기 = 가운데 단추 끌기", "Pan = drag with the middle button"], - App_Settings_Rule_Pick: ["고르기 = 왼쪽 단추", "Select = left button"], + /* 아래 규칙 값 = 한 줄에 「입력 = 동작」 · 줄바꿈(\n)으로 줄 나눔 · ko · en 줄 수 같게 */ + App_Settings_Rules: ["마우스 버튼", "Mouse buttons"], + App_Settings_Rule_Pan: ["가운데 버튼 끌기 = 화면 옮김", "Middle button drag = pan"], + App_Settings_Rule_Pick: ["왼쪽 버튼 = 고르기", "Left button = select"], App_Settings_Rule_Right: [ - "오른쪽 단추 = 메뉴 · CAD 에서는 명령 중 Enter · 쉴 때 반복 · Shift = 스냅 메뉴 · CAD 휠 두 번 = 범위", - "Right button = menu · in CAD Enter during a command · repeat when idle · Shift = snap menu · CAD wheel double-click = extents", + "오른쪽 버튼 = 메뉴\n오른쪽 버튼(CAD 명령 중) = Enter\n오른쪽 버튼(CAD 쉴 때) = 반복\nShift+오른쪽 버튼(CAD) = 스냅 메뉴\n휠 두 번 누름(CAD) = 범위", + "Right button = menu\nRight button (CAD, during a command) = Enter\nRight button (CAD, idle) = repeat\nShift+right button (CAD) = snap menu\nWheel double-click (CAD) = extents", ], App_Settings_Rule_Pinch: [ - "트랙패드 · 손가락 벌림 = 늘 확대(휠 방향과 상관없음)", - "Trackpad · finger spread = always zoom in (whatever the wheel direction)", + "트랙패드 손가락 벌림 = 늘 확대(휠 방향 무관)", + "Trackpad finger spread = always zoom in (any wheel direction)", ], App_Settings_Cad_Help: [ "CAD 는 명령 이름 > 내 별칭 > 기본 별칭 차례로 찾음 · 영문 · 숫자만 · 여러 개는 쉼표로", @@ -144,38 +145,38 @@ export const ui_locales_common = { App_Settings_Leave: ["저장 안 한 설정이 있음", "You have unsaved settings"], App_Settings_Keys_All: ["모든 화면", "All views"], App_Settings_Keys_All_Keys: [ - "Esc = ☰ · 창 닫기 · 고름 풀기 · Z 누른 채 또는 오른쪽 0.4초 누름 = 돋보기(휠 = 배율)", - "Esc = ☰ · close window · clear selection · hold Z or right button 0.4 s = loupe (wheel = zoom)", + "Esc = ☰ · 창 닫기 · 고름 풀기\nZ 누른 채 = 돋보기\n오른쪽 버튼 0.4초 누름 = 돋보기\n돋보기 중 휠 = 배율", + "Esc = ☰ · close window · clear selection\nHold Z = loupe\nRight button 0.4 s = loupe\nWheel in loupe = zoom", ], App_Settings_Keys_Profile: ["B05 종단", "B05 profile"], App_Settings_Keys_Profile_Keys: [ - "Ctrl+Z 되돌림 · Ctrl+Shift+Z 다시 · 방향키 = 옮김 · 자유지정 Enter = 끝 · Esc · Backspace", - "Ctrl+Z undo · Ctrl+Shift+Z redo · arrows = move · free mode Enter = finish · Esc · Backspace", + "Ctrl+Z = 되돌림\nCtrl+Shift+Z = 다시\n방향키 = 옮김\nEnter(자유지정) = 끝\nEsc · Backspace", + "Ctrl+Z = undo\nCtrl+Shift+Z = redo\nArrows = move\nEnter (free mode) = finish\nEsc · Backspace", ], App_Settings_Keys_RouteEdit: ["B05 노선 편집", "B05 route edit"], App_Settings_Keys_RouteEdit_Keys: [ - "Ctrl+Z 되돌림 · Ctrl+Y · Ctrl+Shift+Z 다시", - "Ctrl+Z undo · Ctrl+Y · Ctrl+Shift+Z redo", + "Ctrl+Z = 되돌림\nCtrl+Y = 다시\nCtrl+Shift+Z = 다시", + "Ctrl+Z = undo\nCtrl+Y = redo\nCtrl+Shift+Z = redo", ], App_Settings_Keys_Section: ["B06 횡단", "B06 cross section"], App_Settings_Keys_Section_Keys: [ - "방향키 · ▲▼ = 측점 옮김 · Enter · Space = 고름 · Esc", - "Arrows · ▲▼ = move station · Enter · Space = pick · Esc", + "방향키 = 측점 옮김\n▲▼ = 측점 옮김\nEnter = 고름\nSpace = 고름\nEsc", + "Arrows = move station\n▲▼ = move station\nEnter = pick\nSpace = pick\nEsc", ], App_Settings_Keys_Cad: ["CAD", "CAD"], App_Settings_Keys_Cad_Keys: [ - "F3 스냅 · F7 그리드 · F8 직교 · F10 45° · Ctrl+Z · Ctrl+Y · Ctrl+A · Ctrl+S(M02) · Delete · Esc · Enter · Space = Enter · ↑↓ = 기록 · 최근 값 · Ctrl+C · X · 1 · ← → · Shift+↑↓ = 화면 옮김 · 글자 = 명령", - "F3 snap · F7 grid · F8 ortho · F10 45° · Ctrl+Z · Ctrl+Y · Ctrl+A · Ctrl+S (M02) · Delete · Esc · Enter · Space = Enter · ↑↓ = history · recent values · Ctrl+C · X · 1 · ← → · Shift+↑↓ = pan · letters = command", + "F3 = 스냅\nF7 = 그리드\nF8 = 직교\nF10 = 45°\nCtrl+Z = 되돌림\nCtrl+Y = 다시\nCtrl+S(M02) = 저장\nSpace = Enter\n↑↓ = 기록 · 최근 값\nShift+↑↓ = 화면 옮김\n글자 = 명령\nCtrl+A · Delete · Esc · Enter · Ctrl+C · X · 1 · ← →", + "F3 = snap\nF7 = grid\nF8 = ortho\nF10 = 45°\nCtrl+Z = undo\nCtrl+Y = redo\nCtrl+S (M02) = save\nSpace = Enter\n↑↓ = history · recent values\nShift+↑↓ = pan\nLetters = command\nCtrl+A · Delete · Esc · Enter · Ctrl+C · X · 1 · ← →", ], App_Settings_Keys_Table: ["B08 · B09 표", "B08 · B09 tables"], App_Settings_Keys_Table_Keys: [ - "Enter · F2 = 입력 · 방향키 = 칸 옮김 · Esc = 그만", - "Enter · F2 = edit · arrows = move cell · Esc = cancel", + "Enter = 입력\nF2 = 입력\n방향키 = 칸 옮김\nEsc = 그만", + "Enter = edit\nF2 = edit\nArrows = move cell\nEsc = cancel", ], App_Settings_Keys_M02: ["M02 양식", "M02 templates"], App_Settings_Keys_M02_Keys: [ - "Ctrl+S 저장 · Ctrl+C · Ctrl+V · Delete · Esc · Space+끌기 = 화면 옮김 · Ctrl+휠 = 배율 · 시트 = 엑셀 키", - "Ctrl+S save · Ctrl+C · Ctrl+V · Delete · Esc · Space+drag = pan · Ctrl+wheel = zoom · sheet = Excel keys", + "Ctrl+S = 저장\nSpace+끌기 = 화면 옮김\nCtrl+휠 = 배율\n시트 안 = 엑셀 키 그대로\nCtrl+C · Ctrl+V · Delete · Esc", + "Ctrl+S = save\nSpace+drag = pan\nCtrl+wheel = zoom\nInside a sheet = Excel keys\nCtrl+C · Ctrl+V · Delete · Esc", ], App_Footer_Copyright: [ "© 2026 임도설계 및 견적 자동화. All rights reserved.",