- B05 칸 틀(페이지 설정 · 계획노선 · 선택 포인트) = .ui-panel-form - B08 옵션 카드 · B09 데이터 점검 카드 = createPanelCard · 틈 덧칠 정리 - 아래 단추 묶음은 그대로 - 시험 test_269 점검(빠진 곳 0) · 122 · 203-1 · 240-1 기대값 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QND7Co43B24zK2P937rdxt
175 lines
8.0 KiB
Python
175 lines
8.0 KiB
Python
# -*- coding: utf-8 -*-
|
|
"""269 좌측 패널 컨테이너 공용 양식 — 기준 = B05/B06 「구조물 배치」.
|
|
|
|
못박는 것
|
|
- 공용 양식 = ui_template 한 곳(`.ui-panel-form` · `.ui-panel-btn` · 카드 `createPanelCard`) ·
|
|
칸 높이 · 라벨 틈 토큰 = theme 한 곳 · 「구조물 배치」도 같은 토큰.
|
|
- B07 컨테이너 = 공용 카드 · 도면 단추 = `.ui-panel-btn` · 페이지 덧칠(크기 · 글자 · 바탕) 없음.
|
|
- B06 컨테이너(횡단 보기 설정 · 표준 횡단면 설정) = 칸 틀 `createSectionFrame` 이 공용 양식을 붙임 ·
|
|
단추 · 입력칸 = 공용 함수(createButton · createInputField · createSelectField) · B06 덧칠 없음.
|
|
"""
|
|
|
|
import re
|
|
from pathlib import Path
|
|
|
|
ROOT = Path(__file__).resolve().parents[2]
|
|
|
|
|
|
def _read(rel: str) -> str:
|
|
return (ROOT / rel).read_text(encoding="utf-8")
|
|
|
|
|
|
THEME = _read("ui_template/ui_template_theme.css")
|
|
OVERLAY = _read("ui_template/ui_template_overlay.css")
|
|
COLLAPSIBLE = _read("ui_template/ui_template_collapsible.ts")
|
|
B05_STRUCT_CSS = _read("B05_Profile/B05_Profile_UI_Style_Structures.css")
|
|
B07_CSS = _read("B07_DesignDetail/B07_DesignDetail_UI_Style.css")
|
|
B07_PANELS = _read("B07_DesignDetail/B07_DesignDetail_UI_Panels.ts")
|
|
B07_PLAN = _read("B07_DesignDetail/B07_DesignDetail_UI_PlanKinds.ts")
|
|
DESIGN_PANEL = _read("A00_Common/design/design_panel.ts")
|
|
B06_CSS = _read("B06_Section/B06_Section_UI_Style.css")
|
|
B06_PANEL = _read("B06_Section/B06_Section_UI_Page_Panel.ts")
|
|
B06_STD = _read("B06_Section/B06_Section_UI_Standard_Panel.ts")
|
|
|
|
|
|
def _block(css: str, selector: str) -> str:
|
|
m = re.search(r"(?:^|\n)" + re.escape(selector) + r"\s*\{([^}]*)\}", css)
|
|
assert m, selector
|
|
return m.group(1)
|
|
|
|
|
|
def test_공용_양식_토큰은_theme_한_곳_구조물_배치도_같은_토큰():
|
|
assert "--panel-control-h: 26px;" in THEME
|
|
assert "--panel-label-gap: 2px;" in THEME
|
|
assert "--b05-control-h: var(--panel-control-h);" in B05_STRUCT_CSS
|
|
assert "--b05-label-gap: var(--panel-label-gap);" in B05_STRUCT_CSS
|
|
|
|
|
|
def test_공용_양식_칸_라벨_단추_규칙():
|
|
field = _block(
|
|
OVERLAY,
|
|
'.ui-panel-form input:not([type="checkbox"], [type="radio"], [type="range"]),\n'
|
|
".ui-panel-form select",
|
|
)
|
|
assert "height: var(--panel-control-h);" in field
|
|
assert "padding: 0 6px;" in field
|
|
assert "font-size: var(--text-caption);" in field
|
|
label = _block(OVERLAY, ".ui-panel-form .ui-field,\n.ui-panel-form .b05-route__field")
|
|
assert "gap: var(--panel-label-gap);" in label
|
|
assert "display: none;" in _block(OVERLAY, ".ui-panel-form .ui-field__error:not(.is-visible)")
|
|
button = _block(OVERLAY, ".ui-panel-form .ui-btn:not(.ui-help-btn)")
|
|
# 「구조물 배치」 단추(b05-route__irregular-btn)와 같은 크기
|
|
assert "padding: var(--spacing-8);" in button
|
|
assert "font-size: var(--text-caption);" in button
|
|
assert "border-radius: var(--radius-inputs);" in button
|
|
raw = _block(OVERLAY, ":where(.ui-panel-btn)")
|
|
for decl in (
|
|
"padding: var(--spacing-8);",
|
|
"border-radius: var(--radius-inputs);",
|
|
"background: var(--color-surface);",
|
|
"font-size: var(--text-caption);",
|
|
):
|
|
assert decl in raw, decl
|
|
# 아래 단추 묶음은 컨테이너 밖 — 공용 양식이 `.ui-sidebar-actions` 를 겨누지 않음
|
|
form_rules = OVERLAY[OVERLAY.index("좌측 패널 컨테이너 공용 양식(269)") :]
|
|
form_rules = form_rules[: form_rules.index("/* 카드 안에 다시 카드")]
|
|
assert "ui-sidebar-actions {" not in form_rules and "ui-sidebar-actions ." not in form_rules
|
|
|
|
|
|
def test_공용_카드_함수():
|
|
assert "export function createPanelCard(" in COLLAPSIBLE
|
|
assert "ui-collapsible ui-sidebar-section ui-sidebar-card ui-panel-form" in COLLAPSIBLE
|
|
|
|
|
|
def test_B07_컨테이너_공용_카드_도면_단추_공용_꼴():
|
|
assert "createPanelCard(`${group.label} ${items.length}`)" in B07_PANELS
|
|
assert "createPanelCard(`평면도 ${items.length}`)" in B07_PLAN
|
|
for src in (B07_PANELS, B07_PLAN):
|
|
assert "ui-collapsible ui-sidebar-section" not in src # 손으로 짠 카드 없음
|
|
assert B07_PANELS.count('"b07-drawing-button ui-panel-btn"') == 2
|
|
assert '"ui-panel-btn b07-plan-manage-open"' in B07_PLAN
|
|
|
|
|
|
def test_B07_페이지_덧칠_없음():
|
|
assert not re.search(r"(?:^|\n)\.b07-drawing-group\s*\{", B07_CSS)
|
|
assert ".b07-drawing-group h3 {" not in B07_CSS
|
|
assert ".b07-plan-manage-open {" not in B07_CSS
|
|
button = _block(B07_CSS, ".b07-drawing-button")
|
|
for prop in ("min-height", "padding", "border-radius", "background", "font-size"):
|
|
assert not re.search(r"(?:^|\s)" + prop + r"\s*:", button), prop
|
|
assert "font-size" not in _block(B07_CSS, ".b07-drawing-button__name")
|
|
assert ".b07-cross-layout .ui-btn" not in B07_CSS
|
|
assert ".b07-cross-layout .ui-field__error" not in B07_CSS
|
|
|
|
|
|
def test_B06_컨테이너_공용_양식():
|
|
frame = DESIGN_PANEL[DESIGN_PANEL.index("export function createSectionFrame(") :]
|
|
frame = frame[: frame.index("\n}\n")]
|
|
cross = frame[frame.index("b06-profile__group ui-collapsible") :]
|
|
assert "ui-panel-form" in cross.splitlines()[0]
|
|
for src in (B06_PANEL, B06_STD):
|
|
assert "createSectionFrame(" in src or "createButton(" in src
|
|
assert "<button" not in src and 'createElement("button")' not in src
|
|
assert 'createElement("input")' not in src and 'createElement("select")' not in src
|
|
assert "createInputField(" in B06_PANEL and "createButton(" in B06_PANEL
|
|
# 덧칠 없음 — 칸 글자 · 오류 칸 접기는 공용 양식 몫
|
|
group = _block(B06_CSS, ".b06-profile__group")
|
|
assert "font-size" not in group and not re.search(r"(?:^|\s)color\s*:", group)
|
|
assert ".b06-profile__field-row .ui-field__error" not in B06_CSS
|
|
for sel in (".ui-btn {", ".ui-input {", ".ui-select {"):
|
|
for line in B06_CSS.splitlines():
|
|
if line.endswith(sel) and line.startswith(".b06-profile"):
|
|
rule = _block(B06_CSS, line[:-2])
|
|
for prop in ("height", "padding", "font-size"):
|
|
assert not re.search(r"(?:^|\s)" + prop + r"\s*:", rule), (line, prop)
|
|
|
|
|
|
B08_OPTIONS = _read("B08_Quantity/B08_Quantity_UI_Options.ts")
|
|
B09_SHELL = _read("B09_Estimation/B09_Estimation_UI_Shell.ts")
|
|
# 기준(「구조물 배치」 폼 자신) · 부르는 곳 없는 옛 함수는 점검 밖
|
|
PANEL_DIRS = (
|
|
"A00_Common/design",
|
|
"B05_Profile",
|
|
"B06_Section",
|
|
"B07_DesignDetail",
|
|
"B08_Quantity",
|
|
"B09_Estimation",
|
|
)
|
|
REFERENCE = {
|
|
"B05_Profile/B05_Profile_UI_Structures_Form.ts",
|
|
"B05_Profile/B05_Profile_UI_IrregularStations.ts",
|
|
}
|
|
|
|
|
|
def test_B05_칸_틀_두_보기_모두_공용_양식():
|
|
frame = DESIGN_PANEL[DESIGN_PANEL.index("export function createSectionFrame(") :]
|
|
frame = frame[: frame.index("\n}\n")]
|
|
assert frame.count("ui-sidebar-section ui-panel-form") == 2
|
|
|
|
|
|
def test_B08_B09_카드_공용_카드():
|
|
assert "createPanelCard(L(title))" in B08_OPTIONS
|
|
assert 'createPanelCard("데이터 점검")' in B09_SHELL
|
|
for src in (B08_OPTIONS, B09_SHELL):
|
|
assert "ui-sidebar-card" not in src
|
|
|
|
|
|
def test_점검_B05_이상_좌측_컨테이너는_모두_공용_양식():
|
|
"""손으로 짠 컨테이너(ui-sidebar-section)에 공용 양식이 빠진 곳 = 0."""
|
|
misses, users = [], []
|
|
for page in PANEL_DIRS:
|
|
for path in (ROOT / page).glob("*.ts"):
|
|
rel = path.relative_to(ROOT).as_posix()
|
|
text = path.read_text(encoding="utf-8")
|
|
if "createIrregularStationsSection(" in text:
|
|
users.append(path.name)
|
|
if rel in REFERENCE:
|
|
continue
|
|
for n, line in enumerate(text.splitlines(), 1):
|
|
code = line.split("//")[0]
|
|
if "ui-sidebar-section" in code and "ui-panel-form" not in code:
|
|
misses.append(f"{rel}:{n}")
|
|
assert misses == []
|
|
# 점검 밖 옛 함수 = 정말 부르는 곳 없음(살아나면 점검에 넣음)
|
|
assert users == ["B05_Profile_UI_IrregularStations.ts"]
|