feat(B06): 조정창 항목 2행 구조 + 이동 버튼 십자(D-pad) 배치
- 항목별 1행 = 이름 라벨, 2행 = 값 조작(구조물 형식·재질·높이·단 수·이동) - 이동 버튼 십자 배치: ▲ 위 / ◀ ↺ ▶ 가운데 / ▼ 아래 — 중앙이 초기화 - __controls(flex)와의 우선순위 충돌은 복합 선택자로 해결 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -77,6 +77,19 @@ function makeButton(label: string, title: string, onClick: () => void): HTMLButt
|
||||
return button;
|
||||
}
|
||||
|
||||
/** 항목 행 — 1행 이름 라벨 + 2행 값 조작(2026-08-22 사용자 확정 2행 구조). */
|
||||
function makeRow(labelText: string): { row: HTMLElement; controls: HTMLElement } {
|
||||
const row = document.createElement("div");
|
||||
row.className = "b06-structure-panel__struct";
|
||||
const label = document.createElement("span");
|
||||
label.className = "b06-structure-panel__label";
|
||||
label.textContent = labelText;
|
||||
const controls = document.createElement("div");
|
||||
controls.className = "b06-structure-panel__controls";
|
||||
row.append(label, controls);
|
||||
return { row, controls };
|
||||
}
|
||||
|
||||
/** 구조물 조정 오버레이 창을 만든다. 처음에는 숨어 있다. */
|
||||
export function buildStructurePanel(deps: StructurePanelDeps): StructurePanelHandle {
|
||||
const root = document.createElement("div");
|
||||
@@ -96,41 +109,57 @@ export function buildStructurePanel(deps: StructurePanelDeps): StructurePanelHan
|
||||
if (current) run(current);
|
||||
};
|
||||
|
||||
const buttons = document.createElement("div");
|
||||
buttons.className = "b06-structure-panel__buttons";
|
||||
const moveRow = makeRow(L("B06_Cross_Move_Label"));
|
||||
// 버튼 묶음 클래스는 컨트롤 행에 — **십자(D-pad) 배치**(2026-08-22 사용자):
|
||||
// ▲ 위 / ◀ ↺ ▶ 가운데 / ▼ 아래. 초기화가 십자 중앙이다.
|
||||
moveRow.controls.classList.add("b06-structure-panel__buttons");
|
||||
const buttons = moveRow.controls;
|
||||
const dpad = (
|
||||
label: string,
|
||||
slot: "up" | "down" | "left" | "right" | "reset",
|
||||
title: string,
|
||||
onClick: () => void,
|
||||
): HTMLButtonElement => {
|
||||
const button = makeButton(label, title, onClick);
|
||||
button.classList.add(`b06-structure-panel__btn--${slot}`);
|
||||
return button;
|
||||
};
|
||||
buttons.append(
|
||||
makeButton(
|
||||
"◀",
|
||||
L("B06_Cross_Revet_Left"),
|
||||
act((key) => deps.nudge(key, STEP_M)),
|
||||
),
|
||||
makeButton(
|
||||
"▶",
|
||||
L("B06_Cross_Revet_Right"),
|
||||
act((key) => deps.nudge(key, -STEP_M)),
|
||||
),
|
||||
makeButton(
|
||||
dpad(
|
||||
"▲",
|
||||
"up",
|
||||
L("B06_Cross_Revet_Up"),
|
||||
act((key) => deps.nudgeSlope(key, -STEP_M)),
|
||||
),
|
||||
makeButton(
|
||||
"▼",
|
||||
L("B06_Cross_Revet_Down"),
|
||||
act((key) => deps.nudgeSlope(key, STEP_M)),
|
||||
dpad(
|
||||
"◀",
|
||||
"left",
|
||||
L("B06_Cross_Revet_Left"),
|
||||
act((key) => deps.nudge(key, STEP_M)),
|
||||
),
|
||||
makeButton(
|
||||
dpad(
|
||||
"↺",
|
||||
"reset",
|
||||
L("B06_Cross_Revet_Reset"),
|
||||
act((key) => deps.reset(key)),
|
||||
),
|
||||
dpad(
|
||||
"▶",
|
||||
"right",
|
||||
L("B06_Cross_Revet_Right"),
|
||||
act((key) => deps.nudge(key, -STEP_M)),
|
||||
),
|
||||
dpad(
|
||||
"▼",
|
||||
"down",
|
||||
L("B06_Cross_Revet_Down"),
|
||||
act((key) => deps.nudgeSlope(key, STEP_M)),
|
||||
),
|
||||
);
|
||||
|
||||
// 재질 행(2026-08-22 사용자 ④ — 높이 행 **위**, 폭 축소: 한계는 툴팁으로).
|
||||
const materialRow = document.createElement("label");
|
||||
materialRow.className = "b06-structure-panel__struct";
|
||||
const materialLabelEl = document.createElement("span");
|
||||
materialLabelEl.textContent = L("B06_Cross_Mat_Label");
|
||||
const materialParts = makeRow(L("B06_Cross_Mat_Label"));
|
||||
const materialRow = materialParts.row;
|
||||
const materialSelect = document.createElement("select");
|
||||
materialSelect.className = "b06-structure-panel__select";
|
||||
const MATERIAL_LABEL: Record<RevetMaterial, string> = {
|
||||
@@ -148,13 +177,11 @@ export function buildStructurePanel(deps: StructurePanelDeps): StructurePanelHan
|
||||
materialSelect.addEventListener("change", () => {
|
||||
if (current) deps.setMaterial(current, materialSelect.value as RevetMaterial);
|
||||
});
|
||||
materialRow.append(materialLabelEl, materialSelect);
|
||||
materialParts.controls.append(materialSelect);
|
||||
|
||||
// 높이 행 — ±0.1m, 한계는 재질이 정한다.
|
||||
const heightRow = document.createElement("div");
|
||||
heightRow.className = "b06-structure-panel__struct";
|
||||
const heightLabel = document.createElement("span");
|
||||
heightLabel.textContent = L("B06_Cross_Height_Label");
|
||||
const heightParts = makeRow(L("B06_Cross_Height_Label"));
|
||||
const heightRow = heightParts.row;
|
||||
const heightValue = document.createElement("span");
|
||||
heightValue.className = "b06-structure-panel__hval";
|
||||
const heightMinus = makeButton(
|
||||
@@ -167,13 +194,11 @@ export function buildStructurePanel(deps: StructurePanelDeps): StructurePanelHan
|
||||
L("B06_Cross_Height_Plus"),
|
||||
act((key) => deps.nudgeHeight(key, HEIGHT_STEP_M)),
|
||||
);
|
||||
heightRow.append(heightLabel, heightMinus, heightValue, heightPlus);
|
||||
heightParts.controls.append(heightMinus, heightValue, heightPlus);
|
||||
|
||||
// 유입측 구조물 형식 드롭다운(2026-08-22 사용자) — 자동/기슭막이/집수정 I·ㄴ·ㄷ.
|
||||
const structureRow = document.createElement("label");
|
||||
structureRow.className = "b06-structure-panel__struct";
|
||||
const structureLabel = document.createElement("span");
|
||||
structureLabel.textContent = L("B06_Cross_Struct_Label");
|
||||
const structureParts = makeRow(L("B06_Cross_Struct_Label"));
|
||||
const structureRow = structureParts.row;
|
||||
const select = document.createElement("select");
|
||||
select.className = "b06-structure-panel__select";
|
||||
const OPTIONS: Array<[InletStructureChoice, string]> = [
|
||||
@@ -192,13 +217,11 @@ export function buildStructurePanel(deps: StructurePanelDeps): StructurePanelHan
|
||||
select.addEventListener("change", () => {
|
||||
deps.setStructure(select.value as InletStructureChoice);
|
||||
});
|
||||
structureRow.append(structureLabel, select);
|
||||
structureParts.controls.append(select);
|
||||
|
||||
// 다단 기슭막이 단 수(2026-08-22 사용자) — 숫자 입력 + +/- 병행(스피너는 CSS 제거).
|
||||
const extraRow = document.createElement("label");
|
||||
extraRow.className = "b06-structure-panel__struct";
|
||||
const extraLabel = document.createElement("span");
|
||||
extraLabel.textContent = L("B06_Cross_Extra_Count");
|
||||
const extraParts = makeRow(L("B06_Cross_Extra_Count"));
|
||||
const extraRow = extraParts.row;
|
||||
const countInput = document.createElement("input");
|
||||
countInput.type = "number";
|
||||
countInput.min = "0";
|
||||
@@ -218,7 +241,7 @@ export function buildStructurePanel(deps: StructurePanelDeps): StructurePanelHan
|
||||
const countPlus = makeButton("+", L("B06_Cross_Extra_Add"), () =>
|
||||
deps.setExtraCount(clampCount(Number(countInput.value) + 1)),
|
||||
);
|
||||
extraRow.append(extraLabel, countMinus, countInput, countPlus);
|
||||
extraParts.controls.append(countMinus, countInput, countPlus);
|
||||
|
||||
const closeButton = makeButton("✕", L("B06_Cross_Revet_Close"), () => deps.close());
|
||||
closeButton.classList.add("b06-structure-panel__close");
|
||||
@@ -226,7 +249,7 @@ export function buildStructurePanel(deps: StructurePanelDeps): StructurePanelHan
|
||||
const head = document.createElement("div");
|
||||
head.className = "b06-structure-panel__head";
|
||||
head.append(title, closeButton);
|
||||
root.append(head, value, structureRow, materialRow, heightRow, extraRow, buttons);
|
||||
root.append(head, value, structureRow, materialRow, heightRow, extraRow, moveRow.row);
|
||||
|
||||
return {
|
||||
root,
|
||||
@@ -259,7 +282,7 @@ export function buildStructurePanel(deps: StructurePanelDeps): StructurePanelHan
|
||||
}
|
||||
select.value = structure;
|
||||
}
|
||||
buttons.classList.toggle("is-hidden", !movable);
|
||||
moveRow.row.classList.toggle("is-hidden", !movable);
|
||||
materialRow.classList.toggle("is-hidden", !movable);
|
||||
heightRow.classList.toggle("is-hidden", !movable);
|
||||
if (movable) {
|
||||
|
||||
@@ -601,11 +601,38 @@
|
||||
font-size: var(--text-caption);
|
||||
}
|
||||
|
||||
.b06-structure-panel__buttons {
|
||||
display: flex;
|
||||
/* 이동 조작 = 십자(D-pad) 배치(2026-08-22 사용자) — 중앙이 초기화.
|
||||
__controls(flex)보다 뒤에 선언된 것과 무관하게 이기도록 복합 선택자. */
|
||||
.b06-structure-panel__controls.b06-structure-panel__buttons {
|
||||
display: grid;
|
||||
grid-template-areas:
|
||||
". up ."
|
||||
"left reset right"
|
||||
". down .";
|
||||
justify-content: start;
|
||||
gap: 2px;
|
||||
}
|
||||
|
||||
.b06-structure-panel__btn--up {
|
||||
grid-area: up;
|
||||
}
|
||||
|
||||
.b06-structure-panel__btn--down {
|
||||
grid-area: down;
|
||||
}
|
||||
|
||||
.b06-structure-panel__btn--left {
|
||||
grid-area: left;
|
||||
}
|
||||
|
||||
.b06-structure-panel__btn--right {
|
||||
grid-area: right;
|
||||
}
|
||||
|
||||
.b06-structure-panel__btn--reset {
|
||||
grid-area: reset;
|
||||
}
|
||||
|
||||
.b06-structure-panel__btn.is-hidden {
|
||||
display: none;
|
||||
}
|
||||
@@ -643,14 +670,28 @@
|
||||
}
|
||||
|
||||
/* 유입 구조물 형식 드롭다운(2026-08-22 사용자) — 라벨 + select 한 줄. */
|
||||
/* 항목 행 = 2행 구조(2026-08-22 사용자): 1행 이름 라벨, 2행 값 조작. */
|
||||
.b06-structure-panel__struct {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: var(--spacing-8);
|
||||
flex-direction: column;
|
||||
align-items: stretch;
|
||||
gap: 2px;
|
||||
color: var(--color-text-secondary);
|
||||
font-size: var(--text-caption);
|
||||
}
|
||||
|
||||
.b06-structure-panel__label {
|
||||
color: var(--color-text-muted);
|
||||
font-size: var(--text-caption);
|
||||
line-height: 1.2;
|
||||
}
|
||||
|
||||
.b06-structure-panel__controls {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 2px;
|
||||
}
|
||||
|
||||
.b06-structure-panel__struct.is-hidden {
|
||||
display: none;
|
||||
}
|
||||
|
||||
@@ -265,6 +265,7 @@ export const ui_locales_b2 = {
|
||||
"Cannot move further down the slope",
|
||||
],
|
||||
B06_Cross_Height_Label: ["높이", "Height"],
|
||||
B06_Cross_Move_Label: ["이동(좌우·사면 상하)", "Move (lateral / along slope)"],
|
||||
B06_Cross_Height_Minus: ["높이 −0.1m", "Height −0.1m"],
|
||||
B06_Cross_Height_Plus: ["높이 +0.1m", "Height +0.1m"],
|
||||
B06_Cross_Height_Limit: [
|
||||
|
||||
Reference in New Issue
Block a user