|
|
@@ -1564,9 +1564,16 @@ final class DashboardView: NSView, NSTextFieldDelegate {
|
|
1564
|
1564
|
}
|
|
1565
|
1565
|
DispatchQueue.main.async { [weak self] in
|
|
1566
|
1566
|
guard let self else { return }
|
|
|
1567
|
+ let scroll: () -> Void = {
|
|
|
1568
|
+ if isUser {
|
|
|
1569
|
+ self.scrollChatToBottom()
|
|
|
1570
|
+ } else {
|
|
|
1571
|
+ self.scrollChatToShowTopOfView(host)
|
|
|
1572
|
+ }
|
|
|
1573
|
+ }
|
|
1567
|
1574
|
if self.prefersReducedMotion {
|
|
1568
|
1575
|
self.updateChatBubbleWidths()
|
|
1569
|
|
- self.scrollChatToBottom()
|
|
|
1576
|
+ scroll()
|
|
1570
|
1577
|
return
|
|
1571
|
1578
|
}
|
|
1572
|
1579
|
NSAnimationContext.runAnimationGroup { ctx in
|
|
|
@@ -1575,7 +1582,7 @@ final class DashboardView: NSView, NSTextFieldDelegate {
|
|
1575
|
1582
|
host.animator().alphaValue = 1
|
|
1576
|
1583
|
}
|
|
1577
|
1584
|
self.updateChatBubbleWidths()
|
|
1578
|
|
- self.scrollChatToBottom()
|
|
|
1585
|
+ scroll()
|
|
1579
|
1586
|
}
|
|
1580
|
1587
|
}
|
|
1581
|
1588
|
|
|
|
@@ -1746,6 +1753,24 @@ final class DashboardView: NSView, NSTextFieldDelegate {
|
|
1746
|
1753
|
chatScrollView.reflectScrolledClipView(chatScrollView.contentView)
|
|
1747
|
1754
|
}
|
|
1748
|
1755
|
|
|
|
1756
|
+ /// Scrolls so the top of `view` sits at the top of the chat clip (flipped document coords). Long assistant replies stay readable from the first line instead of jumping to the end.
|
|
|
1757
|
+ private func scrollChatToShowTopOfView(_ view: NSView) {
|
|
|
1758
|
+ chatDocumentView.layoutSubtreeIfNeeded()
|
|
|
1759
|
+ view.layoutSubtreeIfNeeded()
|
|
|
1760
|
+ let doc = chatDocumentView
|
|
|
1761
|
+ let visibleHeight = chatScrollView.contentView.bounds.height
|
|
|
1762
|
+ let docHeight = doc.bounds.height
|
|
|
1763
|
+ guard docHeight > 0, visibleHeight > 0 else {
|
|
|
1764
|
+ scrollChatToBottom()
|
|
|
1765
|
+ return
|
|
|
1766
|
+ }
|
|
|
1767
|
+ let rectInDoc = view.convert(view.bounds, to: doc)
|
|
|
1768
|
+ let maxY = max(0, docHeight - visibleHeight)
|
|
|
1769
|
+ let targetY = min(max(0, rectInDoc.minY), maxY)
|
|
|
1770
|
+ chatScrollView.contentView.scroll(to: NSPoint(x: 0, y: targetY))
|
|
|
1771
|
+ chatScrollView.reflectScrolledClipView(chatScrollView.contentView)
|
|
|
1772
|
+ }
|
|
|
1773
|
+
|
|
1749
|
1774
|
private func addInlineChatThinkingRow() {
|
|
1750
|
1775
|
removeInlineChatThinkingRow()
|
|
1751
|
1776
|
let host = NSView()
|