feat(지도 도구줄): 좁으면 한 줄 가로 밀기 · 넘친 쪽 끝 흐림 · 휠 가로 밀기 · D03 도구줄이 겹 단추줄을 안 덮음 (PLAN 571-1 · 요구 399)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -14,7 +14,7 @@
|
||||
min-height: 0;
|
||||
}
|
||||
|
||||
/* 도구줄 — 지도 왼쪽 위(공용 `ui-map-tools` · 넘치면 줄바꿈 · 빈 자리는 지도 조작 통과) · [?] 안내 판은 그 아래. */
|
||||
/* 도구줄 — 지도 왼쪽 위(공용 `ui-map-tools` · 넘치면 가로 밀기 · 빈 자리는 지도 조작 통과) · [?] 안내 판은 그 아래. */
|
||||
.b05-routeedit__tools {
|
||||
position: absolute;
|
||||
z-index: 2;
|
||||
|
||||
@@ -25,10 +25,13 @@
|
||||
touch-action: none;
|
||||
}
|
||||
|
||||
/* 571-1 — 왼쪽은 겹 단추줄(222px) 오른쪽까지 · 그 사이가 모자라면 도구줄이 가로 밀림 · 오른쪽 붙임 그대로 */
|
||||
.d03-plan__tools {
|
||||
position: absolute;
|
||||
top: var(--spacing-8);
|
||||
right: var(--spacing-8);
|
||||
left: calc(2 * var(--spacing-8) + 222px);
|
||||
align-items: flex-end;
|
||||
}
|
||||
|
||||
/* 569-2 바탕 겹 단추 — 왼쪽 위 · 급경사 범례 — 왼쪽 아래 */
|
||||
|
||||
@@ -79,3 +79,16 @@ def test_켬끔_안내_판():
|
||||
assert "display: none;" in hint[: hint.index("}")]
|
||||
assert "display: grid;" in CSS[CSS.index(".ui-map-tools__hint.is-open {") :]
|
||||
assert "pointer-events: none;" in CSS # 빈 자리 · 글판은 지도 조작 통과
|
||||
|
||||
|
||||
def test_571_1_한_줄_가로_밀기():
|
||||
bar = CSS[CSS.index(".ui-map-tools > .ui-toolbar {") :]
|
||||
bar = bar[: bar.index("}")]
|
||||
assert "flex-wrap: nowrap;" in bar # 줄바꿈 없음
|
||||
assert "overflow-x: auto;" in bar # 밀기 칸
|
||||
assert "scrollbar-width: none;" in bar
|
||||
assert "mask-image" in bar # 넘친 끝 흐림
|
||||
assert ".ui-toolbar.is-more-end" in CSS and ".ui-toolbar.is-more-start" in CSS
|
||||
assert "flex-shrink: 0;" in CSS # 단추가 찌그러지지 않음
|
||||
assert "watchOverflow(bar);" in TS
|
||||
assert '"wheel"' in TS and "passive: false" in TS # 휠 = 가로 밀기
|
||||
|
||||
@@ -10,6 +10,36 @@
|
||||
.ui-map-tools > .ui-toolbar {
|
||||
max-width: 100%;
|
||||
pointer-events: auto;
|
||||
/* 571-1 — 한 줄 고정 · 모자라면 가로 밀기(막대 숨김) · 넘친 쪽 끝만 흐림 */
|
||||
flex-wrap: nowrap;
|
||||
overflow-x: auto;
|
||||
overscroll-behavior-x: contain;
|
||||
scrollbar-width: none;
|
||||
--map-tools-fade-start: 0px;
|
||||
--map-tools-fade-end: 0px;
|
||||
mask-image: linear-gradient(
|
||||
to right,
|
||||
transparent,
|
||||
var(--color-text-body) var(--map-tools-fade-start),
|
||||
var(--color-text-body) calc(100% - var(--map-tools-fade-end)),
|
||||
transparent
|
||||
);
|
||||
}
|
||||
|
||||
.ui-map-tools > .ui-toolbar::-webkit-scrollbar {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.ui-map-tools > .ui-toolbar > * {
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.ui-map-tools > .ui-toolbar.is-more-start {
|
||||
--map-tools-fade-start: var(--spacing-24);
|
||||
}
|
||||
|
||||
.ui-map-tools > .ui-toolbar.is-more-end {
|
||||
--map-tools-fade-end: var(--spacing-24);
|
||||
}
|
||||
|
||||
/* 안내 판 — 기본 접힘 · 2열 · 글판은 클릭 통과 */
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
* 꼴 = 유리 도구줄(`createToolbar` glass · 32) 한 줄 · 묶음 사이 나눔선 · 단추는 모두 아이콘(마우스 올리면 이름)
|
||||
* [?] 안내 판 = 도구줄 아래 2열 글판(기본 접힘 · 클릭은 지도로 통과)
|
||||
* 크기 = 단 32 하나(지도 위 도구)
|
||||
* 좁을 때 = 줄바꿈 없이 가로 밀기(터치 · 휠) · 넘친 쪽 끝만 흐림(`is-more-start` · `is-more-end`)
|
||||
* 상태 = 켬끔 단추는 `aria-pressed`(눌림 꼴) · 막힘 `disabled` · [?] 는 `aria-expanded`
|
||||
* 쓰는 법 = createMapTools({ label: "평면 도구", groups: [["undo", "redo"], ["rotate-ccw", "rotate-cw", "measure"]],
|
||||
* hint: { lines: ["휠 = 확대"] } }) → { root, bar, hint, button(act) }
|
||||
@@ -74,6 +75,29 @@ export interface MapTools {
|
||||
button(act: MapToolAct): HTMLButtonElement | null;
|
||||
}
|
||||
|
||||
/** 넘침 표시 + 휠을 가로 밀기로 — 도구줄이 넘칠 때만 */
|
||||
function watchOverflow(bar: HTMLElement): void {
|
||||
const mark = (): void => {
|
||||
const max = bar.scrollWidth - bar.clientWidth;
|
||||
bar.classList.toggle("is-more-start", bar.scrollLeft > 1);
|
||||
bar.classList.toggle("is-more-end", max - bar.scrollLeft > 1);
|
||||
};
|
||||
bar.addEventListener("scroll", mark, { passive: true });
|
||||
bar.addEventListener(
|
||||
"wheel",
|
||||
(ev) => {
|
||||
if (bar.scrollWidth <= bar.clientWidth || Math.abs(ev.deltaX) > Math.abs(ev.deltaY)) return;
|
||||
ev.preventDefault();
|
||||
bar.scrollLeft += ev.deltaY;
|
||||
},
|
||||
{ passive: false },
|
||||
);
|
||||
if (typeof ResizeObserver === "undefined") return;
|
||||
const observer = new ResizeObserver(mark);
|
||||
observer.observe(bar);
|
||||
for (const child of Array.from(bar.children)) observer.observe(child);
|
||||
}
|
||||
|
||||
export function createMapTools(opts: MapToolsOptions): MapTools {
|
||||
const root = document.createElement("div");
|
||||
root.className = "ui-map-tools";
|
||||
@@ -110,6 +134,7 @@ export function createMapTools(opts: MapToolsOptions): MapTools {
|
||||
});
|
||||
root.append(bar);
|
||||
if (hint) root.append(hint);
|
||||
watchOverflow(bar);
|
||||
return {
|
||||
root,
|
||||
bar,
|
||||
|
||||
Reference in New Issue
Block a user