@@ -8,7 +8,108 @@ import remarkGfm from 'remark-gfm'
88import remarkBreaks from 'remark-breaks'
99import { Pre } from './Pre'
1010import { Hyperlink } from './Hyperlink'
11- import { memo } from 'react'
11+ import { memo , useState } from 'react'
12+ import { useTranslation } from 'react-i18next'
13+
14+ // eslint-disable-next-line
15+ const ThinkComponent = ( { node, children, ...props } ) => {
16+ const { t } = useTranslation ( )
17+ const [ isExpanded , setIsExpanded ] = useState ( true )
18+ const isEmpty =
19+ ! children ||
20+ ( Array . isArray ( children ) &&
21+ // eslint-disable-next-line
22+ ( children . length === 0 ||
23+ // eslint-disable-next-line
24+ ( children . length === 1 && typeof children [ 0 ] === 'string' && children [ 0 ] . trim ( ) === '' ) ) )
25+
26+ const toggleExpanded = ( ) => {
27+ setIsExpanded ( ! isExpanded )
28+ }
29+
30+ return isEmpty ? (
31+ < > </ >
32+ ) : (
33+ < div
34+ style = { {
35+ marginBottom : '16px' ,
36+ borderRadius : '12px' ,
37+ border : '1px solid #e2e8f0' ,
38+ boxShadow : '0 2px 8px rgba(0, 0, 0, 0.06)' ,
39+ overflow : 'hidden' ,
40+ transition : 'all 0.3s ease' ,
41+ } }
42+ >
43+ < div
44+ onClick = { toggleExpanded }
45+ style = { {
46+ cursor : 'pointer' ,
47+ padding : '12px 16px' ,
48+ borderBottom : isExpanded ? '1px solid rgba(255, 255, 255, 0.2)' : 'none' ,
49+ display : 'flex' ,
50+ alignItems : 'center' ,
51+ justifyContent : 'space-between' ,
52+ fontSize : '14px' ,
53+ fontWeight : '500' ,
54+ transition : 'all 0.3s ease' ,
55+ position : 'relative' ,
56+ } }
57+ >
58+ < div style = { { display : 'flex' , alignItems : 'center' , gap : '8px' } } >
59+ < span
60+ style = { {
61+ display : 'inline-block' ,
62+ width : '6px' ,
63+ height : '6px' ,
64+ borderRadius : '50%' ,
65+ animation : isExpanded ? 'pulse 2s infinite' : 'none' ,
66+ } }
67+ />
68+ < span style = { { fontSize : '13px' , letterSpacing : '0.5px' } } >
69+ 💭 { t ( 'Thinking Content' ) }
70+ </ span >
71+ </ div >
72+ < div
73+ style = { {
74+ transform : isExpanded ? 'rotate(180deg)' : 'rotate(0deg)' ,
75+ transition : 'transform 0.3s ease' ,
76+ fontSize : '12px' ,
77+ } }
78+ >
79+ ▼
80+ </ div >
81+ </ div >
82+ < div
83+ style = { {
84+ maxHeight : isExpanded ? '1000px' : '0' ,
85+ overflow : 'hidden' ,
86+ transition : 'max-height 0.4s ease, padding 0.3s ease' ,
87+ padding : isExpanded ? '16px 20px' : '0 20px' ,
88+ borderTop : isExpanded ? '1px solid #e2e8f0' : 'none' ,
89+ } }
90+ >
91+ < div
92+ style = { {
93+ whiteSpace : 'pre-wrap' ,
94+ fontSize : '13px' ,
95+ lineHeight : '1.6' ,
96+ fontFamily : '"SF Mono", "Monaco", "Inconsolata", "Roboto Mono", monospace' ,
97+ opacity : isExpanded ? 1 : 0 ,
98+ transition : 'opacity 0.3s ease 0.1s' ,
99+ } }
100+ >
101+ { children }
102+ </ div >
103+ </ div >
104+ < style > { `
105+ @keyframes pulse {
106+ 0%, 100% { opacity: 1; }
107+ 50% { opacity: 0.5; }
108+ }
109+ ` } </ style >
110+ </ div >
111+ )
112+ }
12113
13114export function MarkdownRender ( props ) {
14115 return (
@@ -73,6 +174,8 @@ export function MarkdownRender(props) {
73174 'a' ,
74175 'pre' ,
75176 'cite' ,
177+
178+ 'think' ,
76179 ] }
77180 unwrapDisallowed = { true }
78181 remarkPlugins = { [ remarkMath , remarkGfm , remarkBreaks ] }
@@ -90,10 +193,11 @@ export function MarkdownRender(props) {
90193 components = { {
91194 a : Hyperlink ,
92195 pre : Pre ,
196+ think : ThinkComponent ,
93197 } }
94198 { ...props }
95199 >
96- { props . children }
200+ { props . children . replace ( '</think>' , '\n\n</think>\n\n' ) }
97201 </ ReactMarkdown >
98202 </ div >
99203 )
0 commit comments