Merge remote-tracking branch 'origin/sub_laptop_1' into main_laptop_1

This commit is contained in:
2026-10-10 12:56:43 +09:00
5 changed files with 101 additions and 9 deletions
@@ -44,6 +44,12 @@
gap: var(--spacing-8);
}
/* 185-2 보기 단추 글 한 줄 */
.b09-estimation__bar .ui-btn {
flex: none;
white-space: nowrap;
}
/* 182 설계내역서 레벨 — 글자 크기(줄 높이 28px 고정 → 16px 까지) · 첫 칸 들여쓰기 1em × (레벨 − 1) */
.b09-estimation .ui-data-table__table tbody tr.is-lv1 td {
font-size: var(--text-body);
@@ -177,7 +177,7 @@ function numberFormat(spec: TabTable, key: string): (v: number | null | undefine
/** 이 화면 안 보기(기억이 안 돼도 바꾼 보기 유지) */
const chosen = new Map<TabId, GroupView>();
/** 묶음 탭 — 머리(안내 + 보기 단추) · 고른 보기(카드 · 표) */
/** 묶음 탭 — 카드 = 안내 + 카드 판(보기 단추는 가로 열 수 줄) · 표 = 머리(안내 + 보기 단추) + 표 */
export function renderGroupPanel(o: {
tab: TabId;
spec: TabTable;
@@ -199,9 +199,6 @@ export function renderGroupPanel(o: {
},
});
toggle.dataset.b09GroupView = view;
const bar = document.createElement("div");
bar.className = "b09-estimation__bar";
bar.append(...(o.hint ? [o.hint] : []), toggle);
const at = o.focus === undefined ? -1 : rowIndex(o.spec.rows, o.focus);
if (view === "cards") {
const first = o.spec.columns[0]?.key ?? "";
@@ -213,10 +210,14 @@ export function renderGroupPanel(o: {
focus: at,
money: numberFormat(o.spec, "sum"),
qty: numberFormat(o.spec, "qty"),
actions: [toggle], // 185-2 가로 열 수 단추와 한 줄
});
cards.dataset.b09Table = o.tab;
return [bar, cards];
return [...(o.hint ? [o.hint] : []), cards];
}
const bar = document.createElement("div");
bar.className = "b09-estimation__bar";
bar.append(...(o.hint ? [o.hint] : []), toggle);
const range = pickRange(o.spec.rows, o.focus);
const table = o.makeTable((i) => pickClass(range, i));
if (at >= 0) requestAnimationFrame(() => table.focusRow(at));
@@ -146,13 +146,14 @@ def test_화면_보기_바꿈_누름_이동():
"\nconst o = { tab: 'dg', spec, hint: null, focus: 'DG1|1', goto: (l) => gone.push(l),"
" redraw: () => redraws++, makeTable: () => ({ root: document.createElement('table'),"
" focusRow: (i) => focused.push(i) }) };"
"\nconst [bar, view] = renderGroupPanel(o);"
"\nconst label = bar.children[0].textContent;"
"\nconst [view] = renderGroupPanel(o);"
"\nconst btn = view.querySelector('[data-b09-group-view]');"
"\nconst label = btn.textContent;"
"\nview.querySelector('[data-at=\"2\"]').click();"
"\nview.querySelector('[data-at=\"0\"]').click();"
"\nconst lit = view.querySelector('[data-at=\"3\"]').classList.contains('is-focus');"
"\nconst box = view.querySelector('.ui-group-card').classList.contains('is-pick');"
"\nbar.children[0].click();"
"\nbtn.click();"
"\nconst [bar2, view2] = renderGroupPanel(o);"
"\nconsole.log(JSON.stringify({ label, table: view.dataset.b09Table, gone, lit, box, redraws,"
" label2: bar2.children[0].textContent, tag2: view2.tagName, focused,"
@@ -0,0 +1,76 @@
"""185-2 B09 묶음 탭 도구 줄 — 보기 바꿈 단추 글 한 줄 · 가로 열 수 단추와 같은 줄.
- 카드 보기 = 보기 바꿈 단추가 가로 열 수 줄(`ui-group-cards__bar`) 안 · 표 보기 = 머리 줄(`b09-estimation__bar`)
- 단추 · 라벨 = `white-space: nowrap` · 도구 줄 = 줄바꿈 없음(`flex-wrap: nowrap`)
"""
import json
import re
import sys
from pathlib import Path
ROOT = Path(__file__).resolve().parents[2]
if str(ROOT) not in sys.path:
sys.path.insert(0, str(ROOT))
from resources.tester.helper_b09_group_cards import COMMON, GROUPS, RAW, TABS, run # noqa: E402
B09 = "B09_Estimation/B09_Estimation_UI_Tabs_"
DG = {"id": "DG1", "no": 1, "name": "찰쌓기", "unit": "m2", "lines": [], "sum": 0}
HINT = "(() => { const h = document.createElement('p'); h.className = 'hint'; return h; })()"
def _block(css: str, selector: str) -> str:
m = re.search(re.escape(selector) + r"\s*\{([^}]*)\}", css)
assert m, selector
return m.group(1)
def _panel(view: str, hint: str):
"""고른 보기 · 안내 글로 그린 뒤 보기 바꿈 단추가 든 줄 · 그 줄의 열 수 단추."""
return run(
[COMMON, TABS, f"{B09}Labor.ts", GROUPS],
f"\nconst spec = buildDaegaBlocks({{ sheets: {{ daega_blocks: [{json.dumps(DG, ensure_ascii=False)}] }} }});"
f"\nchosen.set('dg', '{view}');"
f"\nconst o = {{ tab: 'dg', spec, hint: {hint}, goto: () => {{}}, redraw: () => {{}},"
" makeTable: () => ({ root: document.createElement('table'), focusRow: () => {} }) };"
"\nconst out = renderGroupPanel(o);"
"\nconst top = out.find((e) => e.all('[data-b09-group-view]').length || e.dataset.b09GroupView);"
"\nconst btn = top.dataset.b09GroupView ? top : top.querySelector('[data-b09-group-view]');"
"\nconst bar = btn.closest('.ui-group-cards__bar') ?? btn.closest('.b09-estimation__bar') ?? top;"
"\nconsole.log(JSON.stringify({ n: out.length, first: out[0].className, label: btn.textContent,"
" bar: bar.className, cols: bar.all('[data-group-cols]').map((b) => b.dataset.groupCols) }));",
RAW,
)
def test_카드_보기_단추가_가로_열수_줄에():
out = _panel("cards", "null")
assert out["bar"] == "ui-group-cards__bar" and out["label"] == "표로 보기"
assert out["cols"] == ["1", "2", "3", "4"] # 같은 줄에 열 수 단추 넷
assert out["n"] == 1 # 안내 글 없으면 카드 판 하나뿐
def test_카드_보기_안내_글은_카드_위에_따로():
out = _panel("cards", HINT)
assert out["n"] == 2 and out["first"] == "hint"
assert out["bar"] == "ui-group-cards__bar"
def test_표_보기_단추는_머리_줄():
out = _panel("table", "null")
assert out["bar"] == "b09-estimation__bar" and out["label"] == "박스보기"
assert out["cols"] == [] # 표 보기 = 열 수 단추 없음
def test_CSS_한_줄_nowrap():
cards = (ROOT / "ui_template" / "ui_template_group_cards.css").read_text("utf-8")
assert "flex-wrap: nowrap" in _block(cards, ".ui-group-cards__bar")
item = _block(
cards,
".ui-group-cards__bar .ui-btn,\n.ui-group-cards__label,\n.ui-group-cards__count",
)
assert "white-space: nowrap" in item and "flex: none" in item
page = (ROOT / "B09_Estimation" / "B09_Estimation_UI_Page.css").read_text("utf-8")
assert "white-space: nowrap" in _block(page, ".b09-estimation__bar .ui-btn")
assert "actions: [toggle]" in (ROOT / GROUPS).read_text("utf-8")
+9 -1
View File
@@ -10,11 +10,19 @@
.ui-group-cards__bar {
display: flex;
flex-wrap: wrap;
flex-wrap: nowrap;
align-items: center;
gap: var(--spacing-8);
}
/* 185-2 도구 줄 = 한 줄 · 단추 · 글 줄바꿈 없음 */
.ui-group-cards__bar .ui-btn,
.ui-group-cards__label,
.ui-group-cards__count {
flex: none;
white-space: nowrap;
}
.ui-group-cards__cols {
display: inline-flex;
align-items: center;