feat: монорепо миграция, Discover/SearxNG улучшения
- Миграция на монорепозиторий (apps/frontend, apps/chat-service, etc.) - Discover: проверка SearxNG, понятное empty state при ненастроенном поиске - searxng.ts: валидация URL, проверка JSON-ответа, авто-добавление http:// - docker/searxng-config: настройки для JSON API SearxNG Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
108
apps/frontend/src/components/Chat.tsx
Normal file
108
apps/frontend/src/components/Chat.tsx
Normal file
@@ -0,0 +1,108 @@
|
||||
'use client';
|
||||
|
||||
import { Fragment, useEffect, useRef, useState } from 'react';
|
||||
import MessageInput from './MessageInput';
|
||||
import MessageBox from './MessageBox';
|
||||
import MessageBoxLoading from './MessageBoxLoading';
|
||||
import { useChat } from '@/lib/hooks/useChat';
|
||||
|
||||
const Chat = () => {
|
||||
const { sections, loading, messageAppeared, messages } = useChat();
|
||||
|
||||
const [dividerWidth, setDividerWidth] = useState(0);
|
||||
const dividerRef = useRef<HTMLDivElement | null>(null);
|
||||
const messageEnd = useRef<HTMLDivElement | null>(null);
|
||||
const lastScrolledRef = useRef<number>(0);
|
||||
|
||||
useEffect(() => {
|
||||
const updateDividerWidth = () => {
|
||||
if (dividerRef.current) {
|
||||
setDividerWidth(dividerRef.current.offsetWidth);
|
||||
}
|
||||
};
|
||||
|
||||
updateDividerWidth();
|
||||
|
||||
const resizeObserver = new ResizeObserver(() => {
|
||||
updateDividerWidth();
|
||||
});
|
||||
|
||||
const currentRef = dividerRef.current;
|
||||
if (currentRef) {
|
||||
resizeObserver.observe(currentRef);
|
||||
}
|
||||
|
||||
window.addEventListener('resize', updateDividerWidth);
|
||||
|
||||
return () => {
|
||||
if (currentRef) {
|
||||
resizeObserver.unobserve(currentRef);
|
||||
}
|
||||
resizeObserver.disconnect();
|
||||
window.removeEventListener('resize', updateDividerWidth);
|
||||
};
|
||||
}, [sections.length]);
|
||||
|
||||
useEffect(() => {
|
||||
const scroll = () => {
|
||||
messageEnd.current?.scrollIntoView({ behavior: 'auto' });
|
||||
};
|
||||
|
||||
if (messages.length === 1) {
|
||||
document.title = `${messages[0].query.substring(0, 30)} - GooSeek`;
|
||||
}
|
||||
|
||||
if (sections.length > lastScrolledRef.current) {
|
||||
scroll();
|
||||
lastScrolledRef.current = sections.length;
|
||||
}
|
||||
}, [messages]);
|
||||
|
||||
return (
|
||||
<div className="flex flex-col space-y-6 pt-8 pb-44 lg:pb-28 sm:mx-4 md:mx-8">
|
||||
{sections.map((section, i) => {
|
||||
const isLast = i === sections.length - 1;
|
||||
|
||||
return (
|
||||
<Fragment key={section.message.messageId}>
|
||||
<MessageBox
|
||||
section={section}
|
||||
sectionIndex={i}
|
||||
dividerRef={isLast ? dividerRef : undefined}
|
||||
isLast={isLast}
|
||||
/>
|
||||
{!isLast && (
|
||||
<div className="h-px w-full bg-light-secondary dark:bg-dark-secondary" />
|
||||
)}
|
||||
</Fragment>
|
||||
);
|
||||
})}
|
||||
{loading && !messageAppeared && <MessageBoxLoading />}
|
||||
<div ref={messageEnd} className="h-0" />
|
||||
{dividerWidth > 0 && (
|
||||
<div
|
||||
className="fixed z-40 bottom-24 lg:bottom-6"
|
||||
style={{ width: dividerWidth }}
|
||||
>
|
||||
<div
|
||||
className="pointer-events-none absolute -bottom-6 left-0 right-0 h-[calc(100%+24px+24px)] dark:hidden"
|
||||
style={{
|
||||
background:
|
||||
'linear-gradient(to top, #ffffff 0%, #ffffff 35%, rgba(255,255,255,0.95) 45%, rgba(255,255,255,0.85) 55%, rgba(255,255,255,0.7) 65%, rgba(255,255,255,0.5) 75%, rgba(255,255,255,0.3) 85%, rgba(255,255,255,0.1) 92%, transparent 100%)',
|
||||
}}
|
||||
/>
|
||||
<div
|
||||
className="pointer-events-none absolute -bottom-6 left-0 right-0 h-[calc(100%+24px+24px)] hidden dark:block"
|
||||
style={{
|
||||
background:
|
||||
'linear-gradient(to top, #0d1117 0%, #0d1117 35%, rgba(13,17,23,0.95) 45%, rgba(13,17,23,0.85) 55%, rgba(13,17,23,0.7) 65%, rgba(13,17,23,0.5) 75%, rgba(13,17,23,0.3) 85%, rgba(13,17,23,0.1) 92%, transparent 100%)',
|
||||
}}
|
||||
/>
|
||||
<MessageInput />
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default Chat;
|
||||
Reference in New Issue
Block a user