diff --git a/web/src/components/ui/layouts/AppPageLayout.tsx b/web/src/components/ui/layouts/AppPageLayout.tsx index 7093607e9..14fbcf408 100644 --- a/web/src/components/ui/layouts/AppPageLayout.tsx +++ b/web/src/components/ui/layouts/AppPageLayout.tsx @@ -20,6 +20,7 @@ export const AppPageLayout: React.FC< headerBorderVariant?: 'default' | 'ghost'; headerClassName?: string; mainClassName?: string; + contentContainerId?: string; }> > = ({ children, @@ -29,7 +30,8 @@ export const AppPageLayout: React.FC< headerSizeVariant = 'default', headerBorderVariant = 'default', headerClassName = '', - mainClassName = '' + mainClassName = '', + contentContainerId }) => { return (
+ scrollable={scrollable} + id={contentContainerId}> {header && scrollable && headerBorderVariant === 'ghost' && (
)} diff --git a/web/src/components/ui/layouts/AppPageLayoutContent.tsx b/web/src/components/ui/layouts/AppPageLayoutContent.tsx index 5002a2ba4..426015626 100644 --- a/web/src/components/ui/layouts/AppPageLayoutContent.tsx +++ b/web/src/components/ui/layouts/AppPageLayoutContent.tsx @@ -6,13 +6,15 @@ export const AppPageLayoutContent: React.FC< PropsWithChildren<{ className?: string; scrollable?: boolean; + id?: string; }> -> = ({ className = '', children, scrollable = true }) => { +> = ({ className = '', children, scrollable = true, id }) => { const Selector = scrollable ? ScrollArea : 'main'; const ChildSelector = scrollable ? 'main' : React.Fragment; return ( {children} diff --git a/web/src/components/ui/scroll-area/ScrollArea.tsx b/web/src/components/ui/scroll-area/ScrollArea.tsx index e2e23636a..79d0f2054 100644 --- a/web/src/components/ui/scroll-area/ScrollArea.tsx +++ b/web/src/components/ui/scroll-area/ScrollArea.tsx @@ -9,8 +9,9 @@ const ScrollArea = React.forwardRef< React.ElementRef, React.ComponentPropsWithoutRef & { viewportRef?: React.RefObject; + id?: string; } ->(({ className, children, viewportRef, ...props }, ref) => ( +>(({ className, children, viewportRef, id = 'scroll-area-viewport', ...props }, ref) => ( + id={id}> {children} diff --git a/web/src/layouts/ChatLayout/ChatContainer/ChatContainer.tsx b/web/src/layouts/ChatLayout/ChatContainer/ChatContainer.tsx index f3203be18..4fea26eac 100644 --- a/web/src/layouts/ChatLayout/ChatContainer/ChatContainer.tsx +++ b/web/src/layouts/ChatLayout/ChatContainer/ChatContainer.tsx @@ -3,9 +3,12 @@ import { ChatHeader } from './ChatHeader'; import { ChatContent } from './ChatContent'; import { AppPageLayout } from '@/components/ui/layouts'; +export const CHAT_CONTENT_CONTAINER_ID = 'chat-container-content'; + export const ChatContainer = React.memo(() => { return ( } headerBorderVariant="ghost" scrollable diff --git a/web/src/layouts/ChatLayout/ChatContainer/ChatContent/ChatMessageBlock.tsx b/web/src/layouts/ChatLayout/ChatContainer/ChatContent/ChatMessageBlock.tsx index 1810e207f..7bef6aa20 100644 --- a/web/src/layouts/ChatLayout/ChatContainer/ChatContent/ChatMessageBlock.tsx +++ b/web/src/layouts/ChatLayout/ChatContainer/ChatContent/ChatMessageBlock.tsx @@ -1,3 +1,5 @@ +'use client'; + import React from 'react'; import { ChatUserMessage } from './ChatUserMessage'; import { ChatResponseMessages } from './ChatResponseMessages'; diff --git a/web/src/layouts/ChatLayout/ChatContainer/ChatContent/ChatScrollToBottom.tsx b/web/src/layouts/ChatLayout/ChatContainer/ChatContent/ChatScrollToBottom.tsx new file mode 100644 index 000000000..d539d899f --- /dev/null +++ b/web/src/layouts/ChatLayout/ChatContainer/ChatContent/ChatScrollToBottom.tsx @@ -0,0 +1,24 @@ +import { type useAutoScroll } from '@/hooks/useAutoScroll'; +import React from 'react'; +import { ChevronDown } from '@/components/ui/icons'; +import { cn } from '@/lib/utils'; + +export const ChatScrollToBottom: React.FC<{ + isAutoScrollEnabled: boolean; + scrollToBottom: ReturnType['scrollToBottom']; +}> = React.memo(({ isAutoScrollEnabled, scrollToBottom }) => { + return ( + + ); +}); + +ChatScrollToBottom.displayName = 'ChatScrollToBottom';