diff --git a/Plugin/unraid/include/ai_chat.php b/Plugin/unraid/include/ai_chat.php index bace1c2..9f52705 100644 --- a/Plugin/unraid/include/ai_chat.php +++ b/Plugin/unraid/include/ai_chat.php @@ -956,12 +956,31 @@ vv_ai_profiles_script(); // panel is pinned at the bottom and the views above it are sized from what is left, so without // this the chat grows downward off the end of the panel and takes its own composer with it — // which is precisely what it did. - function toggleBig() { big = !big; applyHeights(); scroll(); onResize(big); } + // Announced twice: now, so a page that lays out around this tracks the change as it happens, + // and again once it has finished. + // + // The transcript animates its height — see the transition on .vv-ai-chat — so a page that + // measures the moment we change it reads a box that is still moving. The Scheduler sizes the + // view above from the panel's measured height, and re-measuring one frame after a collapse + // read a dock caught part of the way down: the view came out short by roughly the height the + // chat was shrinking from, leaving a dead strip under the content that nothing filled. It only + // ever showed on collapse, because on expand the same error sizes the view too large and flex + // quietly shrinks it back. + let settle = null; + function announceResize() { + onResize(big); + clearTimeout(settle); + // Comfortably past the 140ms transition. A timer rather than transitionend, which does not + // fire at all when the computed height happens not to change. + settle = setTimeout(() => onResize(big), 220); + } + + function toggleBig() { big = !big; applyHeights(); scroll(); announceResize(); } // Only meaningful while expanded, and the button is only reachable then. The shortcut has to // check for itself rather than silently changing a size nobody can see. function toggleSize() { if (!big) return; - large = !large; applyHeights(); scroll(); onResize(big); + large = !large; applyHeights(); scroll(); announceResize(); } if (growBtn) growBtn.addEventListener('click', toggleBig); @@ -990,8 +1009,10 @@ vv_ai_profiles_script(); applyKeys(open); scroll(); // The total is meant to hold, but the floor above can break that on a small placement, so - // the page is told either way rather than being left to find out by clipping. - onResize(big); + // the page is told either way rather than being left to find out by clipping. Through the + // same settle as the size controls: the list appears at once but the transcript animates + // to its new height, so an immediate measurement is of a box still moving. + announceResize(); }); } @@ -1121,6 +1142,8 @@ vv_ai_profiles_script(); }, teardown() { clearInterval(pendingTimer); + // Would otherwise fire a re-layout at a page whose instance no longer exists. + clearTimeout(settle); window.removeEventListener('error', onErr); window.removeEventListener('unhandledrejection', onRej); document.removeEventListener('click', onDocClick);