feat(m02): 상세 머리 이동 단추 — 지금 페이지 숨김 · 이동 단추 · 머리 [?] 보통 크기(113-2)

- DetailNav 지금 상세 단추 hidden · size sm 지움 · 눌림 CSS 지움
- 머리 [?] 만 ui-btn--sm 뺌 · 카드 [?] 는 작게 그대로
- test_m02_detail_nav 기대 고침 · test_m02_layer_screen 머리 줄 정규식에 nav.root

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01W4uKaV4ZBhsJN4GHG7yRj4
This commit is contained in:
2026-10-08 18:24:16 +09:00
co-authored by Claude Opus 5.5
parent 4defeb529b
commit a6ddc84f1b
5 changed files with 25 additions and 20 deletions
@@ -1,7 +1,7 @@
/* =============================================================================
* M02_MasterTemplete_DetailNav.ts
* 상세 머리 제목과 [?] 사이 [도면][일위대가][면적산출] 묶음(105-4) — 같은 열의 다른 상세로 옮겨 감.
* 지금 상세 = 눌림(aria-pressed) · 그 열 문서가 없으면 그 단추 꺼짐(번호 목록에 번호 없음).
* 지금 상세 단추 = 숨김(113-2) · 단추 크기 = 머리 [다시 열기]와 같은 보통 · 그 열 문서가 없으면 그 단추 꺼짐(번호 목록에 번호 없음).
* 보임 조건 · 옮겨 가기(confirmLeave → open)는 부른 쪽(`UI_Main`) 몫.
* ========================================================================== */
@@ -26,13 +26,13 @@ const NONE = "이 열은 문서가 없음";
export interface DetailNav {
root: HTMLElement;
/** 연 상세 — null 이면 숨김 · 눌림 · 꺼짐을 새로 */
/** 연 상세 — null 이면 숨김 · 지금 상세 단추 숨김 · 꺼짐을 새로 */
update: (at: { layer: Layer; kind: Kind; name: string } | null) => void;
}
export function createDetailNav(go: (kind: DetailKind) => void): DetailNav {
const buttons = ITEMS.map(([kind, label]) => {
const button = createButton({ label, size: "sm", variant: "ghost", onClick: () => go(kind) });
const button = createButton({ label, variant: "ghost", onClick: () => go(kind) });
button.dataset.detailNav = kind;
return button;
});
@@ -48,9 +48,9 @@ export function createDetailNav(go: (kind: DetailKind) => void): DetailNav {
const mine = ++ask;
buttons.forEach((button, i) => {
const on = ITEMS[i][0] === at?.kind;
button.setAttribute("aria-pressed", String(on)); // 눌림 = 지금 상세(누르면 그대로)
button.hidden = on; // 지금 상세 단추는 숨김(113-2)
button.disabled = false;
button.title = on ? "" : TIP;
button.title = TIP;
});
// 번호 목록은 지금 층만(프로젝트 층 · 남의 층이면 안 끔)
if (!at || at.layer === "project" || at.layer !== getActiveLayer()) return;
@@ -250,6 +250,7 @@ export function createMain(
nav.update(back.hidden ? null : sel); // 보임 조건 = 뒤로 단추와 같음
const kind = sel && sel.kind in HELP_TITLE ? (sel.kind as keyof typeof HELP_TITLE) : null;
const help = kind && helpParts(HELP_TITLE[kind], detailHelp(kind)); // 열 때마다 새로 — 상자는 닫힘
help?.button.classList.remove("ui-btn--sm"); // 머리 [?] = [다시 열기]와 같은 보통 크기(113-2 · 카드 [?]는 작게)
helpSlot.replaceChildren(...(help ? [help.button, help.box] : []));
};
@@ -242,12 +242,7 @@
display: none;
}
/* 상세 이동 [도면][일위대가][면적산출](105-4) — 지금 상세 = 눌림(강조색 · 밝음 · 어두움 같은 토큰) */
/* 상세 이동 [도면][일위대가][면적산출](105-4) — 지금 상세 단추는 숨김(113-2) */
.m02-main__nav[hidden] {
display: none;
}
.m02-main__nav .ui-btn[aria-pressed="true"] {
border-color: var(--color-accent);
color: var(--color-accent);
}
+17 -8
View File
@@ -1,7 +1,7 @@
"""상세 이동 단추 · 도면 상세 → 면적산출(PLAN 105-2 · 105-4) — Node 로 판정 · 화면은 ORCA.
못박는 것
- 머리 제목과 [?] 사이 [도면][일위대가][면적산출](`ui-btn-group`) · 지금 상세 = 눌림(aria-pressed) ·
- 머리 제목과 [?] 사이 [도면][일위대가][면적산출](`ui-btn-group` · 보통 크기) · 지금 상세 단추 = 숨김(113-2) ·
그 열 문서(번호)가 없으면 그 단추 꺼짐 · 프로젝트 층 · 남의 층은 번호를 안 읽고 다 켬 · 상세 아니면 숨김.
- 보임 조건 = 뒤로 단추와 같음 · 누름 = confirmLeave → open({...sel, kind}) · 지금 것 누름 = 그대로.
- 도면 상세 머리 [면적산출로 보내기] = CAD 요청 · 받은 표(TOAREA 도 같은 길) → 같은 열 면적 상세로 옮겨 가
@@ -27,7 +27,7 @@ const js = ts.transpileModule(src, {
let fetched = 0;
let numbers = {};
const button = (o) => {
const b = { label: o.label, size: o.size, dataset: {}, attrs: {}, disabled: false, title: "", onClick: o.onClick };
const b = { label: o.label, size: o.size, dataset: {}, attrs: {}, disabled: false, hidden: false, title: "", onClick: o.onClick };
b.setAttribute = (k, v) => (b.attrs[k] = v);
return b;
};
@@ -47,12 +47,16 @@ const gone = [];
const nav = box.exports.createDetailNav((kind) => gone.push(kind));
const view = () => ({
hidden: nav.root.hidden,
pressed: nav.root.children.map((b) => b.attrs["aria-pressed"]),
shown: nav.root.children.map((b) => !b.hidden),
disabled: nav.root.children.map((b) => b.disabled),
});
const tick = () => new Promise((r) => setTimeout(r, 0));
(async () => {
const out = { className: nav.root.className, labels: nav.root.children.map((b) => b.label) };
const out = {
className: nav.root.className,
labels: nav.root.children.map((b) => b.label),
sizes: nav.root.children.map((b) => b.size ?? null),
};
numbers = { c1: { 도번: "SD-000001", 일위대가번: "", 면적번: "SA-000001" } };
nav.update({ layer: "system", kind: "area", name: "c1" });
out.before = view();
@@ -96,17 +100,18 @@ def _text(name: str) -> str:
def test_단추_셋_묶음(run):
assert run["labels"] == ["도면", "일위대가", "면적산출"]
assert "ui-btn-group" in run["className"]
assert run["sizes"] == [None, None, None] # 113-2 — [다시 열기]와 같은 보통 크기
def test_지금_것_눌림_없는_문서_꺼짐(run):
assert run["before"]["pressed"] == ["false", "false", "true"]
def test_지금_것_숨김_없는_문서_꺼짐(run):
assert run["before"]["shown"] == [True, True, False] # 113-2 — 지금 상세 단추 숨김
assert run["before"]["disabled"] == [False, False, False] # 번호 받기 전엔 켬
assert run["area"]["disabled"] == [False, True, False] # 일위대가번 없음 = 꺼짐
assert run["area"]["hidden"] is False
def test_프로젝트_남의_층은_안_읽음(run):
assert run["project"]["pressed"] == ["true", "false", "false"]
assert run["project"]["shown"] == [False, True, True]
assert run["project"]["disabled"] == [False, False, False]
assert run["other"]["disabled"] == [False, False, False]
assert run["fetched"] == 1
@@ -124,7 +129,11 @@ def test_머리_줄_자리와_보임_조건():
assert "if (!at || at.kind === kind || !(await confirmLeave())) return;" in main
assert "void open({ ...at, kind });" in main
css = (M02 / "M02_MasterTemplete_UI_Style.css").read_text(encoding="utf-8")
assert '.m02-main__nav .ui-btn[aria-pressed="true"]' in css
assert "aria-pressed" not in css # 113-2 — 눌림 대신 숨김
# 머리 [?] 만 보통 크기 · 카드 [?] 는 작게 그대로(`helpParts` sm)
assert 'help?.button.classList.remove("ui-btn--sm");' in main
shell = _text("M02_MasterTemplete_CardShell.ts")
assert 'createButton({ label: CARD_TEXT.help, variant: "ghost", size: "sm" })' in shell
def test_도면_상세에서_면적으로_보내기():
+1 -1
View File
@@ -305,7 +305,7 @@ def test_구조물_조합_제목_줄_새_항목():
main = _text(M02 / "M02_MasterTemplete_UI_Main.ts")
assert "export function newItemButton(" in main and 'classList.add("m02-main__new")' in main
assert re.search(
r"children: \[\s*back,\s*title,\s*helpSlot,\s*slot,\s*reload,\s*save,"
r"children: \[\s*back,\s*title,\s*nav\.root,\s*helpSlot,\s*slot,\s*reload,\s*save,"
r"\s*\.\.\.\(extras\.newItem \? \[extras\.newItem\] : \[\]\),?\s*\]",
main,
)