Spaces:
Sleeping
Sleeping
File size: 3,407 Bytes
037dc25 760b33c 60f8c0d 037dc25 d76cdcf 60f8c0d 037dc25 d76cdcf 60f8c0d 037dc25 60f8c0d d76cdcf 60f8c0d d76cdcf 037dc25 60f8c0d 037dc25 760b33c 037dc25 760b33c 037dc25 760b33c 037dc25 760b33c 037dc25 760b33c 037dc25 760b33c 037dc25 760b33c 037dc25 760b33c 037dc25 760b33c 037dc25 760b33c 60f8c0d |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 |
// web/src/components/Message.tsx
import React from "react";
import ReactMarkdown from "react-markdown";
import remarkGfm from "remark-gfm";
import type { Message as MessageType, LearningMode } from "../App";
interface MessageProps {
message: MessageType;
// existing props you are already passing in ChatArea
showSenderInfo?: boolean;
userId?: string;
isLoggedIn: boolean;
learningMode: LearningMode;
docType?: string;
lastUserText?: string;
}
export function Message({
message,
showSenderInfo,
userId,
isLoggedIn,
learningMode,
docType,
lastUserText,
}: MessageProps) {
const isUser = message.role === "user";
// If you already have avatar / sender rendering logic, keep it.
// The only critical change is content rendering below.
return (
<div className={`flex gap-3 ${isUser ? "justify-end" : "justify-start"}`}>
{!isUser && (
<div className="w-8 h-8 rounded-full bg-gradient-to-br from-purple-500 to-blue-500 flex items-center justify-center flex-shrink-0">
<span className="text-white text-sm">C</span>
</div>
)}
<div className={`max-w-[85%] ${isUser ? "text-right" : "text-left"}`}>
{/* Optional sender info (group mode) */}
{showSenderInfo && message.sender && !isUser && (
<div className="text-xs text-muted-foreground mb-1">
{message.sender.name}
</div>
)}
<div
className={[
"rounded-2xl px-4 py-3 border",
isUser
? "bg-primary text-primary-foreground border-primary/20"
: "bg-muted text-foreground border-border",
].join(" ")}
>
{/* ✅ THE FIX: render markdown instead of plain text */}
<ReactMarkdown
remarkPlugins={[remarkGfm]}
className={[
// prose improves markdown typography; max-w-none prevents narrow column
"prose prose-sm max-w-none",
// keep readable in chat bubble
"prose-p:my-2 prose-li:my-1 prose-ul:my-2 prose-ol:my-2",
// make headings not too large inside bubble
"prose-h1:text-base prose-h2:text-base prose-h3:text-sm",
// avoid code blocks overflowing
"prose-pre:overflow-x-auto",
// inherit bubble colors
isUser ? "prose-invert" : "",
].join(" ")}
>
{message.content || ""}
</ReactMarkdown>
{/* If you already render references, keep your original block here */}
{message.references && message.references.length > 0 && (
<div className="mt-3 pt-3 border-t border-border/50 text-xs text-muted-foreground space-y-1">
<div className="font-medium">References</div>
{message.references.map((r, idx) => (
<div key={idx} className="truncate">
{r}
</div>
))}
</div>
)}
{/* If you already have feedback buttons inside Message, keep them here.
Do not change logic—only keep UI. */}
</div>
</div>
{isUser && (
<div className="w-8 h-8 rounded-full bg-primary flex items-center justify-center flex-shrink-0">
<span className="text-primary-foreground text-sm">U</span>
</div>
)}
</div>
);
}
|