Scrolling up through a thread now rests the composer on one line (when Settings → Collapse composer on scroll is on, as it is by default in T3 Code); the scroll used to be swallowed by the list. The resting composer shows its line in full, and the jump back down is T3's "Scroll to end" pill. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Showing 1 changed file with 17 additions and 9 deletions.
| @@ -204,6 +204,8 @@ pub struct ChatView { | ||
| 204 | 204 | folded: std::cell::Cell<(bool, bool)>, |
| 205 | 205 | /// The composer rests on one line while the conversation scrolls. |
| 206 | 206 | collapsed: bool, |
| 207 | + /// Whether the conversation was scrolled away from its end last frame. | |
| 208 | + was_scrolled_up: bool, | |
| 207 | 209 | _subscriptions: Vec<Subscription>, |
| 208 | 210 | _ticker: Task<()>, |
| 209 | 211 | } |
| @@ -331,6 +333,7 @@ impl ChatView { | ||
| 331 | 333 | setup_details: false, |
| 332 | 334 | folded: Default::default(), |
| 333 | 335 | collapsed: false, |
| 336 | + was_scrolled_up: false, | |
| 334 | 337 | _subscriptions: subscriptions, |
| 335 | 338 | _ticker: ticker, |
| 336 | 339 | }; |
| @@ -1414,18 +1417,12 @@ impl ChatView { | ||
| 1414 | 1417 | .flex() |
| 1415 | 1418 | .flex_col() |
| 1416 | 1419 | // Scrolling rests the composer, when set to. |
| 1417 | - .on_scroll_wheel(cx.listener(|this, _, _, cx| { | |
| 1418 | - let empty = this.composer.read(cx).value().is_empty() && this.attachments.is_empty(); | |
| 1419 | - if !this.collapsed && empty && settings::get(|settings| settings.collapse_composer) { | |
| 1420 | - this.collapsed = true; | |
| 1421 | - cx.notify(); | |
| 1422 | - } | |
| 1423 | - })) | |
| 1424 | 1420 | .child( |
| 1425 | 1421 | MessageScroller::new("transcript", self.scroller.clone(), move |ix, window, cx| { |
| 1426 | 1422 | timeline::render_item(&session, &scroller, &chat, ix, window, cx) |
| 1427 | 1423 | }) |
| 1428 | 1424 | .with_jump_button_label("Scroll to end") |
| 1425 | + .with_jump_button_renderer(|button| button.icon(IconName::ChevronDown).label("Scroll to end")) | |
| 1429 | 1426 | .flex_1() |
| 1430 | 1427 | .w_full() |
| 1431 | 1428 | .with_row_style(StyleRefinement::default().pb_0()) |
| @@ -1686,10 +1683,11 @@ impl ChatView { | ||
| 1686 | 1683 | .size_full() |
| 1687 | 1684 | }; |
| 1688 | 1685 | |
| 1686 | + let rows = if collapsed { (1, 1) } else if approval { (2, 9) } else { (3, 9) }; | |
| 1689 | 1687 | let textarea = div() |
| 1690 | 1688 | .text_size(px(14.)) |
| 1691 | 1689 | .text_color(p.ink) |
| 1692 | - .child(MarkdownInput::new(&self.composer).rows(if approval { 2 } else { 3 }, 9)); | |
| 1690 | + .child(MarkdownInput::new(&self.composer).rows(rows.0, rows.1)); | |
| 1693 | 1691 | let card = if collapsed { |
| 1694 | 1692 | // Resting: one line, a click (or typing) away from the full composer. |
| 1695 | 1693 | h_flex() |
| @@ -1709,7 +1707,7 @@ impl ChatView { | ||
| 1709 | 1707 | this.focus_composer(window, cx); |
| 1710 | 1708 | })) |
| 1711 | 1709 | .child(measure) |
| 1712 | - .child(textarea.flex_1().min_w_0().h(px(22.)).overflow_hidden()) | |
| 1710 | + .child(textarea.flex_1().min_w_0().overflow_hidden()) | |
| 1713 | 1711 | .child(self.render_actions(start, cx)) |
| 1714 | 1712 | .into_any_element() |
| 1715 | 1713 | } else { |
| @@ -1871,6 +1869,16 @@ impl ChatView { | ||
| 1871 | 1869 | impl Render for ChatView { |
| 1872 | 1870 | fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement { |
| 1873 | 1871 | let is_empty = self.session.read(cx).items.is_empty(); |
| 1872 | + // Scrolling up through the conversation rests the composer, when set | |
| 1873 | + // to, as in T3 Code; a click or typing wakes it. | |
| 1874 | + let scrolled_up = self.scroller.read(cx).is_scrolled_up(); | |
| 1875 | + if scrolled_up && !self.was_scrolled_up { | |
| 1876 | + let empty = self.composer.read(cx).value().is_empty() && self.attachments.is_empty(); | |
| 1877 | + if empty && settings::get(|settings| settings.collapse_composer) { | |
| 1878 | + self.collapsed = true; | |
| 1879 | + } | |
| 1880 | + } | |
| 1881 | + self.was_scrolled_up = scrolled_up; | |
| 1874 | 1882 | let on_diff = { |
| 1875 | 1883 | let chat = cx.entity().downgrade(); |
| 1876 | 1884 | move |action: DiffAction, window: &mut Window, cx: &mut App| { |