mirror of
https://github.com/SamyRai/turash.git
synced 2025-12-26 23:01:33 +00:00
- Remove nested git repository from bugulma/frontend/.git - Add all frontend files to main repository tracking - Convert from separate frontend/backend repos to unified monorepo - Preserve all frontend code and development history as tracked files - Eliminate nested repository complexity for simpler development workflow This creates a proper monorepo structure with frontend and backend coexisting in the same repository for easier development and deployment.
73 lines
2.6 KiB
TypeScript
73 lines
2.6 KiB
TypeScript
import React from 'react';
|
|
import { ChatMessage } from '@/types.ts';
|
|
import { useTranslation } from '@/hooks/useI18n.tsx';
|
|
import TypingIndicator from '@/components/chatbot/TypingIndicator.tsx';
|
|
import MarkdownRenderer from '@/components/chatbot/MarkdownRenderer.tsx';
|
|
import Button from '@/components/ui/Button.tsx';
|
|
import { Check, Copy } from 'lucide-react';
|
|
|
|
interface ChatHistoryProps {
|
|
messages: ChatMessage[];
|
|
messagesEndRef: React.RefObject<HTMLDivElement>;
|
|
copiedText: string | null;
|
|
onCopy: (text: string) => void;
|
|
}
|
|
|
|
const ChatHistory = ({ messages, messagesEndRef, copiedText, onCopy }: ChatHistoryProps) => {
|
|
const { t } = useTranslation();
|
|
|
|
return (
|
|
<div className="flex-1 p-4 overflow-y-auto space-y-4">
|
|
{messages.map((msg) => (
|
|
<div
|
|
key={msg.id}
|
|
className={`flex items-end gap-2 group ${msg.role === 'user' ? 'justify-end' : ''}`}
|
|
>
|
|
{msg.role === 'model' && (
|
|
<div className="h-8 w-8 rounded-full bg-primary text-primary-foreground flex items-center justify-center font-bold text-sm shrink-0 self-start">
|
|
{t('chatbot.aiAcronym')}
|
|
</div>
|
|
)}
|
|
<div
|
|
className={`max-w-[calc(100%-3rem)] p-3 rounded-2xl ${msg.role === 'user' ? 'bg-primary text-primary-foreground rounded-br-none' : 'bg-muted rounded-bl-none'}`}
|
|
>
|
|
{msg.imageUrl && (
|
|
<div className="mb-2 rounded-lg overflow-hidden border">
|
|
<img
|
|
src={msg.imageUrl}
|
|
alt="Chat image"
|
|
className="max-w-full h-auto"
|
|
loading="lazy"
|
|
decoding="async"
|
|
onError={(e) => {
|
|
(e.target as HTMLImageElement).style.display = 'none';
|
|
}}
|
|
/>
|
|
</div>
|
|
)}
|
|
{msg.isLoading ? <TypingIndicator /> : <MarkdownRenderer text={msg.text} />}
|
|
</div>
|
|
{msg.role === 'model' && !msg.isLoading && msg.text && (
|
|
<Button
|
|
variant="ghost"
|
|
size="sm"
|
|
className="p-1.5 h-7 w-7 opacity-0 group-hover:opacity-100 transition-opacity"
|
|
onClick={() => onCopy(msg.text)}
|
|
aria-label={t('chatbot.copyLabel')}
|
|
>
|
|
{copiedText === msg.text ? (
|
|
<Check className="h-4 text-current text-success w-4" />
|
|
) : (
|
|
<Copy className="h-4 text-current w-4" />
|
|
)}
|
|
</Button>
|
|
)}
|
|
</div>
|
|
))}
|
|
<div ref={messagesEndRef} />
|
|
</div>
|
|
);
|
|
};
|
|
|
|
export default React.memo(ChatHistory);
|