refactor(B06): 카드 설계 줄 · 아래 띠 단추를 부품으로 — 분할 고르기 · 켜기 칩 · 단추 · 아이콘 단추 (PLAN 553-2)
- 측구 · 측구형식 · 경사 방향 묶음 = 부품 분할 고르기 20 · 토사 · 측구 · 단경사 켜고 끄기 = 켜기 칩 20 · [상세] = 단추(고스트) 20 - ⋯ 넘침 펼침 = 아이콘 단추(선) 22 꼴(펼침 = aria-pressed) · 암 경계 ▲▼↺ · 암 절토 ↺ = 아이콘 단추 22 - 지운 자체 CSS — b06-design__btn(--active) · 펼침 보라 채움 · rockb 단추 꼴 · 사이 금 · 글 0.72rem → --text-caption - 부품 아이콘 단추의 display 가 hidden 을 덮어 선 칸 숨김 단추는 페이지에 숨김 한 줄 - 카드 높이 7 px 줄음(설계 줄 단추 24 → 20 · 지반 칩 24 → 20) · 그림 색 전후 같음(34 장면 × 102~120 선) - 시험 헬퍼 둘 — helper_318 = 단추 줄 시험이 진짜 부품 파일을 흉내 노드로 실음 · helper_472 = 켜기 칩 글을 안쪽 span 에서 읽음 - Line_Cell · CutSlope 는 흉내 DOM 시험(370-3 등)이 @ui 를 안 풀어 부품 클래스 · data-size 계약으로 붙임 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -105,7 +105,8 @@ export function buildCutSlopeControl(section: CrossSection, control: CutSlopeCon
|
||||
|
||||
const reset = document.createElement("button");
|
||||
reset.type = "button";
|
||||
reset.className = "b06-design__rockb-btn is-reset";
|
||||
reset.className = "ui-icon-btn ui-icon-btn--ghost b06-design__rockb-btn is-reset"; // 부품 아이콘 단추 22
|
||||
reset.setAttribute("data-size", "22");
|
||||
reset.textContent = "↺";
|
||||
reset.title = `표준값으로 되돌리기 (1:${standard.toFixed(2)} · ${ratioToDegrees(standard).toFixed(1)}°)`;
|
||||
reset.disabled = sameRatio(ratio, standard);
|
||||
|
||||
@@ -14,7 +14,10 @@
|
||||
* 병합된다.
|
||||
* ========================================================================== */
|
||||
|
||||
import { createButton, setUiSize } from "@ui/ui_template_button";
|
||||
import { currentLanguageIndex, ui_locales } from "@ui/ui_template_locale";
|
||||
import { createSegment } from "@ui/ui_template_segment";
|
||||
import { createToggle } from "@ui/ui_template_toggle";
|
||||
import type {
|
||||
CrossSection,
|
||||
DitchSide,
|
||||
@@ -156,25 +159,19 @@ function segment<T extends string>(
|
||||
legendEl.textContent = legend;
|
||||
wrap.append(legendEl);
|
||||
}
|
||||
const group = document.createElement("div");
|
||||
group.className = "b06-design__seg-buttons";
|
||||
for (const [value, labelKey] of options) {
|
||||
const button = document.createElement("button");
|
||||
button.type = "button";
|
||||
button.className = `b06-design__btn${value === selected ? " b06-design__btn--active" : ""}`;
|
||||
button.textContent = L(labelKey);
|
||||
button.setAttribute("aria-pressed", value === selected ? "true" : "false");
|
||||
// 선행 조건 미충족 시 비활성(상시 노출하되 클릭 불가·사유 툴팁) — E-6.
|
||||
button.disabled = disabled;
|
||||
if (disabled && reason) button.title = reason;
|
||||
else button.addEventListener("click", () => onPick(value));
|
||||
group.append(button);
|
||||
}
|
||||
// 부품 분할 고르기 20(553-2) — 선행 조건 미충족 시 비활성(클릭 불가·사유 툴팁) — E-6.
|
||||
const group = createSegment({
|
||||
options: options.map(([value, labelKey]) => ({ value, label: L(labelKey), disabled })),
|
||||
value: selected ?? "",
|
||||
size: 20,
|
||||
onChange: (value) => onPick(value as T),
|
||||
}).root;
|
||||
if (disabled && reason) group.title = reason;
|
||||
wrap.append(group);
|
||||
return wrap;
|
||||
}
|
||||
|
||||
/** 온/오프 토글 하나(포장·2단계 경사 공용). 세그먼트와 같은 컨테이너/버튼 스타일을 쓴다. */
|
||||
/** 온/오프 토글 하나(포장·2단계 경사 공용) — 부품 켜기 칩 20(553-2). */
|
||||
function toggle(
|
||||
legend: string,
|
||||
on: boolean,
|
||||
@@ -192,18 +189,16 @@ function toggle(
|
||||
legendEl.textContent = legend;
|
||||
wrap.append(legendEl);
|
||||
}
|
||||
const buttons = document.createElement("div");
|
||||
buttons.className = "b06-design__seg-buttons";
|
||||
const button = document.createElement("button");
|
||||
button.type = "button";
|
||||
button.className = `b06-design__btn${on ? " b06-design__btn--active" : ""}`;
|
||||
button.textContent = on ? onLabel : offLabel;
|
||||
button.setAttribute("aria-pressed", on ? "true" : "false");
|
||||
button.disabled = disabled;
|
||||
const button = createToggle({
|
||||
kind: "chip",
|
||||
label: on ? onLabel : offLabel,
|
||||
checked: on,
|
||||
size: 20,
|
||||
disabled,
|
||||
onChange: onToggle,
|
||||
}).root;
|
||||
if (disabled && reason) button.title = reason;
|
||||
else button.addEventListener("click", onToggle);
|
||||
buttons.append(button);
|
||||
wrap.append(buttons);
|
||||
wrap.append(button);
|
||||
return { wrap, button };
|
||||
}
|
||||
|
||||
@@ -375,18 +370,26 @@ export function buildDesignControls(
|
||||
const more = document.createElement("details");
|
||||
more.className = "b06-design__more";
|
||||
const moreSummary = document.createElement("summary");
|
||||
moreSummary.className = "b06-design__more-summary";
|
||||
// 부품 아이콘 단추(선) 22 꼴 — 펼침 = 눌림(aria-pressed)
|
||||
moreSummary.className = "ui-icon-btn ui-icon-btn--outline b06-design__more-summary";
|
||||
setUiSize(moreSummary, 22);
|
||||
moreSummary.textContent = "⋯";
|
||||
moreSummary.title = L("B06_Design_More");
|
||||
moreSummary.setAttribute("aria-pressed", "false");
|
||||
more.addEventListener("toggle", () =>
|
||||
moreSummary.setAttribute("aria-pressed", String(more.open)),
|
||||
);
|
||||
const morePanel = document.createElement("div");
|
||||
morePanel.className = "b06-design__more-panel";
|
||||
more.append(moreSummary, morePanel);
|
||||
// [상세](138-4) — 맨 오른쪽 · 넘침 정리(moveable) 밖이라 늘 보임
|
||||
const detail = document.createElement("button");
|
||||
detail.type = "button";
|
||||
detail.className = "b06-design__btn b06-design__detail";
|
||||
detail.textContent = L("B06_Design_Detail");
|
||||
detail.addEventListener("click", () => openCrossDetail(section));
|
||||
const detail = createButton({
|
||||
label: L("B06_Design_Detail"),
|
||||
variant: "ghost",
|
||||
size: 20,
|
||||
onClick: () => openCrossDetail(section),
|
||||
});
|
||||
detail.classList.add("b06-design__detail");
|
||||
bar.append(slopeDirSeg, ...moveable, more, detail);
|
||||
refreshCrossDetail(section);
|
||||
|
||||
|
||||
@@ -87,7 +87,9 @@ export function buildLineCell(): LineCell {
|
||||
const buttons = SLOTS.map(([slot, text]) => {
|
||||
const button = document.createElement("button");
|
||||
button.type = "button";
|
||||
button.className = `b06-design__rockb-btn ${CELL_BTN}${slot}`;
|
||||
// 부품 아이콘 단추 22(553-2) — 클래스 · data-size 계약(시험 흉내 DOM 이 @ui 를 안 풂)
|
||||
button.className = `ui-icon-btn ui-icon-btn--ghost b06-design__rockb-btn ${CELL_BTN}${slot}`;
|
||||
button.setAttribute("data-size", "22");
|
||||
if (slot === "reset") button.classList.add("is-reset");
|
||||
button.textContent = text;
|
||||
// 길게 누름 — 누르면 즉시 1회 · 반복 예약 · 이어지는 click 은 삼킴
|
||||
|
||||
@@ -414,29 +414,7 @@
|
||||
stroke-width: 8;
|
||||
}
|
||||
|
||||
/* 암 경계선 상/하/리셋 제어 (B05 측점 선 제어 ▲/▼/↺ 버튼 패턴 재활용) */
|
||||
.b06-design__rockb-btn {
|
||||
width: 22px;
|
||||
height: 22px;
|
||||
padding: 0;
|
||||
font-size: 0.7rem;
|
||||
line-height: 1;
|
||||
color: var(--color-text-secondary);
|
||||
background: var(--color-surface);
|
||||
border: none;
|
||||
border-left: 1px solid var(--color-border);
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.b06-design__rockb-btn:first-child {
|
||||
border-left: none;
|
||||
}
|
||||
|
||||
.b06-design__rockb-btn:hover {
|
||||
color: var(--color-text);
|
||||
background: var(--color-surface-raised);
|
||||
}
|
||||
|
||||
/* 암 경계선 상/하/리셋 제어 — 단추 = 부품 아이콘 단추 22(553-2) · ↺ 만 경고 글색 */
|
||||
.b06-design__rockb-btn.is-reset {
|
||||
color: var(--color-warning);
|
||||
}
|
||||
|
||||
@@ -206,19 +206,8 @@
|
||||
margin-left: auto;
|
||||
}
|
||||
|
||||
/* ⋯ = 부품 아이콘 단추(선) 22 — 펼침 표시만 지움 */
|
||||
.b06-design__more-summary {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 24px;
|
||||
height: 22px;
|
||||
border: 1px solid var(--color-border);
|
||||
border-radius: var(--radius-inputs);
|
||||
background: var(--color-surface);
|
||||
color: var(--color-text-secondary);
|
||||
font-size: 0.9rem;
|
||||
line-height: 1;
|
||||
cursor: pointer;
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
@@ -226,12 +215,6 @@
|
||||
display: none;
|
||||
}
|
||||
|
||||
.b06-design__more[open] .b06-design__more-summary {
|
||||
color: var(--color-surface);
|
||||
background: var(--color-royal-amethyst);
|
||||
border-color: var(--color-royal-amethyst);
|
||||
}
|
||||
|
||||
.b06-design__more-panel {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
@@ -254,7 +237,7 @@
|
||||
}
|
||||
|
||||
.b06-design__seg-legend {
|
||||
font-size: 0.72rem;
|
||||
font-size: var(--text-caption);
|
||||
color: var(--color-text-secondary);
|
||||
white-space: nowrap;
|
||||
}
|
||||
@@ -271,31 +254,11 @@
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.b06-design__btn {
|
||||
padding: 3px 8px;
|
||||
font-size: 0.72rem;
|
||||
color: var(--color-text-secondary);
|
||||
background: var(--color-surface);
|
||||
border: none;
|
||||
border-left: 1px solid var(--color-border);
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.b06-design__btn:first-child {
|
||||
border-left: none;
|
||||
}
|
||||
|
||||
.b06-design__btn--active {
|
||||
color: var(--color-surface);
|
||||
background: var(--color-royal-amethyst);
|
||||
font-weight: var(--font-weight-medium);
|
||||
}
|
||||
|
||||
.b06-design__areas {
|
||||
display: inline-flex;
|
||||
gap: var(--spacing-8);
|
||||
margin-left: auto;
|
||||
font-size: 0.72rem;
|
||||
font-size: var(--text-caption);
|
||||
font-family: var(--font-mono);
|
||||
}
|
||||
|
||||
@@ -329,13 +292,11 @@
|
||||
|
||||
.b06-cross-card__linecell .b06-design__rockb-btn {
|
||||
flex: 0 0 auto;
|
||||
border-left: none;
|
||||
}
|
||||
|
||||
.b06-cross-card__linecell
|
||||
.b06-design__rockb-btn:not([hidden])
|
||||
~ .b06-design__rockb-btn:not([hidden]) {
|
||||
border-left: 1px solid var(--color-border);
|
||||
/* 부품 아이콘 단추의 display 가 hidden 을 덮음 — 상태에 없는 칸은 숨김 */
|
||||
.b06-design__rockb-btn[hidden] {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* 측점별 암 절토 경사(2026-09-07) — 행의 **오른쪽 끝**(암 경계 = 왼쪽). */
|
||||
@@ -349,7 +310,7 @@
|
||||
.b06-design__cutslope-input {
|
||||
width: 44px;
|
||||
padding: 0 2px;
|
||||
font-size: 0.72rem;
|
||||
font-size: var(--text-caption);
|
||||
font-family: var(--font-mono);
|
||||
text-align: right;
|
||||
color: var(--color-text);
|
||||
@@ -367,7 +328,7 @@
|
||||
|
||||
.b06-design__cutslope-unit {
|
||||
padding: 0 2px 0 1px;
|
||||
font-size: 0.72rem;
|
||||
font-size: var(--text-caption);
|
||||
color: var(--color-text-secondary);
|
||||
align-self: center;
|
||||
}
|
||||
|
||||
@@ -445,11 +445,16 @@ const out = {};
|
||||
|
||||
// ── 3. 단추 줄(318-1) — 빈자리 누름 = 카드 고름 · 조작 누름 = 안 넘김 ───────────
|
||||
{
|
||||
// 단추 줄 = 부품 단추 · 분할 · 켜기(553-2) — 진짜 부품 파일을 흉내 노드로 돌림
|
||||
const UI = (name) => path.join(ROOT, "ui_template", `${name}.ts`);
|
||||
const parts = ["ui_template_button", "ui_template_segment", "ui_template_toggle"];
|
||||
const loadUi = makeLoader([...parts, "ui_template_elements_base"].map(UI));
|
||||
const load = makeLoader([B06("B06_Section_UI_Cross_Design")], {
|
||||
"@ui/ui_template_locale": {
|
||||
currentLanguageIndex: 0,
|
||||
ui_locales: new Proxy({}, { get: (_t, key) => [String(key)] }),
|
||||
},
|
||||
...Object.fromEntries(parts.map((name) => [`@ui/${name}`, loadUi(UI(name))])),
|
||||
});
|
||||
const { buildDesignControls } = load(B06("B06_Section_UI_Cross_Design"));
|
||||
const { bar } = buildDesignControls(
|
||||
|
||||
@@ -155,10 +155,13 @@ const walk = (node) => {
|
||||
walk(groundSegment);
|
||||
walk(bar);
|
||||
const press = (pick) => buttons.find(pick)?.listeners.click?.forEach((fn) => fn({}));
|
||||
// 부품 켜기 칩(553-2) — 글은 안쪽 span 에 · 자식 글을 이어 읽음
|
||||
const text = (node) =>
|
||||
typeof node === "string"
|
||||
? node
|
||||
: (node?.textContent ?? "") + (node?.children ?? []).map(text).join("");
|
||||
out.soilPressed = buttons[0]?.getAttribute("aria-pressed");
|
||||
press(
|
||||
(b) => b.textContent === "측구" || b.textContent === "측구 없음" || /측구/.test(b.textContent),
|
||||
);
|
||||
press((b) => /측구/.test(text(b)));
|
||||
out.ditchChange = sent.at(-1) ?? null;
|
||||
// 새 카드 · 토사 단추 — 지반만(측구형식은 이미 일반이라 안 실림)
|
||||
buttons.length = 0;
|
||||
|
||||
Reference in New Issue
Block a user