Merge remote-tracking branch 'origin/sub_laptop_1' into main_laptop_1
This commit is contained in:
@@ -2,6 +2,7 @@ import { createButton } from "@ui/ui_template_elements";
|
||||
import { createSidePanels, type SidePanels } from "@ui/ui_template_side_panels";
|
||||
import { bindFootprintToggle } from "./B05_Profile_UI_RouteEdit_Footprint";
|
||||
import { bindMarkToggle } from "./B05_Profile_UI_RouteEdit_Marks";
|
||||
import { infoLiftPx } from "./logic/B05_Profile_RouteEdit_InfoLift";
|
||||
|
||||
/* =============================================================================
|
||||
* B05_Profile_UI_RouteEdit_Chrome.ts
|
||||
@@ -205,6 +206,24 @@ export function createRouteEditChrome(
|
||||
setInfo(infoCollapsed);
|
||||
infoToggle.addEventListener("click", () => setInfo(!infoCollapsed));
|
||||
|
||||
// 뜬 종단 판(이웃 칸)이 지도 아래를 덮으면 상태 · 범례를 그 위로(408-2) — 판 높이 끌기 · 접기 ·
|
||||
// 창 분할(판이 다른 창으로 감 = 못 찾음)을 판 크기 관찰로 따라감.
|
||||
let watchedProfile: Element | null = null;
|
||||
const liftInfo = (): void => {
|
||||
if (!overlay.isConnected) return; // 붙기 전 첫 알림 · 걷힌 뒤 — 판 관찰은 판과 함께 사라짐
|
||||
const profile =
|
||||
overlay.closest(".design-page__main")?.querySelector(".b05-route-profile") ?? null;
|
||||
if (profile && profile !== watchedProfile) lift.observe((watchedProfile = profile));
|
||||
const map = overlay.getBoundingClientRect();
|
||||
const top = profile?.isConnected ? profile.getBoundingClientRect().top : null;
|
||||
overlay.style.setProperty(
|
||||
"--b05-profile-cover",
|
||||
`${infoLiftPx(map.bottom, map.height, top)}px`,
|
||||
);
|
||||
};
|
||||
const lift = new ResizeObserver(liftInfo);
|
||||
lift.observe(overlay);
|
||||
|
||||
const measureCloseButton = createButton({ label: "✕", variant: "ghost" });
|
||||
measureCloseButton.classList.add("b05-routeedit__measure-close");
|
||||
measureCloseButton.setAttribute("aria-label", "닫기");
|
||||
|
||||
@@ -88,10 +88,10 @@
|
||||
display: grid;
|
||||
}
|
||||
|
||||
/* 상태 · 범례 — 지도 왼쪽 아래(사용자 지시 ⑫) · 뜬 종단 판이 덮으면 가려진 채(349-0).
|
||||
/* 상태 · 범례 — 지도 왼쪽 아래(사용자 지시 ⑫) · 뜬 종단 판이 덮으면 그 위로(408-2 · `_Chrome` 이 적음).
|
||||
두 줄 안 · 좁은 폭(345-5 덧 3) — 왼쪽 상태 글(두 줄에서 자름) · 가운데 범례 두 줄 · 오른쪽 ▾. */
|
||||
.b05-routeedit__info {
|
||||
bottom: var(--spacing-12);
|
||||
bottom: calc(var(--spacing-12) + var(--b05-profile-cover, 0px));
|
||||
left: var(--spacing-12);
|
||||
display: grid;
|
||||
grid-template-columns: minmax(0, 1fr) auto auto;
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
/* =============================================================================
|
||||
* B05_Profile/logic/B05_Profile_RouteEdit_InfoLift.ts
|
||||
* 평면 상태 · 범례 올림(408-2) — 뜬 종단 판이 지도 아래를 덮은 높이만큼 위로.
|
||||
* 파이썬 짝 아님. 순수 계산 — 화면 · fetch · sessionStorage 없음. 부르는 쪽은 `_UI_RouteEdit_Chrome`.
|
||||
* ========================================================================== */
|
||||
|
||||
/** 상태 글판이 이 높이(px)는 지도 위에 남게 — 판을 끝까지 올려도 지도 밖으로 안 나감. */
|
||||
const KEEP_PX = 120;
|
||||
|
||||
/** 올릴 높이(px) — `profileTop` = 종단 판 윗변(없음 · 접힘 · 창 분할 = null) · 지도 칸 아래 · 높이. */
|
||||
export function infoLiftPx(
|
||||
mapBottom: number,
|
||||
mapHeight: number,
|
||||
profileTop: number | null,
|
||||
): number {
|
||||
if (profileTop === null) return 0;
|
||||
const cover = Math.max(0, mapBottom - profileTop);
|
||||
return Math.round(Math.min(cover, Math.max(0, mapHeight - KEEP_PX)));
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
/* 408-2 평면 상태줄 올림 — `logic/B05_Profile_RouteEdit_InfoLift.ts` 를 Node 로 돌려 JSON 한 줄
|
||||
* (`test_408_2_status_lift.py` 가 판정).
|
||||
* node helper_408_2_status_lift.cjs
|
||||
*/
|
||||
const fs = require("fs");
|
||||
const path = require("path");
|
||||
const ts = require(path.join(__dirname, "..", "..", "config", "node_modules", "typescript"));
|
||||
|
||||
const file = path.join(
|
||||
__dirname,
|
||||
"..",
|
||||
"..",
|
||||
"B05_Profile",
|
||||
"logic",
|
||||
"B05_Profile_RouteEdit_InfoLift.ts",
|
||||
);
|
||||
const js = ts.transpileModule(fs.readFileSync(file, "utf8"), {
|
||||
compilerOptions: { module: ts.ModuleKind.CommonJS, target: ts.ScriptTarget.ES2020 },
|
||||
}).outputText;
|
||||
const box = { exports: {} };
|
||||
new Function("exports", "module", "require", js)(box.exports, box, require);
|
||||
const { infoLiftPx } = box.exports;
|
||||
|
||||
// 화면 1078 px · 지도 칸 0~1078
|
||||
process.stdout.write(
|
||||
JSON.stringify({
|
||||
open: infoLiftPx(1078, 1078, 430), // 종단 판 열림(648 px)
|
||||
collapsed: infoLiftPx(1078, 1078, 1077), // 접힘(테두리 1 px)
|
||||
popout: infoLiftPx(1078, 1078, null), // 창 분할 = 판 없음
|
||||
below: infoLiftPx(600, 600, 700), // 횡단 보기 = 판이 지도 아래 흐름
|
||||
tall: infoLiftPx(1078, 1078, 20), // 판을 끝까지 올림 = 지도 안에 남김
|
||||
}),
|
||||
);
|
||||
@@ -56,8 +56,8 @@ def test_상태_범례_접기_한_줄_기억() -> None:
|
||||
|
||||
def test_상태_글판_작게_반투명_자리() -> None:
|
||||
info = _rule(".b05-routeedit__info")
|
||||
# 왼쪽 아래 제자리 — 뜬 판이 덮으면 가려진 채(349-0) · 폭 줄임
|
||||
assert "bottom: var(--spacing-12);" in info
|
||||
# 왼쪽 아래 제자리 — 뜬 판이 덮으면 그 위로(408-2) · 폭 줄임
|
||||
assert "bottom: calc(var(--spacing-12) + var(--b05-profile-cover, 0px));" in info
|
||||
assert "max-width: min(460px, 46%);" in info and "grid-template-columns:" in info
|
||||
# 상태 글 두 줄에서 자름 · 범례는 옆 칸 두 줄
|
||||
assert "-webkit-line-clamp: 2;" in _rule(".b05-routeedit__status")
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
"""408-2 창 나눔(종단 판 열림) 때 평면 상태줄이 종단 표 밑에 깔림 — 판이 덮은 높이만큼 상태 · 범례를
|
||||
위로(`logic/B05_Profile_RouteEdit_InfoLift.ts` · `_Chrome` 이 판 크기 관찰로 `--b05-profile-cover` 적음).
|
||||
|
||||
TS 셈은 `helper_408_2_status_lift.cjs`(Node).
|
||||
|
||||
./venv/Scripts/python.exe -m pytest resources/tester/test_408_2_status_lift.py -q
|
||||
"""
|
||||
|
||||
import json
|
||||
import subprocess
|
||||
from pathlib import Path
|
||||
|
||||
import pytest
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[2]
|
||||
B05 = ROOT / "B05_Profile"
|
||||
HELPER = Path(__file__).with_name("helper_408_2_status_lift.cjs")
|
||||
|
||||
|
||||
@pytest.fixture(scope="module")
|
||||
def got() -> dict:
|
||||
run = subprocess.run( # noqa: S603 — 고정 실행 파일
|
||||
["node", str(HELPER)], capture_output=True, text=True, encoding="utf-8", timeout=60
|
||||
)
|
||||
assert run.returncode == 0, run.stderr
|
||||
return json.loads(run.stdout)
|
||||
|
||||
|
||||
def test_올릴_높이(got) -> None:
|
||||
assert got["open"] == 648 # 판 윗변 위로
|
||||
assert got["collapsed"] == 1 and got["popout"] == 0 and got["below"] == 0
|
||||
assert got["tall"] == 1078 - 120 # 지도 안에 120 px 남김
|
||||
|
||||
|
||||
def test_상태_글판이_올림_값을_씀() -> None:
|
||||
css = (B05 / "B05_Profile_UI_Style_RouteEdit.css").read_text(encoding="utf-8")
|
||||
block = css[css.index(".b05-routeedit__info {\n bottom") :]
|
||||
assert block.startswith(
|
||||
".b05-routeedit__info {\n bottom: calc(var(--spacing-12) + var(--b05-profile-cover, 0px));"
|
||||
)
|
||||
|
||||
|
||||
def test_편집기가_판_크기를_관찰() -> None:
|
||||
chrome = (B05 / "B05_Profile_UI_RouteEdit_Chrome.ts").read_text(encoding="utf-8")
|
||||
assert "new ResizeObserver(liftInfo)" in chrome and "lift.observe(overlay)" in chrome
|
||||
assert '"--b05-profile-cover"' in chrome and ".b05-route-profile" in chrome
|
||||
assert "lift.disconnect" not in chrome # 붙기 전 첫 알림에 끊으면 영영 안 올라감
|
||||
Reference in New Issue
Block a user