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';