|
2 | 2 |
|
3 | 3 | import { KeyboardEvent, useEffect, useMemo, useRef, useState } from 'react' |
4 | 4 | import { ArrowUp, Loader2, Lock, Mail } from 'lucide-react' |
| 5 | +import ReactMarkdown from 'react-markdown' |
5 | 6 | import { Button } from '@/components/ui/button' |
6 | 7 | import { Input } from '@/components/ui/input' |
7 | 8 | import { OTPInputForm } from '@/components/ui/input-otp-form' |
@@ -30,6 +31,40 @@ interface ChatConfig { |
30 | 31 | authType?: 'public' | 'password' | 'email' |
31 | 32 | } |
32 | 33 |
|
| 34 | +// Markdown renderer component with proper styling |
| 35 | +function MarkdownRenderer({ content }: { content: string }) { |
| 36 | + return ( |
| 37 | + <div |
| 38 | + className="prose dark:prose-invert max-w-none |
| 39 | + text-base leading-normal |
| 40 | + text-[#0D0D0D] dark:text-gray-100 |
| 41 | + [&>*]:text-base |
| 42 | + [&>*]:leading-normal |
| 43 | + [&>p]:my-[0.35em] |
| 44 | + [&>p+p]:mt-[0.7em] |
| 45 | + [&>ul]:my-[0.35em] |
| 46 | + [&>ol]:my-[0.35em] |
| 47 | + [&>h1]:text-xl [&>h1]:font-semibold [&>h1]:mb-[0.5em] [&>h1]:mt-[0.7em] |
| 48 | + [&>h2]:text-lg [&>h2]:font-semibold [&>h2]:mb-[0.4em] [&>h2]:mt-[0.7em] |
| 49 | + [&>h3]:text-base [&>h3]:font-semibold [&>h3]:mb-[0.3em] [&>h3]:mt-[0.6em] |
| 50 | + [&>ul>li]:pl-0 [&>ol>li]:pl-0 |
| 51 | + [&>ol>li]:relative [&>ul>li]:relative |
| 52 | + [&>ul>li]:pl-5 [&>ol>li]:pl-5 |
| 53 | + [&>ul>li]:mb-[0.2em] [&>ol>li]:mb-[0.2em] |
| 54 | + [&>ul]:pl-1 [&>ol]:pl-1 |
| 55 | + [&>pre]:bg-gray-100 [&>pre]:dark:bg-gray-800 [&>pre]:p-3 [&>pre]:rounded-md [&>pre]:my-[0.7em] |
| 56 | + [&>code]:text-[0.9em] [&>code]:bg-gray-100 [&>code]:dark:bg-gray-800 [&>code]:px-1 [&>code]:py-0.5 [&>code]:rounded-md |
| 57 | + [&>p>code]:text-[0.9em] [&>p>code]:bg-gray-100 [&>p>code]:dark:bg-gray-800 [&>p>code]:px-1 [&>p>code]:py-0.5 [&>p>code]:rounded-md |
| 58 | + [&>blockquote]:border-l-4 [&>blockquote]:border-gray-200 [&>blockquote]:pl-4 [&>blockquote]:py-0.5 [&>blockquote]:my-[0.7em] [&>blockquote]:italic [&>blockquote]:text-gray-700 [&>blockquote]:dark:text-gray-300 |
| 59 | + [&>table]:border-collapse [&>table]:w-full [&>table]:my-[0.7em] |
| 60 | + [&>table>thead>tr>th]:border [&>table>thead>tr>th]:border-gray-300 [&>table>thead>tr>th]:dark:border-gray-700 [&>table>thead>tr>th]:p-2 [&>table>thead>tr>th]:bg-gray-100 [&>table>thead>tr>th]:dark:bg-gray-800 |
| 61 | + [&>table>tbody>tr>td]:border [&>table>tbody>tr>td]:border-gray-300 [&>table>tbody>tr>td]:dark:border-gray-700 [&>table>tbody>tr>td]:p-2" |
| 62 | + > |
| 63 | + <ReactMarkdown>{content}</ReactMarkdown> |
| 64 | + </div> |
| 65 | + ) |
| 66 | +} |
| 67 | + |
33 | 68 | // ChatGPT-style message component |
34 | 69 | function ClientChatMessage({ message }: { message: ChatMessage }) { |
35 | 70 | // Check if content is a JSON object |
@@ -68,7 +103,7 @@ function ClientChatMessage({ message }: { message: ChatMessage }) { |
68 | 103 | {isJsonObject ? ( |
69 | 104 | <pre>{JSON.stringify(message.content, null, 2)}</pre> |
70 | 105 | ) : ( |
71 | | - <span>{message.content}</span> |
| 106 | + <MarkdownRenderer content={message.content as string} /> |
72 | 107 | )} |
73 | 108 | </div> |
74 | 109 | </div> |
|
0 commit comments