style(setting_row): 설정 줄 부품에 좁은 꼴 추가 · E06 설정 줄을 부품으로 · D03 3D 창의 B05 클래스 빌림 끊음 (PLAN 553-4 뒤처리)

- 설정 줄 좁은 꼴(compact · 줄 28 · 글 12 · 선 없음) + 부품 모음 견본 + 지킴 시험
- E06 e06-setting 걷음 · 가이드 장면 선택자 갱신
- D03 3D 창 = 자기 클래스(d03-plan__3d-modal · 3d-body) · 모달 부품 그대로 · 가이드 장면 선택자 갱신

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-26 23:04:33 +09:00
co-authored by Claude Sonnet 5.5
parent ffa26b2281
commit 917127a63c
11 changed files with 61 additions and 26 deletions
+1 -1
View File
@@ -7,6 +7,6 @@
{"name":"D03_05_station_cross","route":"#/d03-plan-analysis","project":"plan","viewport":[1600,1250],"before":[{"wait":".d03-plan__map canvas"},{"wait":".d03-plan__mode"},{"wait_ms":4000},{"eval":"window.__d03Plan.pick(100)"},{"wait":".d03-plan__cross-body svg"},{"wait_ms":600}],"settle_ms":2000,"clip":".d03-plan__cross","callouts":[{"n":1,"sel":".d03-plan__cross-head"},{"n":2,"sel":".d03-plan__cross-body"}]},
{"name":"D03_06_cross_fold","route":"#/d03-plan-analysis","project":"plan","viewport":[1600,900],"before":[{"wait":".d03-plan__map canvas"},{"wait":".d03-plan__mode"},{"wait_ms":4000},{"eval":"window.__d03Plan.pick(400)"},{"wait":".d03-plan__cross-body svg"},{"wait_ms":600},{"click":".d03-plan__cross .ui-workflow-overlay__handle"},{"wait_ms":800}],"settle_ms":2000,"clip":null,"callouts":[{"n":1,"sel":".d03-plan__cross .ui-workflow-overlay__handle","pos":"tr"}]},
{"name":"D03_07_buttons","route":"#/d03-plan-analysis","project":"plan","viewport":[1600,1250],"before":[{"wait":".d03-plan__map canvas"},{"wait":".d03-plan__mode"},{"wait_ms":4000}],"settle_ms":2000,"clip":".ui-sidebar-actions","callouts":[{"n":1,"sel":".ui-sidebar-actions > button:nth-child(1)"},{"n":2,"sel":".ui-sidebar-actions > button:nth-child(2)"},{"n":3,"sel":".ui-sidebar-actions > button:nth-child(3)"},{"n":4,"sel":".ui-sidebar-actions > button:nth-child(4)"},{"n":5,"sel":".ui-sidebar-actions > button:nth-child(5)"},{"n":6,"sel":".ui-sidebar-actions > button:nth-child(6)"}]},
{"name":"D03_08_3d_modal","route":"#/d03-plan-analysis","project":"plan","viewport":[1600,1250],"before":[{"wait":".d03-plan__map canvas"},{"wait":".d03-plan__mode"},{"wait_ms":4000},{"click":".ui-sidebar-actions > button:nth-child(6)"},{"wait":".b05-route__3d-modal"},{"wait_ms":9000},{"wait":".d03-plan__3d-corridor input:checked"}],"settle_ms":2000,"clip":null,"callouts":[{"n":1,"sel":".d03-plan__3d-year"},{"n":2,"sel":".d03-plan__3d-corridor"},{"n":3,"sel":".b05-route__3d-body .b05-route__viewport","pos":"br"}]},
{"name":"D03_08_3d_modal","route":"#/d03-plan-analysis","project":"plan","viewport":[1600,1250],"before":[{"wait":".d03-plan__map canvas"},{"wait":".d03-plan__mode"},{"wait_ms":4000},{"click":".ui-sidebar-actions > button:nth-child(6)"},{"wait":".d03-plan__3d-modal"},{"wait_ms":9000},{"wait":".d03-plan__3d-corridor input:checked"}],"settle_ms":2000,"clip":null,"callouts":[{"n":1,"sel":".d03-plan__3d-year"},{"n":2,"sel":".d03-plan__3d-corridor"},{"n":3,"sel":".d03-plan__3d-body .b05-route__viewport","pos":"br"}]},
{"name":"D03_09_ip_edit","route":"#/d03-plan-analysis","project":"plan","viewport":[1600,1250],"before":[{"wait":".d03-plan__map canvas"},{"wait":".d03-plan__mode"},{"wait_ms":4000},{"eval":"window.__d03Plan.nudge(3, 18, 14)"},{"eval":"window.__d03Plan.pick(200)"},{"wait":".d03-plan__cross-body svg"},{"wait_ms":600}],"settle_ms":2000,"clip":null,"callouts":[{"n":1,"sel":".d03-plan__map","pos":"tr"},{"n":2,"sel":".d03-plan__year[data-year=\"2027\"] .d03-plan__year-head:nth-child(2)","pos":"tr"},{"n":3,"sel":".d03-plan__year[data-year=\"2027\"] .d03-plan__mode.is-picked","pos":"tr"},{"n":4,"sel":".ui-sidebar-actions > button:nth-child(7)","pos":"tr"}]}
]
+2 -2
View File
@@ -85,11 +85,11 @@
"callouts": [
{
"n": 1,
"sel": ".e06-cards > section:nth-child(2) .ui-field:nth-of-type(1), .e06-cards > section:nth-child(2) .e06-setting:nth-of-type(1)"
"sel": ".e06-cards > section:nth-child(2) .ui-field:nth-of-type(1), .e06-cards > section:nth-child(2) .ui-setting-row:nth-of-type(1)"
},
{
"n": 2,
"sel": ".e06-cards > section:nth-child(2) .e06-setting__ctl"
"sel": ".e06-cards > section:nth-child(2) .e06-ctl"
}
]
},
+2 -2
View File
@@ -136,9 +136,9 @@ export function openPlan3d(projectId: string, years: Plan3dYear[], firstYear: nu
title: "3D 보기 — 지형 + 노선",
closeLabel: "닫기",
wide: true,
dialogClass: "b05-route__3d-modal",
dialogClass: "d03-plan__3d-modal",
mount: (body) => {
body.classList.add("b05-route__3d-body");
body.classList.add("d03-plan__3d-body");
body.append(top, viewer!.root);
viewer!.setActive(true);
},
@@ -86,6 +86,17 @@
font-size: 0.85rem;
}
/* 3D 큰 모달 — 3D 화면이 모달 몸을 꽉 채움 · 몸 스크롤 없음 */
.ui-modal--wide > .ui-modal__body.d03-plan__3d-body {
overflow: hidden;
}
.d03-plan__3d-body > .b05-route__viewport {
flex: 1 1 auto;
min-height: 0;
border-radius: var(--radius-md);
}
.d03-plan__3d-top {
display: flex;
gap: var(--spacing-8);
+4 -5
View File
@@ -8,6 +8,7 @@
import { createPanelCard } from "@ui/ui_template_collapsible";
import { createButton, createInputField, createSelectField, el } from "@ui/ui_template_elements";
import { t, type LocaleKey } from "@ui/ui_template_locale";
import { settingRow as settingRowPart } from "@ui/ui_template_setting_row";
import { e06Table, note } from "./E06_StabRock_UI_Parts";
export interface JointSet {
@@ -169,11 +170,9 @@ function jointTable(view: JointsView): HTMLElement {
return wrap;
}
/** 좁은 패널 설정 줄 — 설정 줄 부품(줄 52 · 큰 글)은 이 폭에 안 맞아 옛 꼴 그대로 */
/** 좁은 패널 설정 줄 — 설정 줄 부품 좁은 꼴 */
function settingRow(label: LocaleKey, control: HTMLElement): HTMLElement {
const row = el("label", { className: "e06-setting" });
row.append(el("span", { text: t(label) }), control);
return row;
return settingRowPart(t(label), "", control, { compact: true });
}
function select<T extends string>(
@@ -211,7 +210,7 @@ function minBlockControl(view: JointsView, s: RockSettings): HTMLElement {
},
});
reset.disabled = !view.editable;
const box = el("span", { className: "e06-setting__ctl" });
const box = el("span", { className: "e06-ctl" });
box.append(
numberInput(view, s.min_block_m3, "min_block_m3", (v) => (s.min_block_m3 = v ?? NaN), {
step: "0.01",
+2 -12
View File
@@ -74,21 +74,11 @@ select.e06-input {
margin-top: var(--spacing-4);
}
.e06-setting {
display: flex;
align-items: center;
justify-content: space-between;
gap: var(--spacing-8);
margin: 2px 0;
font-size: 12px;
color: var(--color-text);
}
.e06-setting .e06-input {
.ui-setting-row .e06-input {
width: 5.5em;
}
.e06-setting__ctl {
.e06-ctl {
display: flex;
align-items: center;
gap: var(--spacing-4);
@@ -13,6 +13,9 @@ def test_setting_row():
)
css = _text("ui_template_setting_row.css")
assert "min-height: 52px" in css and "max-width: 55%" in css
ts = _text("ui_template_setting_row.ts")
assert "compact?: boolean" in ts and 'dataset.size = "compact"' in ts
assert '[data-size="compact"]' in css and "min-height: 28px" in css
b01 = ROOT / "B01_Dashboard"
kit = (b01 / "B01_Dashboard_UI_PageKit.ts").read_text(encoding="utf-8")
assert (
+5
View File
@@ -46,6 +46,10 @@ def test_d03_parts():
assert 'createElement("input")' not in three and "createCheckbox" in three
for dead in (".d03-plan__bar", ".d03-plan__mode", "is-picked"):
assert dead not in css, dead
assert "b05-route__3d-modal" not in three and "b05-route__3d-body" not in three # 빌림 끊음
assert 'dialogClass: "d03-plan__3d-modal"' in three and ".d03-plan__3d-body" in css
scenes = _src("A05_EduDetail/guide/D03/_scenes.json")
assert "b05-route__3d-modal" not in scenes # 촬영 장면이 `.d03-plan__3d-modal` 로 잡음
def test_d04_parts():
@@ -159,6 +163,7 @@ def test_e06_parts():
assert part in parts, part
assert "createLegend(" in ts["Stereonet"] and "createBanner(" in ts["Page"]
assert "createInputField(" in ts["Joints"] and "createSelectField(" in ts["Joints"]
assert "compact: true" in ts["Joints"] and ".e06-setting" not in css # 설정 줄 부품 좁은 꼴
assert (
'classList.add("e06-toggle")' in parts
) # 촬영 장면이 `.e06-toggle button[data-value]` 로 잡음
+16
View File
@@ -40,3 +40,19 @@
text-align: right;
overflow-wrap: anywhere;
}
/* 좁은 꼴 — 좁은 왼쪽 패널 · 줄 28 · 글 12 · 선 없음 */
.ui-setting-row[data-size="compact"] {
gap: var(--spacing-8);
min-height: 28px;
padding: 2px 0;
border-bottom: 0;
font-size: var(--text-caption);
color: var(--color-text);
}
.ui-setting-row[data-size="compact"] .ui-setting-row__side {
max-width: none;
gap: var(--spacing-4);
}
.ui-setting-row[data-size="compact"] strong {
font-weight: inherit;
}
+13 -2
View File
@@ -3,6 +3,7 @@
* 부품 「설정 줄」(552-3 · 목록 33) — 왼쪽 제목 · 설명 / 오른쪽 값 · 조작 한 줄(Linear 꼴) · 여러 줄은 둥근 상자 하나에.
* 꼴 = 값 줄(`valueText` · 없으면 「-」) · 조작 줄(오른쪽에 입력 · 고르기 · 켜기 · 단추) · 설명 없는 줄
* 크기 = 줄 최소 52 · 여백 8 / 16 · 오른쪽 칸 최대 55 %
* 좁은 꼴 = `settingRow(제목, 설명, 오른쪽, { compact: true })` — 좁은 왼쪽 패널용 · 줄 최소 28 · 글 12 · 아래 선 없음 · 줄 통째가 label(`data-size="compact"`)
* 상태 = 기본만(조작 부품이 저마다 상태를 가짐)
* 쓰는 법 = `settingCard([settingRow("회사 이름", "보고서 머리에 들어감", valueText("산림설계"))])`
* 대신하는 옛 변종 = B01 `settingRow` · `settingCard`(`.b01-pg-row` · `.b01-pg-settings`) · `.b01-dashboard__setting-card` · E02 `e02-field` · E06 `e06-setting` · B08 `b08-hydro__row`
@@ -12,7 +13,12 @@ import { el } from "./ui_template_elements_base";
import "./ui_template_setting_row.css";
/** 한 줄 — 제목 · 설명 왼쪽 · 값 · 조작 오른쪽 */
export function settingRow(title: string, desc: string, right: Node): HTMLElement {
export function settingRow(
title: string,
desc: string,
right: Node,
opts: { compact?: boolean } = {},
): HTMLElement {
const left = el("div", {
className: "ui-setting-row__text",
children: [el("strong", { text: title })],
@@ -20,7 +26,12 @@ export function settingRow(title: string, desc: string, right: Node): HTMLElemen
if (desc) left.append(el("span", { className: "ui-setting-row__desc", text: desc }));
const side = el("div", { className: "ui-setting-row__side" });
side.append(right);
return el("div", { className: "ui-setting-row", children: [left, side] });
const row = el(opts.compact ? "label" : "div", {
className: "ui-setting-row",
children: [left, side],
});
if (opts.compact) row.dataset.size = "compact";
return row;
}
/** 값 글 — 없으면 「-」 */
+2 -2
View File
@@ -280,8 +280,8 @@ export const KIT_PARTS: KitPart[] = [
demo: (s) => (s === "default" ? col(createBarChart([{ label: "산림설계", value: 12 }, { label: "녹색기술", value: 7 }, { label: "그 밖 3 곳", value: 4 }]), createDonut([{ label: "임도", value: 5 }, { label: "예정노선", value: 3 }, { label: "안정성", value: 2 }]), createLineChart({ series: [{ name: "CPU", values: [20, 35, 30, 50, 42, 60], colorIndex: 0 }], height: 120 })) : null) },
{ key: "legend", name: "범례", group: "compound", kinds: "색 칩 · 선 · 점선 · 점 · 꺼짐 · 세로", file: "ui_template_flow_legend.ts",
demo: (s) => (s === "default" ? col(createLegend([{ label: "임도", color: "var(--color-chart-0)" }, { label: "설계선", color: "var(--color-chart-2)", kind: "line" }, { label: "원지반선", color: "var(--color-chart-1)", kind: "dash" }, { label: "관", color: "var(--color-chart-3)", kind: "dot" }, { label: "꺼진 층", color: "var(--color-chart-0)", off: true }], { onToggle: noop }), createLegend([{ label: "절토", color: "var(--color-danger)" }, { label: "성토", color: "var(--color-info)" }], { vertical: true })) : null) },
{ key: "setting-row", name: "설정 줄", group: "compound", kinds: "제목 · 설명 왼쪽 · 오른쪽 값 · 조작 · 줄 52", file: "ui_template_setting_row.ts",
demo: (s) => (s === "default" ? settingCard([settingRow("회사 이름", "보고서 머리에 들어감", valueText("산림설계")), settingRow("단위", "", valueText(null)), settingRow("기본 노폭", "새 노선에 먼저 들어감", createInputField({ placeholder: "3.0 m" }).root), settingRow("글꼴 파일", "", createButton({ label: "바꾸기", variant: "ghost", size: 28, onClick: noop }))]) : null) },
{ key: "setting-row", name: "설정 줄", group: "compound", kinds: "제목 · 설명 왼쪽 · 오른쪽 값 · 조작 · 줄 52 · 좁은 꼴(줄 28)", file: "ui_template_setting_row.ts",
demo: (s) => (s === "default" ? col(settingCard([settingRow("회사 이름", "보고서 머리에 들어감", valueText("산림설계")), settingRow("단위", "", valueText(null)), settingRow("기본 노폭", "새 노선에 먼저 들어감", createInputField({ placeholder: "3.0 m" }).root), settingRow("글꼴 파일", "", createButton({ label: "바꾸기", variant: "ghost", size: 28, onClick: noop }))]), settingCard([settingRow("측면 한계각(°)", "", createInputField({ placeholder: "30", size: 24 }).root, { compact: true }), settingRow("균열 모드", "", valueText("없음"), { compact: true })])) : null) },
{ key: "drop", name: "파일 놓기 칸", group: "compound", kinds: "끌어 놓기 · 고르기 단추 · 받는 꼴 안내 · 진행 · 오류", file: "ui_template_drop.ts",
demo: (s) => { if (s === "active") return null; const d = createDrop({ accept: ".las,.laz", hint: "LAS · LAZ · 2 GB 까지", onFiles: noop, disabled: s === "disabled" });
if (s === "error") d.setError("LAS · LAZ 파일만 받음"); if (s === "hover" || s === "error") markState(d.root, s);