fix(ui): 51-8 오른쪽 패널 높이 — 칸 크기가 바뀌면 다시 잼(M01 로직 상세 240 고정 해소)

- 원인: 패널 높이를 붙은 직후 한 번만 잼 · M01 은 내용이 늦게 차 그때 칸이 짧아 최소 240 · 스크롤·창 크기 바뀜 전까지 그대로
- 고침: 패널 · 부모 칸 크기 지켜봄(ResizeObserver) — 다시 붙음 · 내용 늦게 참에도 다시 잼
- 51-1 확인: 스크롤 알림 없는 「그대로」 줄 추가(알림이 흠을 가림)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NPJGtfXo6GMbcpiboQC4uK
This commit is contained in:
2026-10-05 20:01:14 +09:00
co-authored by Claude Opus 5.5
parent 440e063c13
commit ae04b403d6
2 changed files with 20 additions and 1 deletions
@@ -1,7 +1,7 @@
/* 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
* 기대: ok = true · h = want(innerHeight − max(머리띠, 칸 위)) ±2 · 칸이 올라가 붙은 뒤는 innerHeight − 머리띠 · inView = 그대로·처음·중간·끝 모두 true
*/
(async () => {
const w = (ms) => new Promise((r) => setTimeout(r, ms));
@@ -38,7 +38,16 @@
};
};
const was = scroller.scrollTop;
// 스크롤 알림 없이 지금 높이 — 내용이 늦게 차도 스스로 다시 쟀는지(알림을 쏘면 가려짐 · 가린 탭은 먼저 orca screenshot 으로 한 장 그림)
const r0 = sp.getBoundingClientRect();
const still = {
name: "그대로",
h: Math.round(r0.height),
want: Math.round(innerHeight - Math.max(head, sp.parentElement.getBoundingClientRect().top)),
inView: r0.top >= head - 2 && r0.bottom <= innerHeight + 2,
};
const rows = [
still,
await sample("처음", 0),
await sample("중간", Math.round(max / 2)),
await sample("끝", max),
+10
View File
@@ -185,10 +185,18 @@ function scroller(node: HTMLElement): HTMLElement | null {
*/
function followView(node: HTMLElement): void {
const ref = new WeakRef(node); // 떼었다 다시 붙이는 화면(M01)도 있어 떼어져도 듣기는 남김 · 버려지면 그침
// 다시 붙음 · 칸 내용이 늦게 차 칸 크기가 바뀜(스크롤 없이) → 다시 잼
const sized = new ResizeObserver(() => place());
let watched: Element | null = null;
const place = (): void => {
const root = ref.deref();
if (!root) return stop();
if (!root.isConnected) return;
if (root.parentElement && root.parentElement !== watched) {
if (watched) sized.unobserve(watched);
watched = root.parentElement;
sized.observe(watched);
}
const box = scroller(root)?.getBoundingClientRect();
const head = document.querySelector(".app-header")?.getBoundingClientRect().bottom ?? 0;
const view = Math.max(head, box?.top ?? 0);
@@ -206,8 +214,10 @@ function followView(node: HTMLElement): void {
const stop = (): void => {
window.removeEventListener("scroll", place, true);
window.removeEventListener("resize", place);
sized.disconnect();
};
window.addEventListener("scroll", place, true);
window.addEventListener("resize", place);
sized.observe(node);
setTimeout(place); // 붙은 뒤 한 번
}