Merge remote-tracking branch 'origin/dev' into sub_laptop_3
This commit is contained in:
@@ -0,0 +1,54 @@
|
||||
/* 51-1 — 오른쪽 패널(공용 ui_template_side_panels) 높이 = innerHeight − 머리띠 · 스크롤 처음/중간/끝 화면 안
|
||||
* 시작 화면: 패널이 이미 열린 상세 화면 하나(M02 일위대가 상세 · M02 면적산출 · M01 로직 상세 중 하나) · 화면마다 한 번씩 부름
|
||||
* 부르는 법: orca eval --expression "$(tr '\n' ' ' < 이 파일)" (async 식 · JSON 글을 돌려줌)
|
||||
* 기대: ok = true · h = want(innerHeight − max(머리띠, 칸 위)) ±2 · 칸이 올라가 붙은 뒤는 innerHeight − 머리띠 · inView = 처음·중간·끝 모두 true
|
||||
*/
|
||||
(async () => {
|
||||
const w = (ms) => new Promise((r) => setTimeout(r, ms));
|
||||
const sp = [...document.querySelectorAll(".ui-side-panels")].find(
|
||||
(s) => !s.classList.contains("is-collapsed") && s.getClientRects().length,
|
||||
);
|
||||
if (!sp) return JSON.stringify({ error: "펴진 패널 없음" });
|
||||
const head = document.querySelector(".app-header")?.getBoundingClientRect().bottom ?? 0;
|
||||
const scroller = (() => {
|
||||
for (let n = sp.parentElement; n; n = n.parentElement) {
|
||||
const y = getComputedStyle(n).overflowY;
|
||||
if ((y === "auto" || y === "scroll") && n.scrollHeight > n.clientHeight + 1) return n;
|
||||
}
|
||||
return document.scrollingElement;
|
||||
})();
|
||||
const max = scroller.scrollHeight - scroller.clientHeight;
|
||||
const sample = async (name, y) => {
|
||||
scroller.scrollTop = y;
|
||||
window.dispatchEvent(new Event("scroll")); // 뒤에 가린 탭은 스크롤 알림이 안 와서 직접
|
||||
await w(150);
|
||||
const r = sp.getBoundingClientRect();
|
||||
const want = Math.round(
|
||||
innerHeight - Math.max(head, sp.parentElement.getBoundingClientRect().top),
|
||||
);
|
||||
const body = sp.querySelector(".ui-side-panels__panel:not([hidden]) .ui-side-panels__body");
|
||||
return {
|
||||
name,
|
||||
top: Math.round(r.top),
|
||||
bottom: Math.round(r.bottom),
|
||||
h: Math.round(r.height),
|
||||
want,
|
||||
inView: r.top >= head - 2 && r.bottom <= innerHeight + 2,
|
||||
bodyScrolls: body ? body.scrollHeight > body.clientHeight : null,
|
||||
};
|
||||
};
|
||||
const was = scroller.scrollTop;
|
||||
const rows = [
|
||||
await sample("처음", 0),
|
||||
await sample("중간", Math.round(max / 2)),
|
||||
await sample("끝", max),
|
||||
];
|
||||
scroller.scrollTop = was;
|
||||
return JSON.stringify({
|
||||
innerHeight,
|
||||
head: Math.round(head),
|
||||
scrollMax: Math.round(max),
|
||||
rows,
|
||||
ok: rows.every((r) => Math.abs(r.h - r.want) <= 2 && r.inView),
|
||||
});
|
||||
})();
|
||||
@@ -180,7 +180,7 @@ function scroller(node: HTMLElement): HTMLElement | null {
|
||||
}
|
||||
|
||||
/**
|
||||
* 패널 묶음을 보이는 칸 안에 붙임 — 높이 = 보이는 칸 · 본문을 굴려도 그 자리(몸만 따로 스크롤)
|
||||
* 패널 묶음을 보이는 칸 안에 붙임 — 높이 = 보이는 창 높이 − 머리띠(칸이 아래에 있으면 칸 위부터) · 본문을 굴려도 그 자리(몸만 따로 스크롤)
|
||||
* CSS sticky 는 위 칸의 overflow 가 막아 JS 로 — 어느 칸이 굴러도(capture) 다시 잼
|
||||
*/
|
||||
function followView(node: HTMLElement): void {
|
||||
@@ -191,13 +191,16 @@ function followView(node: HTMLElement): void {
|
||||
if (!root.isConnected) return;
|
||||
const box = scroller(root)?.getBoundingClientRect();
|
||||
const head = document.querySelector(".app-header")?.getBoundingClientRect().bottom ?? 0;
|
||||
const top = Math.max(head, box?.top ?? 0) + 8;
|
||||
const bottom = Math.min(window.innerHeight, box?.bottom ?? window.innerHeight) - 8;
|
||||
const view = Math.max(head, box?.top ?? 0);
|
||||
const bottom = Math.min(window.innerHeight, box?.bottom ?? window.innerHeight);
|
||||
const row = root.parentElement?.getBoundingClientRect();
|
||||
if (!row) return;
|
||||
const height = Math.max(240, bottom - top);
|
||||
// 칸이 아직 화면 아래에 있으면 칸 위에 맞춤 · 올라가 붙으면 보이는 칸 전체 높이
|
||||
const top = Math.max(view, row.top);
|
||||
// 칸 바닥(+ 쪽 아래 여백)을 넘지 않음 · 너무 줄면 최소 높이로 두고 칸 바닥에 맞춰 올라감
|
||||
const height = Math.max(240, Math.min(bottom, row.bottom + 48) - top);
|
||||
root.style.height = `${height}px`;
|
||||
const shift = Math.min(Math.max(0, top - row.top), Math.max(0, row.height - height));
|
||||
const shift = Math.min(Math.max(0, view - row.top), Math.max(0, row.height + 48 - height));
|
||||
root.style.transform = shift ? `translateY(${Math.round(shift)}px)` : "";
|
||||
};
|
||||
const stop = (): void => {
|
||||
|
||||
Reference in New Issue
Block a user