diff --git a/B08_Quantity/B08_Quantity_UI_Drawing.css b/B08_Quantity/B08_Quantity_UI_Drawing.css index ddc31120a..b6133d76d 100644 --- a/B08_Quantity/B08_Quantity_UI_Drawing.css +++ b/B08_Quantity/B08_Quantity_UI_Drawing.css @@ -84,6 +84,24 @@ border-color: var(--color-danger); } +/* 칩 테두리 상태 색(170-3) — 연결됨 · 마스터가 바뀜 · 고침 있음 · 원본 없어짐(빨강 점선) */ +.b08-link__chip.is-linked { + border-color: var(--color-success); +} + +.b08-link__chip.is-changed { + border-color: var(--color-warning); +} + +.b08-link__chip.is-edited { + border-color: var(--color-info); +} + +.b08-link__chip.is-gone { + border-style: dashed; + border-color: var(--color-danger); +} + .b08-link__state { overflow: hidden; max-width: 18rem; diff --git a/B08_Quantity/B08_Quantity_UI_Link.ts b/B08_Quantity/B08_Quantity_UI_Link.ts index e3865b214..0fa90c214 100644 --- a/B08_Quantity/B08_Quantity_UI_Link.ts +++ b/B08_Quantity/B08_Quantity_UI_Link.ts @@ -102,10 +102,11 @@ async function update(projectId: string, info: ProjectItemInfo): Promise { @@ -124,6 +125,15 @@ async function paintCopyState( if (info.고침) badges.append(badge("B08_Quantity_Link_Edited", false)); if (info.원본없음) badges.append(badge("B08_Quantity_Link_Gone", true)); else if (info.마스터바뀜) badges.append(badge("B08_Quantity_Link_Changed", true)); + // 테두리 상태 색(170-3) — 앞섬 = 없어짐 › 바뀜 › 고침 › 연결 + const tone = info.원본없음 + ? "is-gone" + : info.마스터바뀜 + ? "is-changed" + : info.고침 + ? "is-edited" + : null; + if (tone) chip.classList.replace("is-linked", tone); button.disabled = !info.마스터바뀜 || !!info.원본없음; button.title = button.disabled ? L("B08_Quantity_Link_UpdateSame") @@ -163,7 +173,7 @@ export function linkSection( line.append(head); for (const slot of facility.slots) { const chip = document.createElement("span"); - chip.className = slot.linked ? "b08-link__chip" : "b08-link__chip is-missing"; + chip.className = slot.linked ? "b08-link__chip is-linked" : "b08-link__chip is-missing"; chip.dataset.b08LinkSlot = slot.copy; const name = document.createElement("span"); name.className = "b08-link__name"; @@ -204,7 +214,9 @@ export function linkSection( ); updateButton.disabled = true; // 원본판 대조를 받기 전엔 꺼 둠 buttons.append(updateButton); - void paintCopyState(projectId, slot, badges, updateButton).then((got) => (info = got)); + void paintCopyState(projectId, slot, chip, badges, updateButton).then( + (got) => (info = got), + ); } chip.append(name, state, badges, buttons); line.append(chip); diff --git a/resources/tester/test_163_b08_modal.py b/resources/tester/test_163_b08_modal.py index b2a0d8166..732c7c7a5 100644 --- a/resources/tester/test_163_b08_modal.py +++ b/resources/tester/test_163_b08_modal.py @@ -17,7 +17,7 @@ LOCALE = (ROOT / "ui_template/ui_template_locale_b4.ts").read_text(encoding="utf def test_163_1_칩_한_줄_공용_접기(): assert 'line.className = "b08-link__row"' in LINK # 시설마다 한 줄 - assert '"b08-link__chip"' in LINK and "chip.dataset.b08LinkSlot = slot.copy" in LINK + assert '"b08-link__chip is-linked"' in LINK and "chip.dataset.b08LinkSlot = slot.copy" in LINK # 모두 연결이면 접힘 · 미연결 있으면 펼침 assert 'ui-collapsible${missing ? "" : " is-collapsed"}' in LINK assert "ui-collapsible__title" in LINK and "attachCollapsible(section)" in LINK diff --git a/resources/tester/test_170_b08_modal_head.py b/resources/tester/test_170_b08_modal_head.py index 8892a24df..e3a9fdb21 100644 --- a/resources/tester/test_170_b08_modal_head.py +++ b/resources/tester/test_170_b08_modal_head.py @@ -24,3 +24,31 @@ def test_170_4_집계표_보조_탭_줄_자리(): assert ".b08-quantity__tabs--blank > .ui-btn {\n visibility: hidden;" in PAGE_CSS.replace( "\r\n", "\n" ) + + +LINK = (ROOT / "B08_Quantity/B08_Quantity_UI_Link.ts").read_text(encoding="utf-8") +DRAWING_CSS = (ROOT / "B08_Quantity/B08_Quantity_UI_Drawing.css").read_text(encoding="utf-8") +THEME = (ROOT / "ui_template/ui_template_theme.css").read_text(encoding="utf-8") + + +def test_170_3_칩_테두리_상태_색(): + assert 'slot.linked ? "b08-link__chip is-linked" : "b08-link__chip is-missing"' in LINK + assert "paintCopyState(projectId, slot, chip, badges, updateButton)" in LINK + # 앞섬 = 없어짐 › 바뀜 › 고침 › 연결 + tone = LINK.split("const tone = info.원본없음", 1)[1].split(";", 1)[0] + assert tone.index('"is-gone"') < tone.index('"is-changed"') < tone.index('"is-edited"') + assert 'chip.classList.replace("is-linked", tone)' in LINK + for cls, token in ( + ("is-linked", "success"), + ("is-missing", "danger"), + ("is-changed", "warning"), + ("is-edited", "info"), + ("is-gone", "danger"), + ): + rule = DRAWING_CSS.split(f".b08-link__chip.{cls} {{", 1)[1].split("}", 1)[0] + assert f"border-color: var(--color-{token});" in rule + assert f"--color-{token}:" in THEME # 밝음 · 어두움 토큰 + assert ( + "border-style: dashed;" + in DRAWING_CSS.split(".b08-link__chip.is-gone {", 1)[1].split("}", 1)[0] + )