Repository navigation
Conversation
Clicking a message-content search result re-opens the topic, which turns bottom-follow back on, then scrolls the hit into view 100ms later. In a long topic the content-visibility messages the smooth scroll passes grow, the follow ResizeObserver sees a taller list and pulls the view back to the bottom, so the hit is never shown. Follow currently only turns off on user input (wheel up, touch, scrollbar drag), and a programmatic jump has no way to say "I am leaving the bottom on purpose". ui-helpers.js gains releaseChatScrollFollow(): it bumps the scroll generation, cancels any queued bottom scroll and turns follow off. Reaching the bottom again re-enables follow exactly as before. searchManager calls it right before scrollIntoView. Follow flips are now funnelled through one setter that dispatches `vcp-chat-follow-change` (exported as CHAT_FOLLOW_CHANGE_EVENT) on the scroll container, so UI that depends on follow state can subscribe instead of re-deriving it from geometry. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A thin rail on the left of the main chat with one short bar per user question. Hovering a bar magnifies it and its neighbours and shows a card with the question and the start of the answer; clicking jumps to that turn. The rail hides when the chat column is narrower than 864px instead of squeezing in next to the messages; it also hides when the topic has fewer than two questions. Idle bars are 8px; hovered ones magnify to about 31 / 20 / 15px. Settings > 界面与外观 gains 显示提问导航条 (enableTurnNavigator, on by default). Turning it off disposes the navigator with all its observers; renderer.js mounts or disposes it on global-settings-updated, which fires after settings load and save. Plain DOM plus styles/ui-system/turn-navigator.css. Entries come straight from the message DOM: each .message-item.user is one turn. The rail mounts under <main>, so it carries .vcp-ui-scope itself and takes its colours from the vcp-ui tokens; its pointer-driven bar scale and measured offsets are allowlisted in check-ui-system.mjs. A jump that lands away from the bottom first calls releaseChatScrollFollow() (passed in as releaseFollow), otherwise the content-visibility messages that grow while the smooth scroll passes them let bottom-follow pull the view back. Jumps farther than 1.5 viewports land at once and only nearby ones animate. After landing, a ResizeObserver on the message list keeps the question at its position before each paint. That stops when the view has been still for 1.2s or on user wheel, touch, pointer or key input. Long topics stay cheap. The active bar is found by binary search over the questions, which sit in DOM order (O(log n) rects per frame; a test checks it against the linear reference). Bars are reused by key while older history batches prepend, and only bars whose state changed are restyled. In the app's renderer, on 3000 synthetic messages, refresh went from 262ms to 13ms and the cost per history batch from 619ms to 23ms. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Once the reader leaves the bottom of a long conversation there is no
quick way back to the latest message. A small round arrow-down button
now sits centred 8px above the input card whenever bottom-follow is off
and the topic has messages; clicking it re-enables follow and scrolls to
the bottom.
28px outlined circle, 16px arrow, shown when follow is off and the topic has messages. The button does not
measure scroll geometry itself; it listens for the
`vcp-chat-follow-change` event from ui-helpers.js and calls
resetChatScrollFollow() + scrollToBottom({ force: true }), so follow
state keeps a single owner.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The message list used to stop at the top of the input area, so the scrollbar ended there too. The scroller now runs to the bottom of the window and the input area floats over its last stretch. chat-composer-inset.js measures the input area with a ResizeObserver and publishes its height (and the scrollbar width) as CSS variables on <main>, then adds .vcp-chat-composer-overlay. chat-composer-inset.css lays the input area over the scroller, pads the scroller by the composer height plus a 20px fade, and masks the messages out behind the composer with a short fade above it. The scrollbar column is left unmasked. Without the script the layout is unchanged. When the composer grows (multi-line input) a view that follows the bottom stays pinned; a reader scrolled up is left where they are. The turn navigator now treats the padded stretch as outside the viewport. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Contributor
Author
|
Folded into #225 as its fourth commit. |
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.
Summary
The message list used to stop at the top of the input area, so the scrollbar ended there too. Now the scroller runs to the bottom of the window and the input area floats over its last stretch.
chat-composer-inset.jsmeasures the input area with a ResizeObserver. It publishes the composer height and the scrollbar width as CSS variables on<main>and adds.vcp-chat-composer-overlay.chat-composer-inset.cssdoes three things:The scrollbar column stays unmasked, so it reaches the bottom of the window.
Without the script the layout is unchanged.
When the composer grows (multi-line input), a view that follows the bottom stays pinned. A reader who has scrolled up stays where they are.
The turn navigator from feat(chat): turn navigator, back-to-bottom button and scroller under the composer #225 treats the padded stretch as outside the viewport, so the active bar matches what is visible above the composer.
Test plan
node --test tests/chat-composer-inset.test.mjsplus the feat(chat): turn navigator, back-to-bottom button and scroller under the composer #225 suites: 65 passupstream/mainat8d9a8656: no new failures. Same known failures onmainas listed in feat(chat): turn navigator, back-to-bottom button and scroller under the composer #225.main(after style(shell): 收紧外壳、侧栏与输入框样式(修正版) #224): composer growth, scrollbar reaching the window bottom, back-to-bottom button placement, dark theme.🤖 Generated with Claude Code