Skip to content

Commit 51cfe0f

Browse files
committed
feat: remove expander
1 parent f65ca69 commit 51cfe0f

1 file changed

Lines changed: 43 additions & 63 deletions

File tree

webapp/_webapp/src/views/chat/body/index.tsx

Lines changed: 43 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { useEffect, useMemo, useRef, useState } from "react";
1+
import { useEffect, useMemo, useRef, useState, useCallback } from "react";
22
import { MessageCard } from "../../../components/message-card";
33
import { Conversation } from "../../../pkg/gen/apiclient/chat/v2/chat_pb";
44
import {
@@ -29,7 +29,6 @@ export const ChatBody = ({ conversation }: ChatBodyProps) => {
2929
const setCurrentConversation = useConversationStore((s) => s.setCurrentConversation);
3030
const chatContainerRef = useRef<HTMLDivElement>(null);
3131
const lastUserMsgRef = useRef<HTMLDivElement>(null);
32-
const expanderRef = useRef<HTMLDivElement>(null);
3332
const [reloadSuccess, setReloadSuccess] = useState(ReloadStatus.Default);
3433

3534
const conversationMode = useSettingStore((s) => s.conversationMode);
@@ -54,42 +53,34 @@ export const ChatBody = ({ conversation }: ChatBodyProps) => {
5453
[visibleMessages]
5554
);
5655

57-
// Scroll to the top of the last user message
58-
useEffect(() => {
59-
if (expanderRef.current) {
60-
expanderRef.current.style.height = "1000px";
61-
}
62-
63-
const chatContainerHeight = chatContainerRef.current?.clientHeight ?? 0;
64-
const expanderViewOffset =
65-
(expanderRef.current?.getBoundingClientRect().top ?? 0) -
66-
(chatContainerRef.current?.getBoundingClientRect().y ?? 0);
67-
68-
let expanderHeight: number;
69-
if (expanderViewOffset < 0) {
70-
expanderHeight = 0;
71-
} else {
72-
expanderHeight = chatContainerHeight - expanderViewOffset;
73-
}
74-
75-
if (expanderRef.current) {
76-
const lastUserMsgHeight = lastUserMsgRef.current?.clientHeight ?? 0;
77-
expanderRef.current.style.height = chatContainerHeight - lastUserMsgHeight - 8 + "px";
78-
}
56+
// Get the last user message ID to track when it changes
57+
const lastUserMessageId = useMemo(() => {
58+
if (lastUserMessageIndex === -1) return null;
59+
return visibleMessages[lastUserMessageIndex]?.id ?? null;
60+
}, [visibleMessages, lastUserMessageIndex]);
61+
62+
// Scroll the last user message to the top of the viewport (container only)
63+
const scrollToLastUserMessage = useCallback(() => {
64+
if (!lastUserMsgRef.current || !chatContainerRef.current) return;
65+
66+
const container = chatContainerRef.current;
67+
const target = lastUserMsgRef.current;
68+
69+
container.scrollTo({
70+
top: target.offsetTop,
71+
behavior: "smooth",
72+
});
73+
}, []);
7974

80-
if (lastUserMsgRef.current && chatContainerRef.current) {
81-
const container = chatContainerRef.current;
82-
const target = lastUserMsgRef.current;
83-
container.scrollTo({
84-
top: target.offsetTop,
85-
behavior: "smooth",
86-
});
87-
} else {
88-
if (expanderRef.current) {
89-
expanderRef.current.style.height = (expanderHeight < 0 ? 0 : expanderHeight) + "px";
90-
}
91-
}
92-
}, [visibleMessages.length]);
75+
// Auto-scroll only when a new user message is added
76+
useEffect(() => {
77+
if (!lastUserMessageId) return;
78+
79+
// Use requestAnimationFrame to ensure DOM has updated
80+
requestAnimationFrame(() => {
81+
scrollToLastUserMessage();
82+
});
83+
}, [lastUserMessageId, scrollToLastUserMessage]);
9384

9485
// Render all messages using the unified DisplayMessage array
9586
const messageCards = useMemo(
@@ -119,38 +110,20 @@ export const ChatBody = ({ conversation }: ChatBodyProps) => {
119110
return <EmptyView />;
120111
}
121112

122-
const expander = (
123-
<div
124-
style={{
125-
height: "0px",
126-
backgroundColor: "transparent",
127-
position: "absolute",
128-
top: 0,
129-
left: 0,
130-
right: 0,
131-
zIndex: 0,
132-
pointerEvents: "none",
133-
}}
134-
aria-hidden="true"
135-
id="expander"
136-
ref={expanderRef}
137-
/>
138-
);
139-
140113
return (
141114
<div className="pd-app-tab-content-body" id="pd-chat-item-container" ref={chatContainerRef}>
142-
<div id="pd-chat-item-container-messages" style={{ zIndex: 3 }}>
115+
{/* Spacer that pushes content down and provides scroll space for last user message */}
116+
<div className="flex-1 min-h-0" aria-hidden="true" />
117+
118+
<div id="pd-chat-item-container-messages">
143119
{messageCards}
144120
</div>
145121

146-
<div id="pd-chat-item-container-status" style={{ position: "relative" }}>
147-
<div id="pd-chat-item-container-status-indicator" style={{ position: "relative", zIndex: 2 }}>
148-
<StatusIndicator conversation={conversation} />
149-
</div>
150-
151-
{expander}
122+
<div id="pd-chat-item-container-status" className="relative">
123+
<StatusIndicator conversation={conversation} />
124+
152125
{isDebugMode && (
153-
<div className="text-xs text-gray-300 z-1 noselect">
126+
<div className="text-xs text-gray-300 noselect">
154127
<span>* Debug mode is enabled, </span>
155128
<span
156129
className={`${reloadSuccess ? "text-emerald-300" : "text-gray-300"} underline cursor-pointer rnd-cancel`}
@@ -178,6 +151,13 @@ export const ChatBody = ({ conversation }: ChatBodyProps) => {
178151
</div>
179152
)}
180153
</div>
154+
155+
{/* Bottom spacer to allow scrolling the last user message to the top */}
156+
<div
157+
className="flex-shrink-0"
158+
style={{ minHeight: "calc(100% - 80px)" }}
159+
aria-hidden="true"
160+
/>
181161
</div>
182162
);
183163
};

0 commit comments

Comments
 (0)