perf(chat): hold the previous timeline while a session loads; fade only when waited

- ChatContainer swaps the timeline on a deferred copy of the selection so the
  active row, URL, and tab commit first. (This part had been overwritten by a
  concurrent edit before the previous commit and is restored here.)
- A session whose messages are not in memory keeps the previous conversation
  on screen for up to 400ms while they load, instead of flashing a skeleton
  between two conversations.
- The reveal fade runs only for a session the user waited for and is 100ms;
  a session that was ready at the click appears in the same frame.
- The sidebar prefetches the two rows on either side of the open session
  150ms after it settles, two at a time, so neighbouring switches are warm.
This commit is contained in:
Bohdan Triapitsyn
2026-08-29 17:22:31 +03:00
parent 115138f5a3
commit c2136ce838
4 changed files with 82 additions and 17 deletions
+7
View File
@@ -441,6 +441,13 @@ in a transition behind it. Selection *policy* inside `ChatContainer` (auto-
opening a draft when nothing is selected) reads the live store value, because
the deferred one still names the previous session for one commit.
A session whose messages are not in memory at the click keeps the previous
timeline on screen while they load (up to 400ms), then swaps straight to the
finished view; the skeleton appears only when loading takes longer. A session
the user waited for fades in (100ms); one that was ready appears in the same
frame. The sidebar prefetches the two rows on either side of the open session
shortly after it settles, so most neighbouring switches are warm.
The timeline's first paint for a session is atomic. `ChatContainer` owns a
`TimelineRevealGate` per session key (`components/chat/timelineRevealGate.ts`):
a markdown renderer whose first paint is provisional (blocks not yet in the