diff --git a/B05_Profile/B05_Profile_UI_Style_Structures.css b/B05_Profile/B05_Profile_UI_Style_Structures.css index d8fcc2277..ed8512694 100644 --- a/B05_Profile/B05_Profile_UI_Style_Structures.css +++ b/B05_Profile/B05_Profile_UI_Style_Structures.css @@ -569,7 +569,7 @@ } /* 상자 안 작은 단추 템플릿(54-41) — 높이 = 숫자 칸 [-][+](`--b05-control-h`) · 글 · 안 여백도 그 높이에 · - * 상자 이름표 [삭제]도 같은 틀(136-3) · 상자 밖 [추가] · [삭제] · [리셋]은 제외 */ + * 상자 이름표 [삭제]도 같은 틀(136-3) · 상자 밖 [추가] · [삭제] · [리셋]은 아래 205-1 */ .b05-structure__group-body button:not(.b05-structure__step), .b05-structure__group > legend > button { box-sizing: border-box; @@ -580,6 +580,24 @@ line-height: 1; } +/* 「구조물 배치」 맨 아래 [추가] · [삭제] · [리셋] 줄(205-1) — 단추 높이 = 상자 안 작은 단추(`--b05-control-h`) · + * 폼이 길어도 스크롤 영역 아래 끝에 붙어 늘 보임(자리 고정 · 뒤 내용이 비치지 않게 불투명 배경) */ +.b05-structure-section .b05-route__irregular-actions { + position: sticky; + bottom: 0; + z-index: 1; + background: var(--color-surface-raised); +} + +.b05-structure-section .b05-route__irregular-actions > button { + box-sizing: border-box; + height: var(--b05-control-h); + min-height: 0; + padding-block: 0; + font-size: var(--text-caption); + line-height: 1; +} + /* 노면공 「확폭 구간」 상자(PLAN 87-3) — 구간마다 단추 한 줄 */ .b05-structure__widening[hidden] { display: none; diff --git a/resources/tester/test_205_1_structure_actions_height.py b/resources/tester/test_205_1_structure_actions_height.py new file mode 100644 index 000000000..9d3ae79b4 --- /dev/null +++ b/resources/tester/test_205_1_structure_actions_height.py @@ -0,0 +1,50 @@ +"""205-1 「구조물 배치」 맨 아래 [추가] · [삭제] · [리셋] 줄 — 단추 높이 = 상자 안 작은 단추 · 늘 보임. + +- 높이 = `--b05-control-h`(상자 안 단추 · 입력 칸과 같은 값) · 상자 이름표 [삭제]와 같은 높이 식 +- 줄 = 스크롤 영역 아래 끝에 붙음(sticky · bottom 0) · 단추 · 줄에 hidden · display none · visibility · + 호버 조건이 없음 +""" + +import re +from pathlib import Path + +ROOT = Path(__file__).resolve().parents[2] +CSS = (ROOT / "B05_Profile/B05_Profile_UI_Style_Structures.css").read_text(encoding="utf-8") +FORM = (ROOT / "B05_Profile/B05_Profile_UI_Structures_Form.ts").read_text(encoding="utf-8") +SECTION = ".b05-structure-section .b05-route__irregular-actions" + + +def _block(selector: str) -> str: + m = re.search(r"(?m)^" + re.escape(selector) + r"\s*\{([^}]*)\}", CSS) + assert m, selector + return m.group(1) + + +def _decl(block: str, prop: str) -> str: + m = re.search(r"(?:^|;|\s)" + re.escape(prop) + r"\s*:\s*([^;]+);", block) + assert m, prop + return m.group(1).strip() + + +def test_buttons_same_height_as_inner_buttons(): + outer = _block(SECTION + " > button") + inner = re.search(r"\.b05-structure__group > legend > button\s*\{([^}]*)\}", CSS).group(1) + assert _decl(outer, "height") == "var(--b05-control-h)" + for prop in ("height", "box-sizing", "padding-block", "font-size", "line-height"): + assert _decl(outer, prop) == _decl(inner, prop), prop + assert re.search(r"--b05-control-h:\s*26px;", CSS) + + +def test_row_always_visible(): + row = _block(SECTION) + assert _decl(row, "position") == "sticky" + assert _decl(row, "bottom") == "0" + assert "background" in row + for text in (_block(SECTION), _block(SECTION + " > button")): + assert not re.search(r"display\s*:\s*none|visibility|opacity|overflow", text) + assert not re.search(re.escape(SECTION) + r"[^{]*(:hover|:focus-within|\[hidden\])", CSS) + + +def test_form_never_hides_buttons(): + assert "removeButton.hidden" not in FORM and "resetButton.hidden" not in FORM + assert "actions.hidden" not in FORM