diff --git a/B05_Profile/B05_Profile_UI_Style_Structures.css b/B05_Profile/B05_Profile_UI_Style_Structures.css index 846d3623c..c3f163646 100644 --- a/B05_Profile/B05_Profile_UI_Style_Structures.css +++ b/B05_Profile/B05_Profile_UI_Style_Structures.css @@ -453,10 +453,10 @@ background: color-mix(in srgb, var(--color-success) 18%, var(--color-surface)); } -/* 미연결 — 연한 노랑 배경 + 노랑 테두리(경고 · 밝음 · 어두움 같은 토큰). */ +/* 미연결 — 옅은 회색 배경 + 회색 테두리(구조물 리스트 램프 색 · 밝음 · 어두움 같은 토큰 · 258-3). */ .b05-structure__summary-name:not(.is-assigned) { - border-color: var(--color-warning); - background: color-mix(in srgb, var(--color-warning) 18%, var(--color-surface)); + border-color: var(--color-text-muted); + background: color-mix(in srgb, var(--color-text-muted) 12%, var(--color-surface)); } .b05-structure__summary .b05-route__irregular-btn { diff --git a/resources/tester/test_177_1_summary_unassigned_bg.py b/resources/tester/test_177_1_summary_unassigned_bg.py index bafa3cf4f..7af55cb66 100644 --- a/resources/tester/test_177_1_summary_unassigned_bg.py +++ b/resources/tester/test_177_1_summary_unassigned_bg.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -"""PLAN 177-1 — 구조물 조합 미연결 라벨 = 연한 노랑(경고) 배경 + 테두리(소스 시험).""" +"""PLAN 177-1 → 258-3 — 구조물 조합 미연결 라벨 = 옅은 회색(구조물 리스트 램프 색) 배경 + 테두리(소스 시험).""" import os import re @@ -15,10 +15,10 @@ def _rule(sel: str) -> str: return m.group(1) -def test_미연결_배경_테두리_경고색_글자색_없음(): +def test_미연결_배경_테두리_회색_글자색_없음(): body = _rule(".b05-structure__summary-name:not(.is-assigned)") - assert re.search(r"border-color:\s*var\(--color-warning\)", body) - assert re.search(r"background:\s*color-mix\([^;]*--color-warning[^;]*--color-surface", body) + assert re.search(r"border-color:\s*var\(--color-text-muted\)", body) + assert re.search(r"background:\s*color-mix\([^;]*--color-text-muted[^;]*--color-surface", body) assert not re.search(r"(^|[;\s])color:", body) diff --git a/resources/tester/test_243_1_double_click_tables.py b/resources/tester/test_243_1_double_click_tables.py index 5629a735d..a261089b1 100644 --- a/resources/tester/test_243_1_double_click_tables.py +++ b/resources/tester/test_243_1_double_click_tables.py @@ -1,7 +1,7 @@ -"""243-1 · 126 — B08 · B09 값 고칠 수 있는 표 전부 더블클릭 입력 · 고칠 칸 테두리 = 246-1 에서 지움. +"""243-1 · 126 — B08 · B09 값 고칠 수 있는 표 전부 더블클릭 입력 · 고칠 칸 테두리 = 258-2 에서 옅게 되살림. - 공용 표 editOnDouble = 한 번 누름 = 글 상자 안 열림 · 더블클릭 · 칸 누른 뒤 Enter · F2 = 그 칸 글 상자 -- 고칠 수 있는 칸(td) 표시 `is-can-edit` 없음(246-1 · 241 앞 모양) +- 고칠 수 있는 칸(td) = 글일 때도 `is-can-edit`(옅은 outline · 258-2) · 못 고치는 칸 · 옛 방식 표 = 없음 - B09 = 표 만드는 길 한 곳(Shell) · B08 = 고칠 칸 있는 표(자재 집계표 셋) 모두 editOnDouble - 칸 누름으로 여는 메뉴 · 고르기 · 이동(onCellClick · choices · link)은 그대로 """ @@ -76,7 +76,7 @@ setTimeout(() => { def test_공용_표_더블클릭_Enter_F2(): out = json.loads(_node(TABLE + HARNESS + SCENE_JS)) - assert out["can"] == [] # 246-1 고칠 칸 td 표시 없음 + assert out["can"] == ["3"] # 고칠 수 있는 칸만 · 글일 때도 표시(258-2) assert out["start"] == [] # 처음 = 글 상자 없음 assert out["click"] == [[], ["click 1:qty"]] # 한 번 누름 = 안 열림 · 누름 알림은 그대로 assert out["f2"] == ["1:qty"] # F2 = 누른 칸 입력 @@ -90,10 +90,18 @@ def test_공용_표_더블클릭_Enter_F2(): assert out["old"] == [["1:qty"], []] # editOnDouble 없는 표 = 예전대로(테두리 class 없음) -def test_고칠_칸_테두리_CSS_없음(): +def test_고칠_칸_테두리_CSS_옅게_테마_변수만(): css = (ROOT / "ui_template" / "ui_template_data_table.css").read_text("utf-8") - ts = (ROOT / "ui_template" / "ui_template_data_table.ts").read_text("utf-8") - assert "is-can-edit" not in css and "is-can-edit" not in ts # 246-1 되돌림 + m = re.search(r"\.ui-data-table__table td\.is-can-edit \{([^}]*)\}", css) + assert m + body = m.group(1) + assert ( + "outline: 1px solid color-mix(in srgb, var(--color-accent) 28%, var(--color-canvas));" + in body + ) + assert "outline-offset: -1px;" in body # 칸 크기 불변 + assert "box-shadow" not in body # 빨강 이동 상자(box-shadow)와 안 겹침 + assert "#" not in body # 하드코딩 색 없음 def _sources(*folders: str) -> list[Path]: diff --git a/resources/tester/test_246_1_b09_bill_menu_simple.py b/resources/tester/test_246_1_b09_bill_menu_simple.py index 450d2dd66..4df6d88a6 100644 --- a/resources/tester/test_246_1_b09_bill_menu_simple.py +++ b/resources/tester/test_246_1_b09_bill_menu_simple.py @@ -16,11 +16,12 @@ ROOT = Path(__file__).resolve().parents[2] OLD_ADDS = ["위에 줄 추가", "아래에 줄 추가", "아래에 하위 줄 추가", "새 공종 추가(1단)"] -def test_입력_칸_테두리_없음(): +def test_입력_칸_채움_색_td_테두리_옅게(): css = (ROOT / "ui_template" / "ui_template_data_table.css").read_text("utf-8") body = css.split(".ui-data-table__input {")[1].split("}")[0] assert "background: color-mix(in srgb, var(--color-accent) 5%, var(--color-canvas));" in body - assert "box-shadow" not in body and "is-can-edit" not in css + assert "box-shadow" not in body + assert "td.is-can-edit {" in css # 258-2 — 고칠 칸 옅은 outline 되살림 def test_더함_하나_줄_삭제_연결_이름_셋(): diff --git a/resources/tester/test_258_1_table_width_var.py b/resources/tester/test_258_1_table_width_var.py new file mode 100644 index 000000000..7831b90d7 --- /dev/null +++ b/resources/tester/test_258_1_table_width_var.py @@ -0,0 +1,52 @@ +"""258-1 · 258-2 · 258-3 — 표 폭 CSS 변수 · 입력 칸 테두리 옅게 · 구조물 조합 미지정 회색(소스 시험). + +- 템플릿 표 인라인 = `--dt-w`(열 합) · css `width: var(--dt-w)` → 페이지 css 가 width 로 덮음 +- 거리이정표 표 = 틀 폭 100% +- 고칠 칸 td.is-can-edit = accent 28% outline · box-shadow 아님 +- B05 미지정 = 회색(text-muted) +""" + +import re +from pathlib import Path + +ROOT = Path(__file__).resolve().parents[2] +DT_CSS = ROOT / "ui_template" / "ui_template_data_table.css" +DT_TS = ROOT / "ui_template" / "ui_template_data_table.ts" + + +def _rule(css: str, selector: str) -> str: + m = re.search(re.escape(selector) + r" \{([^}]*)\}", css) + assert m, selector + return m.group(1) + + +def test_표_폭_인라인_변수_css_width_변수(): + ts = DT_TS.read_text("utf-8") + assert '' in ts + assert 'style="width:${x}px"' not in ts # 인라인 width 가 페이지 css 를 이기지 않음 + body = _rule(DT_CSS.read_text("utf-8"), ".ui-data-table__table") + assert "width: var(--dt-w);" in body + assert "table-layout: fixed;" in body + + +def test_거리이정표_표_틀_폭_전체(): + css = (ROOT / "B08_Quantity" / "B08_Quantity_UI_Milestone.css").read_text("utf-8") + body = _rule(css, ".b08-milestone > .ui-data-table .ui-data-table__table") + assert "width: 100%;" in body # 변수 규칙(0,1,0)보다 선택자가 구체적 + + +def test_입력_칸_테두리_옅게_outline(): + css = DT_CSS.read_text("utf-8") + body = _rule(css, ".ui-data-table__table td.is-can-edit") + m = re.search(r"var\(--color-accent\) (\d+)%", body) + assert m and 25 <= int(m.group(1)) <= 30 # 예전 60% → 옅게 + assert "outline: 1px solid" in body and "box-shadow" not in body + assert '"is-can-edit"' in DT_TS.read_text("utf-8") + + +def test_구조물_조합_미지정_회색(): + css = (ROOT / "B05_Profile" / "B05_Profile_UI_Style_Structures.css").read_text("utf-8") + body = _rule(css, ".b05-structure__summary-name:not(.is-assigned)") + assert "border-color: var(--color-text-muted);" in body + assert "--color-text-muted" in body.split("background:")[1] + assert "--color-warning" not in body diff --git a/resources/tester/test_ui_data_table.py b/resources/tester/test_ui_data_table.py index 70ab16487..6b61be801 100644 --- a/resources/tester/test_ui_data_table.py +++ b/resources/tester/test_ui_data_table.py @@ -108,7 +108,7 @@ def test_155_1_글자_14px_열_폭_같은_비율(r): assert abs(r["scale"] - 14 / 12) < 1e-9 w = r["widths"] assert '' in w - assert 'style="width:350px"' in w # 표 폭 = 112 + 98 + 140 + assert 'style="--dt-w:350px"' in w # 표 폭 = 112 + 98 + 140 (258-1 · css 변수) assert 'class="is-frozen is-edge" style="left:112px"' in w # 둘째 고정 열 left 도 같이 assert "font-size: var(--text-body-sm);" in r["css"] assert "--dt-row-h: 28px;" in r["css"] diff --git a/ui_template/ui_template_data_table.css b/ui_template/ui_template_data_table.css index f17dc400a..ed9f05f32 100644 --- a/ui_template/ui_template_data_table.css +++ b/ui_template/ui_template_data_table.css @@ -33,6 +33,8 @@ } .ui-data-table__table { + /* 258-1 — 표 폭 = 열 합(--dt-w · 인라인) · 페이지 css 가 width 로 덮음 */ + width: var(--dt-w); table-layout: fixed; border-collapse: separate; border-spacing: 0; @@ -175,6 +177,12 @@ text-align: right; } +/* 고칠 수 있는 칸(PLAN 258-2 · editOnDouble) — 글일 때도 옅은 입력 칸 테두리(outline 안쪽 · 줄 고름 box-shadow 와 안 겹침) */ +.ui-data-table__table td.is-can-edit { + outline: 1px solid color-mix(in srgb, var(--color-accent) 28%, var(--color-canvas)); + outline-offset: -1px; +} + .ui-data-table__input:focus { outline: 2px solid var(--color-focus-ring); outline-offset: -2px; diff --git a/ui_template/ui_template_data_table.ts b/ui_template/ui_template_data_table.ts index afc3bc564..44c2e69d8 100644 --- a/ui_template/ui_template_data_table.ts +++ b/ui_template/ui_template_data_table.ts @@ -17,6 +17,7 @@ * 나무(PLAN 235-1 · tree) = 접히지 않는 나무 안내선(├ is-tee · └ is-end · │ is-bar) + 폴더 · 파일 아이콘(공용 나무 꼴) * 더블클릭 입력(PLAN 235-1 · editOnDouble) = 고칠 칸도 글로 그림 · 더블클릭 · t.edit(줄) = 그 칸만 글 상자 · * Enter(조합 끝난 뒤) · 초점 떠남 = 입력 끝(onEdit) — 한 번 누름 = 줄 고름 · 끌기 + * 고칠 수 있는 칸 = 글일 때도 칸에 입력 칸 테두리 class `is-can-edit`(PLAN 258-2 · 옅은 outline) · * 칸 누른 뒤 Enter · F2 = 그 칸 입력 시작(PLAN 243-1 · keyEdit false = 표 밖이 맡음) * 같은 값 세로 병합(PLAN 201-1) = mergeSame [열] → 위아래로 같은 값이 이어지면 한 칸(rowSpan) · 본문만 * 앞 병합 열이 갈리면 뒤 병합 열도 갈림 · 빈 값 · 고칠 칸은 안 합침 · 칸 → 열 = `cellColumn`(병합 표는 data-c) @@ -183,7 +184,7 @@ function rowHtml( more: RowMore = {}, ): string { let tr = ""; - const { lv, spans } = more; + const { lv, spans, can } = more; for (let j = 0; j < cols.length; j++) { const key = cols[j].key; const span = spans?.[j] ?? 1; @@ -209,6 +210,7 @@ function rowHtml( frz && left[j + 1] == null && "is-edge", empty && "is-empty", cellClass?.(key), + can?.(key) && "is-can-edit", lvc.trim(), span > 1 && "is-merged", ] @@ -241,6 +243,8 @@ function rowHtml( interface RowMore { lv?: { key: string; n: number; node: boolean; tree?: string }; spans?: number[]; + /** 고칠 수 있는 칸인지(editOnDouble · 글로 그린 칸에 `is-can-edit` 표시 · 258-2) */ + can?: (key: string) => boolean; } /** 칸 → 열 번호 — 병합 표는 칸이 빠져 cellIndex 가 밀리므로 data-c */ @@ -356,6 +360,7 @@ export function renderDataTableHtml(o: DataTableOptions, win?: RowWindow): strin { ...(o.level ? { lv: { key: o.level.key, n: lvN, node, tree: tree?.[i] } } : {}), ...(spans ? { spans: spans[i - from] } : {}), + ...(o.editOnDouble && o.editable ? { can: (key: string) => o.editable!(i, key) } : {}), }, ); } @@ -363,7 +368,7 @@ export function renderDataTableHtml(o: DataTableOptions, win?: RowWindow): strin const foot = o.total ? `${rowHtml(cols, fmts, left, o.total, false, blank)}` : ""; const cap = o.caption ? `` : ""; return ( - `
${esc(o.caption)}
${cap}${colgroup}` + + `
${cap}${colgroup}` + `${headHtml(cols, left)}${body}${foot}
` ); }