feat(ui): 연결창 단추 넷 머리 · 큰 창 · 글 묻는 창 [확인] 머리 · [취소] 지움(147-2)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QND7Co43B24zK2P937rdxt
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
"""공용 모달 머리 단추 · 큰 창 · M02 수량산출 창(PLAN 147) — 소스 검사 · 화면 판정은 사용자.
|
||||
|
||||
· 147-1 곁값 `actions`(머리 [닫기] 바로 왼쪽 · 넘긴 창만) · `wide`(96vw × 94vh · 몸만 스크롤)
|
||||
· 147-2 연결창 단추 넷 → 머리 · 큰 창 · 글 묻는 창 [확인] 머리 · [취소] 없음
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
@@ -42,3 +43,27 @@ def test_147_1_머리_자리_큰_창_css():
|
||||
assert rule in wide, rule
|
||||
body = _block(css, ".ui-modal--wide > .ui-modal__body")
|
||||
assert "overflow: auto;" in body and "min-height: 0;" in body
|
||||
|
||||
|
||||
def test_147_2_연결창_머리_단추_큰_창():
|
||||
ts = _text("ui_template/ui_template_item_picker.ts")
|
||||
assert "children: [copyButton, manageButton, clearButton, applyButton]," in ts
|
||||
assert "actions: [headButtons]," in ts and "wide: true," in ts
|
||||
# 편집 화면 = 머리 단추도 숨김(편집 중 [적용] 막음) · 돌아오면 다시
|
||||
assert "headButtons.hidden = true;" in ts and "headButtons.hidden = false;" in ts
|
||||
# 안내 글(구조물 [저장]) 은 아래 남김
|
||||
assert "ui-item-picker__saveline" in ts
|
||||
css = _text("ui_template/ui_template_item_picker.css")
|
||||
assert ".ui-item-picker .ui-modal__actions[hidden]" in css
|
||||
assert "width: min(1320px, 96vw);" not in css
|
||||
|
||||
|
||||
def test_147_2_글_묻는_창_확인만_머리():
|
||||
ask = _text("ui_template/ui_template_item_picker_ask.ts")
|
||||
assert "head.append(createButton({ label: opts.okLabel" in ask
|
||||
assert "cancelLabel" not in ask
|
||||
for rel in (
|
||||
"ui_template/ui_template_item_picker.ts",
|
||||
"ui_template/ui_template_item_picker_detail.ts",
|
||||
):
|
||||
assert "cancelLabel" not in _text(rel), rel
|
||||
|
||||
@@ -30,9 +30,9 @@ def test_공용_모달_위_고정():
|
||||
assert "max-height: var(--modal-max, 80vh);" in modal
|
||||
assert "margin-top: calc((100vh - var(--modal-max, 80vh)) / 2);" in modal
|
||||
# 큰 창은 max-height 대신 --modal-max(위 거리가 함께 맞음)
|
||||
assert "--modal-max: 94vh;" in _block(
|
||||
_text("ui_template/ui_template_item_picker.css"), ".ui-modal.ui-item-picker"
|
||||
)
|
||||
# 고르기 창 = 공용 큰 창 곁값(147-2)
|
||||
assert "--modal-max: 94vh;" in _block(css, ".ui-modal.ui-modal--wide")
|
||||
assert "wide: true," in _text("ui_template/ui_template_item_picker.ts")
|
||||
assert "--modal-max: 92vh;" in _block(
|
||||
_text("B05_Profile/B05_Profile_UI_Style_RouteRecommend.css"), ".ui-modal.b05-routerec"
|
||||
)
|
||||
|
||||
@@ -1,13 +1,5 @@
|
||||
/* 항목 고르기 모달 — 왼쪽 나무 · 오른쪽 폴더 모양 · 아래 단추 */
|
||||
/* 공용 모달(.ui-modal)의 폭 · 높이보다 앞서게 — 불러오는 차례에 따라 뒤집히지 않도록 두 클래스 */
|
||||
.ui-modal.ui-item-picker {
|
||||
width: min(1320px, 96vw);
|
||||
--modal-max: 94vh;
|
||||
}
|
||||
|
||||
.ui-item-picker .ui-modal__body {
|
||||
height: min(80vh, 800px);
|
||||
}
|
||||
/* 항목 고르기 모달 — 왼쪽 나무 · 오른쪽 폴더 모양 · 머리 단추(147-2) */
|
||||
/* 크기 = 공용 큰 창(곁값 wide · 96vw × 94vh · 147-2) */
|
||||
|
||||
.ui-item-picker__cols {
|
||||
display: grid;
|
||||
@@ -51,6 +43,7 @@
|
||||
|
||||
.ui-item-picker__cols[hidden],
|
||||
.ui-item-picker__actions[hidden],
|
||||
.ui-item-picker .ui-modal__actions[hidden],
|
||||
.ui-item-picker__edit-host[hidden] {
|
||||
display: none;
|
||||
}
|
||||
|
||||
@@ -103,7 +103,6 @@ const NEW_TEXT = {
|
||||
name: "이름",
|
||||
unit: "단위",
|
||||
ok: "만들기",
|
||||
cancel: "취소",
|
||||
empty: "{label} 을(를) 넣을 것",
|
||||
made: "새 항목을 만들어 지정했음 — 구조물 [저장]을 눌러야 이 구조물 복사본이 남음",
|
||||
failed: "새 항목을 만들지 못함 — {value}",
|
||||
@@ -289,7 +288,6 @@ export function openItemPicker(opts: ItemPickerOptions): Promise<ItemPickerResul
|
||||
{ key: "unit", label: NEW_TEXT.unit, placeholder: "m · ㎥ · 개소", required: true },
|
||||
],
|
||||
okLabel: NEW_TEXT.ok,
|
||||
cancelLabel: NEW_TEXT.cancel,
|
||||
closeLabel: t("M02_Close"),
|
||||
emptyText: NEW_TEXT.empty,
|
||||
});
|
||||
@@ -308,17 +306,16 @@ export function openItemPicker(opts: ItemPickerOptions): Promise<ItemPickerResul
|
||||
}
|
||||
}
|
||||
|
||||
// 단추 넷 = 머리 [닫기] 왼쪽(147-2) · 안내 글은 아래 남김
|
||||
const headButtons = el("div", {
|
||||
className: "ui-modal__actions",
|
||||
children: [copyButton, manageButton, clearButton, applyButton],
|
||||
});
|
||||
const actions = el("div", {
|
||||
className: "ui-item-picker__actions",
|
||||
children: [
|
||||
...(opts.projectId
|
||||
? [el("span", { className: "ui-item-picker__saveline", text: NEW_TEXT.saveLine })]
|
||||
: []),
|
||||
copyButton,
|
||||
manageButton,
|
||||
clearButton,
|
||||
applyButton,
|
||||
],
|
||||
children: opts.projectId
|
||||
? [el("span", { className: "ui-item-picker__saveline", text: NEW_TEXT.saveLine })]
|
||||
: [],
|
||||
});
|
||||
|
||||
/** 카드 [수정] — 모달 안에서 편집 화면으로 바뀜(나무 · 카드 · 단추는 숨김) */
|
||||
@@ -328,6 +325,7 @@ export function openItemPicker(opts: ItemPickerOptions): Promise<ItemPickerResul
|
||||
editHost.replaceChildren(view.root);
|
||||
cols.hidden = true;
|
||||
actions.hidden = true;
|
||||
headButtons.hidden = true;
|
||||
editHost.hidden = false;
|
||||
view.start();
|
||||
}
|
||||
@@ -338,6 +336,7 @@ export function openItemPicker(opts: ItemPickerOptions): Promise<ItemPickerResul
|
||||
editHost.hidden = true;
|
||||
cols.hidden = false;
|
||||
actions.hidden = false;
|
||||
headButtons.hidden = false;
|
||||
if (saved) detailView.markEdited();
|
||||
detailView.reload();
|
||||
}
|
||||
@@ -346,6 +345,8 @@ export function openItemPicker(opts: ItemPickerOptions): Promise<ItemPickerResul
|
||||
title: t("M02_PickerTitle"),
|
||||
closeLabel: t("M02_Close"),
|
||||
dialogClass: "ui-item-picker",
|
||||
wide: true,
|
||||
actions: [headButtons],
|
||||
// 닫기 단추 · Esc · 바깥 누르기 = 취소 — 편집 중 저장 안 한 고침이 있으면 물음
|
||||
beforeClose: async () => {
|
||||
if (editView && !(await editView.leave())) return false;
|
||||
@@ -354,7 +355,7 @@ export function openItemPicker(opts: ItemPickerOptions): Promise<ItemPickerResul
|
||||
return true;
|
||||
},
|
||||
mount: (body) => {
|
||||
body.append(cols, editHost, actions);
|
||||
body.append(cols, editHost, ...(opts.projectId ? [actions] : []));
|
||||
paintDetail();
|
||||
void load(null);
|
||||
},
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
/* =============================================================================
|
||||
* ui_template_item_picker_ask.ts
|
||||
* 고르기 모달에서 글을 물을 때 쓰는 작은 입력 창(계획서 26-3b) — [개인에 저장](경로 · 이름) ·
|
||||
* 나무 오른쪽 클릭 「새 항목」(이름 · 단위). 확인 = 넣은 글들 · 취소 · 닫기 = null.
|
||||
* 나무 오른쪽 클릭 「새 항목」(이름 · 단위). 확인 = 넣은 글들 · 닫기 = null.
|
||||
* [확인] = 머리 [닫기] 왼쪽 · [취소] 없음(머리 [닫기] = 취소 · 147-2).
|
||||
* ========================================================================== */
|
||||
|
||||
import { createButton, createInputField, el } from "./ui_template_elements";
|
||||
@@ -22,7 +23,6 @@ export interface AskOptions {
|
||||
note?: string;
|
||||
fields: AskField[];
|
||||
okLabel: string;
|
||||
cancelLabel: string;
|
||||
closeLabel: string;
|
||||
/** 빈 값 알림 — `{label}` 자리에 칸 이름 */
|
||||
emptyText: string;
|
||||
@@ -45,7 +45,7 @@ export function askFields(opts: AskOptions): Promise<Record<string, string> | nu
|
||||
finish(null);
|
||||
return true;
|
||||
},
|
||||
mount: (body, close) => {
|
||||
mount: (body, close, head) => {
|
||||
const inputs = opts.fields.map((field) => ({
|
||||
field,
|
||||
input: createInputField({
|
||||
@@ -76,21 +76,8 @@ export function askFields(opts: AskOptions): Promise<Record<string, string> | nu
|
||||
body.append(
|
||||
...(opts.note ? [el("p", { className: "ui-item-picker__where", text: opts.note })] : []),
|
||||
...inputs.map(({ input }) => input.root),
|
||||
el("div", {
|
||||
className: "ui-item-picker__actions",
|
||||
children: [
|
||||
createButton({
|
||||
label: opts.cancelLabel,
|
||||
variant: "ghost",
|
||||
onClick: () => {
|
||||
finish(null);
|
||||
close();
|
||||
},
|
||||
}),
|
||||
createButton({ label: opts.okLabel, variant: "filled", onClick: submit }),
|
||||
],
|
||||
}),
|
||||
);
|
||||
head.append(createButton({ label: opts.okLabel, variant: "filled", onClick: submit }));
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
@@ -98,7 +98,6 @@ const TEXT = {
|
||||
saved: "개인 층에 저장했음",
|
||||
saveFailed: "개인에 저장하지 못함 — {value}",
|
||||
ok: "확인",
|
||||
cancel: "취소",
|
||||
close: "닫기",
|
||||
empty: "{label} 을(를) 넣을 것",
|
||||
importFailed: "이 구조물로 가져오지 못함 — {value}",
|
||||
@@ -267,7 +266,6 @@ export function createItemDetail(opts: ItemDetailOptions): ItemDetail {
|
||||
{ key: "name", label: TEXT.nameLabel, value: itemName(row), required: true },
|
||||
],
|
||||
okLabel: TEXT.ok,
|
||||
cancelLabel: TEXT.cancel,
|
||||
closeLabel: TEXT.close,
|
||||
emptyText: TEXT.empty,
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user