Merge remote-tracking branch 'origin/sub_laptop_2' into main_laptop_1
This commit is contained in:
@@ -51,6 +51,8 @@ export const STATE_REGISTRY = {
|
||||
legacy: () => "b05-route-profile-collapsed",
|
||||
},
|
||||
"profile-height": { bucket: "pref", scope: "global", legacy: () => "b05-route-profile-height" },
|
||||
/** B06 위 평면 겹침 패널 높이(436) */
|
||||
"plan-peek-height": { bucket: "pref", scope: "global" },
|
||||
/** 배수유역 판 접힘 — 기억 없음 = 닫힘(392-1 · 옛 "false" 기억 버림). */
|
||||
"drainage-collapsed": { bucket: "pref", scope: "global", version: 2 },
|
||||
"drainage-width": { bucket: "pref", scope: "global", legacy: () => "b05-route-drainage-width" },
|
||||
|
||||
@@ -92,8 +92,9 @@
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* 횡단 보기 위 평면 겹침 패널(요구 258 · 425 · `design_plan_peek`) — 카드 칸 위에 뜸(자리 안 차지) ·
|
||||
닫히면 손잡이만 위 가운데 · 열면 가운데 칸 높이 45 % · 보기 · 팬 · 휠만이라 편집 도구는 감춤. */
|
||||
/* 횡단 보기 위 평면 겹침 패널(요구 258 · 263 · `design_plan_peek`) — 카드 칸 위에 뜸(자리 안 차지) ·
|
||||
닫히면 손잡이만 위 가운데 · 열면 처음 높이 32 %(160 px 아래로 안 감) · 아래 끝 끌어 조절 · 조작은 B05 평면 그대로라
|
||||
단추 줄 · 안내 · 상태줄 등만 감춤. */
|
||||
.design-plan-peek {
|
||||
position: absolute;
|
||||
z-index: 4;
|
||||
@@ -105,7 +106,19 @@
|
||||
}
|
||||
|
||||
.design-plan-peek.is-open {
|
||||
height: 45%;
|
||||
height: var(--design-plan-peek-height, max(32%, 160px)); /* 종단 판 펼친 B06 = 칸이 낮음 */
|
||||
}
|
||||
|
||||
/* 높이 끌기 손잡이 = 패널 아래 끝(공용 세로 손잡이는 위 끝) · 열렸을 때만 */
|
||||
.design-plan-peek > .ui-resizer {
|
||||
top: auto;
|
||||
bottom: -3px;
|
||||
display: none;
|
||||
pointer-events: auto;
|
||||
}
|
||||
|
||||
.design-plan-peek.is-open > .ui-resizer {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.design-plan-peek__body {
|
||||
|
||||
@@ -4,11 +4,13 @@
|
||||
* 그대로 옮겨 붙여 보여 줌(둘째 캔버스 없음 · 편집기는 페이지에 하나). 열 때 옮기고 · 닫을 때 ·
|
||||
* 횡단 보기가 숨을 때 제자리(자리표 주석)로 돌림. 누름 · 휠은 캔버스에 붙어 함께 옴.
|
||||
*
|
||||
* 보기 · 가운데 버튼 팬 · 휠 확대만 — 왼쪽 · 오른쪽 누름(끌기 · 끼우기 · 지우기 · 재기)은 패널이
|
||||
* 캡처에서 먼저 받아 캔버스로 안 보냄(편집은 B05 평면). 단추 줄 · 상태줄 등은 `design_page.css`.
|
||||
* 조작 · 되돌리기 · 옵션 값은 B05 평면 그대로(같은 편집기 · 436) — 단추 줄 · 안내 · 상태줄 등만 감춤
|
||||
* (`design_page.css`). 높이 = 아래 끝 끌기(화면 기억) · 열 때 · 크기 바뀔 때 내용 맞춤 없음.
|
||||
* ========================================================================== */
|
||||
|
||||
import { createWorkflowPanelHandle } from "@ui/ui_template_overlay";
|
||||
import { createPanelResizer } from "@ui/ui_template_resizer";
|
||||
import { stateKey } from "../b_page_state";
|
||||
import type { DesignPageHost } from "./design_page";
|
||||
import type { DesignPageShared } from "./design_shared";
|
||||
|
||||
@@ -26,28 +28,20 @@ export function mountPlanPeek(
|
||||
note.className = "design-plan-peek__note";
|
||||
body.append(note);
|
||||
const handle = createWorkflowPanelHandle("bottom", "up", "평면");
|
||||
root.append(body, handle.root);
|
||||
// 아래 끝 끌어 높이 — 120 px ~ 칸 높이 − 48 px(손잡이 자리) · 두 번 누름 = 처음 높이(32 %)
|
||||
// 칸 = 패널 % 높이가 재는 자리(offsetParent) — `center` 는 높이 0
|
||||
const resizer = createPanelResizer({
|
||||
axis: "vertical",
|
||||
target: root,
|
||||
cssVar: "--design-plan-peek-height",
|
||||
direction: 1,
|
||||
min: 120,
|
||||
max: () => (root.offsetParent?.clientHeight ?? 0) - 48,
|
||||
storageKey: stateKey("plan-peek-height") ?? undefined,
|
||||
});
|
||||
root.append(body, resizer.root, handle.root);
|
||||
center.append(root);
|
||||
|
||||
// 편집 몫 누름 막음 — 가운데 버튼(팬)만 통과 · 두 번 클릭(끼우기) · 오른쪽 클릭(지우기)도 막음.
|
||||
// ponytail: 손가락 팬도 막힘(왼쪽 누름과 같은 단추 0) — 터치 기기에서 필요하면 pointerType 으로 가름.
|
||||
body.addEventListener(
|
||||
"pointerdown",
|
||||
(event) => {
|
||||
if (event.button !== 1) event.stopPropagation();
|
||||
},
|
||||
true,
|
||||
);
|
||||
for (const type of ["dblclick", "contextmenu"])
|
||||
body.addEventListener(
|
||||
type,
|
||||
(event) => {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
},
|
||||
true,
|
||||
);
|
||||
|
||||
let opened = false;
|
||||
let plan: HTMLElement | null = null;
|
||||
let home: Comment | null = null;
|
||||
@@ -66,6 +60,7 @@ export function mountPlanPeek(
|
||||
|
||||
const open = async (): Promise<void> => {
|
||||
setOpen(true);
|
||||
resizer.restore(); // 기억한 높이를 지금 칸에 맞춰 다시 씌움(세울 때는 칸 크기 0)
|
||||
note.hidden = false;
|
||||
note.textContent = "평면을 여는 중…";
|
||||
await shared.ensureView("profile"); // B06 바로 열기 = 종단 보기를 숨긴 채 세움
|
||||
|
||||
@@ -285,8 +285,13 @@ export async function mountRouteEditor(
|
||||
let viewWanted = false; // 자료를 읽었다 — 칸 크기가 서면 보던 화면(18 ③) · 없으면 노선 전체로.
|
||||
function openView(): void {
|
||||
if (!viewWanted || !meta || view.width <= 0) return;
|
||||
const opening = openingView(projectId, meta, view, planned, contours?.layer ?? null);
|
||||
view = opening.view;
|
||||
// B06 겹침 평면(436)에서 처음 보여도 B05 칸 크기로 셈 — 그 배율이 B05 평면에 남음(433-8).
|
||||
const atHome = overlay.closest(".b05-route__main") !== null;
|
||||
const page = atHome ? null : overlay.closest(".design-page__center");
|
||||
const [w, h] = page ? [page.clientWidth, page.clientHeight] : [view.width, view.height];
|
||||
const home = { ...view, width: w, height: h, mapRect: computeMapRect(meta, w, h) };
|
||||
const opening = openingView(projectId, meta, home, planned, contours?.layer ?? null);
|
||||
view = { ...view, ...restoreSavedView(meta, view, captureView(meta, opening.view, 0)) };
|
||||
rotation.set(opening.rotationRad);
|
||||
viewReady = true;
|
||||
}
|
||||
|
||||
@@ -105,7 +105,7 @@ export function bindRouteEditKeys(params: RouteEditPointerParams, dragging: () =
|
||||
|
||||
function onKeyDown(event: KeyboardEvent): void {
|
||||
if (!canvas.isConnected) return detach();
|
||||
if (!isArrowKey(event.key) || !lastPointerWithin(".b05-route__main .b05-routeedit")) return; // B06 겹침 평면 = 키 안 먹음(425)
|
||||
if (!isArrowKey(event.key) || !lastPointerWithin(".b05-routeedit")) return; // B06 겹침 평면도 같음(436)
|
||||
const target = event.target as HTMLElement | null;
|
||||
if (target?.closest?.("input, select, textarea, [contenteditable='true']")) return;
|
||||
// 평면이 삼킴 — 종단도(▲▼ 계획고 · `defaultPrevented` 면 비킴) · 횡단 조정창으로 안 감
|
||||
|
||||
@@ -370,11 +370,7 @@ export function bindStructureMarks(
|
||||
function onKeyDown(event: KeyboardEvent): void {
|
||||
if (!canvas.isConnected) return detach();
|
||||
const escape = event.key === "Escape";
|
||||
if (
|
||||
(!escape && !isArrowKey(event.key)) ||
|
||||
!lastPointerWithin(".b05-route__main .b05-routeedit")
|
||||
)
|
||||
return; // 겹침 평면 = 안 먹음(425)
|
||||
if ((!escape && !isArrowKey(event.key)) || !lastPointerWithin(".b05-routeedit")) return;
|
||||
const target = event.target as HTMLElement | null;
|
||||
if (target?.closest?.("input, select, textarea, [contenteditable='true']")) return;
|
||||
// Esc = 마커 고름만 풂(공용 Esc 풀기는 오른쪽 판까지 비우므로 앞에서 받음)
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
"""258 · 425 — B06 위 평면 겹침 패널.
|
||||
"""258 · 425 · 436 — B06 위 평면 겹침 패널.
|
||||
|
||||
종단 보기 평면 노드를 옮겨 붙임(둘째 캔버스 없음) · 닫을 때 · 횡단 숨김 때 제자리 · 손잡이 =
|
||||
공용 bottom 위로 접힘 · z 4 · 높이 45 % · 편집 도구 감춤 · 가운데 버튼 팬 · 휠만(편집 누름 막음) ·
|
||||
평면 방향키는 B05 평면 안에서만. 배선은 글로 봄.
|
||||
공용 bottom 위로 접힘 · z 4 · 처음 높이 32 % · 아래 끝 끌어 높이(화면 기억) · 단추 줄 · 안내 등 감춤 ·
|
||||
조작(끌기 · 끼우기 · 지우기 · 방향키 · 휠 · 팬)은 B05 평면 그대로 · 처음 보일 때 B05 칸 크기로 셈.
|
||||
배선은 글로 봄.
|
||||
./venv/Scripts/python.exe -m pytest resources/tester/test_258_b06_plan_peek.py -q
|
||||
"""
|
||||
|
||||
@@ -41,19 +42,33 @@ def test_평면_노드를_옮기고_제자리로() -> None:
|
||||
assert len(PEEK.splitlines()) <= 700
|
||||
|
||||
|
||||
def test_편집_누름은_막고_팬_휠은_통과() -> None:
|
||||
down = PEEK[PEEK.index('"pointerdown"') :]
|
||||
down = down[: down.index("true,")]
|
||||
assert "if (event.button !== 1) event.stopPropagation();" in down
|
||||
assert 'for (const type of ["dblclick", "contextmenu"])' in PEEK
|
||||
assert '"wheel"' not in PEEK # 휠 확대는 캔버스 그대로
|
||||
def test_조작은_B05_평면_그대로() -> None:
|
||||
# 패널이 누름 · 휠을 가로채지 않음 — 캔버스에 붙은 B05 처리기가 그대로 받음
|
||||
for event in ('"pointerdown"', '"dblclick"', '"contextmenu"', '"wheel"', '"keydown"'):
|
||||
assert event not in PEEK
|
||||
assert "stopPropagation" not in PEEK
|
||||
|
||||
|
||||
def test_높이_끌기와_기억() -> None:
|
||||
assert "createPanelResizer({" in PEEK
|
||||
assert 'cssVar: "--design-plan-peek-height",' in PEEK and "direction: 1," in PEEK
|
||||
assert 'storageKey: stateKey("plan-peek-height")' in PEEK
|
||||
assert "max: () => (root.offsetParent?.clientHeight ?? 0) - 48," in PEEK
|
||||
assert "resizer.restore();" in PEEK[PEEK.index("const open = async") :]
|
||||
state = (ROOT / "A00_Common" / "b_page_state.ts").read_text(encoding="utf-8")
|
||||
assert '"plan-peek-height": { bucket: "pref", scope: "global" },' in state
|
||||
handle = _rule(".design-plan-peek > .ui-resizer")
|
||||
assert "bottom: -3px;" in handle and "display: none;" in handle
|
||||
assert "display: block;" in _rule(".design-plan-peek.is-open > .ui-resizer")
|
||||
|
||||
|
||||
def test_겹침_자리와_감춤() -> None:
|
||||
root = _rule(".design-plan-peek")
|
||||
assert "position: absolute;" in root and "z-index: 4;" in root
|
||||
assert "pointer-events: none;" in root # 닫힌 동안 카드 누름 통과
|
||||
assert "height: 45%;" in _rule(".design-plan-peek.is-open")
|
||||
assert "height: var(--design-plan-peek-height, max(32%, 160px));" in _rule(
|
||||
".design-plan-peek.is-open"
|
||||
)
|
||||
hidden = CSS[CSS.index(".design-plan-peek .b05-routeedit__tools,") :]
|
||||
hidden = hidden[: hidden.index("}")]
|
||||
for part in ("__tools", "__info", "__measure", "__side-wrap", "b05-contourlock"):
|
||||
@@ -61,8 +76,18 @@ def test_겹침_자리와_감춤() -> None:
|
||||
assert "display: none;" in hidden
|
||||
|
||||
|
||||
def test_평면_방향키는_B05_평면_안만() -> None:
|
||||
def test_평면_방향키는_마지막_누름이_평면_안() -> None:
|
||||
for name in ("B05_Profile_UI_RouteEdit_Keys.ts", "B05_Profile_UI_RouteEdit_StructureMarks.ts"):
|
||||
text = (B05 / name).read_text(encoding="utf-8")
|
||||
assert 'lastPointerWithin(".b05-route__main .b05-routeedit")' in text
|
||||
assert 'lastPointerWithin(".b05-routeedit")' not in text
|
||||
assert 'lastPointerWithin(".b05-routeedit")' in text # 겹침 평면도(436)
|
||||
assert ".b05-route__main .b05-routeedit" not in text
|
||||
|
||||
|
||||
def test_처음_보일_때_B05_칸_크기로_셈() -> None:
|
||||
editor = (B05 / "B05_Profile_UI_RouteEdit.ts").read_text(encoding="utf-8")
|
||||
body = editor[editor.index("function openView(): void {") :]
|
||||
body = body[: body.index("\n }")]
|
||||
assert 'const atHome = overlay.closest(".b05-route__main") !== null;' in body
|
||||
assert 'atHome ? null : overlay.closest(".design-page__center")' in body
|
||||
assert "openingView(projectId, meta, home," in body
|
||||
assert "restoreSavedView(meta, view, captureView(meta, opening.view, 0))" in body
|
||||
|
||||
@@ -64,8 +64,8 @@ def test_이음_끌기_걸기_한_줄_창_가로채기() -> None:
|
||||
assert pointer.count("bindRouteEditKeys(") == 1
|
||||
keys = _read("B05_Profile_UI_RouteEdit_Keys.ts")
|
||||
assert 'window.addEventListener("keydown", onKeyDown, true)' in keys # 앞서 받음(capture)
|
||||
# 본 평면만(425) — B06 겹침 평면 위 화살표는 안 먹음
|
||||
assert 'lastPointerWithin(".b05-route__main .b05-routeedit")' in keys
|
||||
# 마지막 누름이 평면 안 — B06 겹침 평면도 같음(436)
|
||||
assert 'lastPointerWithin(".b05-routeedit")' in keys
|
||||
assert "event.preventDefault();\n event.stopPropagation();" in keys
|
||||
assert "state.apexLock[index] === true" in keys # 고정 IP 는 안 옮김
|
||||
assert "shortfallCrossed(" in keys # 하한 검사 = 끌기와 같음
|
||||
|
||||
Reference in New Issue
Block a user