mirror of https://github.com/buster-so/buster.git
chat scroll
This commit is contained in:
parent
ca90b09186
commit
8e4e423f1a
|
@ -1,11 +1,14 @@
|
|||
'use client';
|
||||
|
||||
import React from 'react';
|
||||
import React, { useEffect, useRef } from 'react';
|
||||
import { useGetChat, useGetChatMessage } from '@/api/buster_rest/chats';
|
||||
import { ReasoningMessageSelector } from './ReasoningMessages';
|
||||
import { BlackBoxMessage } from './ReasoningMessages/ReasoningBlackBoxMessage';
|
||||
import { FileIndeterminateLoader } from '@/components/features/FileIndeterminateLoader';
|
||||
import { ScrollArea } from '@/components/ui/scroll-area';
|
||||
import { useAutoScroll } from '@/hooks/useAutoScroll';
|
||||
import isEmpty from 'lodash/isEmpty';
|
||||
import { ReasoningScrollToBottom } from './ReasoningScrollToBottom';
|
||||
|
||||
interface ReasoningControllerProps {
|
||||
chatId: string;
|
||||
|
@ -16,24 +19,43 @@ export const ReasoningController: React.FC<ReasoningControllerProps> = ({ chatId
|
|||
const { data: hasChat } = useGetChat({ id: chatId || '' }, (x) => !!x.id);
|
||||
const reasoningMessageIds = useGetChatMessage(messageId, (x) => x?.reasoning_message_ids);
|
||||
const isCompletedStream = useGetChatMessage(messageId, (x) => x?.isCompletedStream);
|
||||
const viewportRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
const { isAutoScrollEnabled, scrollToBottom, enableAutoScroll } = useAutoScroll(viewportRef, {
|
||||
observeSubTree: true,
|
||||
enabled: false
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
if (hasChat && reasoningMessageIds) {
|
||||
enableAutoScroll();
|
||||
}
|
||||
}, [hasChat, isEmpty(reasoningMessageIds)]);
|
||||
|
||||
if (!hasChat || !reasoningMessageIds) return <FileIndeterminateLoader />;
|
||||
|
||||
return (
|
||||
<ScrollArea>
|
||||
<div className="h-full flex-col space-y-2 overflow-y-auto p-5">
|
||||
{reasoningMessageIds?.map((reasoningMessageId) => (
|
||||
<ReasoningMessageSelector
|
||||
key={reasoningMessageId}
|
||||
reasoningMessageId={reasoningMessageId}
|
||||
isCompletedStream={isCompletedStream ?? true}
|
||||
chatId={chatId}
|
||||
messageId={messageId}
|
||||
/>
|
||||
))}
|
||||
<>
|
||||
<ScrollArea viewportRef={viewportRef}>
|
||||
<div className="h-full flex-col space-y-2 overflow-y-auto p-5">
|
||||
{reasoningMessageIds?.map((reasoningMessageId) => (
|
||||
<ReasoningMessageSelector
|
||||
key={reasoningMessageId}
|
||||
reasoningMessageId={reasoningMessageId}
|
||||
isCompletedStream={isCompletedStream ?? true}
|
||||
chatId={chatId}
|
||||
messageId={messageId}
|
||||
/>
|
||||
))}
|
||||
|
||||
<BlackBoxMessage messageId={messageId} />
|
||||
</div>
|
||||
</ScrollArea>
|
||||
<BlackBoxMessage messageId={messageId} />
|
||||
</div>
|
||||
</ScrollArea>
|
||||
|
||||
<ReasoningScrollToBottom
|
||||
isAutoScrollEnabled={isAutoScrollEnabled}
|
||||
scrollToBottom={scrollToBottom}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -0,0 +1,31 @@
|
|||
import { ChevronDown } from '@/components/ui/icons';
|
||||
import { AppTooltip } from '@/components/ui/tooltip';
|
||||
import { cn } from '@/lib/classMerge';
|
||||
import React from 'react';
|
||||
|
||||
export const ReasoningScrollToBottom: React.FC<{
|
||||
isAutoScrollEnabled: boolean;
|
||||
scrollToBottom: () => void;
|
||||
}> = React.memo(({ isAutoScrollEnabled, scrollToBottom }) => {
|
||||
return (
|
||||
<div
|
||||
className={cn(
|
||||
'absolute right-4 bottom-4 z-10 duration-300',
|
||||
isAutoScrollEnabled
|
||||
? 'pointer-events-none scale-90 opacity-0'
|
||||
: 'pointer-events-auto scale-100 cursor-pointer opacity-100'
|
||||
)}>
|
||||
<AppTooltip title="Stick to bottom" sideOffset={12} delayDuration={500}>
|
||||
<button
|
||||
onClick={scrollToBottom}
|
||||
className={
|
||||
'bg-background/90 hover:bg-item-hover/90 cursor-pointer rounded-full border p-2 shadow transition-all duration-300 hover:scale-105 hover:shadow-md'
|
||||
}>
|
||||
<ChevronDown />
|
||||
</button>
|
||||
</AppTooltip>
|
||||
</div>
|
||||
);
|
||||
});
|
||||
|
||||
ReasoningScrollToBottom.displayName = 'ReasoningScrollToBottom';
|
|
@ -221,7 +221,6 @@ export const useAutoScroll = (
|
|||
// Only disable auto–scroll if we're not near the bottom.
|
||||
if (!isAtBottom(container, bottomThreshold)) {
|
||||
setIsAutoScrollEnabled(false);
|
||||
console.log('disableAutoScrollHandler', isAutoScrollEnabled, enabled);
|
||||
|
||||
// Stop any ongoing animations
|
||||
if (rAFIdRef.current) {
|
||||
|
|
|
@ -11,7 +11,7 @@ export const ChatScrollToBottom: React.FC<{
|
|||
return (
|
||||
<div
|
||||
className={cn(
|
||||
'absolute -top-9 right-3 z-10',
|
||||
'absolute -top-9 right-3 z-10 transition-all duration-300 hover:scale-105 hover:shadow-md',
|
||||
isAutoScrollEnabled
|
||||
? 'pointer-events-none scale-90 opacity-0'
|
||||
: 'pointer-events-auto scale-100 cursor-pointer opacity-100'
|
||||
|
@ -20,7 +20,7 @@ export const ChatScrollToBottom: React.FC<{
|
|||
<button
|
||||
onClick={scrollToBottom}
|
||||
className={
|
||||
'bg-background/90 hover:bg-item-hover/90 cursor-pointer rounded-full border p-2 shadow transition-all duration-300 hover:scale-105 hover:shadow-md'
|
||||
'bg-background/90 hover:bg-item-hover/90 cursor-pointer rounded-full border p-2 shadow transition-all duration-300'
|
||||
}>
|
||||
<ChevronDown />
|
||||
</button>
|
||||
|
|
Loading…
Reference in New Issue