perf(dialog): add render window to prevent long-conversation DOM freeze#3
Open
lingion wants to merge 15 commits into
Open
perf(dialog): add render window to prevent long-conversation DOM freeze#3lingion wants to merge 15 commits into
lingion wants to merge 15 commits into
Conversation
Long conversations (500+ messages) would freeze because all messages were rendered into the DOM with full KaTeX markdown. Three optimizations applied: 1. Render window (useMessageWindow composable): - Initial render: last 100 messages, max cap: 200 - Infinite scroll-up via IntersectionObserver sentinel - Scroll position preserved during loadMore() via height delta 2. Lazy markdown for off-screen messages: - Messages >30 positions from renderEnd render as plain text - Skips md-editor-v3 KaTeX rendering (costly per-message) - Reuses existing streaming plain-text pipeline 3. Stable keys: visible slice uses message IDs as keys so Vue doesn't remount existing items when the window shifts
…d gate - Update version in package.json and build.gradle (2.0.8.9 → 2.0.8.12) - Add v-if guards in DialogView template: msgRoute/chain access now checked for undefined before rendering message-item - Add scrollTop > 60 guard in loadMore() to prevent false triggers when soft keyboard appears and shrinks viewport
pageFhStyle sets overflow-y:auto inline on q-page. When the Android soft keyboard appears, the viewport shrinks and the q-page height decreases. The browser then scrolls the PAGE to keep the focused input visible, which drags the absolutely-positioned composer dock with it — causing it to appear to fly to the top. Fix: !important on .dialog-page overflow:hidden to beat the inline style. All scrolling is handled by the inner scrollContainer.
Root cause: WebView resize triggers pageFhStyle recalculation BEFORE Capacitor keyboardWillShow sets --sab. Two-phase jump: page height shrinks -> composer snaps, then --sab adds padding. User sees dock fly. Fix: CSS transition on padding-bottom so --sab-driven padding change animates smoothly. Revert !important overflow experiment.
Changed .dialog-composer-area from position:absolute (anchored to q-page which gets wrong height from pageFhStyle during keyboard resize) to position:fixed (anchored to viewport). This prevents the dock from flying to the top when soft keyboard opens.
With position:fixed, the viewport already shrinks above the keyboard. The --sab keyboard-height padding was designed for position:absolute (where the page keeps full height and the composer sits behind the keyboard). Adding --sab padding on a fixed composer pushed content far above the input area — this was the actual "height error." Now padding only uses env(safe-area-inset-bottom) for nav bar.
When soft keyboard opens, the browser attempts to scroll the page to keep the focused input visible. Since pageFhStyle sets overflow-y:auto on q-page, the entire page scrolls — dragging the absolutely-positioned composer dock with it, making it appear to fly to the top. Fix: overflow:hidden!important on .dialog-page to beat the inline overflow-y:auto from pageFhStyle. All scrolling is handled by the inner scrollContainer — the page itself should never scroll.
pageFhStyle calculates page height from Quasar internals which may produce wrong values during Android soft-keyboard transitions, causing the absolutely-positioned composer (bottom:0) to fly to the top. Replace with explicit height:100dvh — dynamic viewport height correctly accounts for keyboard presence on Chrome 108+.
Use adjustNothing so the WebView keeps its full height, then anchor the fixed composer with bottom: var(--sab). Convert Capacitor Android keyboard/status-bar physical-pixel heights to CSS pixels before writing safe-area variables; raw native values were roughly devicePixelRatio too large and pushed the dock almost entirely off-screen. Remove the incorrect 100dvh page override and keep pageFhStyle for the page layout.
Use keyboardDidShow instead of keyboardWillShow so the dock offset is applied after the IME reaches its final position. Keep the fixed dock above the IME using the CSS-pixel-converted keyboard inset and avoid adding the inset to the dock padding.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
Long conversations (500+ messages) freeze the entire app because all messages are rendered into the DOM simultaneously with full KaTeX markdown rendering.
Root causes addressed
Solution
1. Render window (use-message-window.ts)
2. Lazy markdown (lazyPlainText prop)
3. Stable keys
Files changed
Build
npx quasar build → Build succeeded