@@ -149,12 +112,61 @@ export function createRouteEditChrome(
`;
parent.append(overlay);
- // 부른 쪽 단추([3D])도 같은 유리 단추로 — 지도 위에 떠 있는 도구줄.
- tools.forEach((tool) => {
- tool.classList.replace("ui-btn--ghost", "ui-btn--glass");
- tool.setAttribute("data-size", "32"); // 도구줄 단 32(553-2)
+ // 스냅 간격 고르기 · 설계 지형 이름 칩 — 단추 아님(도구줄에 요소로 끼움).
+ const extras = document.createElement("div");
+ extras.innerHTML = `
+
+
`;
+ const [snapStep, terrainName] = extras.children as unknown as [HTMLElement, HTMLElement];
+ const mapTools = createMapTools({
+ label: "평면 도구",
+ hint: { lines: HINT_LINES, open: hintOpen, onToggle: (open) => (hintOpen = open) },
+ groups: [
+ [
+ mapToolButton("undo", { title: "되돌리기 (Ctrl+Z)", disabled: true }),
+ mapToolButton("redo", { title: "다시하기 (Ctrl+Y)", disabled: true }),
+ ],
+ tools, // 부른 쪽 단추([3D])
+ [
+ "rotate-ccw",
+ "rotate-cw",
+ mapToolButton("contour-minor", {
+ title: "1m 등고선 — 1m 간격 등고선을 얇고 옅게 겹칩니다 (확대하면 보임)",
+ disabled: true,
+ }),
+ mapToolButton("stations", {
+ title: "측점 — 측점 눈금 · 번호를 평면에 보이기 · 숨기기 (시점 · 종점 이름표는 늘 보임)",
+ }),
+ mapToolButton("slopes", {
+ title: "기울기 — 측점 사이 기울기(%)를 평면에 보이기 · 숨기기 (확대해야 보임)",
+ }),
+ mapToolButton("footprint", {
+ title: "절/성토선 — 도로 끝 · 비탈 끝(깎기 붉음 · 쌓기 청록)을 평면에 겹칩니다",
+ }),
+ mapToolButton("measure", {
+ title: "거리 재기 — 노선 위 두 점을 눌러 거리·기울기를 잽니다 (Shift+클릭도 같음)",
+ }),
+ ],
+ [
+ mapToolButton("station-snap", {
+ title:
+ "측점 스냅 — 켜면 고친 곡선의 가운데(MC)를 고른 간격 배수에 맞춥니다 — 일반측점(20 m)은 그대로 · MC 가 일반측점 위가 아니면 「No.N+10 (MC)」 특별측점을 더함 · 손대지 않은 곡선은 그 자리 유지 · 고정 교각점은 그대로 · 못 맞춘 곡선은 상태줄 「측점 밖 곡선」 · [저장] 때 저장",
+ }),
+ snapStep,
+ ],
+ [terrainName],
+ ],
});
- overlay.querySelector('[data-slot="tools"]')!.replaceWith(...tools);
+ mapTools.root.classList.add("b05-routeedit__tools");
+ mapTools.hint!.classList.add("b05-routeedit__hint"); // 가이드 촬영 · 엿보기 숨김이 잡음
+ overlay.querySelector('[data-slot="map-tools"]')!.replaceWith(mapTools.root);
// 횡단 미리보기 = 패널 양식(382-1 · 손잡이 · 머리 · 폭 끌기 · 열림 · 폭 기억) · 자리는 지도 위 덮개 그대로 ·
// 기본 접힘(393-1 · 키 -v2 = 옛 열림 기억 한 번 버림) · 열림 · 닫힘은 손잡이만(513-2) · 잰 값 창이 판을 비킴(--b05-side-open).
@@ -177,17 +189,6 @@ export function createRouteEditChrome(
overlay.querySelector(".b05-routeedit__side-wrap")!.append(panels.root);
setSideOpen();
- // 도움말 = 기본 접힘 · [?] 한 번에 펼침(345-5 덧 3).
- const hint = overlay.querySelector
(".b05-routeedit__hint")!;
- const hintToggle = overlay.querySelector('[data-act="hint-toggle"]')!;
- const setHint = (open: boolean): void => {
- hintOpen = open;
- hint.classList.toggle("is-open", open);
- hintToggle.setAttribute("aria-expanded", String(open));
- };
- setHint(hintOpen);
- hintToggle.addEventListener("click", () => setHint(!hintOpen));
-
// 상태 · 범례 접기 — 접으면 한 줄 「계획노선 N m」(상태 글에서 읽음 · 345-5 덧 3).
const info = overlay.querySelector(".b05-routeedit__info")!;
const infoToggle = info.querySelector('[data-act="info-toggle"]')!;
@@ -243,16 +244,13 @@ export function createRouteEditChrome(
syncSummary();
const measureBox = overlay.querySelector(".b05-routeedit__measure")!;
const measureText = overlay.querySelector(".b05-routeedit__measure-text")!;
- const measureButton = overlay.querySelector('[data-act="measure"]')!;
+ const measureButton = mapTools.button("measure")!;
const busy = overlay.querySelector(".b05-routeedit__busy")!;
- const minorContourButton = overlay.querySelector(
- '[data-act="contour-minor"]',
- )!;
- const terrainName = overlay.querySelector('[data-slot="terrain-name"]')!;
- const stationSnapButton = overlay.querySelector('[data-act="station-snap"]')!;
- bindFootprintToggle(overlay.querySelector('[data-act="footprint"]')!);
- bindMarkToggle(overlay.querySelector('[data-act="stations"]')!, "stations");
- bindMarkToggle(overlay.querySelector('[data-act="slopes"]')!, "slopes");
+ const minorContourButton = mapTools.button("contour-minor")!;
+ const stationSnapButton = mapTools.button("station-snap")!;
+ bindFootprintToggle(mapTools.button("footprint")!);
+ bindMarkToggle(mapTools.button("stations")!, "stations");
+ bindMarkToggle(mapTools.button("slopes")!, "slopes");
return {
overlay,
diff --git a/B05_Profile/B05_Profile_UI_RouteEdit_Measure.ts b/B05_Profile/B05_Profile_UI_RouteEdit_Measure.ts
index 98cda38de..2e4a90118 100644
--- a/B05_Profile/B05_Profile_UI_RouteEdit_Measure.ts
+++ b/B05_Profile/B05_Profile_UI_RouteEdit_Measure.ts
@@ -169,12 +169,14 @@ export function bindMeasureControls(params: MeasureControlsParams): {
button.addEventListener("click", () => {
mode = !mode;
button.classList.toggle("is-active", mode);
+ button.setAttribute("aria-pressed", String(mode)); // 아이콘 단추 눌림 꼴(568-2)
if (!mode) measure.clear();
});
params.closeButton.addEventListener("click", () => {
measure.clear(); // 닫으면 잰 것이 지워진다(㉔).
mode = false;
button.classList.remove("is-active");
+ button.setAttribute("aria-pressed", "false");
sync();
params.redraw();
});
diff --git a/B05_Profile/B05_Profile_UI_Style_RouteEdit.css b/B05_Profile/B05_Profile_UI_Style_RouteEdit.css
index d8fd0a8c2..7c6680997 100644
--- a/B05_Profile/B05_Profile_UI_Style_RouteEdit.css
+++ b/B05_Profile/B05_Profile_UI_Style_RouteEdit.css
@@ -1,8 +1,8 @@
/* 계획노선 편집(평면) — 종단 보기 가운데 위 본문(옛 3D 자리 · 345-3). 덮개 · 전체 화면은 걷음 —
재계산 대기 막만 화면을 덮는다(노선 재탐색 · CLAUDE.md 5장). 색은 전부 테마 토큰을 쓴다. */
-/* 평면 = 가운데 칸 전체(352-1) — 머리 줄 · 테두리 없음. 도구줄은 3D 와 같은 떠 있는 유리 단추
- (`.b05-route__view-controls` · ☰ 비킴 `--wf-burger-pad`) · 횡단 판은 오른쪽을 덮는 판. */
+/* 평면 = 가운데 칸 전체(352-1) — 머리 줄 · 테두리 없음. 도구줄은 공용 지도 도구줄(568-2 · 유리 아이콘 줄 ·
+ ☰ 비킴 `--wf-burger-pad`) · 횡단 판은 오른쪽을 덮는 판. */
.b05-routeedit {
--b05-side-open: 0px; /* 횡단 판이 지도를 덮는 폭(손잡이 포함 · `_Chrome` 이 적음) */
/* 아래 줄 반 폭(408-4) — 횡단 판 왼쪽 빈 폭을 상태 글판 · 잰 값 창이 반씩(안 겹침 · 좁으면 줄바꿈) ·
@@ -14,15 +14,18 @@
min-height: 0;
}
-/* 도구줄 — 3D 도구줄 규격 그대로 · 회전 단추도 이 줄(366-2) · 넘치면 줄바꿈. */
+/* 도구줄 — 지도 왼쪽 위(공용 `ui-map-tools` · 넘치면 줄바꿈 · 빈 자리는 지도 조작 통과) · [?] 안내 판은 그 아래. */
.b05-routeedit__tools {
+ position: absolute;
+ z-index: 2;
+ top: var(--spacing-16);
right: var(--spacing-12);
- flex-wrap: wrap;
- pointer-events: none; /* 빈 자리는 지도 조작을 통과 */
+ left: var(--spacing-16);
}
-.b05-routeedit__tools > * {
- pointer-events: auto;
+/* ☰ 들여쓰기(7-2) */
+html.is-bm-route .b05-routeedit__tools {
+ left: max(var(--spacing-16), var(--wf-burger-pad, 0px));
}
.b05-routeedit__canvas-wrap {
@@ -43,8 +46,9 @@
/* 지도 위에 얹는 판들 — 아래 정보행을 없애고 여기로 옮겼다(2026-09-12 사용자 지시 ⑩·⑫·⑬).
글판은 **클릭을 통과시킨다** — 지도 조작을 가리면 안 된다(접기 단추만 받음 · 345-5 덧 3). */
-.b05-routeedit__hint-body,
.b05-routeedit__info {
+ position: absolute;
+ z-index: 1;
border: 1px solid color-mix(in srgb, var(--color-border) 65%, transparent);
border-radius: var(--radius-cards);
background: color-mix(in srgb, var(--color-surface-raised) 72%, transparent);
@@ -55,41 +59,6 @@
pointer-events: none;
}
-.b05-routeedit__hint,
-.b05-routeedit__info {
- position: absolute;
- z-index: 1;
-}
-
-/* 조작 설명 — 도구줄 아래 왼쪽 · 기본 접힘 · [?] 로 펼침(345-5 덧 3 · 352-1) · 펼치면 **2열**(사용자 지시 ⑩). */
-.b05-routeedit__hint {
- top: calc(var(--spacing-16) + 32px + var(--spacing-8));
- left: var(--spacing-16);
- display: flex;
- align-items: flex-start;
- gap: var(--spacing-8);
- max-width: 60%;
- pointer-events: none;
-}
-
-.b05-routeedit__hint-toggle.ui-btn[data-size] {
- flex: none;
- padding-inline: var(--spacing-8);
- font-weight: 600;
- pointer-events: auto;
-}
-
-.b05-routeedit__hint-body {
- display: none;
- grid-template-columns: auto auto;
- gap: 2px var(--spacing-16);
- padding: var(--spacing-8) var(--spacing-12);
-}
-
-.b05-routeedit__hint.is-open > .b05-routeedit__hint-body {
- display: grid;
-}
-
/* 상태 · 범례 — 지도 왼쪽 아래(사용자 지시 ⑫) · 뜬 종단 판이 덮으면 그 위로(408-2 · `_Chrome` 이 적음).
두 줄 안 · 좁은 폭(345-5 덧 3) — 왼쪽 상태 글(두 줄에서 자름) · 가운데 범례 두 줄 · 오른쪽 ▾. */
.b05-routeedit__info {
@@ -365,7 +334,7 @@
}
/* 분석 지형이 숨으면 앞 구분선도(390-1) · 스냅 끔이면 간격 고르기 흐림(390-2). */
-.b05-route__view-separator:has(+ .b05-routeedit__terrain[hidden]) {
+.ui-toolbar__divider:has(+ .b05-routeedit__terrain[hidden]) {
display: none;
}
diff --git a/D03_PlanAnalysis/D03_PlanAnalysis_Api.ts b/D03_PlanAnalysis/D03_PlanAnalysis_Api.ts
index 12d06ee61..4cdd47984 100644
--- a/D03_PlanAnalysis/D03_PlanAnalysis_Api.ts
+++ b/D03_PlanAnalysis/D03_PlanAnalysis_Api.ts
@@ -135,10 +135,11 @@ export async function fetchPlanSurface(projectId: string): Promise;
}
export const fetchPlanCadastral = (projectId: string): Promise =>
diff --git a/D03_PlanAnalysis/D03_PlanAnalysis_UI_Layers.ts b/D03_PlanAnalysis/D03_PlanAnalysis_UI_Layers.ts
index 6d695d82e..250eb3551 100644
--- a/D03_PlanAnalysis/D03_PlanAnalysis_UI_Layers.ts
+++ b/D03_PlanAnalysis/D03_PlanAnalysis_UI_Layers.ts
@@ -60,11 +60,6 @@ const LAYERS: readonly LayerDef[] = [
const PREF_KEY = "aislo:pref:d03.layers";
/** 등고선을 받아 올 그은 선 둘레(m). */
const CONTOUR_PAD_M = 600;
-const SLOPE_STEPS = [
- { label: "15°", token: "--draw-slope-15" },
- { label: "35°", token: "--draw-slope-35" },
- { label: "40°", token: "--draw-slope-40" },
-];
interface Prepared {
contour: PreparedLayer;
@@ -142,10 +137,7 @@ export function createPlanLayers(opts: {
bar.classList.add("d03-plan__layers");
const legend = document.createElement("div");
legend.className = "d03-plan__legend";
- legend.title = "급경사 색 — 그 값 이상";
- legend.append(
- createLegend(SLOPE_STEPS.map((step) => ({ label: step.label, color: `var(${step.token})` }))),
- );
+ legend.title = "급경사 색 — 단계 · 받은 지형 안 넓이 비율";
function sync(): void {
for (const def of LAYERS) {
@@ -159,6 +151,8 @@ export function createPlanLayers(opts: {
legend.hidden = !meta || !on.slope || !data.slope;
}
+ sync();
+
function toggle(key: PlanLayerKey): void {
on[key] = !on[key];
writeByKey(PREF_KEY, JSON.stringify(on));
@@ -239,6 +233,15 @@ export function createPlanLayers(opts: {
} else {
const raster = await fetchPlanRaster(projectId, "slope");
data.slope = { raster, image: await loadImage(raster.image) };
+ // 범례 = 서버 단계 색 그대로(색 한 곳)
+ legend.replaceChildren(
+ createLegend(
+ raster.bands.map((band) => ({
+ label: `${band.min_deg}${band.max_deg < 90 ? `~${band.max_deg}°` : "°↑"} ${(band.ratio * 100).toFixed(1)} %`,
+ color: band.color,
+ })),
+ ),
+ );
}
}
@@ -271,7 +274,7 @@ export function createPlanLayers(opts: {
draw: (context, map) => {
if (!on.cadastral || !data.cadastral) return;
context.globalAlpha = 0.8;
- stroke(context, map, data.cadastral, themeColor("--draw-map-parcel", "#facc15"), 0.8);
+ stroke(context, map, data.cadastral, themeColor("--draw-map-parcel", "#f0abfc"), 0.8);
},
},
{
diff --git a/D03_PlanAnalysis/D03_PlanAnalysis_UI_Style.css b/D03_PlanAnalysis/D03_PlanAnalysis_UI_Style.css
index 950185186..1df8f3989 100644
--- a/D03_PlanAnalysis/D03_PlanAnalysis_UI_Style.css
+++ b/D03_PlanAnalysis/D03_PlanAnalysis_UI_Style.css
@@ -29,7 +29,6 @@
position: absolute;
top: var(--spacing-8);
right: var(--spacing-8);
- align-items: flex-end;
}
/* 569-2 바탕 겹 단추 — 왼쪽 위 · 급경사 범례 — 왼쪽 아래 */
diff --git a/resources/tester/helper_345_2_3d_modal.cjs b/resources/tester/helper_345_2_3d_modal.cjs
index c0732987d..fae800bb0 100644
--- a/resources/tester/helper_345_2_3d_modal.cjs
+++ b/resources/tester/helper_345_2_3d_modal.cjs
@@ -52,10 +52,11 @@ global.document = { createElement: (tag) => new FakeNode(tag) };
const modals = [];
const STUBS = {
- "@ui/ui_template_elements": {
- createButton: ({ label, onClick }) => {
+ "@ui/ui_template_map_tools": {
+ mapToolButton: (act, { title, onClick }) => {
const button = new FakeNode("button");
- button.label = label;
+ button.act = act;
+ button.title = title;
if (onClick) button.addEventListener("click", onClick);
return button;
},
diff --git a/resources/tester/test_345_5c_info_hint_collapse.py b/resources/tester/test_345_5c_info_hint_collapse.py
index dec4d6269..01edf58ae 100644
--- a/resources/tester/test_345_5c_info_hint_collapse.py
+++ b/resources/tester/test_345_5c_info_hint_collapse.py
@@ -28,15 +28,13 @@ def _rule(selector: str) -> str:
def test_도움말_기본_접힘_펼침_기억() -> None:
assert "let hintOpen = false;" in CHROME # 기본 접힘 · 모듈 값 = 페이지 동안 기억
- assert 'data-act="hint-toggle" aria-expanded="false"' in CHROME and ">?" in CHROME
- assert "hintOpen = open;" in CHROME and 'hint.classList.toggle("is-open", open);' in CHROME
- assert "setHint(hintOpen);" in CHROME
- assert 'hintToggle.addEventListener("click", () => setHint(!hintOpen));' in CHROME
- # 접힘 = 몸통 없음 · 펼침 = 2열 · 단추만 클릭 받음
- assert "display: none;" in _rule(".b05-routeedit__hint-body")
- assert "display: grid;" in _rule(".b05-routeedit__hint.is-open > .b05-routeedit__hint-body")
- assert "pointer-events: auto;" in _rule(".b05-routeedit__hint-toggle.ui-btn[data-size]")
- assert "pointer-events: none;" in _rule(".b05-routeedit__hint")
+ # 568-2 — [?] 단추 · 안내 판 = 공용 지도 도구줄(접힘 · 2열 · 클릭 통과는 test_568_1)
+ assert (
+ "hint: { lines: HINT_LINES, open: hintOpen, onToggle: (open) => (hintOpen = open) }"
+ in CHROME
+ )
+ assert 'mapTools.hint!.classList.add("b05-routeedit__hint")' in CHROME # 가이드 촬영 선택자
+ assert '"Ctrl+휠 = 돌리기(한 칸 5°)",' in CHROME
def test_상태_범례_접기_한_줄_기억() -> None:
@@ -63,7 +61,8 @@ def test_상태_글판_작게_반투명_자리() -> None:
# 상태 글 두 줄에서 자름 · 범례는 옆 칸 두 줄
assert "-webkit-line-clamp: 2;" in _rule(".b05-routeedit__status")
assert "flex-direction: column;" in _rule(".b05-routeedit__legend")
- glass = _rule(".b05-routeedit__hint-body,\n.b05-routeedit__info")
+ glass = CSS[CSS.index("\n.b05-routeedit__info {") :]
+ glass = glass[: glass.index("}")]
assert "color-mix(in srgb, var(--color-surface-raised) 72%, transparent)" in glass
assert not re.search(r"#[0-9a-fA-F]{3,6}\b", glass) # 바탕 · 글 색은 토큰
diff --git a/resources/tester/test_346_2_footprint_draw.py b/resources/tester/test_346_2_footprint_draw.py
index c5c105ba4..ea72830c3 100644
--- a/resources/tester/test_346_2_footprint_draw.py
+++ b/resources/tester/test_346_2_footprint_draw.py
@@ -104,7 +104,7 @@ def test_편집기가_발자국을_그리고_단추로_켬끔() -> None:
# 등고선 뒤 · 노선 앞(노선이 발자국 위에 보임)
assert render.index("drawFootprint(context") < render.index("scene.expected,")
chrome = (B05 / "B05_Profile_UI_RouteEdit_Chrome.ts").read_text(encoding="utf-8")
- assert 'data-act="footprint"' in chrome and "bindFootprintToggle(" in chrome
+ assert 'mapToolButton("footprint"' in chrome and "bindFootprintToggle(" in chrome
footprint = (B05 / "B05_Profile_UI_RouteEdit_Footprint.ts").read_text(encoding="utf-8")
assert 'subscribe("footprint"' in footprint and "let shown = true;" in footprint
css = (B05 / "B05_Profile_UI_Style_RouteEdit_Footprint.css").read_text(encoding="utf-8")
diff --git a/resources/tester/test_353_1_cut_fill_line_smooth.py b/resources/tester/test_353_1_cut_fill_line_smooth.py
index 2be252fc6..d8d4094fe 100644
--- a/resources/tester/test_353_1_cut_fill_line_smooth.py
+++ b/resources/tester/test_353_1_cut_fill_line_smooth.py
@@ -195,5 +195,5 @@ def test_깎기_쌓기_바뀜_자리는_도로_끝(pieces) -> None:
def test_단추_이름은_절성토선() -> None:
chrome = (ROOT / "B05_Profile" / "B05_Profile_UI_RouteEdit_Chrome.ts").read_text("utf-8")
- at = chrome.index('data-act="footprint"')
- assert ">절/성토선" in chrome[at : at + 200] and ">발자국<" not in chrome
+ at = chrome.index('mapToolButton("footprint"')
+ assert 'title: "절/성토선 — ' in chrome[at : at + 200] and "발자국" not in chrome
diff --git a/resources/tester/test_551_2_draw_tokens.py b/resources/tester/test_551_2_draw_tokens.py
index fb631cd70..9e2925ac0 100644
--- a/resources/tester/test_551_2_draw_tokens.py
+++ b/resources/tester/test_551_2_draw_tokens.py
@@ -124,7 +124,7 @@ def test_draw_values_are_literal_hex():
assert draws, mode
for name, value in draws.items():
assert HEX.fullmatch(value), (mode, name, value)
- assert len([k for k in blocks["light"] if k.startswith("--draw-")]) == 24
+ assert len([k for k in blocks["light"] if k.startswith("--draw-")]) == 21
def test_drawing_css_uses_no_screen_tokens():
diff --git a/resources/tester/test_b05_routeedit_initial.py b/resources/tester/test_b05_routeedit_initial.py
index 378bb25a2..6d63e1b10 100644
--- a/resources/tester/test_b05_routeedit_initial.py
+++ b/resources/tester/test_b05_routeedit_initial.py
@@ -209,40 +209,39 @@ def test_노선_추천_다듬기_23_3():
return open(os.path.join(page, name), encoding="utf-8").read()
chrome = read("B05_Profile_UI_RouteEdit_Chrome.ts")
- # 366-2 — [?] | ↶ ↷ | 3D | ⟲ ⟳ · 1m 등고선 · 절/성토선 · 거리 재기 | 측점 스냅 · 간격 | 분석 지형(맨 오른쪽)
+ # 366-2 · 568-2 — [?] | ↶ ↷ | 3D | ⟲ ⟳ · 1m 등고선 · 측점 · 기울기 · 절/성토선 · 거리 재기 | 측점 스냅 · 간격 |
+ # 설계 지형 이름(맨 오른쪽) — 공용 지도 도구줄 묶음 차례([?] 는 hint 가 맨 앞에 붙임)
bar = chrome[
- chrome.index("b05-routeedit__tools") : chrome.index('')
+ chrome.index("createMapTools({") : chrome.index('classList.add("b05-routeedit__tools")')
]
order = [
- 'data-act="hint-toggle"',
- "|",
- 'data-act="undo"',
- 'data-act="redo"',
- "|",
- 'data-slot="tools"',
- "|",
- 'data-act="rotate-ccw"',
- 'data-act="rotate-cw"',
- 'data-act="contour-minor"',
- 'data-act="stations"', # 381-2 [측점] [기울기] = 절/성토선 왼쪽
- 'data-act="slopes"',
- 'data-act="footprint"',
- 'data-act="measure"',
- "|",
- 'data-act="station-snap"',
- 'data-act="snap-step"', # 390-2 스냅 간격 = [측점 스냅] 오른쪽
- "|", # 390-1 [측점 스냅] | 설계 지형 이름(509-5)
- 'class="b05-routeedit__terrain" data-slot="terrain-name" hidden',
+ "hint: { lines: HINT_LINES",
+ "groups: [",
+ 'mapToolButton("undo"',
+ 'mapToolButton("redo"',
+ "],",
+ "tools, // 부른 쪽 단추([3D])",
+ '"rotate-ccw",',
+ '"rotate-cw",',
+ 'mapToolButton("contour-minor"',
+ 'mapToolButton("stations"', # 381-2 [측점] [기울기] = 절/성토선 왼쪽
+ 'mapToolButton("slopes"',
+ 'mapToolButton("footprint"',
+ 'mapToolButton("measure"',
+ "],",
+ 'mapToolButton("station-snap"',
+ "snapStep,", # 390-2 스냅 간격 = [측점 스냅] 오른쪽
+ "],", # 390-1 [측점 스냅] | 설계 지형 이름(509-5)
+ "[terrainName],",
]
at = 0
for mark in order:
- key = "b05-route__view-separator" if mark == "|" else mark
- at = bar.index(key, at) + 1
- assert bar.count("b05-route__view-separator") == 5
- assert chrome.count("b05-route__view-separator") == 5
+ at = bar.index(mark, at) + 1
+ assert 'class="b05-routeedit__terrain" data-slot="terrain-name" hidden' in chrome
+ assert "b05-route__view-separator" not in chrome # 나눔선 = 공용 도구줄
# 분석 지형이 숨으면 앞 구분선도 숨김 · 스냅 끔이면 간격 고르기 흐림
style = read("B05_Profile_UI_Style_RouteEdit.css")
- assert ".b05-route__view-separator:has(+ .b05-routeedit__terrain[hidden])" in style
+ assert ".ui-toolbar__divider:has(+ .b05-routeedit__terrain[hidden])" in style
assert '[data-act="station-snap"][aria-pressed="false"] + .b05-routeedit__snap-step' in style
assert "b05-routeedit__spin" not in chrome # 회전 = 도구줄(추천 모달 CSS 는 남음)
shared = read("B05_Profile_UI_RouteEdit_Recommend_Map.ts")
diff --git a/ui_template/ui_template_map_tools.css b/ui_template/ui_template_map_tools.css
index 29457cbfe..d12e6fbb0 100644
--- a/ui_template/ui_template_map_tools.css
+++ b/ui_template/ui_template_map_tools.css
@@ -31,3 +31,9 @@
.ui-map-tools__hint.is-open {
display: grid;
}
+
+/* 숨김 — display 가 [hidden] 을 덮지 않게 */
+.ui-map-tools[hidden],
+.ui-map-tools__hint[hidden] {
+ display: none !important;
+}
diff --git a/ui_template/ui_template_map_tools.ts b/ui_template/ui_template_map_tools.ts
index 1c2496a6f..524b4deb8 100644
--- a/ui_template/ui_template_map_tools.ts
+++ b/ui_template/ui_template_map_tools.ts
@@ -77,9 +77,9 @@ export interface MapTools {
export function createMapTools(opts: MapToolsOptions): MapTools {
const root = document.createElement("div");
root.className = "ui-map-tools";
- const groups = opts.groups.map((group) =>
- group.map((item) => (typeof item === "string" ? mapToolButton(item) : item)),
- );
+ const groups = opts.groups
+ .filter((group) => group.length)
+ .map((group) => group.map((item) => (typeof item === "string" ? mapToolButton(item) : item)));
let hint: HTMLElement | null = null;
if (opts.hint) {
const { lines, onToggle } = opts.hint;
diff --git a/ui_template/ui_template_theme.css b/ui_template/ui_template_theme.css
index 065f1a4d5..7384c6da8 100644
--- a/ui_template/ui_template_theme.css
+++ b/ui_template/ui_template_theme.css
@@ -554,10 +554,7 @@ html.is-bm-route .m01lab-src__body * {
--draw-map-contour: #ffd68c; /* 위성 위 겹(노선분석) — 도엽 등고선 */
--draw-map-stream: #38bdf8; /* 세류 · 하천 */
--draw-map-road: #f8fafc; /* 기존 도로 */
- --draw-map-parcel: #facc15; /* 지적 경계 */
- --draw-slope-15: #fde047; /* 급경사 색 15° 이상 */
- --draw-slope-35: #f97316; /* 35° 이상 */
- --draw-slope-40: #dc2626; /* 40° 이상 */
+ --draw-map-parcel: #f0abfc; /* 지적 경계 */
}
:root[data-theme="dark"] {